Modularity, cohesion and coupling
Every architecture is a way of splitting a system into parts. Whether the split helps or hurts depends on two measurable things: how well each part holds together (cohesion) and how much the parts depend on each other (coupling). Get them right and a change stays inside one part; get them wrong and every change ripples through half the system, whatever the architecture diagram says.
1. The idea
Modularity means grouping related code into parts with clear boundaries: packages, namespaces, components, services. Two properties tell you whether the grouping is good:
Cohesion: how well a part holds together
High cohesion means everything inside serves one purpose and changes for the same reasons. A "Pricing" component that calculates prices, discounts and tax is cohesive; a "Utils" package with date formatting, email sending and PDF generation is not: it has no reason to exist except convenience.
Coupling: how much parts depend on each other
Afferent coupling (Ca) counts incoming dependencies: how many parts use this one. Efferent coupling (Ce) counts outgoing ones: how many parts this one uses. A part with high afferent coupling is risky to change, because every change reaches all its users.
Three numbers that describe a component
- Instability I = Ce ÷ (Ca + Ce). Near 0: many depend on it and it depends on little, so it's hard to change (stable). Near 1: it depends on many and nothing depends on it, so it's easy to change but breaks when they change.
- Abstractness A = abstract types (interfaces, abstract classes) ÷ all types. Near 0: all concrete code. Near 1: mostly contracts.
- Distance from the main sequence D = |A + I − 1|. Healthy components sit near the line A + I = 1: stable ones are abstract (others depend on contracts that rarely change), unstable ones are concrete. A component that is stable and concrete sits in the zone of pain: everyone depends on code that keeps changing. One that is abstract and unstable sits in the zone of uselessness: contracts nobody uses.
Kinds of cohesion, best to worst
| Kind | Parts are together because... |
|---|---|
| Functional | they all contribute to one well-defined task (best) |
| Sequential | the output of one is the input of the next |
| Communicational | they work on the same data |
| Procedural | they must run in a certain order |
| Temporal | they run at the same time (start-up, nightly jobs) |
| Logical | they're the same kind of thing but unrelated (all "string helpers") |
| Coincidental | nothing: they just ended up in the same file (worst) |
2. How it works
Afferent coupling is blast radius
Six components of an online shop. Box text shows each one's incoming and outgoing dependencies. Watch two changes of the same size have very different reach.
The Law of Demeter: talk only to your neighbours
A component should call only the things it directly knows, not reach through them into their internals. Code like order.getCustomer().getAddress().getPostcode() couples the caller to three classes' structure. Watch what happens when one of them changes.
3. Try it yourself
Coupling metrics calculator
The matrix says which component depends on which (row uses column). Toggle dependencies and set how abstract each component is. The chart plots each one's instability against its abstractness: aim for the dashed main sequence and stay out of the coloured corners.
Tools such as JDepend (Java), NDepend (.NET) and dependency-cruiser (JavaScript) compute these numbers from real code. In an architecture review, run them and look first at the components in the zone of pain.
4. Trade-offs
Reuse vs coupling
A shared component avoids duplicated code, and makes everything that uses it change when it changes. Reuse stable, abstract things freely; think twice before sharing fast-changing business logic (Module 06's lab has this decision).
Abstraction vs simplicity
Interfaces move a stable component out of the zone of pain, but every interface is indirection. Add them where many depend on a component, not everywhere.
Fine vs coarse parts
Many small parts are each cohesive but add coupling between them; a few big parts have little coupling but mix concerns. The right size groups code that changes together.
Demeter vs convenience
Following the Law of Demeter adds small delegating methods (order.shippingPostcode()). They're boilerplate, and they're what lets the internals change freely.
5. In real projects
Modularity is the architecture's foundation. Every style in Level 3 is a choice of where to put module boundaries and how strongly to enforce them: inside one codebase (layered, modular monolith), or as separate deployments (service-based, microservices). A codebase with poor modularity doesn't get better by being split into services; it becomes a distributed mess.
Watch the "common" and "shared" packages. They're where the zone of pain usually lives: concrete code with dozens of dependents. Split them by purpose, make the stable parts abstract, and move the business logic back to the components that own it.
Check it automatically. Coupling drifts quietly. A test that fails when a forbidden dependency appears ("nothing in Orders may use Reports") keeps the structure honest (Module 26).
Say it in the interview
- "Cohesion vs coupling?" Cohesion is how well the code inside a part belongs together; coupling is how much parts depend on each other. We want high cohesion and low coupling, so changes stay inside one part.
- "What's afferent coupling?" The number of parts that depend on this one: its blast radius. High afferent coupling means changes are risky, so such a component should be stable and preferably abstract.
- "What's the Law of Demeter?" Only talk to your immediate collaborators, never reach through them into their internals. It keeps callers from depending on the structure of classes they don't own.
- A "common" module that everything depends on, full of business logic.
- Proposing microservices to fix tangled code without fixing the modularity first.
- Passing whole entities between services "in case they're needed".
6. Remember it
How this hook works: what "things that change together, live together" means
What the slogan means, phrase by phrase
- "Things that change together"
- Code that changes for the same business reason, at the same time.
- "live together"
- Belongs in the same component, so one change touches one part.
Why this picture fits: it defines cohesion by its purpose (local change) and implies low coupling: if things that change together are together, few changes cross a boundary.
The story → the concept
| The kitchen | The code |
|---|---|
| A baking station with everything for baking | A functionally cohesive component |
| The baker never walks to the grill | Low coupling |
| The one knife every station shares | A component with high afferent coupling |
| A drawer of random gadgets | Coincidental cohesion ("Utils") |
The trap it saves you from
Grouping code by what it looks like ("all the helpers") instead of what it's for.
7. Common mistakes
a.getB().getC().doSomething() spread knowledge of internal structure to every caller.8. Design exercise (30 minutes)
- Draw the dependencies (10 min). For a codebase you know, list its top-level packages or modules and draw who depends on whom. Count Ca and Ce for each.
- Find the pain (10 min). Which component has the highest afferent coupling? Is it abstract? What changed in it last month, and how many other parts had to change?
- Fix one (10 min). Pick one train-wreck call or one over-shared object in your code and rewrite it so the caller asks for exactly what it needs.
9. Self-check quiz
A component has high afferent coupling. What does that mean?
Ca = 6, Ce = 0. What is its instability?
What puts a component in the zone of pain?
How do you fix order.getCustomer().getAddress().getPostcode()?
Which kind of cohesion is the strongest?
10. Go deeper
| Resource | Time | Why |
|---|---|---|
| Fundamentals of Software Architecture, 2nd edition (Richards and Ford) | book | Chapter 3 covers modularity, cohesion, coupling and the main sequence. |
| Software package metrics (Robert C. Martin's metrics, summarised) | 10 min | The original definitions of Ca, Ce, I, A and D. |
| Law of Demeter | 10 min | The principle and its origin, with examples. |