Cohesion

Concept

How much the code inside one unit is devoted to a single job rather than to several unrelated ones.

Why it exists

For a long time every developer had a different rule for deciding which file a piece of code belonged in. A new function had no obvious home, so it went into a file called utils, and the next person put theirs there for the same reason. Six months later that file held a date formatter, a password hashing routine and an Excel export side by side.

The cost showed up the moment something needed changing. A request as small as "reword the message we show when a payment fails" meant opening seven files: the code that calculated the charge lived in one place, the code that decided a charge had failed in another, and the wording somewhere else again. Miss one of them and each screen showed a different message — a bug customers usually found before the team did.

Cohesion is the name that turned this situation into something measurable. It doesn't ask how many pieces the system was cut into. It asks whether the things inside one piece have anything to do with each other. Once the word existed, "this code doesn't belong here" stopped being a matter of taste and became an argument someone could actually support.

How it works

Open one unit and check whether the code inside it changes for the same reason. If a change to the pricing rules means touching every function in the file, cohesion is high. If half of them have nothing to do with pricing and sit untouched, it's low.

Looking at why things ended up grouped together gives a rough ladder. Each rung is more cohesive than the one above it.

  1. Grouped because there was nowhere else — the utils file again. Nothing connects the contents, which makes this the weakest form.
  2. Grouped because they look similar — email format checks and credit card number checks filed together under "validation." The name sounds reasonable, but a change to email rules gives nobody a reason to open the card code.
  3. Grouped because they run at the same moment — everything the app does at startup, piled into "initialization." Only the timing is shared, so when a line is deleted nobody can predict what breaks.
  4. Grouped because they accomplish one job together — discount calculation, the charge request and receipt generation all living in the payment unit. It's rare for one of the three to change alone, so the number of files to open drops to one.

Take document sharing at Pagedeck. Creating the link, checking permissions and computing the expiry time in one unit is the fourth kind. Add the code that emails a notification about the share and it slides to the second: now changing email wording means opening the sharing feature, which puts the permission checks within reach of an accidental edit.

There's no formula that produces a number here. What teams use instead is how many files a single request made them open. If requests of the same shape keep taking five files or more, that feature is scattered.

Where it shows up

Code review is where the word comes up most. Saying "this function doesn't belong here" in terms of cohesion turns it into a concrete proposal about what moves where. If notification code has drifted into the payment module, the argument becomes clear: move it so payments stop being redeployed because someone edited a sentence in an email.

It also matters when boundaries are being redrawn. A monolith puts everything in one deployable unit, and moving toward microservices, where each feature ships on its own, requires visible lines to cut along. Cut while cohesion is low and the payment service comes out with notification code stuck to it, which means shipping payments again every time a notification changes. The old tangle simply moves to a more expensive place. That's why teams gather things inside the single unit first and split afterward.

A third place it surfaces is estimation. When a request lands and nobody can say how long it takes until someone has searched the codebase, low cohesion is usually the reason: the work is spread across files nobody has a map of. Teams that track this notice the pattern quickly, because the same kind of request keeps producing wildly different estimates depending on who picks it up. Gathering the scattered code narrows that spread, and the estimate stops depending on which person happens to remember where everything lives.

Deciding where the lines go has its own method. Domain-driven design draws boundaries using the language the business already speaks rather than the shape of database tables, and following it tends to raise cohesion on its own, because things that change together in the business are usually called by the same name.

How it sounds at work

"Cohesion in this module is too low — the notification code should come out."

One unit is holding jobs of different kinds, so something should move.

"I had to open six files to change one sentence."

Making the case with a number instead of an opinion.

"The boundaries are still fuzzy. Let's raise cohesion first and split after."

Tidy the inside of the unit before changing the structure around it.

Document export used to be a recurring headache at Pagedeck. The PDF generation lived with document editing, the filename logic lived with sharing, and the code counting exports lived with billing, since each plan allowed a different number of them.

Theo proposed pulling all three into a single export unit, leaving billing with one entry point that answers how many exports remain this month. After that, export requests ended inside one file. When Mia asked for the per-plan limits to change, only the number on the billing side needed editing.

What people get wrong

The most common mistake is believing that chopping files into smaller pieces raises cohesion. Developers hear complaints about large files often enough that length and cohesion blur together. But what's being measured is relatedness, not size. Split a 300-line file into six 50-line files and, if those six still have nothing to do with each other, cohesion hasn't moved — there are just more places to search. Meanwhile 500 lines that all serve one job are a highly cohesive file.

The other misreading is that raising cohesion costs you something in coupling, as though the two traded against each other. In practice they move together. When related things sit in one place, the units have less to say to each other, so the connections between them thin out as well. If the two appear to fight, the boundary was drawn in the wrong place, and the fix is the position of the line rather than some balance between the two numbers.

Easily confused with

TermWhat it looks atHow it differs
CouplingThe space between unitsCohesion looks inside one unit; coupling counts the lines running out of it. Gather the inside well and fewer lines leave, which is why both usually improve at once

Where to go next

Last updated 2026-09-16