Extract Method, Class, and Interface
Extraction is the most fundamental refactoring skill. When code is too long, too complex, or has too many responsibilities, extraction is usually the answer. This article covers the three core extractions - Method, Class, and Interface - with step-by-step techniques and real examples.
📋 At a Glance
| Aspect | Details |
|---|---|
| Patterns Covered | Extract Method, Extract Class, Extract Interface |
| Primary Use | Reducing complexity, improving cohesion |
| IDE Support | Excellent (all major IDEs) |
| Risk Level | Low (behavior-preserving) |
| Time Investment | Minutes per extraction |
🎯 What You'll Learn
- Extract Method with proper parameter and return handling
- Extract Class by identifying responsibility boundaries
- Extract Interface for testability and flexibility
- Introduce Parameter Object for long parameter lists
- Safe extraction techniques that preserve behavior
- IDE shortcuts for automated extraction
🔥 Production Story: The 1,000-Line Method Tamed
TransactionProcessor method that had grown to 1,047 lines over 5 years. Nobody dared touch it because:- Any change took 2-3 days to understand the code
- Tests took 15 minutes to run
- 40% of production bugs originated from this method
The team spent 2 weeks systematically extracting:
- 23 methods from the original monolith
- 4 collaborating classes (Validator, Calculator, Persister, Notifier)
- 3 interfaces for external dependencies
- Average method: 18 lines (was: 1,047)
- Test runtime: 45 seconds (was: 15 minutes)
- Bug rate: Dropped 70% in following quarter
- Developer satisfaction: "I actually understand this code now"
🧠 Mental Model: The Extraction Decision Tree
TEXT(21 lines)CodeLoading syntax highlighter...
🔬 Deep Dive
Pattern 1: Extract Method
- Method longer than 20 lines
- Code block has a comment explaining what it does
- Same code appears in multiple places
- Code block operates at different abstraction level
Step-by-Step Process
JAVA(20 lines)CodeLoading syntax highlighter...
TEXT(3 lines)CodeLoading syntax highlighter...
JAVA(25 lines)CodeLoading syntax highlighter...
Handling Complex Extractions
JAVA(39 lines)CodeLoading syntax highlighter...
JAVA(22 lines)CodeLoading syntax highlighter...
Pattern 2: Extract Class
- Class has multiple distinct responsibilities
- Groups of methods use different subsets of fields
- Class name includes "And" or is vague ("Manager", "Handler", "Util")
- LCOM metric suggests low cohesion
Step-by-Step Process
JAVA(25 lines)CodeLoading syntax highlighter...
JAVA(46 lines)CodeLoading syntax highlighter...
JAVA(24 lines)CodeLoading syntax highlighter...
Pattern 3: Extract Interface
- Need to mock a class for testing
- Multiple implementations possible (now or future)
- Want to define a contract separate from implementation
- Breaking dependency cycles
For Testing
JAVA(47 lines)CodeLoading syntax highlighter...
For Multiple Implementations
JAVA(46 lines)CodeLoading syntax highlighter...
Pattern 4: Introduce Parameter Object
- Method has more than 4 parameters
- Same group of parameters appears in multiple methods
- Parameters are logically related
JAVA(62 lines)CodeLoading syntax highlighter...
⚠️ Common Mistakes
Mistake 1: Extracting Too Little
JAVA(20 lines)CodeLoading syntax highlighter...
Mistake 2: Passing Object When Part Suffices
JAVA(9 lines)CodeLoading syntax highlighter...
Mistake 3: Extracting Without Good Names
JAVA(9 lines)CodeLoading syntax highlighter...
🐛 Debug This: The Extraction That Broke Everything
A developer reports: "I extracted a method to make the code cleaner, but now random tests are failing. I didn't change any logic!"
JAVA(45 lines)CodeLoading syntax highlighter...
JAVA(3 lines)CodeLoading syntax highlighter...
This side effect was embedded in the calculation loop. When extracted to a stream, this price-lookup logic was dropped.
- Hidden side effect - calculation also modified item prices
- Incomplete extraction - functionality was lost, not just reorganized
- Mixed concerns - calculation + data fixing in one loop
JAVA(12 lines)CodeLoading syntax highlighter...
💻 Exercises
Exercise 1: Extract Methods
⭐ Difficulty: Easy | ⏱️ Time: 15 minutes
JAVA(36 lines)CodeLoading syntax highlighter...
JAVA(39 lines)CodeLoading syntax highlighter...
Exercise 2: Extract Class
⭐⭐ Difficulty: Medium | ⏱️ Time: 20 minutes
JAVA(21 lines)CodeLoading syntax highlighter...
JAVA(32 lines)CodeLoading syntax highlighter...
Exercise 3: Extract Interface
⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes
JAVA(11 lines)CodeLoading syntax highlighter...
JAVA(29 lines)CodeLoading syntax highlighter...
Exercise 4: Extract Superclass
⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes
JAVA(26 lines)CodeLoading syntax highlighter...
JAVA(36 lines)CodeLoading syntax highlighter...
Exercise 5: Recognize Extraction Opportunities
⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes
JAVA(39 lines)CodeLoading syntax highlighter...
JAVA(55 lines)CodeLoading syntax highlighter...
🎤 Senior-Level Interview Questions
Question #1: How do you decide what to extract?
I look for these signals:
- Comments as section headers - "// Calculate totals" → Extract
calculateTotals() - Different abstraction levels - High-level flow mixed with low-level details
- Repeated code patterns - Same 3 lines in multiple places
- Conditional blocks - Complex if/else often extracts well
- Loop bodies - Loop setup + iteration + body can be separated
The goal is: after extraction, the original method reads like a high-level summary.
Question #2: When should you extract an interface vs just use the class?
Extract interface when:
- Testing requires mocking - Interface makes stubbing easy
- Multiple implementations exist - Now or planned soon
- Dependency inversion needed - High-level shouldn't depend on low-level
- Plugin architecture - Allow extension without modification
Don't extract when:
- Only one implementation will ever exist
- Class is a simple data object
- Testing can use the real class
- It's an internal implementation detail
Question #3: How do you handle extraction in legacy code without tests?
Safe extraction process for legacy code:
- Characterization test first - Capture current behavior
JAVA(5 lines)CodeLoading syntax highlighter...
-
Extract mechanically - Use IDE refactoring, don't modify logic
-
Run characterization tests - Must still pass
-
Add focused tests - Now that methods are smaller
-
Commit after each extraction - Easy rollback if something breaks
📝 Summary & Key Takeaways
Extraction Quick Reference
| Pattern | When to Use | IDE Shortcut |
|---|---|---|
| Extract Method | Long method, duplicated code | Ctrl+Alt+M |
| Extract Class | Low cohesion, multiple responsibilities | Refactor menu |
| Extract Interface | Need mock, multiple implementations | Ctrl+Shift+Alt+T |
| Parameter Object | 4+ parameters, related data | Refactor menu |
Extraction Checklist
Before extracting:
- Tests exist (or write characterization tests)
- Clear name for extracted element
- Identified inputs and outputs
- Understand all side effects
After extracting:
- Original code reads as high-level summary
- Extracted element is cohesive
- Names reveal intent
- Tests still pass
🏁 Conclusion
Extraction is the workhorse of refactoring. Master these patterns and you'll be able to tame any complex codebase one extraction at a time.
📅 Review Schedule for This Article
| Day | Task | Time |
|---|---|---|
| Day 1 | Review Extract Method step-by-step diagram | 5 min |
| Day 3 | Redo Exercise 1 (Extract Methods from createInvoice) | 15 min |
| Day 7 | Answer interview questions without looking | 10 min |
| Day 14 | Redo Debug This (side effect preservation) | 10 min |
| Day 30 | Apply Extract Method to one long method in your project | 15 min |