Domain-Driven Refactorings
Warning: This is unfinished work in progress. I hope it can nonetheless be of use.
“All happy families are alike; each unhappy family is unhappy in its own way.” This Anna Karenina principle applies not only to families but also to software systems. Different software systems suffer from different diseases and we need different cures for these. Many legacy systems suffer from:
- model anemia,
- being a big ball of mud, or
- bad team organization.
Most of them suffer from a combination of these diseases. Domain-Driven Design can help transform such systems into a healthier state.
In Refactoring, Martin Fowler describes many standard refactorings; Database Refactorings complements that book on the data side. Josh Kerievsky shows in Refactoring to Patterns how to refactor to the patterns from the Gang of Four’s Design Patterns. On this page, I’m collecting refactorings that help to introduce patterns originally described in Domain-Driven Design by Eric Evans, Patterns of Enterprise Application Architecture from Fowler, and others. The catalog is split into three categories:
- Tactical Refactorings: Change the inner implementation of a bounded context
- Strategic Refactorings: Help with splitting a monolith architecture into bounded contexts.
- Socio-technical Refactorings: Reorganize the teams. This is often enabled by and/or accompanying strategic refactorings.
In the descriptions I follow the classic Fowlerian format of Introduction/Motivation/Mechanics/Example(s).
Big Bang Approach vs. Strangler Fig Application Approach
When dealing with a legacy system, generally two strategies exist:
- Build a new system from scratch and “when it is done” replace the old system with it
- Iteratively transform the old system into a modern state so that it becomes the new system
The idea of strategy no. 1 is that the new system will be build on a greenfield in a clean and save space. Eventually we “just flip the switch” and—snip—a new world is there. Since this reminds of the creation of the universe by the Big Bang this is called a big bang replacement. The steps of this approach are depicted in the following picture:
While it might sound reasonable in theory, practice shows that this approach is problematic. That’s why strategy no. 2 is often preferred. Step-by-step functionality is build or transformed into the new system. As early as possible the users use both the systems. Such a pattern is called a strangler fig application and the evolvement is shown in the following picture:
The functionality in the new system can be the result of either caring out existing functionality from the old system, building it from scratch or replacing it with standard software.
The Catalog
Strategic Refactorings |
---|
Carve Out Bounded Context (out of Monolith) |
Implement Bounded Context from Scratch (and Replace it in the Monolith) |
Carve Out Data Model First |
Carve Out Domain Model First |
EXPLORE: Extract Shared Kernel |
Socio-technical Refactorings (and Patterns) |
---|
Form Cross-Functional Team out of Layer-Team Members |
TODO: Form Enabling Team out of Layer-Team Members |
Form Second Team out of Partly Layer-Team and First-Team Members |
Form Second Team out of Only Layer-Team Members |
Move Operations Team Member to DevOps Team |
Assign Bounded Context to Existing (Cross-Functional) Team |
EXPLORE: Give Core Domains to Best Team |
EXPLORE: Give Every Team one Core Domain (and additional supporting) |
Tactical Refactorings (Against Model Anemia) |
---|
Enforce Ubiquitous Language |
Replace Primitive with Value Object |
Split Active Record into Aggregate and Repository |
Split Repository into Interface and Implementation |
Combine Value Objects |
Replace Collection of Entities with Entity in Its Own Right (=> there is a relationship to Encapsulate Collection) |
Replace Collection of Entities with Repository |
Heal Entity Anemia |
- Remove Setter |
- Replace Setter with Domain-Named Method |
- Move Domain Logic from Service Down to Entity (=> Move Statements into Function, Move Statements to Caller) |
Introduce Contract (=> relationship to Introduce Assertion) |
Tactical Refactorings to Support Strategic Refactorings (Against BBOM) |
---|
Carve Specialized Entity Out of Monolithic Entity |
Carve Specialized Data Model Out of Monolithic Database Table |
Replace Method Call with Domain Event |
Acknowledgement
I thank the participants of the open space “Domain-Driven Refactorings” at KanDDDinsky 2021 conference. As you can see on the right, many of the above described refactorings have been collected there.
Bibliography
Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley, 2004.
Fowler, Martin. Patterns of Enterprise Application Architecture. Boston: Addison-Wesley, 2003.
⸻. “Strangler Fig Application.” Bliki. June 29 2004. https://martinfowler.com/bliki/StranglerFigApplication.html.
⸻. Refactoring: Improving the Design of Existing Code. 2. ed. Boston: Addison-Wesley, 2019.
Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1995.
Kerievsky, Joshua. Refactoring to Patterns. Boston: Addison-Wesley, 2005.
Ambler, Scott W. and Pramod J. Sadalage. Database Refactorings: Evolutionary Database Design. Upper Sadle River, NJ: Addison-Wesley, 2006.