Java

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

AspectDetails
GoalMake code testable by isolating dependencies
Key TechniqueExtract and inject dependencies
Safety NetCharacterization tests before changes
OutcomeTestable 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)
Code
Loading syntax highlighter...
Problems:
  • 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)
Code
Loading syntax highlighter...

šŸ”¬ Deep Dive

Technique 1: Extract and Override Factory Method

JAVA(44 lines)
Code
Loading syntax highlighter...

Technique 2: Parameterize Constructor

JAVA(45 lines)
Code
Loading syntax highlighter...

Technique 3: Wrap Static Calls

JAVA(47 lines)
Code
Loading syntax highlighter...

Technique 4: Break Singleton Dependencies

JAVA(68 lines)
Code
Loading syntax highlighter...

Technique 5: Extract Interface

JAVA(62 lines)
Code
Loading syntax highlighter...

Technique 6: Adapt Parameter

JAVA(46 lines)
Code
Loading syntax highlighter...

Technique 7: Preserve Signatures

JAVA(34 lines)
Code
Loading syntax highlighter...

āš ļø Common Mistakes

Mistake 1: Breaking Too Many Dependencies at Once

TEXT(11 lines)
Code
Loading syntax highlighter...

Mistake 2: Forgetting Backward Compatibility

JAVA(17 lines)
Code
Loading 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)
Code
Loading syntax highlighter...
The factory methods were extracted, but the tests still can't mock them. What went wrong?

āœ… Solution:

Two critical mistakes:

Problem 1: Factory methods are private
JAVA
Code
Loading 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.

Problem 2: Config is still a hidden dependency
JAVA
Code
Loading syntax highlighter...

Even if you could override the factory method, the Config singleton is still called.

Correct implementation:
JAVA(80 lines)
Code
Loading syntax highlighter...
The lesson: Factory methods must be 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

Task: Extract a factory method to make this class testable.
JAVA(13 lines)
Code
Loading syntax highlighter...
āœ… Solution:
JAVA(56 lines)
Code
Loading syntax highlighter...

Exercise 2: Parameterize Constructor

⭐⭐ Difficulty: Medium | ā±ļø Time: 15 minutes

Task: Break the singleton dependency using constructor parameterization while maintaining backward compatibility.
JAVA(14 lines)
Code
Loading syntax highlighter...
āœ… Solution:
JAVA(64 lines)
Code
Loading syntax highlighter...

Exercise 3: Wrap Static Calls

⭐⭐ Difficulty: Medium | ā±ļø Time: 15 minutes

Task: Make this class testable by wrapping the static calls.
JAVA(13 lines)
Code
Loading syntax highlighter...
āœ… Solution:
JAVA(77 lines)
Code
Loading syntax highlighter...

Exercise 4: Extract Interface

⭐⭐⭐ Difficulty: Medium-Hard | ā±ļø Time: 20 minutes

Task: Extract an interface from this concrete class and refactor the dependent code.
JAVA(41 lines)
Code
Loading syntax highlighter...
āœ… Solution:
JAVA(111 lines)
Code
Loading syntax highlighter...

Exercise 5: Full Dependency Breaking Workflow

⭐⭐⭐⭐ Difficulty: Hard | ā±ļø Time: 25 minutes

Task: Apply the full dependency breaking workflow to make this legacy class fully testable.
JAVA(33 lines)
Code
Loading syntax highlighter...
Break all dependencies and write comprehensive tests.
āœ… Solution:
JAVA(277 lines)
Code
Loading syntax highlighter...

šŸ“ Summary

TechniqueUse When
Extract Factory MethodDirect new in method
Parameterize ConstructorSingleton/static dependencies
Wrap Static CallsStatic utility methods
Extract InterfaceNeed to mock concrete class
Adapt ParameterComplex parameters (HttpRequest)
Preserve SignaturesAvoid breaking existing callers

šŸ“… Review Schedule for This Article

DayTaskTime
Day 1Review Dependency Breaking Workflow diagram5 min
Day 3Redo Exercise 1 (Extract Factory Method)10 min
Day 7Identify 3 dependencies to break in your current codebase15 min
Day 14Redo Debug This (The Invisible Seam)10 min
Day 30Apply Parameterize Constructor to a real class20 min

Next: [Part 22: Strangler Fig Pattern]