Incrementally replace an internal implementation by introducing an abstraction layer, building a new implementation behind it, switching over, and removing the abstraction. Use when an engineer needs to swap a library, framework, or internal module without a big-bang replacement.
Replace an internal implementation incrementally by introducing an abstraction boundary, building the new implementation behind it, and switching over - all while the system remains working at every step.
This is the in-codebase equivalent of the Strangler Fig pattern. Where strangler fig works at system/service boundaries with routing layers, branch by abstraction works at code boundaries with interfaces.
Create an interface that represents the capability the implementation provides, not the implementation's API. Design the abstraction around what consumers need, not what the current implementation offers.
Make the existing implementation conform to the new interface. This should be a mechanical refactoring - behavior does not change.
Update all consumers to depend on the abstraction rather than the concrete implementation. Again, purely mechanical - no behavior change.
Verify everything still works. Run existing tests. This step must be a zero-behavior-change refactoring.
Create the new implementation of the abstraction, following end-state ideals:
Test the new implementation against the same interface contract as the old one. Contract tests that run against both implementations are ideal.
Choose a migration strategy:
/dependency-breaker first.Deliver: