Skip to main content

Cohesion: A Class Does One Thing Well

What This Concept Is

Cohesion is how strongly the parts of one module belong together. A cohesive class has a single, crisp answer to the question "what does this class do?" A non-cohesive class answers that question with a list, a paragraph, or an embarrassed pause.

Cohesion is not the same as size. A 300-line class can be cohesive if every line serves the same purpose; a 30-line class can be non-cohesive if it is half parsing and half formatting.

Practical signs of high cohesion:

  • every method uses most of the class's fields
  • the class name accurately predicts what every method does
  • changes for one reason touch this class and nothing else

Why It Matters Here

Low cohesion is expensive because it spreads the blast radius of change. When a class does two unrelated jobs, every change to job A risks breaking the tests for job B. Review time goes up, merge conflicts multiply, and the class becomes a magnet for unrelated work.

Later clusters in this module (SOLID, code smells) are largely specialized diagnoses of low cohesion: Single Responsibility is cohesion at class scope; Feature Envy is cohesion violated across class boundaries.

Concrete Example

Low cohesion, one class doing three jobs:

class Order:
def __init__(self, items): self.items = items
def total(self): return sum(i.price for i in self.items)
def to_html(self): return f"<div>Total: {self.total()}</div>"
def save_to_db(self, conn): conn.execute("INSERT ...")

Order is simultaneously a domain object, an HTML renderer, and a persistence gateway. Three different reviewers (business rules, UI, infrastructure) will all touch this class for unrelated reasons.

Raise cohesion by separating jobs:

class Order:
def __init__(self, items): self.items = items
def total(self): return sum(i.price for i in self.items)

class OrderHtmlView:
def render(self, order): return f"<div>Total: {order.total()}</div>"

class OrderRepository:
def save(self, order, conn): conn.execute("INSERT ...")

Each class now has methods that share a purpose and operate on a shared focus.

Common Confusion / Misconception

"High cohesion means small." It does not. A Polynomial class with twenty methods for addition, multiplication, differentiation, and evaluation can be perfectly cohesive because every method is about polynomials.

A more dangerous misconception: "coupling is bad, so cohesion is good, so they're opposites." They are related, but not opposites. Splitting Order above did remove some accidental cohesion (the three jobs were in one file), but it also introduced new couplings (OrderHtmlView now depends on Order). Good design raises cohesion without paying more coupling than the problem deserves.

How To Use It

When reading or writing a class, apply this sequence:

  1. Write the class's purpose in one sentence, out loud, without "and."
  2. For each method, check whether its behavior is implied by that sentence.
  3. For each field, check whether more than two methods touch it.
  4. If a method never touches the class's fields, it is not about this class (move it).
  5. If several methods share fields that the rest ignore, you have a class inside a class (extract it).

Check Yourself

  1. Can a cohesive class still have many methods? Why?
  2. Why is "this method does not use any fields" a cohesion warning?
  3. What is the relationship between cohesion and the Single Responsibility Principle?

Mini Drill or Application

Take a class from a project you know (yours, or one open-source file under 300 lines). Do all four:

  1. Write its purpose in one sentence without "and" or "also."
  2. List the methods and mark each as core or drift.
  3. For every drift method, name a better home for it.
  4. State whether the class would become easier or harder to change for business reasons after that move.

If you cannot write the one-sentence purpose, you have already found the problem.

Read This Only If Stuck