practice

Change-Reason Cohesion

also called Single Reason to Change, Axis of Change

The working test for a module boundary - things belong together if they change for the same reason, at the same time, driven by the same stakeholder, and share invariants.

cohesionboundarieschargebeebillingcommit-history

Thematic grouping — "these are all billing things" — is the weakest form of cohesion and produces the most common bad module: large, jointly deployed, and changed for entirely unrelated reasons.

The test that works has four parts: same reason, same time, same stakeholder, shared invariants.

Why it matters

The visible cost of low cohesion is that unrelated work collides. The dangerous cost is risk asymmetry: a trivial change is forced through the deployment process of a critical one. Teams respond by becoming slow and careful about the trivial change, or — far worse — by becoming casual about the critical one, because the same pipeline ships both and familiarity erodes caution.

Implementation patterns

  • Use commit history as evidence. If a change to A has never once required a change to B in two years, they are colocated rather than cohesive. This is objective and takes ten minutes.
  • Ask what has to be deployed together, which is the operational form of the same question.
  • Ask what has ever broken together, which finds hidden coupling that the code structure hides.
  • Separate by cadence and stakeholder, not by subject. Domains that change monthly and domains that change daily do not belong in one deployable, even when they share vocabulary.
  • Keep the invariant-bearing core together. Things that must agree about money, or about stock, or about identity, belong inside one transactional boundary, and that outweighs cadence.

Industry example

A subscription-billing platform such as Chargebee typically starts with one "invoice service" that generates invoices, computes tax, sends dunning emails, syncs to accounting systems and renders PDFs. Five responsibilities, five reasons to change, five cadences: billing logic changes rarely and carefully; tax changes whenever a jurisdiction moves; dunning changes constantly because it is a retention experiment; accounting sync changes when a third party's API does; PDF rendering changes for branding.

The cohesive core is invoice generation and proration — they share the money invariants. Tax is a volatile external domain behind an anti-corruption layer. Dunning is a workflow driven by invoice events. Accounting sync is an integration. PDF rendering is presentation, and it should not be able to fail a billing run.

Failure scenarios

  • Copy changes deployed through the money pipeline, making the team slow about both.
  • A tax-law change requiring a full billing regression, because the two live in one deployable.
  • A PDF template error failing an invoice run, because a presentation concern was given the power to break a financial process.
  • Over-correction: splitting proration away from invoice totals, which breaks a shared invariant and converts a local calculation into a distributed consistency problem.

Trade-offs

Higher cohesion means more modules, and more modules means more interfaces, more deployment units and more operational surface. There is a genuine floor below which splitting costs more than it saves — usually reached when a module is small enough that its interface is comparable in size to its implementation.

The judgement is that cohesion is worth paying interface cost for when the cadences differ sharply or the risk profiles differ sharply. Two things that both change monthly and both carry the same risk can stay together whatever the domain model says.

Interview question

"You have an invoice service that also sends emails and renders PDFs. Argue both sides: give me the strongest case for leaving it as one service, and then tell me what evidence from the repository would settle it."