Requirements to Classes
Intermediate · 12 min read · ▶ live playground · ✦ checkpoint
The interviewer finishes reading a machine-coding prompt and the page is still blank. The fastest way forward is not to guess a pattern—it is to turn the language in the prompt into a first model you can challenge.
Noun extraction is a first pass that marks the people, things, places, and concepts named by the requirements as candidate classes or fields. Verb extraction is a second pass that marks the actions and rules as candidate methods or responsibilities.
Both words matter: candidate, not final. The prompt gives you evidence, but grammar does not design the system for you.
Read the prompt twice
On the noun pass, collect repeated domain words before drawing boxes. Do not decide that every marked word deserves a class yet. First build a small vocabulary of what the system talks about.
A noun usually falls into one of four buckets:
- A domain entity is a concept with identity or behavior that matters over time, so it may become a class.
- An attribute is a value that describes another thing, such as a title or timestamp, so it often becomes a field.
- An actor is outside the core model and asks the system to do work, so it may belong in a use case rather than a class box.
- A synonym is another name for a concept you already marked, so merge the words before they create duplicate classes.
On the verb pass, mark what must happen: register, borrow, list, charge, reserve, or cancel. A verb suggests behavior, but its grammatical subject is not automatically the right owner. Assign the behavior to the object that owns the data and invariant the operation needs.
For each verb, ask three questions:
- Which object's state changes?
- Which object has the data needed to enforce the rule?
- Which placement keeps the responsibility cohesive instead of making a distant coordinator inspect fields?
If an operation needs a book's availability, the behavior should live on the book or beside the object that owns the collection—not in a UI controller that happens to receive the click. This is the same change-pressure reasoning behind SRP and cohesion, now applied while the model is still a sketch.
Turn words into a model, not a word cloud
After both passes, collapse the list. Keep nouns with identity, lifecycle, or meaningful behavior. Move descriptive values into fields. Leave external actors at the boundary. Then connect the remaining objects only where the requirements prove a relationship.
Relationships can reveal a missing class. If “member borrows book” also needs a date, status, or return history, the relationship carries data of its own. That is evidence for Loan, rather than a borrowedBook field forced onto either Member or Book.
Method names should express the domain verb while protecting the owner's rule. book.checkout() is stronger than book.available = false because the method can reject a second checkout. catalog.availableBooks() keeps the filtering rule beside the collection it queries.
When not to trust the extraction blindly
A requirements prompt is written for people, not for a parser. A prominent noun such as “system,” “data,” or “manager” may add no domain meaning. A hidden concept may appear only as a rule: “a book cannot be borrowed twice” suggests availability state even if the word availability never appears.
The first pass can also split one idea into synonyms or merge two ideas that later change independently. Interviewers often refine the prompt after you ask questions. New constraints may turn a field into a class, combine two candidate classes, or move behavior to a different owner.
Noun and verb extraction is a starting sketch. Merge and split after you see responsibilities, invariants, and change pressure. Tie the result back to SRP and cohesion: if one box answers unrelated rules, split it; if several boxes protect one tiny idea together, consider merging them. The first extraction is never the final model.
Mini worked example: a lending library
Start with exactly five requirements. During the noun pass, the marked words stand out:
- A member can borrow a book.
- A book has a title and an author.
- A librarian registers new members.
- The catalog lists available books.
- A loan records which member borrowed which book and when.
The repeated domain nouns are member, book, catalog, and loan. Each has a distinct role in the model. title and author describe a book, while “when” becomes Loan.borrowedAt. They are fields, not extra classes. Librarian is the actor initiating registration; no requirement gives a librarian state or rules inside this core model, so it stays outside the four classes.
The noun decisions are:
| Noun | Model choice | Reason |
|---|---|---|
| member | Member class | Has identity and participates in loans |
| book | Book class | Owns bibliographic data and availability |
| loan | Loan class | The member-book relationship carries a date |
| catalog | Catalog class | Owns the searchable book collection |
| title, author, when | Fields | Describe a book or loan |
| librarian | Actor | Initiates registration from outside this core model |
Now assign the verbs to owners. “Registers” becomes Member.register() because member identity is created there; the librarian calls it from the application boundary. “Borrow” and “records” meet at Loan.open(), which creates the dated member-book relationship and asks the book to protect its availability. “Lists available” becomes Catalog.availableBooks() because the catalog owns the collection being filtered.
| Verb phrase | Candidate operation | Why it belongs there |
|---|---|---|
| registers new members | Member.register(id, name) | Creates valid member identity |
| borrows / records | Loan.open(member, book, on) | Owns the relationship and borrowing date |
| prevents a second checkout | Book.checkout() | Protects the book's availability |
| lists available books | Catalog.availableBooks() | Queries the catalog's collection |
The model now has four classes, not one class per marked word:
class diagram
From five requirements to four classes
- 1Member keeps the identity created when the librarian registers someone.
- 2Book turns title and author into fields and protects its availability.
- 3Loan gives the member-book relationship a home for its own date.
- 4The second association records which Book participates in that Loan.
- 5Catalog keeps a book collection and owns the available-books query.
The plain lines record lasting associations. A Loan keeps references to one Member and one Book; a Catalog keeps book references so it can answer searches. The diagram does not invent a base class, repository, or pattern because the five requirements do not need one yet.
The same extraction becomes a small TypeScript skeleton:
class Member {
private id: string;
private name: string;
private constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
public static register(id: string, name: string): Member {
if (id.length === 0 || name.length === 0) {
throw new Error("member id and name are required");
}
return new Member(id, name);
}
}
class Book {
private isbn: string;
private title: string;
private author: string;
private available = true;
public constructor(isbn: string, title: string, author: string) {
this.isbn = isbn;
this.title = title;
this.author = author;
}
public checkout(): void {
if (!this.available) {
throw new Error("book is already on loan");
}
this.available = false;
}
public isAvailable(): boolean {
return this.available;
}
}
class Loan {
private member: Member;
private book: Book;
private borrowedAt: Date;
private constructor(member: Member, book: Book, borrowedAt: Date) {
this.member = member;
this.book = book;
this.borrowedAt = borrowedAt;
}
public static open(
member: Member,
book: Book,
borrowedAt: Date,
): Loan {
book.checkout();
return new Loan(member, book, borrowedAt);
}
public borrowedOn(): Date {
return new Date(this.borrowedAt);
}
}
class Catalog {
private books: Book[] = [];
public add(book: Book): void {
this.books.push(book);
}
public availableBooks(): Book[] {
return this.books.filter((book) => book.isAvailable());
}
}The bodies stay small because the goal is the responsibility map. A later requirement for returns may add Loan.close() and restore book availability. A rule about loan limits may move borrowing coordination toward an object that owns a member's active loans. You can make that change when the prompt supplies the pressure.
Checkpoint
Answer all three to mark this lesson complete
With a vocabulary of principles and a method to find classes, the pattern catalog ahead gives you named solutions to recurring forces. Next come the creational patterns: focused ways to decide how objects are made.