Free preview lesson ยท From the full paid path
Finding the Objects in the Prompt
16 min read
The Candidate Who Modelled Zomato the Company
"Design a food delivery app." That was the whole prompt. The candidate, four years in, nodded and started writing classes with real confidence. Zomato, Restaurant, DeliveryFleet, Warehouse, MarketingCampaign, InvestorRelations. Within five minutes the board had eleven boxes and not one of them was a thing the app actually manipulates. He had modelled the company, not the system. When my co-interviewer asked "which of these does a hungry user's order actually touch," he went quiet, because the honest answer was almost none of them.
The opposite failure is just as common. Another candidate, same prompt, wrote a class for every noun she could think of: Food, Hunger, Cuisine, Taste, Spiciness, DeliveryPersonMood. Thirty boxes, most of them values or feelings, none of them things with state and behaviour worth modelling. She had confused "is a noun in the sentence" with "deserves a class," and drowned the three or four objects that mattered under twenty-six that did not.
Both had the same missing skill. Neither had a method for getting from a sentence to a set of classes. They either free-associated (the company) or literalised (every noun). The skill that was missing is a repeatable pass you can run on any prompt: find who uses the system, find what they do with it, pull the real things out of that, and prune ruthlessly.
Modeling from a prompt is the method for turning "design X" into the handful of classes worth writing. When you finish this page you can take a one-line prompt, identify the actors and use cases, extract the entities and their behaviour, and end up with four or five classes that carry the design, not eleven that model the wrong universe or thirty that model feelings. The next lesson puts these four moves on a 45-minute clock. This page slows them down so you can see each one.
Why Should You Care?
First, the prompt is always vague on purpose, and the first ten minutes decide the whole round. A candidate who free-associates or literalises has lost before writing a single method. A candidate with a method looks calm and lands on the right objects fast.
Second, this is the step where you either match the interviewer's mental model or diverge from it silently. Naming the actors and use cases out loud lets them correct your scope before you build on a wrong assumption, which is worth more than any clever class you draw later.
Third, at work the same skill turns a product ticket into a design. "Let users split a bill" is a prompt. Knowing how to find the Group, Expense, and Split inside it, and to not create a Friendship class nobody needs, is the difference between a clean feature and a sprawling one.
๐ข The Simple Version: Four Moves From Sentence to Classes
In plain words: run the same four moves on every prompt. Find the actors (who pokes the system from outside), list the use cases (what they poke it to do), pull entities from the nouns and behaviour from the verbs, then prune everything that is not a real thing with state and rules.
Think of a wedding caterer taking an order. They do not start by listing every ingredient in the kitchen. They ask: who is this for (the actors: bride's side, groom's side, the planner)? What do they need done (the use cases: 300 plates, three live counters, jain options)? From those answers the real things fall out (the menu, the counter, the headcount), and a hundred irrelevant details (the caterer's rent, the cook's mood) never make it onto the order sheet. A caterer who instead wrote down every noun in the venue would never finish the order.
Here are the four moves, run on "design a parking lot."
Scroll sideways to read, or tap to zoom
Move 1: Actors. Who or what interacts with the system from the outside? For a parking lot: the driver at the entry gate, the driver at the exit gate, maybe an admin who configures rates. Actors are almost always people or external systems. The sharp test, and the one candidates fail: a vehicle is not an actor. A car does not "use" the parking system, it is a thing the system tracks. It is data flowing through, not a user poking from outside. Getting this line right stops you from putting park() on the vehicle.
An actor is not banned from also being a class. If the system only talks to them, they stay outside the model. If it stores state about them, they also earn an entity. A library Member is both: the person at the desk, and a row with fines. A parking-lot vehicle is only data, so it is an entity and not an actor.
Move 2: Use cases. What does each actor do with the system? Park a vehicle. Leave and pay. Check availability. An admin changes the rate card. Each use case is a verb phrase from an actor's point of view, and each one will need a method somewhere. Listing them is how you find the operations before you find the objects.
Move 3: Nouns and verbs. Now read the prompt and the use cases for nouns (candidate entities: parking lot, floor, spot, vehicle, ticket, rate) and verbs (candidate behaviour: park, leave, find a spot, calculate fee). Nouns become candidate classes or fields. Verbs become candidate methods, and each method has to land on some object.
Move 4: Prune. This is the move both failing candidates skipped. Not every noun is a class. Run each candidate noun through the deserves-a-class test from Thinking in Objects: does it have state plus behaviour that protects it? "Vehicle" earns a class (it has a plate and a kind). "Spiciness" does not, it is a value or nothing. The noun "rate" does not become a Rate data class. The verb "calculate fee" becomes a PricingStrategy object. Prune until only the real things remain.
๐ก A Worked Pass, and CRC Cards
Run all four moves on "design a parking lot" to the end and watch the class list appear.
Actors: entry-gate driver, exit-gate driver, admin. Use cases: park a vehicle, leave and pay, refuse when full, change the rate card. Nouns from the prompt and use cases: parking lot, floor, spot, vehicle, ticket, rate, gate. Verbs: park, leave, find a fitting spot, occupy, release, calculate fee.
Now prune the nouns:
- Parking lot earns a class. It holds floors and coordinates park and leave.
- Floor earns one. It holds spots and indexes the free ones.
- Spot earns one. It has state (occupied or free) and behaviour that protects it (occupy throws if taken).
- Vehicle earns one. It has a plate and a kind. A truck is a vehicle in English. Kind is still an enum field, not
Truck extends Vehicle, because only a label and a fit rule vary, and both live outside the vehicle. - Ticket earns one. It records which vehicle, which spot, when.
- Rate does not earn a
Ratedata class. The verb "calculate fee" becomes aPricingStrategyobject, found through the verbs, not the nouns. - Gate does not earn a class in v1. It is where an actor stands, not a thing with state the system protects. It is an actor's location, and it collapses into "the caller of park and leave." If concurrency across gates comes up, it reappears as a reason for a lock, not as a class.
Six real classes from a one-line prompt (ParkingLot, Floor, ParkingSpot, Vehicle, Ticket, PricingStrategy), with a method for every use case. That is the whole move, and it is repeatable on splitwise, movie tickets, or a ride app.
To assign the verbs to the nouns cleanly, the oldest and still best tool is the CRC card: Class, Responsibilities, Collaborators. One index card per class. On it you write the class name, the short list of things it is responsible for, and the other classes it talks to. It is deliberately small, because a card that overflows is a class doing too much.
Scroll sideways to read, or tap to zoom
For the parking lot:
- ParkingLot. Responsible for: coordinate park and leave, find a fitting spot across floors. Collaborators: Floor, PricingStrategy, Ticket.
- Floor. Responsible for: hold spots, hand out a free one of a type, take one back. Collaborators: ParkingSpot.
- ParkingSpot. Responsible for: know if it is free, occupy and release itself, refuse an illegal occupy. Collaborators: Vehicle.
- PricingStrategy. Responsible for: turn a ticket and an exit time into an amount. Collaborators: Ticket.
The value of the card is the constraint. If ParkingLot's responsibility list grows to eight items, the card is telling you it has become a god object, and some of those responsibilities want to move to Floor or a strategy. The card surfaces the "one class doing too much" smell on cheap paper, before it becomes a 400-line class in code. This is called responsibility-driven design, and it is just the discipline of asking "whose job is this?" for every verb until each one has exactly one clear owner.
Run the same four moves on a different prompt to prove they are not parking-lot-specific. "Let friends split a bill." Actors: the user who adds an expense, the user who settles up. Use cases: add an expense, choose how it splits, see who owes whom, settle. Nouns: group, expense, split, balance, friend, bill. Verbs: add, split equally, split by share, compute balances, settle. Now prune. Group earns a class, it holds members and expenses. Expense earns one, it has an amount and who paid. Split earns one, or becomes a strategy, because "split equally" and "split by exact share" are two behaviours behind one idea, exactly the kind of variation the verbs reveal. Balance is a computed result, derived from the expenses, so it is a method's output, not a stored class. And friend? Prune it. Friendship here is just membership in a group, a list on Group, not a thing with state and rules of its own. Four moves, a clean model, and the one tempting noun (friend) correctly left out. The method travels.
๐ด Architect's Corner: The Actor Mistake and the Two Failure Directions
The single most diagnostic error in this whole exercise is treating a core entity as an actor. The vehicle-is-not-an-actor point is not pedantry, it changes the design. If you think of the vehicle as a user of the system, you start putting behaviour on it, vehicle.park(), vehicle.pay(), and now the vehicle knows about spots and rates and gates, which is backwards. The vehicle is data the system moves around. The driver is the actor, and the system (the parking lot) owns the behaviour. Get the actor line wrong and responsibilities end up on the wrong objects for the rest of the design. The same trap hides in every prompt: a Message is not an actor in a chat app (the user is), an Order is not an actor in a food app (the customer is).
The two failure directions are worth naming because you can feel yourself sliding toward one. Analysis paralysis is modelling every noun, the thirty-box candidate. The cure is the prune step and the "deserves a class" test: most nouns are values, and values are fields or enums. The god object is the opposite, refusing to split, so one ParkingLotManager does finding, pricing, ticketing, and concurrency. The cure is the CRC card overflowing: when the responsibility list runs long, the class is hiding several classes. Good modelling lives between these two, and the two tools, the prune test and the CRC card, are what keep you there.
One more senior habit: model the core first and defer the rest out loud. When a prompt is big ("design Swiggy"), you do not model the whole company, you say "for v1 I am modelling the cart, the order, and the pricing, and I am deferring the restaurant onboarding, the rider assignment, and payments, because those are separate subsystems." That is scope control, and it is scored. The candidate who modelled Zomato the company failed precisely because he never drew this line, so his objects sprawled to fill the entire business.
Finally, resist the urge to model the UI. Screens are not classes. "Login screen," "cart screen," "order-tracking screen" are how a user navigates, not things the domain owns. The Order object is the same object whether it is shown on a phone, a tablet, or an SMS. Modelling screens is another way of literalising the wrong nouns, and it is why the first candidate's MarketingCampaign box existed at all.
How This Shows Up in India
Swiggy "design the app." The actors are the customer, the restaurant, the rider, and admin. The use cases are browse, add to cart, place order, accept, pick up, deliver. The real entities that fall out are Cart, Order, MenuItem, RestaurantProfile, not Hunger or Cuisine. Naming the actors first stops you from modelling the restaurant's kitchen equipment.
IRCTC "design ticket booking." The actor at the window is the passenger, and an admin who loads trains. The use cases are search, hold a berth, pay, confirm, cancel. The entities are Booking, Passenger, Berth, Train, FareRule. Passenger is both: the person poking the system, and a row the booking stores (name, age, berth). A Train is only an entity the system tracks, not an actor. That distinction keeps book() on the booking, not on the train.
Splitwise "let friends split a bill." The actor is the user. The use cases are add an expense, choose a split, settle up. The entities are Group, Expense, Split, Balance. The noun "friend" tempts a Friendship class, but prune it: friendship is just membership in a group, a field, not a thing with behaviour worth protecting. That prune is the whole difference between a tight model and a sprawling one.
The Decision Matrix
| In the prompt you see | What it usually becomes | The move that finds it |
|---|---|---|
| A person or external system that pokes the app | An actor. Also an entity if you store state about them | Move 1: actors |
| A verb an actor performs | A method, and a use case | Move 2: use cases |
| A noun with state and protected behaviour | A class | Move 3 + prune |
| A noun that is just a value (spiciness, currency) | A field or an enum | Prune step |
| A rule that changes for business reasons | A strategy, found via a verb | Move 3, verbs |
| A core entity you were about to call an "actor" | Data the system tracks, behaviour lives elsewhere | The actor test |
| A screen or page | Not a class; the domain object is the same across screens | Resist UI modelling |
Common Mistakes
- "Design a food app, so I'll model Zomato, warehouses, and marketing." You modelled the company, not the system. Start from the actors and use cases a hungry user actually triggers, and the eleven business boxes never appear.
- "Every noun in the prompt is a class." Spiciness, hunger, and taste are values or nothing. The prune step and the deserves-a-class test exist to drown these before they drown your three real objects.
- "The vehicle parks itself, so
vehicle.park()." The vehicle is data the system tracks, not an actor. The driver is the actor and the parking lot owns the behaviour. Treating an entity as an actor puts methods on the wrong objects for the rest of the design. - "One
ParkingLotManagerdoes finding, pricing, ticketing, and locking." That is the god object. When a CRC card's responsibility list runs long, the class is hiding several classes. Split by whose job each verb is. - "I'll model the login screen and the cart screen as classes." Screens are navigation, not domain. The
Orderis the same object on a phone or an SMS. Modelling UI is literalising the wrong nouns.
๐ง Key Takeaways
- Run four moves on every prompt: actors, use cases, nouns and verbs, then prune. It turns a vague sentence into four or five real classes instead of eleven wrong ones or thirty useless ones.
- A core entity is not an actor. The driver uses the system; the vehicle is tracked by it. Get this line right or behaviour lands on the wrong objects.
- Nouns are candidate classes, verbs are candidate methods, and most nouns get pruned to fields or enums. The prune step is where the two failure directions are cured.
- CRC cards (Class, Responsibilities, Collaborators) assign verbs to owners and expose god objects. An overflowing card means the class is doing too much.
- Model the core and defer the rest out loud. Scope control is a scored skill, and it is what keeps "design Swiggy" from becoming eleven boxes about the business.
Think About It
"You are given 'design a chat app.' A candidate writes a Message class with a send() method that connects to the network and delivers itself. What is wrong with treating the message this way?" The message is data the system moves, not an actor that acts. Giving it send() makes it know about networks, sockets, and delivery, which is behaviour that belongs to a ChatService or a Connection, not to the payload. The user is the actor, the service owns sending, and the Message just holds sender, text, and timestamp. This is the same actor mistake as vehicle.park().
"On 'design Splitwise,' you list the noun 'friend.' Does it earn a class?" Almost never in v1. Friendship is membership in a group, which is a field or a list on Group, not a thing with state and rules of its own. If the prompt later adds friend requests, blocking, or a friendship status with transitions, then it grows behaviour and might earn a class. Absent that, a Friendship class is a noun literalised into a box that does nothing, and it should be pruned.
"An interviewer gives you 'design all of Uber.' How do you avoid the eleven-box company model?" I name the actors (rider, driver, admin) and pick one core use case to model in depth, say requesting and assigning a ride, and I say out loud that I am deferring payments, surge pricing, and driver onboarding as separate subsystems. That sentence is scope control: it shows I know the system is bigger than what I am drawing, and it keeps my objects focused on the trip, the rider, the driver, and the matcher instead of sprawling into the whole business.
Further Reading
- Rebecca Wirfs-Brock on Responsibility-Driven Design. The origin of CRC cards and the "whose job is this?" discipline, from the person who created the technique.
- Object-Oriented Analysis: finding objects (Craig Larman, Applying UML and Patterns). The classic noun-and-verb extraction method with worked examples and the pruning judgement spelled out.
- Domain-Driven Design distilled, Vaughn Vernon. Why modelling the core domain and deferring the rest, rather than the whole business, is how real systems stay coherent.
Full quizzes, answers, progress, case studies and interview problems available in the paid path.