Breaking Dependencies
Legacy code often has tangled dependencies that make testing and modification difficult. This article covers techniques to identify and break these dependencies safely, enabling incremental improvement.
📋 At a Glance
| Aspect | Details |
|---|---|
| Goal | Make code testable by isolating dependencies |
| Key Technique | Extract and inject dependencies |
| Safety Net | Characterization tests before changes |
| Outcome | Testable code, easier modifications |
🎯 What You'll Learn
- Identifying problematic dependencies (static, global, hidden)
- Dependency breaking techniques (extract, parameterize, wrap)
- Safe refactoring order for untested code
- Dealing with singletons and global state
- Interface extraction for seams
Production Story: The Untestable Monster
A 2000-line service class was impossible to test:
JAVA(27 lines)CodeLoading syntax highlighter...
- Can't test without real database
- Can't test without real Stripe
- Can't disable emails in tests
- Can't verify what was sent/saved
Mental Model: Dependency Breaking
TEXT(34 lines)CodeLoading syntax highlighter...
🔬 Deep Dive
Technique 1: Extract and Override Factory Method
JAVA(44 lines)CodeLoading syntax highlighter...
Technique 2: Parameterize Constructor
JAVA(45 lines)CodeLoading syntax highlighter...
Technique 3: Wrap Static Calls
JAVA(47 lines)CodeLoading syntax highlighter...
Technique 4: Break Singleton Dependencies
JAVA(68 lines)CodeLoading syntax highlighter...
Technique 5: Extract Interface
JAVA(62 lines)CodeLoading syntax highlighter...
Technique 6: Adapt Parameter
JAVA(46 lines)CodeLoading syntax highlighter...
Technique 7: Preserve Signatures
JAVA(34 lines)CodeLoading syntax highlighter...
⚠️ Common Mistakes
Mistake 1: Breaking Too Many Dependencies at Once
TEXT(11 lines)CodeLoading syntax highlighter...
Mistake 2: Forgetting Backward Compatibility
JAVA(17 lines)CodeLoading syntax highlighter...
🐛 Debug This: The Invisible Seam
A developer refactored legacy code to break dependencies, but the tests still can't mock the dependency. "I extracted a factory method like the book says, but I still can't override it in tests!"
JAVA(52 lines)CodeLoading syntax highlighter...
Two critical mistakes:
privateJAVACodeLoading syntax highlighter...
Private methods cannot be overridden by subclasses. The factory method pattern only works if the method can be overridden in a test subclass.
JAVACodeLoading syntax highlighter...
Even if you could override the factory method, the Config singleton is still called.
JAVA(80 lines)CodeLoading syntax highlighter...
protected (not private) to enable the subclass seam pattern. Better yet, use constructor injection with a default constructor for backward compatibility.💻 Exercises
Exercise 1: Extract Factory Method
⭐ Difficulty: Easy | ⏱️ Time: 10 minutes
JAVA(13 lines)CodeLoading syntax highlighter...
JAVA(56 lines)CodeLoading syntax highlighter...
Exercise 2: Parameterize Constructor
⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes
JAVA(14 lines)CodeLoading syntax highlighter...
JAVA(64 lines)CodeLoading syntax highlighter...
Exercise 3: Wrap Static Calls
⭐⭐ Difficulty: Medium | ⏱️ Time: 15 minutes
JAVA(13 lines)CodeLoading syntax highlighter...
JAVA(77 lines)CodeLoading syntax highlighter...
Exercise 4: Extract Interface
⭐⭐⭐ Difficulty: Medium-Hard | ⏱️ Time: 20 minutes
JAVA(41 lines)CodeLoading syntax highlighter...
JAVA(111 lines)CodeLoading syntax highlighter...
Exercise 5: Full Dependency Breaking Workflow
⭐⭐⭐⭐ Difficulty: Hard | ⏱️ Time: 25 minutes
JAVA(33 lines)CodeLoading syntax highlighter...
JAVA(277 lines)CodeLoading syntax highlighter...
📝 Summary
| Technique | Use When |
|---|---|
| Extract Factory Method | Direct new in method |
| Parameterize Constructor | Singleton/static dependencies |
| Wrap Static Calls | Static utility methods |
| Extract Interface | Need to mock concrete class |
| Adapt Parameter | Complex parameters (HttpRequest) |
| Preserve Signatures | Avoid breaking existing callers |
📅 Review Schedule for This Article
| Day | Task | Time |
|---|---|---|
| Day 1 | Review Dependency Breaking Workflow diagram | 5 min |
| Day 3 | Redo Exercise 1 (Extract Factory Method) | 10 min |
| Day 7 | Identify 3 dependencies to break in your current codebase | 15 min |
| Day 14 | Redo Debug This (The Invisible Seam) | 10 min |
| Day 30 | Apply Parameterize Constructor to a real class | 20 min |