Coupling and Cohesion

I just finished a week of training at SKB Kontur in Ekaterinburg, Russia. We covered a lot of ground during the week–TDD, social principles of development, habits for agility. We ended the week talking about software design. During design day we tried to identify the best-designed software there (I recommend this exercise). Because the day was so experiential, we didn’t get to talk about all the design concepts I wanted to discuss. In particular, coupling and cohesion play a central role in the value of software design. As a kind of parting gift to the great group of programmers in the workshop (and because it will bug me if I don’t write it down), here is an introduction to coupling and cohesion.

Yourdon and Constantine in their classic Structured Design identify cost minimization as the goal of software design. The cost of software is dominated by the cost of maintenance, the cost of maintenance is dominated by the cost of changes the ripple through the system, and effective software design minimizes the chance of changes propagating. Changes that touch a single element cost less and are more predictable than changes to one element that require changes to two more, and then three… The expected cost of change can be reduced by paying careful attention to two factors: coupling between elements and cohesion within elements.

(Software design also has a role in increasing or accelerating revenue, but revenue isn’t directly connected to coupling and cohesion so I will deal with this role later.)

Coupling

Two elements are coupled to the degree that changes to one tend to require changes in another. For example, parallel class hierarchies are coupled if a class is added to one, because the other hierarchy will also require another class. Two systems communicating via a wire protocol are coupled with respect to protocol changes–if one system requires a change to the protocol the other will need to change as well. Coupling between elements is a conductor of change.

 

Coupling propogates change

Coupling propagates change

I talk about coupling (and cohesion) in terms of particular changes. This is not the standard definition. Coupling is generally described as a static property: these two elements are temporally coupled, for example, if the calling sequence between them is constrained. These static properties are only potential cost. If nothing ever triggers the coupling, the cost is never realized.

A system could be coupled to a particular vendor’s database by using vendor-specific features. A change to the database would require changes to the system. If the database never changes, though, then the coupling remains potential. Evaluating the cost of coupling precisely requires evaluating the set of changes that are actually required of the system. This can only be done a posteriori. Evaluating the cost prospectively requires estimating the probabilities of the kinds of change that would propagate across a relationship.

The relationship between coupling and change cost goes both ways. Changes that are likely to be expensive are less likely to be chosen. Breaking a coupling can open up the possibility for new kinds of change.

There is much more to say about the various kinds of coupling and the kinds of change that propagate across them, but that detail will have to await another post. The fundamental concept is that elements in a design should not be coupled with respect to the changes that actually take place. This keeps the cost of a change contained.

Cohesion

Coupling measures the spread of a change across elements. Cohesion measures the cost of a change within an element. An element is cohesive to the degree that the entire element changes when the system needs to change.

An element can lack cohesion either by being too large or too small. An element that is too small, solving only part of a problem, will have to be coupled to elements solving the other parts of the problem. Changing the solution will require changing all the elements. An element that solves several problems will only be partly changed. This is riskier and more expensive than changing a whole element because first you need to figure out what part of the element should be changed and then you need to prove that the unchanged part of the element is truly unchanged. Cohesive elements, replaced in total, don’t incur these costs.

Cohesion

Cohesion

(The strategy of isolating change is a way of inducing cohesion before making a change, for example extracting the part of a method that needs to change into its own method before making the change.)

Balance

One of the things about design that makes it such a joy is that it requires balance. If elements are too large, each change will be more expensive than it needs to be. If elements are too small, changes will ripple across elements. And optimizing the design takes place against the backdrop of an unpredictable stream of changes.

Elements that are too large tend to multiply the cost of change: N * C. Change that ripples across elements can potentially be much more expensive: C ^ N. (This math is simplistic and not intended to be taken literally.) This suggests that the most care should be spent on reducing coupling. This is a bit puzzling as my practice is generally to make more smaller pieces. Perhaps I’m just confident of my ability reduce coupling.

One challenge in design is to cheaply reduce coupling. If one element can be insulated from a likely change in another at reasonable cost, then it’s worth doing sooner rather than later. Breaking other forms of coupling will be more expensive and might be better defered until just before a triggering change. Again, it’s the imprecision of this analysis that makes design fun.

The unpredictability of changes renders it impossible to statically determine the “best” design for a system. There will always be some changes that ripple through the system. I speculate that the number of elements changed per change to the system follows a power law distribution. Careful attention to coupling can reduce the slope of the line describing the number of changes but cannot eliminate the distribution. This hypothesis needs experimental backing.

Further topics

When I write about design, I notice that I tend to assume prerequisites that I haven’t yet written about and point to corollaries that I likewise haven’t covered yet. Here is a list of topics I should write about implied by this post:

 

  • Isolate change
  • Design is beneficially relating elements
  • Forms of coupling
  • Cost and benefit of design (in particular the points of diminishing and reversing returns)
  • Design fitness and its evolution
  • Design to maximize revenue
  • Design timing

14 Comments

Michael BoltonApril 7th, 2009 at 7:18 pm

You might be very interested in Herbert Simon’s book, Sciences of the Artificial, which models a system in terms of its internals, the interface that it exposes to the environment, and the environment in which it operates. When anything changes, something else has to change to maintain stability.

—Michael B.

Curtis CooleyApril 8th, 2009 at 7:19 am

First talk about OO design that claims an ‘element’ can be too small. Interesting and well put, as otherwise I would not have agreed. Coming from a UNIX background I’m a “do one thing well” designer.

BillAtHrstApril 8th, 2009 at 7:24 am

FWIW, the classic work is “Reliable Software through Composite Design” by Glenford Myers (http://www.amazon.com/Reliable-software-through-composite-design/dp/0884052842)

Some of the examples are a bit (!) dated (punch cards, anyone?), but the principles have not changed one bit.

I wish more of my colleagues would read this gem — in fact, I often give it is a gift.

[...] DbWorld added an interesting post today on A slightly strange take on coupling and cohesionHere’s a small readingAn element that is too small, solving only part of a problem, will have to be coupled to elements solving the other parts of the problem. [...]

Toby DiPasqualeApril 8th, 2009 at 12:35 pm

There’s a more recent book called “Event-Based Programming” by Ted Faison that does a really great job of describing in specific and concrete terms all of the various types of coupling a system can contain. Its a pretty good and near-formal overview, giving these types of couplings names so they can be discussed more widely. Check it out: http://bit.ly/u9Oi

[...] Max Continuous testing for Eclipse « Coupling and Cohesion Contributing to toolbars with org.eclipse.ui.menus [...]

[...] 왕성한 블로깅 활동을 하

Mike PolenApril 16th, 2009 at 1:30 pm

A former colleague of mine wondered why you never mention information hiding or any of the criteria or techniques that one can use to decide what the hidden decision in a module should be. He and I wondered if you have read The Modular Structure of Complex Systems (http://www.cs.wm.edu/~coppit/other-papers/parnas-modular-structure.pdf)

KentBeckApril 16th, 2009 at 2:07 pm

Mike,

I haven’t read that paper. Thanks for the pointer. Do you have an example where the techniques in the paper have been particularly helpful?

KentBeckApril 16th, 2009 at 4:15 pm

Mike,

I was mistaken. I read the paper many years ago (good news/bad news about age–you have time to have read lots but you don’t remember everything you read).

I think the “secret” metaphor Parnas uses takes a similar role to the “responsibility” metaphor in my design thinking. I also talk (in Implementation Patterns, for example) about separating things that change at different rates. That’s an important heuristic for me while designing.

[...] Coupling and Cohesion – “One of the things about design that makes it such a joy is that it requires balance. If elements are too large, each change will be more expensive than it needs to be. If elements are too small, changes will ripple across elements. And optimizing the design takes place against the backdrop of an unpredictable stream of changes.” [...]

vijay pandeyNovember 19th, 2009 at 4:11 am

Can you solve the problem using only cohesion ,make a software design using only coheson.Please clearly speciy cohesion n terms of design

KentBeckNovember 19th, 2009 at 7:29 am

Vijay,

Thank you for the followup question. I don’t think it’s helpful to only consider cohesion. Low coupling with respect to the changes you actually make is what makes a design inexpensive. Raising cohesion is one way to lower coupling.

As far as the clarity of the specification, the material in this post is my best attempt so far to define cohesion. If you look at an element now can you say whether it is cohesive or not? Are there changes for which it is cohesive and other changes for which it is not?

James NobleMay 25th, 2010 at 11:44 pm

Hi Kent

The best thing about the best ideas is how often they get rediscovered.

So the Aspect folks often talk about scattering and tangling. My take on this is that scattering is basically inverse coupling — if a design concern is scattered across a bunch of modules (for basically any meaning of “module” and “design concern”) then those modules are going to be tightly coupled. Loosely coupled modules mean that there can’t be many concerns scattered around them in common. More obviously, tangling is inverse cohesion: if a module is cohesive, it cannot have multiple concerns tangled within in.

What’s interesting to me about this is that most programming language developments give programmers more control over coupling. At least in the main straightforward story that we tell ourselves (where type checking is more important than garbage collection) languages start with GOTOs and line numbers and absolute linkage addresses, and go through subroutines, recursive subroutines, message sends, to lazy monadic functions or whatever else comes next.
Aspects, on the other hand, don’t really address coupling: if anything, they make it worse.
They are, however, one of the few programming language features that increase cohesion.