Back to the map

Module 01 · Object thinking · Lesson 1 of 4

Classes as responsibilities

Design classes around what they are responsible for knowing and doing, not around nouns or tables. Responsibility-driven design, cohesion and coupling, giving each rule to the class with the information, and spotting a class doing too much.

IntroMust-knowJunior 10 min Updated Nov 2026

Why it matters

The most common first draft of an object model is a set of noun boxes copied from the requirements, each with fields and getters, plus one big "manager" class that holds all the logic. It compiles, and it decays fast: every new rule lands in the manager, which grows until nobody dares touch it. Thinking of classes as bundles of responsibility, rather than bundles of data, is the shift that makes every later principle in this track work.

The idea

A responsibility is something a class knows or does: "a Seat knows whether it is available", "a Booking confirms itself only if its hold is still valid", "a PriceCalculator computes the total for a cart". Responsibility-driven design starts from the behaviour the system needs and asks which object should own each piece, instead of starting from the data and attaching behaviour wherever it fits.

data-centricSeatgettersShowgettersBookinggettersBookingManagerevery rule lives hereresponsibility-centricSeathold(), release()ShowseatsFor(zone)Bookingconfirm(now)Pricingtotal(seats)a thin service only coordinates
Same domain, two shapes. On the left, data holders and one manager that knows everything. On the right, each object owns the rules about its own data.

Assign the rule to the class with the information

A practical heuristic (called information expert in the GRASP principles): give a responsibility to the class that already holds the data needed to fulfil it. Whether a hold has expired depends on the hold's start time and duration, so Hold.isExpired(now) lives on Hold. The total of an order depends on its lines, so Order.total() lives on Order, which asks each line for its own subtotal. Following this rule keeps data and the logic that interprets it together, which is what encapsulation means in design terms.

Cohesion and coupling

Cohesion is how closely a class's responsibilities belong together; coupling is how much a class depends on others' details. Aim for high cohesion and low coupling: each class does one coherent job and talks to others through small, stable interfaces.

SignalHealthyWarning
NameA specific noun or role: Seat, PriceCalculator, ClockManager, Helper, Util, Processor, Data
One-sentence descriptionSays what it is responsible for without 'and'Needs 'and' three times
FieldsUsed by most of its methodsClusters of fields used by disjoint groups of methods
Reasons to changeOne kind of requirement change touches itPricing, notifications and persistence changes all touch it
DependenciesA few, through interfacesMany, including other classes' internals

CRC cards: a quick design technique

Class, Responsibilities, Collaborators: for each candidate class, write its name, what it knows and does, and which other classes it needs. Walking a use case by "passing control" from card to card quickly shows gaps (nobody owns this rule), overloaded classes (one card is full) and pointless ones (a card with no responsibilities is probably an attribute). It works just as well as a narration in an interview as on index cards.

Services are allowed, but thin

Not every responsibility belongs to a domain object. Coordinating several objects, calling external systems and managing transactions belong in a service (BookingService), but a good service is thin: it loads objects, asks them to do their work, and saves the results. When a service starts containing if statements about a single object's fields, that logic wants to move into the object.

Trade-offs

Putting behaviour into domain objects keeps rules in one place and makes them reusable, at the cost of objects that are harder to map to and from databases and JSON, and a temptation to overload them. Putting everything in services is simple at first and turns into duplicated rules and a god class. The balance: domain objects own rules about their own data; services coordinate across objects and with the outside world.

In an interview

Introduce each class with its responsibility sentence: "Seat knows its status and can be held or released; a hold has an expiry and knows if it has lapsed; Booking turns a valid hold into a confirmed booking; BookingService coordinates them in a transaction." Interviewers listen for where the rules live, and this makes it explicit.

Check yourself

In a library system, where should the rule 'a member with any overdue loan cannot borrow' most naturally live?

Classes as responsibilities · Backplane