Domain-Driven Refactoring: Intro

Posts in this series:

A common theme in domain-driven design are design patterns. When you start learning about DDD, you'll be presented with many code-level concepts such as:

  • Aggregates
  • Entities
  • Value Objects
  • Repositories
  • Specifications
  • Factories

With all of these patterns (and more), it's easy to fall into the trap of blindly apply patterns and complex layering with the hope that if we just apply a little more structure, our code will be "clean".

In practice, this is rarely the case. No amount of prescriptive guidance results in automatically "clean" code, or as our goal should be, highly cohesive code. So if structure can't save us, what do we do?

Over the years, the only truly effective technique I've found for creating highly cohesive, maintainable code, is refactoring. But it seems to be a lost art - very few developers I meet or teams I work with treat refactoring as an essential, required skill.

Instead of trying to put code into prescriptive buckets, what I've found worked best is to start with the simplest solution that can possibly work, and once it works, examine the code for code smells. For a given code smell, try a refactoring, and look to see if that refactoring resulted in more cohesive, understandable code. If this sounds a lot like the TDD steps of Red-Green-Refactor - it's no coincidence.

Back to DDD, with its prescriptive (and constraining) patterns, I've also found that the best domain models aren't ones that try to follow highly specific rules, but ones that use code smells and refactoring techniques to build them.

In this series, I'll do exactly that - start with a set of code that's boring, procedural, and has an intentionally anemic domain model. And with standard code smells and refactoring techniques, I'll step-by-step refactor the procedural code, pushing the behavior into the domain, resulting in an actual behavioral domain model that arose naturally through refactoring instead of artificially through layers and rules.