Identifying Objects in Problem Statements
Reading Requirements with an OO Lens
Read aloud is unavailable in this browser.
The Gap Between Requirements and Code
Every software project begins the same way: with requirements. These might come as formal specification documents, user stories scribbled on sticky notes, verbal descriptions from stakeholders, or even a single sentence on a feature request. Yet the journey from these requirements to working object-oriented code remains one of the most challenging leaps in software engineering.
The fundamental question: How do you look at a problem description—often vague, incomplete, and laden with domain jargon—and see the objects that will form the backbone of your solution?
This skill doesn't come naturally. Most developers, when given a new problem, instinctively think about what the code should do—the sequence of operations, the flow of data, the algorithms to apply. This procedural mindset served us well when learning to code, but it's insufficient for building complex, maintainable systems.
By the end of this page, you will understand how to shift your mental approach when reading requirements—from asking 'What should the program do?' to 'What entities exist in this problem domain, and how do they interact?' This shift is the foundation of all object-oriented design.
The Procedural vs Object-Oriented Mindset
Before we can adopt an object-oriented lens, we need to understand what we're moving away from. Most programmers initially learn to think procedurally—breaking problems into sequences of steps, functions that transform inputs to outputs, and flows of control.
Consider this simple requirement:
"The system should allow customers to place orders for products. When an order is placed, the system should calculate the total price including applicable discounts and taxes, then send a confirmation email to the customer."
The procedural approach reads this and immediately thinks:
12345678910
function placeOrder(customerId, productIds, quantities): 1. Fetch customer from database 2. Fetch products from database 3. Calculate subtotal by multiplying prices × quantities 4. Look up applicable discounts 5. Apply discounts to subtotal 6. Calculate tax based on customer location 7. Create order record in database 8. Send email to customer 9. Return order confirmationThis is a valid way to think about the problem, but it immediately couples us to a specific flow. What happens when:
- Business rules for discounts become complex (loyalty programs, seasonal sales, bundle deals)?
- Tax calculations vary by jurisdiction and product category?
- Some customers prefer SMS notifications over email?
- We need to support partial orders, backorders, or pre-orders?
The procedural approach leads to increasingly complex conditional logic, God functions that know everything, and tight coupling between unrelated concerns.
The object-oriented approach reads the same requirement and asks different questions:
- •What entities exist in this domain? — Customer, Order, Product, Discount, Tax, Email
- •What are the responsibilities of each entity? — A Customer places orders. An Order contains products. A Discount knows its rules. Tax calculations depend on jurisdiction.
- •How do these entities relate to each other? — An Order belongs to a Customer. An Order contains OrderItems. Each OrderItem references a Product.
- •What behaviors does each entity exhibit? — An Order can calculate its total. A Discount can apply itself to a price. An EmailNotifier can send confirmations.
- •What are the essential attributes? — A Product has a price. A Customer has an email address. An Order has a status.
Procedural thinking asks: 'What steps solve this problem?' Object-oriented thinking asks: 'What things exist, and how do they collaborate to solve this problem?' The first leads to algorithms; the second leads to architecture.
What Is an Object-Oriented Lens?
An object-oriented lens is a mental framework for interpreting problem statements. It's a deliberate way of reading and analyzing requirements that surfaces the objects, relationships, and behaviors hidden within the text.
Think of it like putting on a special pair of glasses. Without them, a requirements document is just text describing what a system should accomplish. With the OO lens, the same text reveals a cast of characters (objects), their attributes (properties), their abilities (methods), and their relationships (associations).
This lens operates through several key principles:
| Principle | Description | Example Application |
|---|---|---|
| Entity Focus | Look for 'things' that exist in the problem domain, not just actions to perform | In 'customers place orders,' see Customer and Order as entities |
| Responsibility Assignment | Ask what each entity should 'know' and what it should 'do' | An Order should know its items; a Customer should know their contact preferences |
| Relationship Mapping | Identify how entities connect, depend on, or contain each other | A Customer 'has' many Orders; an Order 'contains' OrderItems |
| Behavior Encapsulation | Expect entities to manage their own behaviors, not have behaviors imposed externally | An Order calculates its own total, rather than a separate function calculating it |
| Domain Language | Use the vocabulary from the problem domain, not implementation terms | Say 'Cart' not 'ItemList'; say 'checkout' not 'processPayment' |
The power of this lens is that it forces you to think about the structure of a problem before thinking about its solution. This upfront investment in understanding pays dividends:
- Clearer communication with stakeholders who speak in domain terms
- More stable designs that align with how the business actually works
- Easier evolution when requirements change (and they always do)
- Natural modularity where changes to one entity don't ripple everywhere
The Art of Active Reading
Reading requirements with an OO lens isn't passive. It's an active, analytical process where you engage with the text, question assumptions, and extract structure from prose. Here's a systematic approach:
Step 1: First Pass — Absorb the Domain
- •Read the entire requirements document without trying to design anything
- •Develop an intuitive sense of what the system is about
- •Note unfamiliar terms that need clarification
- •Identify the core purpose—what problem is this system solving?
Step 2: Second Pass — Highlight and Categorize
- •Mark all nouns — these are candidate objects or attributes
- •Mark all verbs — these are candidate methods or behaviors
- •Mark relationships — words like 'has,' 'contains,' 'belongs to,' 'uses'
- •Mark constraints — rules, validations, conditions that must be enforced
Step 3: Third Pass — Question and Clarify
- •For each candidate object: Is this a first-class entity or just an attribute of another?
- •For each candidate method: Which object should own this behavior?
- •For each relationship: What is the cardinality? (one-to-one, one-to-many, many-to-many)
- •What's implicit? What entities exist but aren't explicitly named?
Requirements often omit entities that are obvious to domain experts. When you read 'calculate the total price,' there's an implicit concept of a Price or calculation strategy. When you read 'send notification,' there's an implicit Notification and NotificationChannel. Part of the OO lens is surfacing these hidden entities.
Let's apply this to a concrete example. Consider this parking lot system requirement:
"The parking lot management system tracks the occupancy of a multi-floor parking garage. Each floor has multiple parking spots of different sizes (compact, regular, large) for different vehicle types (motorcycles, cars, trucks). The system records when vehicles enter and exit, calculates parking fees based on duration, and displays available spots on each floor."
- •Parking lot / Parking garage
- •Floor
- •Parking spot
- •Size (compact, regular, large)
- •Vehicle type
- •Motorcycle, Car, Truck
- •Parking fee
- •Duration
- •Display
- •Tracks (occupancy)
- •Has (floors, spots)
- •Enter (vehicles)
- •Exit (vehicles)
- •Records (entry/exit)
- •Calculates (fees)
- •Displays (availability)
Analysis through the OO lens:
- ParkingLot — The top-level entity containing everything
- Floor — An entity with its own identity (floor number) and collection of spots
- ParkingSpot — An entity with size, current occupant (if any), and location
- Vehicle — An entity with type and license plate; but is Motorcycle/Car/Truck a subclass or an attribute?
- ParkingTicket — Implicit! When a vehicle enters, something must record entry time
- ParkingFeeCalculator — Implicit! Fee calculation is a behavior that might have complex rules
Notice how active reading reveals entities that weren't explicitly stated but are essential for a working system.
Domain Objects vs Implementation Details
A critical skill when reading with an OO lens is distinguishing between domain objects (entities that exist in the problem space) and implementation details (technical constructs that exist only in the solution space).
Domain objects are concepts that stakeholders understand. If you explained your design to a business analyst or end user, they should recognize these entities. Implementation details are internal mechanics that support the domain objects but don't directly map to real-world concepts.
| Domain Objects | Implementation Details |
|---|---|
| Customer, Order, Product | CustomerRepository, OrderFactory, ProductCache |
| Payment, Invoice, Receipt | PaymentGateway, DatabaseConnection, JSONSerializer |
| Booking, Room, Guest | BookingValidator, RoomAvailabilityIndex, GuestSession |
| Message, Conversation, User | MessageQueue, ConversationCache, UserAuthenticator |
Why does this distinction matter?
When reading requirements, you should focus primarily on domain objects. Implementation details come later, during detailed design and coding. Mixing them up leads to several problems:
- Polluted domain model — Your core classes become cluttered with database code, network logic, and other infrastructure
- Fragile design — Changes in technology (switching databases, changing frameworks) cascade through your domain
- Lost business logic — The rules that define what your system does become buried under how it does it
- Harder testing — Domain logic becomes untestable without spinning up databases and web servers
When you read 'store order information,' don't immediately think 'OrderDatabase' or 'OrderTable.' Think 'Order' and 'OrderRepository' separately—one is the domain concept, the other is how we persist it. Keep them conceptually distinct.
The test is simple: If you're explaining your design to a non-technical stakeholder, would they recognize this object? If yes, it's probably a domain object. If they'd look at you puzzled, it's probably an implementation detail.
Domain objects should speak the language of the business:
- Not 'UserDTO' but 'User'
- Not 'TransactionProcessor' but 'PaymentService' or simply 'Payment'
- Not 'DataStore' but the specific concept being stored
Common Requirement Patterns and What They Reveal
Over time, you'll recognize patterns in how requirements are phrased. These patterns reliably signal specific object-oriented structures. Learning to recognize them accelerates your ability to see the OO structure hidden in prose.
| Requirement Pattern | What It Suggests | Design Implication |
|---|---|---|
| "Users can be admins or regular users" | Specialization hierarchy | Consider inheritance or role-based design |
| "Each order has multiple items" | One-to-many relationship | Order contains a collection of OrderItem |
| "Products belong to categories" | Classification relationship | Product references Category; consider many-to-many |
| "Customers can have VIP status" | State or role | Could be a flag, enum, or separate decorator/strategy |
| "System notifies users via email, SMS, or push" | Strategy/polymorphism | NotificationChannel interface with multiple implementations |
| "Price is calculated based on rules" | Strategy or specification pattern | PricingStrategy or Rule objects |
| "Workflow moves through pending, approved, rejected" | State machine | State pattern or explicit status field with transition rules |
| "System logs all changes" | Audit trail | Separate audit/history entities or event sourcing |
| "Users can undo their actions" | Command pattern | Command objects with reverse operations |
Initially, recognizing these patterns requires conscious effort. With practice, it becomes automatic. You'll read 'The system should allow different payment methods' and immediately think 'PaymentStrategy interface'—before you even finish the sentence.
Watch for these revealing words:
- 'Different types of...' → Inheritance or strategy pattern
- 'Based on...' → Parameterized behavior, potentially strategies
- 'Can be...' / 'may be...' → Optional attribute or state
- 'At least one...' / 'multiple...' → Cardinality constraints
- 'Only when...' / 'If...' → Business rules, potentially specifications
- 'History of...' / 'previous...' → Audit trail or temporal data
- 'External...' / 'third-party...' → Integration boundary, adapters
Dealing with Ambiguity
Real-world requirements are rarely crisp and complete. They're often vague, contradictory, or silent on crucial details. Reading with an OO lens means not just extracting what's there, but recognizing what's missing and knowing how to proceed.
Types of requirement ambiguity:
- •Underspecified cardinality — 'Customers have addresses' — One address? Many? Which is primary?
- •Unclear ownership — 'Items in the cart' — Does the Cart own Items, or does it reference shared Products?
- •Implicit behaviors — 'Order total' — Does this include tax? Shipping? Discounts? All three?
- •Vague boundaries — 'The system manages inventory' — Does this include warehousing, shipping, returns?
- •Assumed knowledge — Domain-specific terms used without definition
- •Contradictory statements — Later requirements may conflict with earlier ones
How to handle ambiguity:
-
Document your assumptions explicitly. When the requirement says 'customers have addresses,' write down 'Assumed: Customer has multiple addresses with one marked primary.' This creates a paper trail and invites correction.
-
Ask clarifying questions before design. Don't guess when you can ask. Prepare specific, concrete questions: 'Can a product belong to multiple categories?' is better than 'Tell me more about products.'
-
Design for flexibility when truly uncertain. If you genuinely can't determine whether customers have one or many addresses, design for many—it's easier to constrain later than to expand.
-
Create multiple candidate designs. Sometimes ambiguity suggests multiple valid interpretations. Sketch alternatives and present tradeoffs to stakeholders.
-
Use domain experts. The people who will use the system often know things that weren't captured in requirements. A 30-minute conversation with an actual user can resolve hours of speculation.
Don't be frustrated by incomplete requirements—this is the norm, not the exception. Part of professional software engineering is navigating uncertainty intelligently. The OO lens helps by giving you a structured way to identify what you don't know and seek clarification.
Worked Example: Library Management System
Let's walk through a complete example of reading requirements with an OO lens. Here's a partial requirement for a library management system:
"The library system manages a collection of books that members can borrow. Each book has a title, author, and ISBN. Members register with the library by providing their name, email, and a valid ID. A member can borrow up to 5 books at a time for a period of 14 days. If books are returned late, a fine of $0.50 per day is charged. The system should track which books are currently available and allow librarians to add new books or remove damaged ones."
Let's apply our active reading approach:
First Pass Analysis:
Core purpose: Managing book lending in a library.
Key entities mentioned explicitly:
- Library (implied as the system)
- Books
- Members
- Librarians (mentioned in context of adding/removing books)
Key processes:
- Member registration
- Book borrowing and returning
- Fine calculation
- Book management (add/remove)
Second Pass — Extracting Objects:
- •Book — title, author, ISBN
- •Member — name, email, ID
- •Library — collection of books
- •Librarian — admin capability
- •Fine — $0.50 per day
- •Loan — the borrowing event (who, what, when)
- •BookCopy — physical copy vs title (likely multiple copies per book)
- •MembershipCard — the valid ID provided
- •FinePayment — tracking fine status
Critical OO Insight:
The requirement says 'books' but likely means two distinct concepts:
- Book (bibliographic record) — The abstract concept of a book with title/author/ISBN
- BookCopy — Physical copies that can be borrowed
A library might have 3 copies of 'Clean Code.' The Book is one entity (Clean Code, Robert Martin, ISBN X); the BookCopies are three entities that can be independently borrowed.
Third Pass — Behaviors and Relationships:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
class Book: - title: String - author: String - isbn: String - copies: List<BookCopy> + isAvailable(): boolean // Any copy available? + getAvailableCopies(): List<BookCopy> class BookCopy: - book: Book - status: Enum (AVAILABLE, BORROWED, DAMAGED) - currentLoan: Loan? + borrow(member: Member): Loan + return(): void + markDamaged(): void class Member: - name: String - email: String - memberId: String - currentLoans: List<Loan> + canBorrow(): boolean // < 5 books + borrowBook(copy: BookCopy): Loan + returnBook(loan: Loan): Fine? class Loan: - member: Member - bookCopy: BookCopy - borrowDate: Date - dueDate: Date - returnDate: Date? + isOverdue(): boolean + calculateFine(): decimal + complete(returnDate: Date): void class Fine: - loan: Loan - amount: decimal - paid: boolean + pay(): void class Library: - books: List<Book> - members: List<Member> - loans: List<Loan> + registerMember(...): Member + addBook(...): Book + removeBook(copy: BookCopy): void + findAvailableBooks(): List<Book>Notice how a short paragraph of requirements yielded a rich object model with 6 classes, clear attributes, defined behaviors, and explicit relationships. This is the power of reading with an OO lens—you don't just understand what the system does; you see the structure of the solution.
KEEP LEARNING
There’s more to understand.
You’re reading the introduction. Create a free account to read the complete lesson, save notes and keep track of your progress.