Mike's corner of the web.

Coupling and cohesion

"Low coupling, high cohesion" is a phrase that I've heard lots, but often without any further explanation. Here's my attempt. (Beware: the way I use the two terms actually differs slightly from the norm, but makes more sense to me.)

I think we tend to understand coupling better than cohesion. If we can't use one piece of code without using another, then we'd say they're coupled. Sometimes this is in one direction: we can use A without B, but we can't use B without A. Sometimes this is in both directions: A needs to use B, and B needs to use A. We can also say that A is coupled to B if changing B then requires a change in A for A to keep working.

Sometimes this coupling is apparent to the user of the code: I wanted to use A to do a job, but I'm forced to also use B. Sometimes this coupling is in the implementation: when I use A, it uses B under the hood, but I never see B as the caller.

Coupling is usually seen as been bad: other things being equal, low coupling is better than high coupling. If we can rely on an interface instead of a concrete implementation, this is an improvement. If we can get rid of a dependency altogether, even better.

However, coupling is not always bad: it's unnecessary coupling that's bad. Some coupling is intrinsic to the domain: sometimes concepts are inherently related such that you cannot talk about one without talking about the other. This only becomes bad if we try to artifically separate these concepts: they belong in the same place and rely on each other, but we've put them in, say, different classes. Better to have them in the same class: accessing different fields is less painful than constantly accessing another class. This is what I think of as cohesion: concepts are cohesive if they are naturally coupled together. If we split them up, they are just as coupled together, but that coupling becomes far more painful.

Note that it's possible for things to be cohesive without there necessarily being explicit coupling in the code. For instance, suppose you have two methods: one renders a form by referencing an HTML file that should be served. The other takes the form values and processes them appropriately. We could split these two methods into separate classes, and they wouldn't need to call each other. Yet I would suggest they belong together. Firstly, it doesn't make sense for one to exist without the other: there's no system where you'd want to be able to call one method but not the other. Secondly, the two methods still affect each other. If I change the form that's being rendered, then I might well need to change the way the form values are being processed, such as if a field name is changed. Just because that coupling isn't explicit in the code (in this instance) doesn't mean that that coupling doesn't exist.

I think, then, that "low coupling, high cohesion" is really about picking how we carve up our system. We should carve out cohesive objects, so that there's as little dependency between units as possible. Where coupling is intrinsic to the domain, we should put those things near to each other. In other words, high coupling is only acceptable if there's high cohesion.

To expand a little on how this differs from some other definitions: I like to think of cohesion as a property of the domain, the underlying concepts, while coupling is a property of the code. Where there's lots of coupling across boundaries such as classes (which is what often gets referred to as just plain coupling), it suggests either unnecessary dependencies or that cohesive concepts have been split up. What sometimes gets referred to as coincidental cohesion I prefer to call adhesion: these concepts don't belong together, but they've been stuck together.