Advertisements
Posted by: jsonmez | November 9, 2010

Back to Basics: Cohesion and Coupling Part 2

This post is a continuation of my post on cohesion and coupling, it is part of a series of back to basics posts examining and questioning some of the core principles and practices of software development.

In my last post I talked about what cohesion and coupling are and I talked about some of the benefits of each.

Now I want to take a look at the actual application of cohesion and decoupling on software systems.

Granularity affects cohesion and coupling

Here is the key misunderstanding with cohesion and decoupling.

Cohesion and decoupling are completely relative to the granularity of what is a module.

MARBLES

From here on out, I won’t say class or software or system, I am going to say module when referring to cohesion and coupling.

See, the problem is that we need to be able to define what a module is in order to determine if something is loosely coupled or highly cohesive.

Let me give you an example.  Let’s take that linked list class we talked about above.  If we define a module to be any class in our code, then it is pretty decoupled.  But, if we define a module to be any class or primitive type in the system, suddenly our linked list implementation is going to be dependent on many other things.  Now all the variables we declare in our class are dependencies on things like the Array and the String class or integer implementations.

When we zoom deep down into the above level of what a module is we end up with many more dependencies which represent tighter coupling.

What about cohesion?  Consider if you will, Enterprise FizzBuzz.  This is an implementation of the FizzBuzz problem:

  • Print the numbers from 1 to 100
  • If the number is divisible by 3 print “Fizz” instead
  • If the number is divisible by 5 print “Buzz” instead
  • If the number is divisible 3 and 5 print “FizzBuzz” instead

It is an implementation of this simple problem using 3 assemblies and 16+ classes.  If we consider a module to be a class, it is not very cohesive at all, since the responsibilities of what should be in a single method or two are spread out across 16.  If we consider a module to be an assembly, it still isn’t very cohesive.

We have to zoom all the way out to the module is a program level before this software becomes cohesive, but at that level it is very coupled to all the the various other frameworks that it depends on.

There are two important takeaways from this section:

  1. How we define a module when looking at software affects cohesion and coupling.
  2. The granularity we use to build the software affects cohesion and coupling.  (This one was hidden in the enterprise FizzBuzz example.  In this case the author of the code defined a responsibility to be something very very small.)

To summarize, we can look at code from different levels of zooming in and out and determine its coupling and cohesiveness.  We can also build software as different size “Lego blocks” which has the same effect.

When cohesion and coupling are inversely related

With that background, we can finally answer the question of whether or not it is possible to achieve high cohesion and loose coupling.

The answer is “to a degree.”

If we try to push too far into the loose coupling zone, we will find that we end up making our definition of a responsibility very very small at which point we lose the quality of cohesion.

I’m going to pick on overuse of interfaces again to give you an example.

Consider what happens when we create an interface to “reduce coupling” so that we can create unit tests.  We end up decreasing cohesion because the class our class was referencing (one jump), now is an interface which is implemented by a class (two jumps.)

Now consider what happens when we add a dependency injection module or even just a factory to get the implementation.  Our once simple and highly cohesive implementation is spread out across an interface which is implemented by a class that we have to look up in a factory which contains some sort of a mapping file to map the interface to the implementation. (3-4 jumps.)

I know this concept seems very strange, but let me see if I can explain it with a real world example.

Consider again the highly cohesive baseball.  It’s already at the optimum coupling of 0.  It doesn’t depend on anything else.  But, if we wanted to we could try to decouple it.  How?  We have to zoom in to a point where we could consider that the outer stitching is coupled to the casing which is coupled to the inner ball.

We could decouple that baseball by taking it apart and design some kind of interface which allows for different kinds of binding mechanisms for the outer shell and some kind of substrate to prevent the outer shell from directly touching the inner ball.

If we did that we’d have pieces of the ball lying all over the place and it wouldn’t be very cohesive or even functional.

We can do that exact thing with software.  There is a point where we have achieved the maximum qualities of loose coupling and high cohesion, and we can try to push decoupling at the cost of cohesion.

Cohesion is more important

It probably appears that I am saying that cohesion is more important than decoupling, and actually I am.

Why?

If you remember the advantages of tight cohesion and loose coupling, you might have realized that most of the advantages are the same except tight cohesion gives us the benefit of increased understanding.

I tend to value understanding and simplicity in software above most other things, because they aid the most in maintenance and debugging.

It is very important that we consider cohesion when we seek to increase decoupling.  It also can help give us a very clear measure of when we have maximized decoupling.  At the point where any more decoupling will harm cohesion, we are done.

So is dependency injection bad?

No, not at all.  Dependency injection and other methods of decoupling have their places, but it is very important that we don’t just blindly use them for every class in every situation.

We have to be conscious of what we are losing in cohesion and understandability when we consider using any kind of framework or pattern to decouple our software.

I’ll pick on one more thing here, since I think it is not very obvious.  Consider how good a message bus can be for integrating different applications together.  Messaging systems can decouple the different applications that need to communicate with each other making them highly cohesive and very loosely coupled.

Now, consider how bad a message bus can be inside of an application.  I know it is a fairly popular solution for decoupling events, commands, and other communication within an application, but many times the cost of the decoupling is a very high hit to cohesion and understandability.

Don’t get me wrong, sometimes an internal message bus is a good solution for an application, but in many cases it is going to hurt you more than help you.

It’s all about right sized Lego blocks

Scott Hanselman often likes to talk about “right sized Lego blocks”, and I agree with him 100%.  Figuring out how to appropriately decouple your application while maintaining cohesion is all about figuring out what the ideal size of a module is.

Sometimes the answer might even be to split your application into multiple applications.

As always, you can subscribe to this RSS feed to follow my posts on Making the Complex Simple.  Feel free to check out ElegantCode.com where I post about the topic of writing elegant code about once a week.  Also, you can follow me on twitter here.
Advertisements

Responses

  1. […] my next post, I am going to delve much deeper into this topic and look at how granularity affects cohesion and […]

  2. […] Back to Basics: Cohesion and Coupling Part 2 – John Sonmez continues his back to basics series with a second part on Cohesion and Coupling looking at the relationship between the two, breaking problems down into smaller pieces and using Dependency Injection to bring them together. […]

  3. John,
    One lesson that I don’t think is well taught is picking the “right sized Lego blocks” when it comes to Unit Testing. When we started using TDD and DI two years ago, we assumed that “Unit” == “class”, so we have very fine-grained tests involving lots of mocks. This results in it being hard than it ought to refactor existing code, with the tests being more of a hindrance than a help.

    Your point about picking the right “zoom level” is a good one. We don’t feel that we have to mock strings and arrays whenever we use them. Likewise we should pick the right zoom level for unit tests, and realise that sometimes a unit consists of several highly-cohesive classes.

    • Excellent point. While in general a unit is a class, we shouldn’t always assume it is.

  4. Great series! Where does the Single Responsibility Principal fit into this? After reading your first post I figured that cohesion was basically the same concept as SRP, but now I’m not so sure.

    • I think SRP is closely related to cohesion. In my mind, SRP is something that helps us understand what things should be cohesive. All the things doing one responsibility should live together and belong to the same module. Cohesion and coupling are more of the how, and SRP is more of the why.

  5. I love that feeling when I read a post and someone explains what I’ve been thinking for a while but never managed to, or had time to, write down and structure.
    Good stuff. Unit tests and DI are too highly buzzed. Really, software engineering is about fashion.
    Which is why we need to get “back to basics”.

    The enterprise bus story, reminds me of a pattern used in WPF/Silverlight MVVM called event aggregator.

    Any class can publish/subscribe to any events without caring about others. The problem is that it’s extremely hard to debug and to understand the flow, of who published/received the event.
    BAD!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: