Loading learning content...
If there's one technique that every object-oriented designer learns early, it's this: nouns in a problem statement are candidate objects. This simple heuristic has guided countless developers from requirements to code, providing a systematic starting point for design.
But like many simple rules, its effective application requires nuance. Not every noun becomes a class. Some nouns represent attributes, others describe roles or states, and some are simply noise. The real skill lies in separating the meaningful from the meaningless—transforming a raw list of nouns into a refined set of domain objects.
This page teaches you that skill.
You will learn how to systematically extract nouns from problem statements, categorize them into objects, attributes, and noise, apply filtering criteria to identify genuine classes, and handle the edge cases that trip up most developers.
The noun-to-object mapping isn't arbitrary—it reflects a deep connection between language and software design.
In natural language, nouns represent things—concrete entities like 'customer,' 'invoice,' and 'product,' or abstract concepts like 'payment,' 'reservation,' and 'permission.' These are the subjects and objects of sentences, the entities around which actions revolve.
In object-oriented programming, classes represent things—entities that have identity, state, and behavior. They are the nouns of our code, the building blocks around which we organize logic.
This parallel isn't coincidental. Object-oriented programming was designed to model real-world (and conceptual) domains. The vocabulary of the domain—its nouns—naturally maps to the classes in an OO design.
Object-oriented design mirrors natural language: nouns become classes, verbs become methods, adjectives become attributes, and prepositions suggest relationships. This linguistic alignment is why well-designed OO code reads almost like prose.
Historical context:
The noun-extraction technique dates back to the 1980s, popularized by Rebecca Wirfs-Brock in her work on responsibility-driven design and later formalized in methodologies like the Booch Method and UML. It has stood the test of time because it works—not perfectly, but as a reliable starting point.
The technique works because:
Let's formalize the process of extracting nouns from requirements. While it seems straightforward, doing it rigorously ensures you don't miss important candidates.
Step 1: Identify All Nouns
Go through your requirements and mark every noun and noun phrase. Be inclusive at this stage—you'll filter later. Include:
Let's practice with this requirement:
"An online bookstore allows customers to browse books by category, add them to a shopping cart, and checkout using credit cards or gift cards. The store offers discounts for bulk purchases and loyalty points for repeat customers. Customers can track their orders and write reviews for purchased books."
1234567891011121314151617181920
Extracted Nouns and Noun Phrases:──────────────────────────────────────── 1. online bookstore2. customers3. books4. category5. shopping cart6. credit cards7. gift cards8. store9. discounts10. bulk purchases11. loyalty points12. repeat customers13. orders14. reviews15. purchased books Total: 15 noun candidatesStep 2: Create a Candidate List
Organize your extracted nouns into a table for systematic analysis. For each noun, you'll eventually determine:
| Noun | Initial Impression | Notes/Questions |
|---|---|---|
| online bookstore | System/Context | The system itself, likely becomes the application boundary |
| customers | Strong candidate | Users who buy—clear entity with identity |
| books | Strong candidate | Core domain object |
| category | Candidate | Books belong to categories—classification entity |
| shopping cart | Strong candidate | Holds items before checkout |
| credit cards | Candidate | Payment method—could be class or enum |
| gift cards | Candidate | Payment method variant |
| store | Duplicate? | Same as 'online bookstore'? |
| discounts | Candidate | Has rules and amounts—likely a class |
| bulk purchases | Unclear | Is this a type of order or a discount trigger? |
| loyalty points | Candidate | Accumulated over time—needs tracking |
| repeat customers | Role, not class | A Customer with purchase history |
| orders | Strong candidate | Core transactional entity |
| reviews | Candidate | User-generated content with text, rating |
| purchased books | Relationship | OrderItem or Order-Book association |
At this stage, include more rather than less. It's easier to eliminate a noun later than to realize you missed an important one. The filtering process in the next section will separate the wheat from the chaff.
Not all nouns are equal. As you analyze your candidates, you'll find they fall into distinct categories. Understanding these categories helps you make the right design decisions.
| Category | Description | Example | Design Outcome |
|---|---|---|---|
| Concrete Entity | A tangible thing with clear identity | Customer, Book, Order | Becomes a class |
| Abstract Concept | An intangible but important domain concept | Discount, Permission, Rule | Usually becomes a class |
| Role | A temporary capacity or status of another entity | Admin, VIP, Repeat Customer | Attribute, enum, or role class |
| Attribute | A simple property of another entity | Name, Price, ISBN | Becomes a field in a class |
| System Context | The system being built or its boundary | Online Store, Application | Rarely a class—it's the whole system |
| External Actor | Something outside the system that interacts with it | PaymentGateway, EmailService | Interface or adapter (integration point) |
| Event/Action Noun | A noun form of an action that happens | Purchase, Payment, Shipment | Often becomes a class (reified event) |
| Synonym/Duplicate | Same concept with different name | Store/Bookstore, User/Customer | Merge into single concept |
| Implementation Detail | Technical rather than domain concept | Database, Cache, Queue | Not a domain class—infrastructure |
The most valuable categories for OO design are:
Concrete Entities — These almost always become classes. They have identity (two Customers are different even if they have the same name), state (attributes change over time), and behavior (they do things).
Abstract Concepts — These often become classes, especially if they have their own rules and complexity. A Discount isn't just a number—it has conditions, expiration dates, and application logic.
Event/Action Nouns — Words like 'payment,' 'reservation,' 'shipment' represent things that happened. In well-designed systems, these are often modeled as classes so they can be tracked, audited, and reasoned about.
Reification means 'making something a thing.' When an action becomes important enough to track, store, or reason about independently, you reify it into a class. 'Customer places order' → Order class. 'User logs in' → LoginSession class. 'Package ships' → Shipment class.
Now comes the crucial step: filtering your noun candidates to identify genuine classes. Apply these criteria to each candidate:
Applying these criteria to our bookstore example:
| Noun | Decision | Rationale |
|---|---|---|
| online bookstore | ❌ Reject | This is the system being built, not a class within it |
| customers | ✅ Class | Has identity, attributes (name, email), behaviors (browse, buy), lifecycle (registration to inactive) |
| books | ✅ Class | Core entity with title, author, ISBN; has lifecycle (in stock, out of print) |
| category | ✅ Class | Has identity (unique name), attributes (description), books belong to categories |
| shopping cart | ✅ Class | Has state (items), behaviors (add, remove, checkout), lifecycle (active to abandoned/converted) |
| credit cards | ⚠️ Maybe | Could be PaymentMethod class with subclasses, or just a string type on Order |
| gift cards | ⚠️ Maybe | Similar to credit cards—depends on whether gift cards have balance tracking |
| store | ❌ Reject | Duplicate of 'online bookstore' |
| discounts | ✅ Class | Has rules, percentage/amount, expiration, conditions—too complex for just an attribute |
| bulk purchases | ❌ Reject | This is a condition for discount, not a separate entity |
| loyalty points | ⚠️ Maybe | Could be attribute of Customer or separate LoyaltyAccount class |
| repeat customers | ❌ Reject | Role of Customer—captured by purchase history |
| orders | ✅ Class | Core transactional entity with items, totals, status, shipping info |
| reviews | ✅ Class | Has author, text, rating, date, book reference—full entity |
| purchased books | ❌ Reject | Relationship between Order and Book—becomes OrderItem or OrderLine |
Some nouns genuinely sit on the border. Whether 'loyalty points' becomes a separate class or an attribute depends on complexity. If points have complex earning rules, expiration, tiers, and redemption logic, they deserve a class. If they're just a number, they're an attribute. Context matters.
One of the most common decisions during noun analysis is whether something should be a class in its own right or an attribute of another class. This decision has significant design implications.
Consider 'Address' in a customer management system:
When should Address be a class?
The golden rule: If it has behavior, make it a class.
An Address that can format itself for display, validate itself, calculate shipping zones, or compare itself to other addresses has behavior—and thus belongs in a class.
A 'price' is usually an attribute (a simple decimal). But if price has complex behaviors—discount calculations, currency conversion, tax inclusion rules—it might become a Money or Price class.
More examples of the attribute-vs-class decision:
| Noun | Simple Case (Attribute) | Complex Case (Class) |
|---|---|---|
| Single contact email string | Multiple emails, verification status, preferences → EmailAddress class | |
| Status | Simple enum field | Complex state machine with allowed transitions → OrderStatus class |
| Date Range | startDate and endDate fields | Overlapping checks, contains logic → DateRange class |
| Money | Decimal amount field | Currency, rounding, arithmetic → Money class |
| Phone | String phoneNumber | Multiple phones, type (home/work/mobile), formatting → PhoneNumber class |
| Rating | Integer 1-5 | Weighted ratings, aggregations, trending → Rating/RatingSystem class |
When uncertain, start with the simpler choice (attribute). If you later discover complexity, refactoring an attribute into a class is straightforward. Over-engineering upfront creates unnecessary complexity. The key is recognizing when to promote.
Real requirements documents are written by humans, often multiple stakeholders. This means the same concept may appear under different names, and different concepts may accidentally share a name.
Synonyms: Different Words, Same Concept
Consider these appearing in the same requirements:
These might all refer to the same entity—the person who purchases from your system. Recognizing synonyms prevents you from creating redundant classes and aligns your design with a single, consistent vocabulary.
Homonyms: Same Word, Different Concepts
The opposite problem: one word used to mean different things.
Consider 'account':
These are fundamentally different entities that happen to share a name. In code, you might have:
UserAccount or LoginAccount — Authentication and identityFinancialAccount or BillingAccount — Money managementWhen the same word appears to mean different things, check the context. If different stakeholders (IT vs Finance, for example) use the same term differently, each context may need its own class. This is a pattern from Domain-Driven Design called Bounded Contexts.
Detection techniques:
Group by responsibility — Sort your nouns by what they're responsible for. Synonyms cluster together; homonyms spread across multiple groups.
Ask stakeholders — When you encounter 'order' in different contexts, confirm: Is the 'order' from the warehouse and the 'order' from customer service the same thing?
Look at attributes — If two nouns have completely different attributes, they're probably different concepts, even if named similarly.
Consider lifecycle — Do the entities go through the same states? A sales order and a work order have different lifecycles—they're different classes.
Some of the most important classes in your design don't appear explicitly in the requirements. They're implied by relationships, actions, or constraints that the requirements describe.
Implicit nouns from verbs:
When you see actions like 'customer places order,' there's an implicit noun: the placement itself. Is there value in capturing when, how, and in what context the order was placed? If yes, you've discovered an implicit class.
| Verb Phrase | Implicit Noun | When It's Needed |
|---|---|---|
| Customer pays order | Payment | Track payment status, method, history |
| Driver delivers package | Delivery | Track delivery attempts, proof, timing |
| User logs in | Session | Track active sessions, locations, devices |
| Admin approves request | Approval | Audit trail, approval chain, comments |
Implicit nouns from relationships:
When two entities are related with additional information about that relationship, there's often an implicit join entity.
"Students can enroll in courses. The system tracks their grade and enrollment date."
Without Enrollment as a class, you'd struggle to capture per-course grades for each student.
123456789101112131415161718
// Wrong: Where does grade go?class Student { name: string; courses: Course[]; // No place for grades!} // Right: Enrollment captures the relationship dataclass Enrollment { student: Student; course: Course; enrollmentDate: Date; grade: Grade;} class Student { name: string; enrollments: Enrollment[]; // Access courses through enrollments}Implicit nouns from collections:
When requirements describe a collection that needs its own behavior, there's often an implicit collection class.
"The shopping cart should show total price, allow removing items, and suggest related products."
The Cart isn't just a list of items—it has its own behaviors (calculate total, suggest products). It deserves to be a class, not just a List<Product> on Customer.
Ask these questions: 'What stores this information?' 'What tracks this activity?' 'What enforces this constraint?' 'What represents this relationship?' The answers often reveal implicit classes that requirements never named.
Let's apply everything we've learned to a complete example. Here are the requirements for an event ticketing system:
"Design a system where event organizers can create events and list tickets for sale. Events have a name, date, venue, and seating chart. Tickets come in different categories (VIP, Regular, Standing) with different prices. Customers can browse events, select seats, and purchase tickets. The system should prevent double-booking and allow customers to view their purchase history. Event organizers can track sales and see real-time attendance."
Step 1: Extract all nouns
123456789101112131415161718
Extracted Nouns:─────────────────1. system2. event organizers3. events4. tickets5. sale6. name7. date8. venue9. seating chart10. categories (VIP, Regular, Standing)11. prices12. customers13. seats14. purchase history15. sales16. real-time attendanceStep 2: Categorize and filter
| Noun | Category | Decision |
|---|---|---|
| system | System context | ❌ The application itself |
| event organizers | Concrete entity | ✅ User type with special permissions |
| events | Concrete entity | ✅ Core domain object |
| tickets | Concrete entity | ✅ Core domain object |
| sale | Event noun | ⚠️ Could be Purchase/Order class |
| name | Attribute | ❌ Attribute of Event |
| date | Attribute | ❌ Attribute of Event |
| venue | Concrete entity | ✅ Has address, capacity, own identity |
| seating chart | Concrete entity | ✅ Complex structure with sections/rows/seats |
| categories | Abstract concept | ✅ TicketCategory with rules and pricing |
| prices | Attribute | ❌ Attribute of TicketCategory (or Money class if complex) |
| customers | Concrete entity | ✅ User type that purchases |
| seats | Concrete entity | ✅ Individual identifiable positions |
| purchase history | Collection/Relationship | ⚠️ Collection of Purchases—implicit Purchase class |
| sales | Event noun | ⚠️ Same as 'sale' → Purchase class |
| attendance | Abstract concept | ⚠️ Could be derived data or Attendance class |
Step 3: Identify implicit classes
Step 4: Produce initial class list
1234567891011121314151617181920
Core Domain Classes:───────────────────── User (base)├── EventOrganizer└── Customer Event (name, date, venue)Venue (name, address, capacity, seatingChart)SeatingChart (sections)├── Section (name, rows)│ ├── Row (label, seats)│ │ └── Seat (number, status) TicketCategory (name, price, event)Ticket (category, seat, status: available/reserved/sold) Purchase (customer, tickets, purchaseDate, total) [Possibly] Attendance (event, timestamp, headcount)Through systematic extraction and filtering, we went from 16 raw nouns to a clean set of 12 classes. Some nouns were rejected (system, name, date), some were merged (sale → Purchase), and some implicit ones were discovered (SeatingChart hierarchy, User base class).
What's Next:
With nouns covered, the next page turns to verbs as potential methods. You'll learn how to extract behaviors from action words in requirements and assign them to the appropriate classes—answering the question 'What does each object do?'
You now have a systematic technique for extracting objects from nouns in problem statements. By combining generous extraction with rigorous filtering, you can reliably identify the classes that will form the backbone of your object-oriented design.