Decision Guide and Cheatsheet
This final article serves as your comprehensive reference for the entire series. Bookmark it, print it, keep it open while coding. Here you'll find decision trees for pattern selection, quick refactoring recipes, a complete code smell catalog, 50 interview questions, and curated resources for further learning.
📋 At a Glance
| Aspect | Details |
|---|---|
| Purpose | Quick reference for pattern selection |
| Contents | Decision trees, cheatsheets, Q&A bank |
| Usage | Keep open while coding, review before interviews |
| Interview Questions | 50 questions organized by topic |
| Best For | Fast recall, decision making, interview prep |
🎯 What You'll Learn
This reference article provides:
- Pattern Decision Trees - Flowcharts to choose the right pattern
- Refactoring Quick Reference - Step-by-step recipes for common refactorings
- Code Smell → Refactoring Map - What to apply when you detect a smell
- Interview Questions Bank - 50 senior-level questions with answers
- IDE Shortcuts - IntelliJ/VS Code refactoring commands
- Recommended Resources - Books, courses, tools for further learning
- Complete Series Index - Quick navigation to any topic
🔥 Production Story: The Refactoring Decision Paralysis
A development team had a clear mandate: "Clean up the payment module before Black Friday." They identified 47 code smells across 12 classes. But after two weeks, almost no progress had been made.
TEXT(4 lines)CodeLoading syntax highlighter...
TEXT(5 lines)CodeLoading syntax highlighter...
With clear decision criteria, the team refactored all 47 smells in one week. This article is that decision guide, refined over years of real projects.
🧠 Mental Model: The Pattern Selection Framework
TEXT(32 lines)CodeLoading syntax highlighter...
🔬 Pattern Decision Trees
Decision Tree 1: Long Method (> 20 lines)
TEXT(13 lines)CodeLoading syntax highlighter...
Decision Tree 2: Conditional Logic (switch/if-else)
TEXT(23 lines)CodeLoading syntax highlighter...
Decision Tree 3: Null Handling
TEXT(26 lines)CodeLoading syntax highlighter...
Decision Tree 4: Object Creation Complexity
TEXT(24 lines)CodeLoading syntax highlighter...
Decision Tree 5: Inheritance Problems
TEXT(28 lines)CodeLoading syntax highlighter...
Decision Tree 6: Exception Handling
TEXT(29 lines)CodeLoading syntax highlighter...
Decision Tree 7: Legacy Code Refactoring
TEXT(32 lines)CodeLoading syntax highlighter...
📋 Refactoring Quick Reference
Extract Method
- Identify code block to extract
- Create new method with descriptive name
- Pass needed variables as parameters
- Return any modified values
- Replace original code with method call
- Run tests
Ctrl+Alt+M (Windows) / Cmd+Option+M (Mac)JAVA(48 lines)CodeLoading syntax highlighter...
Extract Parameter Object
- Create new class/record for parameters
- Move parameters to new class
- Update method signature
- Update all call sites
- Run tests
Refactor → Extract Parameter ObjectJAVA(21 lines)CodeLoading syntax highlighter...
Replace Conditional with Strategy
- Create Strategy interface
- Create implementation for each case
- Create factory/registry for strategies
- Replace switch with strategy lookup and call
- Run tests
JAVA(45 lines)CodeLoading syntax highlighter...
Introduce Null Object
- Create interface for the object (if not exists)
- Create NullObject implementation
- Return NullObject instead of null
- Remove null checks
- Run tests
JAVA(50 lines)CodeLoading syntax highlighter...
Extract Interface for Testing
- Identify methods used by clients
- Create interface with those methods
- Have class implement interface
- Update clients to depend on interface
- Create test double implementing interface
- Run tests
Refactor → Extract InterfaceJAVA(43 lines)CodeLoading syntax highlighter...
📊 Code Smell → Refactoring Map
| Code Smell | Severity | Refactoring | Article |
|---|---|---|---|
| Long Method (> 20 lines) | High | Extract Method | Part 6 |
| Large Class (> 200 lines) | High | Extract Class | Part 6 |
| Long Parameter List (> 4) | Medium | Parameter Object | Part 6 |
| Primitive Obsession | Medium | Value Object, Record | Part 6, 23 |
| Switch Statements (> 4 cases) | Medium | Strategy Pattern | Part 7 |
| Parallel Conditionals | High | Strategy, Template Method | Part 7, 13 |
| Null Checks Scattered | High | Null Object, Optional | Part 8 |
| Telescoping Constructor | Medium | Builder Pattern | Part 9 |
| Deep Inheritance (> 3 levels) | High | Composition | Part 10 |
| Refused Bequest | Medium | Delegation | Part 10 |
| Feature Envy | Medium | Move Method | Part 6 |
| Inappropriate Intimacy | Medium | Extract Class | Part 6 |
| Message Chains | Low | Hide Delegate | Part 10 |
| Middle Man | Low | Remove Middle Man | Part 10 |
| Comments Explaining Code | Medium | Extract Method (self-documenting) | Part 6 |
| Duplicate Code | High | Extract Method/Class | Part 6 |
| Dead Code | Low | Delete it | - |
| Speculative Generality | Medium | Remove unused abstraction | - |
| Divergent Change | High | Extract Class (SRP) | Part 2, 6 |
| Shotgun Surgery | High | Move Method, Extract Class | Part 2, 6 |
| Data Clumps | Medium | Parameter Object | Part 6 |
| Lazy Class | Low | Inline Class | - |
| Temporary Field | Medium | Extract Class | Part 6 |
| Alternative Classes | Medium | Extract Superclass/Interface | Part 6 |
| Incomplete Library Class | Low | Decorator, Wrapper | Part 10 |
🎤 Interview Questions Bank (50 Questions)
SOLID Principles (10 Questions)
Q1: What is Single Responsibility Principle and how do you identify violations?
- Class has methods serving different stakeholders (e.g., both UI and reporting)
- Method names suggest different responsibilities ("calculate" and "format")
- Change requests from different teams affect same class
- LCOM (Lack of Cohesion) metric is high
UserService with methods like createUser(), sendWelcomeEmail(), generateUserReport() - these serve different actors.Q2: Explain Open/Closed Principle with a real example.
JAVA(11 lines)CodeLoading syntax highlighter...
Q3: What's the Liskov Substitution Principle and what's the classic Rectangle/Square violation?
JAVA(17 lines)CodeLoading syntax highlighter...
Q4: When should you apply Interface Segregation Principle?
- Clients are forced to implement methods they don't use
- Interface has methods for multiple different purposes
- Changes to unused methods force client recompilation
- Test mocks become complex because of unneeded methods
JAVA(12 lines)CodeLoading syntax highlighter...
Q5: What's the difference between Dependency Inversion and Dependency Injection?
- High-level modules shouldn't depend on low-level modules
- Both should depend on abstractions
- Abstractions shouldn't depend on details
- Way to provide dependencies to an object
- Constructor injection, setter injection, field injection
You can have DI without DIP (injecting concrete classes). You can have DIP without DI (factory patterns).
Refactoring Patterns (10 Questions)
Q6: How do you safely refactor a 500-line method?
- Write characterization tests - capture current behavior
- Identify code "paragraphs" - blocks separated by blank lines/comments
- Extract one method at a time - start with clearest, most isolated block
- Run tests after each extraction
- Look for patterns - repeated code → Extract Method
- Identify responsibilities - multiple responsibilities → Extract Class
- Commit frequently - small, reversible steps
Ctrl+Alt+M), automated testsQ7: When would you use Strategy vs State pattern?
- Algorithm selection at runtime
- Strategies are stateless/interchangeable
- Client chooses the strategy
- Example: Sorting algorithms, payment methods
- Object behavior changes based on internal state
- States manage transitions to other states
- Object doesn't know current state details
- Example: Order status, document workflow
Q8: What's the Null Object pattern and when should you avoid it?
- Null checks are repeated for same object
- "No action" is a valid domain behavior
- Want to simplify client code
- Null has specific meaning (error, not found)
- Masking errors would be dangerous (null in payment = problem!)
- Object has side effects (logging, persistence)
JAVA(2 lines)CodeLoading syntax highlighter...
Q9: Explain Builder pattern. When is Step Builder better?
JAVA(8 lines)CodeLoading syntax highlighter...
- Some parameters are required
- Want compile-time safety
- API must be foolproof
Q10: How does composition solve the inheritance problems?
- Fragile base class (changes break subclasses)
- Forced to inherit unwanted behavior
- Can only inherit from one class
- Deep hierarchies hard to understand
JAVA(11 lines)CodeLoading syntax highlighter...
Error Handling (10 Questions)
Q11: How do you design a good exception hierarchy?
TEXT(11 lines)CodeLoading syntax highlighter...
- Extend RuntimeException (unchecked)
- Include context (error code, correlation ID)
- Layer-appropriate messages (no SQL errors to users)
- Exception chaining (preserve root cause)
Q12: When should you use Result pattern vs exceptions?
- Truly exceptional situations (bugs, infrastructure failures)
- Unrecoverable errors
- When caller can't reasonably handle the error
- Expected failures (validation, business rules)
- When caller must handle the failure
- Functional programming style
- Accumulating multiple errors
JAVA(12 lines)CodeLoading syntax highlighter...
Q13: What is RFC 7807 and why use it?
JSON(8 lines)CodeLoading syntax highlighter...
- Industry standard (clients know what to expect)
- Machine-readable error types (URI)
- Extensible (add custom fields)
- Spring 6 has built-in support
Q14: How do you prevent exceptions from leaking sensitive information?
- Sanitize before logging: Remove credentials, PII
- Generic client messages: "An error occurred" (details in logs)
- Map internal to external: SQLException → "Database unavailable"
- Remove stack traces in production: Only log correlation ID
- Review exception messages: No SQL, no file paths
JAVA(8 lines)CodeLoading syntax highlighter...
Q15: What's exception chaining and why is it important?
JAVA(9 lines)CodeLoading syntax highlighter...
- Root cause visible in stack trace
- Debugging is possible
- Original exception type available via
getCause() - Required for proper error analysis in production
Validation (5 Questions)
Q16: Bean Validation vs Fluent Validation - when to use each?
- Annotation-based (
@NotNull,@Size) - Standard, well-supported
- Good for simple constraints
- Integrates with Spring MVC
- Programmatic, composable
- Complex, conditional rules
- Cross-field validation
- Testable in isolation
Q17: How do you implement cross-field validation?
JAVA(22 lines)CodeLoading syntax highlighter...
Q18: Fail-fast vs accumulate-all validation - trade-offs?
- ✅ Simple implementation
- ✅ Efficient (no wasted checks)
- ❌ Poor UX (fix one error, see next)
- Use for: Security validation, quick checks
- ✅ Better UX (see all problems at once)
- ✅ Fewer round trips
- ❌ More complex code
- ❌ May waste resources on invalid input
- Use for: Form validation, API requests
JAVA(8 lines)CodeLoading syntax highlighter...
Legacy Code (5 Questions)
Q19: What are characterization tests and when do you write them?
- Before refactoring legacy code
- When specification is unclear
- When you can't afford to break existing behavior
- Call the method with known input
- Capture actual output
- Assert that output (even if "wrong")
- Repeat for edge cases
JAVA(7 lines)CodeLoading syntax highlighter...
Q20: Explain Strangler Fig pattern for legacy modernization.
- Identify a feature to replace
- Build new implementation alongside old
- Route traffic to new (start with small percentage)
- Gradually increase traffic to new
- Remove old when new is proven
- Repeat for next feature
- No big bang rewrite
- Can roll back if issues
- Continuous delivery
- Lower risk
Modern Java (5 Questions)
Q21: When should you use Records vs Classes?
- Immutable data carriers (DTOs, events, value objects)
- Simple data aggregation
- Pattern matching targets
- Mutable state needed
- Complex validation in constructor
- Non-data behavior (services, controllers)
- Inheritance needed (records are final)
JAVA(8 lines)CodeLoading syntax highlighter...
Q22: How do Sealed Classes enable exhaustive pattern matching?
JAVA(16 lines)CodeLoading syntax highlighter...
Spring Boot (5 Questions)
Q23: Why prefer constructor injection over field injection?
- ✅ Explicit dependencies (visible in signature)
- ✅ Immutable (final fields)
- ✅ Testable (easy to pass mocks)
- ✅ Fails fast if dependency missing
- ✅ No reflection needed
- ❌ Hidden dependencies
- ❌ Mutable (non-final)
- ❌ Requires reflection or Spring for testing
- ❌ Can create partially initialized objects
JAVA(12 lines)CodeLoading syntax highlighter...
Q24: How do you structure packages in a Spring Boot application?
TEXT(11 lines)CodeLoading syntax highlighter...
- Related code together
- Easy to find everything about a feature
- Clearer module boundaries
- Easier to extract microservices later
TEXTCodeLoading syntax highlighter...
Q25: What are test slices and when to use them?
| Slice | Loads | Use For |
|---|---|---|
@WebMvcTest | Controllers, MVC config | Controller tests (no service/repo) |
@DataJpaTest | JPA, repositories | Repository tests (in-memory DB) |
@JsonTest | Jackson config | JSON serialization tests |
@WebFluxTest | WebFlux controllers | Reactive controller tests |
JAVA(8 lines)CodeLoading syntax highlighter...
🛠️ IDE Shortcuts
IntelliJ IDEA
| Action | Windows/Linux | Mac |
|---|---|---|
| Extract Method | Ctrl+Alt+M | Cmd+Option+M |
| Extract Variable | Ctrl+Alt+V | Cmd+Option+V |
| Extract Field | Ctrl+Alt+F | Cmd+Option+F |
| Extract Constant | Ctrl+Alt+C | Cmd+Option+C |
| Extract Parameter | Ctrl+Alt+P | Cmd+Option+P |
| Inline | Ctrl+Alt+N | Cmd+Option+N |
| Rename | Shift+F6 | Shift+F6 |
| Change Signature | Ctrl+F6 | Cmd+F6 |
| Move | F6 | F6 |
| Safe Delete | Alt+Delete | Cmd+Delete |
| Extract Interface | Ctrl+Shift+Alt+T | Ctrl+T → menu |
| Pull Up / Push Down | Ctrl+Shift+Alt+T | Ctrl+T → menu |
VS Code (with Java extensions)
| Action | Windows/Linux | Mac |
|---|---|---|
| Extract Method | Ctrl+Shift+R | Cmd+Shift+R |
| Extract Variable | Context menu | Context menu |
| Rename | F2 | F2 |
| Quick Fix | Ctrl+. | Cmd+. |
📚 Recommended Resources
Books
| Book | Author | Focus |
|---|---|---|
| Clean Code | Robert C. Martin | Fundamentals of clean code |
| Refactoring | Martin Fowler | Refactoring catalog |
| Working Effectively with Legacy Code | Michael Feathers | Legacy modernization |
| Effective Java | Joshua Bloch | Java best practices |
| Head First Design Patterns | Freeman & Robson | Pattern introduction |
| Design Patterns (GoF) | Gamma et al. | Classic pattern reference |
| Implementing DDD | Vaughn Vernon | Domain-Driven Design |
| Clean Architecture | Robert C. Martin | Architecture patterns |
Online Resources
- Refactoring Guru - https://refactoring.guru (patterns, refactorings)
- SourceMaking - https://sourcemaking.com (smells, patterns)
- Baeldung - https://baeldung.com (Java/Spring tutorials)
- Martin Fowler's Blog - https://martinfowler.com (architecture)
Tools
| Tool | Purpose |
|---|---|
| SonarQube | Code quality metrics |
| JaCoCo | Code coverage |
| PIT | Mutation testing |
| SpotBugs | Bug detection |
| Checkstyle | Code style |
| ArchUnit | Architecture tests |
| IntelliJ Inspections | Real-time analysis |
📝 Complete Series Index
Part I: Fundamentals
- Part 0: How to Use This Series
- Part 1: Clean Code Philosophy & Business Value
- Part 2: SOLID - Single Responsibility & Open/Closed
- Part 3: SOLID - Liskov, Interface Segregation, Dependency Inversion
- Part 4: Code Smells - Complete Catalog
- Part 5: Code Quality Metrics Framework
Part II: Refactoring Patterns
- Part 6: Extract Patterns (Method, Class, Interface)
- Part 7: Replace Conditional with Polymorphism
- Part 8: Null Handling Patterns
- Part 9: Builder & Factory Patterns
- Part 10: Composition Over Inheritance
- Part 11: Functional Clean Code (Java 8-21)
- Part 12: Chain of Responsibility & Pipeline
- Part 13: Template Method & Hooks
Part III: Error Handling
- Part 14: Exception Hierarchy Design
- Part 15: Result Pattern & Functional Error Handling
- Part 16: Global Error Handling & RFC 7807
Part IV: Validation
- Part 17: Bean Validation & Custom Constraints
- Part 18: Fluent Validation & Input Sanitization
Part V: Legacy Modernization
- Part 19: Understanding Legacy Code
- Part 20: Characterization Testing
- Part 21: Breaking Dependencies
- Part 22: Strangler Fig & Incremental Refactoring
Part VI: Modern Java
- Part 23: Records, Sealed Classes & Modern Java
- Part 24: Clean Code in Spring Boot
Part VII: Reference
- Part 25: Decision Guide & Cheatsheet (this article)
🐛 Debug This: The Wrong Pattern
A team followed the decision tree for a switch statement but the refactoring made things worse. "We used Strategy pattern like the guide says, but now we have 15 tiny classes and the code is harder to follow!"
JAVA(46 lines)CodeLoading syntax highlighter...
They followed the letter of the decision tree but missed the context questions:
Switch/if-else chain? ├── How many cases? → 5 cases → Consider Strategy ├── Will cases grow over time? → NO! Tax rates are configuration, not code ├── Does each case have complex logic? → NO! Just a multiplication └── Is this behavior that needs to be injected/tested separately? → NO!
-
"Will cases grow over time?" - No. Tax rates are data, not behavior. If rates change, you update config, not add classes.
-
"Is each case complex enough to warrant its own class?" - No. Each is a single line of multiplication.
-
"YAGNI: Do you need this flexibility?" - No. They're solving a problem they don't have.
JAVA(30 lines)CodeLoading syntax highlighter...
JAVA(20 lines)CodeLoading syntax highlighter...
💻 Exercises
Exercise 1: Pattern Selection Practice
⭐ Difficulty: Easy | ⏱️ Time: 10 minutes
| # | Smell | Your Answer |
|---|---|---|
| 1 | Method with 7 parameters | Pattern: ___ (Part: ___) |
| 2 | Switch on payment type (8 cases, complex logic each) | Pattern: ___ (Part: ___) |
| 3 | Repeated null checks for order.getDiscount() | Pattern: ___ (Part: ___) |
| 4 | 400-line class handling orders, payments, emails | Pattern: ___ (Part: ___) |
| 5 | 4-level deep inheritance hierarchy | Pattern: ___ (Part: ___) |
| # | Pattern | Part |
|---|---|---|
| 1 | Parameter Object or Builder | Part 6, 9 |
| 2 | Strategy Pattern | Part 7 |
| 3 | Null Object Pattern | Part 8 |
| 4 | Extract Class (split by responsibility) | Part 6 |
| 5 | Composition over Inheritance | Part 10 |
Exercise 2: Refactoring Recipe Application
⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes
JAVA(21 lines)CodeLoading syntax highlighter...
JAVA(60 lines)CodeLoading syntax highlighter...
Exercise 3: Interview Question Practice
⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes
- What is Single Responsibility Principle and how do you identify violations?
Your answer:
TEXT(3 lines)CodeLoading syntax highlighter...
- When would you use Strategy vs State pattern?
Your answer:
TEXT(3 lines)CodeLoading syntax highlighter...
- How do you safely refactor a 500-line method?
Your answer:
TEXT(3 lines)CodeLoading syntax highlighter...
Exercise 4: Code Smell Diagnosis
⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes
JAVA(62 lines)CodeLoading syntax highlighter...
| Smell | Location | Refactoring | Part |
|---|---|---|---|
| 1. ___ | ___ | ___ | ___ |
| 2. ___ | ___ | ___ | ___ |
| 3. ___ | ___ | ___ | ___ |
| ... | ... | ... | ... |
| Smell | Location | Refactoring | Part |
|---|---|---|---|
| Long Parameter List | processOrder (11 params) | Extract Parameter Objects (OrderRequest, Address, PaymentInfo) | Part 6 |
| Long Method | processOrder (~60 lines) | Extract Method (validate, checkStock, calculatePrice, processPayment, createOrder) | Part 6 |
| Field Injection | @Autowired emailService | Constructor Injection | Part 24 |
| Raw SQL/Connection | dbConnection.query/execute | Repository Pattern | Part 24 |
| Empty Catch Block | catch (Exception e) {} | Proper Exception Handling | Part 14 |
| String Return for Errors | "ERROR: ..." | Result Pattern or Exceptions | Part 15 |
| Primitive Obsession | double price, String cardNumber | Money, CreditCard value objects | Part 6 |
| Feature Envy | PaymentAPI.charge in OrderManager | Extract PaymentService | Part 6 |
| Multiple Responsibilities | Validation, Stock, Payment, Order, Email | Extract Services | Part 2, 6 |
| Magic Numbers | 16, 25.0, 10, 0.9 | Named Constants | - |
| Static Method Call | PaymentAPI.charge | Inject PaymentGateway | Part 21 |
Exercise 5: Create Your Own Decision Tree
⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes
TEXT(15 lines)CodeLoading syntax highlighter...
TEXT(9 lines)CodeLoading syntax highlighter...
📅 Review Schedule for This Article
| Day | Task | Time |
|---|---|---|
| Day 1 | Review the Pattern Decision Trees (all 7) | 10 min |
| Day 3 | Redo Exercise 1 (Pattern Selection Practice) | 10 min |
| Day 7 | Practice answering 5 interview questions without looking | 15 min |
| Day 14 | Redo Debug This (The Wrong Pattern) | 10 min |
| Day 30 | Apply a decision tree to a real refactoring in your project | 20 min |
🏁 Conclusion
You now have a complete reference for making clean code decisions. The key to using this guide effectively:
- Bookmark the decision trees - use them when facing a refactoring choice
- Memorize key metrics - lines > 20, parameters > 4, complexity > 10
- Practice the recipes - apply Extract Method, Strategy Pattern regularly
- Review before interviews - the 50 questions cover senior-level topics
- Apply incrementally - one pattern at a time, not revolutionary rewrites
Final Checklist
Before any refactoring:
- Tests exist (or write characterization tests)
- Identified the code smell
- Measured the problem (metrics)
- Selected pattern using decision tree
- Small, reversible steps planned
During refactoring:
- Preserve behavior (run tests after each change)
- Commit frequently
- Use IDE refactoring tools
- Review for new smells introduced
After refactoring:
- All tests pass
- Metrics improved
- Code review with team
- Document decision if significant
Remember: Clean code is not about perfection. It's about continuous improvement, pragmatic decisions, and code that your future self (and teammates) will thank you for.
Keep refactoring. Keep learning. Keep shipping.