skip to content

High Cohesion (GRASP)

Keep each class focused on a set of closely related responsibilities so it stays understandable and cheap to change. Paired with low coupling, it is the tiebreaker applied to every responsibility-assignment decision.

part ofSoftware design & architectureoverview, primer and where to startread it →
on this pageshow

questions

6

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

open as a page

GRASP tells you to evaluate High Cohesion and Low Coupling together on every responsibility assignment. Why can't you simply maximize one of them in isolation?

level: middleimportance: must knowfreq 52%

basics

~20 s

They pull against each other. Splitting a class to make it more focused creates more classes that must talk to each other, raising coupling. Merging classes to cut dependencies makes each one do too much. You look for the balance point.

open as a page

Software design literature ranks cohesion on a scale from coincidental to functional. Name the main levels of that scale and give an example of a class sitting at a weak level versus a strong one.

level: middleimportance: should knowfreq 45%

basics

~20 s

From worst to best: coincidental (random stuff together), logical (same category), temporal (runs at the same time), procedural/communicational (same sequence or same data), sequential (output feeds the next step), and functional (everything serves one single task). Aim for functional.

open as a page

How would you detect low cohesion in an existing class objectively, and what refactoring sequence would you apply to fix it without breaking clients?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Look for method groups touching disjoint fields (the LCOM metric captures this), vague names, and files changed by many unrelated commits. Fix by extracting each concern into its own class, keeping the old class as a delegating facade until callers migrate.

open as a page

Applying GRASP's Information Expert (assign a responsibility to the class that has the data needed) can grow a class into a God object. How do High Cohesion and Low Coupling act as a check on that, and what do you do instead?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Information Expert says 'put it where the data is', which keeps piling work onto data-rich classes. Cohesion is the veto: if the class stops having one clear purpose, move the responsibility to a new invented class — GRASP calls that Pure Fabrication.

open as a page

Cohesion is usually taught at class level. How does the same principle drive boundaries at module, service and team scale, and what happens when those boundaries are drawn on the wrong criterion?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

The same rule scales up: group things that change together into the same module or service. Grouping by technical layer instead of by business capability spreads every feature across many deployables, so one change needs many coordinated releases.

open as a page