skip to content

In the GRASP set of responsibility-assignment principles, what does High Cohesion mean, and what concrete problems does a low-cohesion class cause?

level: juniorimportance: must knowfreq 68%

answer

  1. Evaluative, not prescriptive — a yardstick, paired with Low Coupling
  2. Intra-module focus; coupling is inter-module
  3. One-sentence test / name test / field-usage clusters
  4. Low cohesion = many reasons to change, big test setup, no reuse
  5. Extreme cohesion → class explosion + more coupling

basics

~20 s

Cohesion is how well everything inside one class belongs together. High Cohesion says a class should keep a small set of closely related responsibilities, so it stays easy to name, understand, change, test and reuse.

solid answer

~40 s

GRASP (General Responsibility Assignment Software Patterns, popularized by Craig Larman) is a vocabulary for deciding which class gets which responsibility. High Cohesion is one of its *evaluative* principles: it names no specific class to create, it gives you a criterion for judging a candidate assignment. A class is highly cohesive when its data and methods all serve one clearly describable purpose — you can state what it does in one sentence without 'and' or 'or'. Low cohesion means a class accumulates unrelated jobs: it is hard to name, hard to understand, it changes for many unrelated reasons, its tests need large unrelated setup, it cannot be reused in isolation, and it becomes a merge-conflict hotspot because everyone edits it. In practice you evaluate it on every responsibility decision, always together with Low Coupling.

code

pseudocode · 13 lines
pseudocode
// LOW cohesion: three unrelated reasons to change in one class
class Order {
  calculateTotal()      // pricing rules
  saveToDatabase()      // persistence/SQL
  renderInvoicePdf()    // document layout
  sendConfirmationMail()// messaging/SMTP
}

// HIGHER cohesion: each class stays describable in one sentence
class Order          { calculateTotal() }        // knows its own line items
class OrderRepository{ save(order) }             // Pure Fabrication for storage
class InvoiceRenderer{ render(order): Document } // layout only
class OrderNotifier  { confirm(order) }          // messaging only

go deeper

for a junior

Define cohesion as 'things inside one class belong together', give the one-sentence/name test, and list two concrete pains: hard to understand, hard to test.

for a middle

Add that it is an evaluative GRASP principle used alongside Low Coupling, tie it to SRP, and show a concrete split (entity vs repository vs renderer) with the reasons-to-change argument.

for a senior

Discuss the yardstick nature of the principle, the interaction with Information Expert (Expert can bloat a class; cohesion is the check), Pure Fabrication as the escape hatch, and the over-splitting trade-off.

for a principal

Frame cohesion at module/service/team scale: alignment of change streams with ownership boundaries, the Common Closure Principle, bounded contexts, and the cost of getting cohesion boundaries wrong at the deployment level.

## Where the principle comes from **GRASP** = *General Responsibility Assignment Software Patterns*, a set of nine principles popularized by Craig Larman for answering one recurring design question: **"which object should be responsible for this?"** The nine are Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations. They split into two flavors: - **Prescriptive** ones suggest a concrete home for a responsibility (Information Expert: give it to the class that holds the data needed; Creator: give object creation to the class that aggregates/contains/closely uses the new object). - **Evaluative** ones give you a *yardstick* to judge any candidate assignment. **High Cohesion and Low Coupling are the two evaluative ones.** They never say "make class X" — they say "of the options on the table, prefer the one that leaves classes focused and connections few". ## Definitions, from scratch - **Responsibility** — an obligation of an object. Larman splits it into *doing* responsibilities (compute something, create something, initiate an action in another object) and *knowing* responsibilities (know its own data, know related objects, know things it can derive). - **Cohesion** — the degree to which the elements *inside* one module (class, function, package, service) belong together and contribute to one purpose. It is an *intra*-module property. - **Coupling** — the degree to which one module depends on *other* modules. It is an *inter*-module property. Different axis, different question. - **High cohesion** — all members of the class pull in the same direction. Low cohesion — the class is a grab-bag. ## The practical test Three cheap heuristics interviewers like: 1. **The one-sentence test.** Describe the class without using "and", "or", "also", "manager of misc stuff". If you can't, cohesion is low. 2. **The name test.** A class you cannot name precisely (`Utils`, `Helper`, `Manager`, `Processor`, `DataHandler`, `Service` with 40 methods) usually has nothing holding it together. 3. **The field-usage test.** If method group A touches only fields 1–3 and method group B touches only fields 4–6, and the two groups never meet, you have two classes wearing one costume. (This intuition is formalized by the LCOM family of metrics.) ## Why low cohesion actually hurts — the mechanisms - **Comprehension cost.** To change one behavior you must read and mentally exclude everything else in the class. Reading cost scales with the whole file, not with the part you need. - **Multiple reasons to change.** A class doing billing *and* PDF rendering changes when tax rules change and when the layout changes. Two unrelated change streams hit one file → merge conflicts, coordination between teams, larger blast radius per release. - **Ripple effects / accidental coupling.** Unrelated responsibilities sharing a class also share its fields, its constructor, and its imports. A change made for reason A can silently break behavior B through shared mutable state. - **Test friction.** Testing one behavior forces you to construct the collaborators of all the others (databases, clocks, mailers). Tests get slow, brittle, and full of irrelevant mocks. - **No reuse.** You cannot take the useful 10% of a grab-bag class into another context without dragging the other 90% and its dependencies with it. - **Rot accelerates.** Because nobody can define what the class *is*, the next person has no reason not to add one more unrelated method. Low cohesion is self-reinforcing. ## Applying it during design When a new responsibility appears, you list candidate homes (often produced by Information Expert or Creator), then *evaluate* each candidate: does the receiving class stay describable in one sentence? Does the assignment force it to know about a whole new area of the system? If yes, look for another home — a new focused class, or a **Pure Fabrication** (an invented class that exists purely to keep the design clean, e.g. a `PaymentGateway` or `OrderRepository` that has no counterpart in the business vocabulary). ## Trade-offs and edge cases (what separates a senior answer) - **Cohesion is not "one method per class".** Pushed to the extreme you get class explosion: dozens of one-method types, more indirection, more wiring, higher *coupling* between all the fragments, and a design nobody can hold in their head. High cohesion is balanced against coupling and against plain simplicity. - **Some low-cohesion-looking classes are legitimate.** A *Facade* or a GRASP *Controller* intentionally aggregates entry points to shield clients; a DTO groups fields by use case rather than by behavior; a framework-mandated class (a config or wiring class) groups by mechanism. Judge these by whether they *delegate* rather than *implement*: a controller that only routes stays thin and cohesive in purpose even if it touches many areas. - **Cohesion is contextual.** A tiny script and a 10-year platform tolerate very different levels. Cohesion is a *quality gradient* to keep an eye on, not a binary rule with a compiler check. - **Cohesion applies at every scale**: statements in a method, methods in a class, classes in a package/module, modules in a service, services in a system. The same reasoning repeats; only the unit changes. ## Relationship to other principles High Cohesion is essentially the object-level expression of the **Single Responsibility Principle** (SRP, the S in SOLID). SRP phrases it as "a class should have one reason to change" — which sharpens *what kind* of relatedness matters: relatedness with respect to who requests changes. Cohesion and SRP are close cousins, not rivals; SRP is the more precise formulation of the same instinct.

  • Is High Cohesion the same thing as the Single Responsibility Principle?
    They are extremely close. Cohesion measures how related a class's members are; SRP sharpens the criterion of relatedness to 'one reason to change / one group of stakeholders requesting change'. SRP is the more precise, change-oriented formulation; cohesion is the broader quality it optimizes.
  • Can a class be too cohesive?
    You cannot be 'too focused' in principle, but you can over-split: chasing maximal cohesion mechanically yields many anemic one-method classes, more wiring, more indirection and higher coupling overall. The real target is the balance point where both cohesion is high and the number of collaborations stays small.
  • How would you spot a low-cohesion class in an unfamiliar codebase quickly?
    Look for vague names (Manager/Util/Helper), long files with method groups that touch disjoint sets of fields, imports spanning unrelated technical areas, high change frequency from many different authors in version-control history, and test files with huge unrelated setup.

A kitchen drawer with only cooking utensils is cohesive: you know instantly what is in it and where new items go. The 'junk drawer' with batteries, receipts, cables and a screwdriver is low cohesion — you search every time, and nobody knows whether the next random object belongs there or not.

saying these in an interview costs you the question

  • Saying cohesion and coupling are the same thing, or using 'cohesion' when you mean 'few dependencies'
  • Claiming High Cohesion prescribes creating a specific class — it is an evaluative criterion, not a recipe
  • Equating high cohesion with 'small class' measured only in lines of code
  • Insisting every class must have exactly one method
  • Treating it as a hard rule with no trade-off against class explosion and indirection

context