LESSON 3.1
From requirements to classes
Read a requirement, underline the nouns and verbs, then ask which noun owns the invariant. That process produces your first class list.
7 min read
A common mistake is to open a code editor before asking what classes exist and what rules they enforce. The result is a tangle of free functions, mutable globals and objects that can be in invalid states. Class discovery is the cheaper step.
The noun-verb pass
Start with the requirement written in plain language. Underline every noun and every verb. Nouns are candidate classes, fields or values. Verbs are candidate methods.
Requirement: A library lends books to members. A member may have at most three books on loan at a time. A book cannot be loaned if it is already on loan.
Nouns: Library, Book, Member, Loan. Verbs: lends, has on loan, is on loan.
Now ask for each noun: does it enforce a rule? If yes, it is a class. If no, it might be a plain record or a field of another class.
- Library enforces the "at most three" rule → class.
- Book knows whether it is on loan → class.
- Member tracks its loans → class.
- Loan records a borrow event → value or simple record.
Invariants first
An invariant is a condition that must always hold. State it in one sentence: A Member can never have more than three active loans. Write the constraint into the class that owns the state that determines it.
If the invariant spans two classes, pick the one that knows the most. The Library knows the member's loan count because it manages both members and books. Putting the check inside Library.lend() is correct.
In code
What to do with leftover nouns
After the invariant pass, some nouns have no rules and no state. They are data, not objects. Loan above is just a borrow event — it can be a simple object or a record with a timestamp and references to the member and book. Making it a full class with validation would be overengineering until an invariant appears.
The test: What goes wrong if this noun is in an invalid state? If the answer is "nothing, because it has no invariants", it is probably a value, not an entity.
Where you have already seen it
Domain-Driven Design formalizes this distinction as entities (have identity and invariants) versus value objects (immutable, compared by value). JPA @Entity annotations reflect the same idea. React's distinction between controlled and uncontrolled inputs is also an invariant question: who owns and enforces the current value?
Try it
Parking Lot LLD
List the nouns, state the invariants, then draw the class boundary before writing any methods.