Problem Decomposition Guide: PhoneBook Lab
1. Understanding the Real-World Problem
What Is a Phone Book?
Before diving into code, think about physical phone books:
Questions to Consider:
- How were phone books organized before smartphones?
- What operations do people perform with phone books?
- What makes a phone book different from a simple list?
- Why might you need to search in both directions?
Exercise: List 5 things you do with your phone’s contact list. Which of these would be easy or hard to implement? Why?
2. The Concept of Abstraction
Why Create a PhoneBook Class?
The lab mentions this is your “first meaningful abstraction.” But what does that mean?
Think About It:
- You could just use a dictionary/HashMap directly. Why create a class?
- What problems does wrapping the data structure solve?
- How does this make your code more maintainable?
Real-World Analogy: A car’s steering wheel is an abstraction. You don’t need to know about rack-and-pinion gears or hydraulic systems—you just turn the wheel. Similarly, users of your PhoneBook class shouldn’t need to know if you use a HashMap, TreeMap, or two separate lists internally.
3. Core Functionality Analysis
Essential Operations
1. Adding Entries
add(name, phoneNumber)
Questions to Consider:
- What if the name already exists?
- Should you overwrite or reject?
- Can one person have multiple numbers?
- What about invalid inputs?
2. Looking Up by Name
lookup(name) → phoneNumber
Questions to Consider:
- What if the name doesn’t exist?
- Should lookup be case-sensitive?
- What about partial matches?
- How do you handle middle names or nicknames?
3. Reverse Lookup by Number
reverseLookup(phoneNumber) → name
Questions to Consider:
- What if multiple people share a number?
- What if the number doesn’t exist?
- How is this different from regular lookup?
4. Data Structure Decisions
Choosing Your Internal Storage
Option 1: Single Data Structure
- One HashMap/Dictionary
- Keys are names, values are numbers
- Problem: How do you do reverse lookup efficiently?
Option 2: Dual Data Structures
- Two HashMaps/Dictionaries
- One for name→number, one for number→name
- Problem: How do you keep them synchronized?
Option 3: List of Objects
- Array/List of PhoneBookEntry objects
- Each entry has name and number
- Problem: How do you search efficiently?
Exercise: Draw diagrams of each approach. List pros and cons for each.
5. Edge Cases and Design Decisions
Input Validation Scenarios
Names:
- Empty names?
- Names with special characters?
- Very long names?
- Duplicate names (John Smith vs. John Smith Jr.)?
Phone Numbers:
- Different formats: (555) 123-4567 vs 555-123-4567 vs 5551234567
- International numbers?
- Extensions?
- Letters in numbers: 1-800-FLOWERS?
Behavior Decisions
When Adding:
- If name exists: Update? Error? Add second number?
- If number exists with different name: Allow? Warning?
When Looking Up:
- Not found: Return null? Empty string? Throw exception?
- Multiple matches: Return first? All? Error?
Exercise: For each scenario above, decide what YOUR implementation will do and document why.
6. Implementation Planning
Phase 1: Minimal Viable PhoneBook
Goals:
- Store name-number pairs
- Basic add and lookup
- No error handling yet
- Test with 5 entries
Phase 2: Add Reverse Lookup
Goals:
- Implement reverseLookup
- Ensure consistency between lookups
- Handle not-found cases
- Test both directions work
Phase 3: Handle Edge Cases
Goals:
- Add input validation
- Decide on duplicate behavior
- Add error messages
- Test with problematic inputs
Phase 4: Enhance Usability
Goals:
- Case-insensitive search?
- Partial name matching?
- Format phone numbers?
- Multiple numbers per person?
7. Testing Strategy
Unit Test Categories
Basic Functionality:
- Add entry, then look it up
- Add entry, then reverse look it up
- Look up non-existent name
- Reverse look up non-existent number
Edge Cases:
- Empty string inputs
- Very long inputs
- Special characters
- Duplicate entries
State Consistency:
- After adding 10 entries, all lookups work
- After updating, both lookups reflect change
- After removing (if implemented), both lookups updated
Test-Driven Thinking
Before implementing each method, write down:
- What should happen in the normal case?
- What could go wrong?
- What should happen in each error case?
8. Design Patterns and Principles
Encapsulation
Your PhoneBook hides HOW it stores data:
- Users don’t know if you use HashMap, TreeMap, or Arrays
- Users don’t care about your internal format
- You can change implementation without breaking user code
Interface Consistency
All methods should behave predictably:
- Similar methods return similar types
- Error handling is consistent
- Naming follows conventions
Single Responsibility
Each method does ONE thing:
add()
only adds (doesn’t also search or validate)lookup()
only retrieves (doesn’t modify)- Validation is separate from storage
9. Common Implementation Pitfalls
Pitfall 1: Inconsistent State
Problem: Name→Number works but Number→Name doesn’t Prevention: Always update both directions together
Pitfall 2: Case Sensitivity Confusion
Problem: “John” and “john” treated as different Prevention: Decide on case handling early and be consistent
Pitfall 3: Null/None Handling
Problem: Returning null/None causes errors in caller code Prevention: Document what you return for “not found”
Pitfall 4: Format Assumptions
Problem: Assuming all numbers look like “555-1234” Prevention: Store numbers as strings, not integers
10. Thinking Exercises
Exercise 1: Real-World Complexity
How would you handle:
- Business entries with multiple locations?
- People who change their names?
- Shared family phone numbers?
- International calling codes?
Exercise 2: Performance Considerations
If your phone book had 1 million entries:
- Which operations would be slow?
- How would you optimize lookup?
- Would reverse lookup be equally fast?
- What data structure changes might help?
Exercise 3: Feature Extensions
Design (don’t implement) these features:
- Search by partial name
- List all entries alphabetically
- Remove an entry
- Export to CSV file
- Merge two phone books
11. Connecting to Larger Concepts
This Lab Teaches:
Data Structure Selection:
- Choosing the right tool for the job
- Understanding trade-offs
- Thinking about performance
API Design:
- Creating intuitive method names
- Consistent parameter ordering
- Clear return value semantics
Software Engineering:
- Separation of interface from implementation
- Planning before coding
- Thinking about user needs
12. The Bigger Picture
Why This Matters
Phone books are simple, but the concepts apply everywhere:
- Databases: Store and retrieve any data
- Caches: Fast lookup of computed values
- User Systems: Username↔UserID mappings
- DNS: Domain names↔IP addresses
Every major system needs to store and retrieve data efficiently. By mastering this simple abstraction, you’re learning patterns that scale to complex systems.
Final Challenge Questions
Before you start coding, answer these:
- Why is this better than just using a raw HashMap/Dictionary?
- What would make your PhoneBook class easy for others to use?
- How can you design it so you can change the internals later?
- What would you put in the documentation?
- How is a PhoneBook different from a general-purpose database?
Remember: The goal isn’t just to make it work—it’s to understand WHY each design decision matters and HOW abstraction makes complex systems manageable!