Concept · Code design
Coupling and cohesion
Keep things that change together in one place (high cohesion) and minimise what each part knows about the others (low coupling).
Coupling measures how much one module depends on another's details. Cohesion measures how closely the contents of one module belong together. The goal, stated by Larry Constantine in the 1970s and still the best single test of a design, is low coupling and high cohesion: changes stay local, and each module is understandable on its own.
Coupling, from worst to best
| Kind | What's shared | Example |
|---|---|---|
| Content | One module edits another's internals | reaching into another package's unexported state via reflection |
| Common | Global mutable state | a package-level var currentConfig many modules write |
| Control | A flag telling another module what to do | Render(doc, true) |
| Stamp | A large structure when only a field is needed | passing a whole User to compute a display name |
| Data | Only the values needed | DisplayName(first, last string) |
| Message | Calls through a narrow interface or events | publishing OrderPaid |
Coupling can also be temporal (things must happen in a particular order) or hidden in shared databases, file formats and assumptions — a column two services both write is coupling, even with no import between them.
Cohesion
A cohesive module's parts change for the same reason. billing holding invoices, tax rules and payment retries is cohesive. utils holding date formatting, HTTP retries and a slug generator has only coincidental cohesion — the parts are together because someone had to put them somewhere. Low cohesion shows up as divergent change (one file edited for unrelated reasons); high coupling shows up as shotgun surgery (one change touches many files).
Using it
- Group code by feature, not by technical layer — see package by feature.
- Depend on small interfaces rather than concrete types (dependency inversion).
- Pass only the data a function needs.
- Ask of every change: how many places did I have to touch, and did they belong together?
Zero coupling isn't the goal — modules that never interact do nothing useful. The aim is to make each dependency deliberate, narrow and stable. The design principles lesson builds the other principles on this pair.