Skip to main content

Posts

Showing posts with the label Domain-Driven Design

Refactoring Anemic Domain Models: Moving Logic from Services to Rich Aggregates

  One of the most pervasive anti-patterns in modern backend development is the   Anemic Domain Model . It often starts innocently: you define your entities as simple data containers (POJOs or POCOs) to play nicely with your ORM. Then, you create a "Service Layer" to handle the business logic. Fast forward six months. Your  OrderService  is 3,000 lines long. Business rules are duplicated across three different handlers. Unit testing requires mocking five different repositories just to verify a status change. This is the  Transaction Script  pattern masquerading as Object-Oriented Programming. In this guide, we will refactor a typical Service-based architecture into a  Rich Domain Model . We will move logic out of the service and into the Aggregate, enforcing invariants where they belong: inside the domain object. The Root Cause: Why Anemia Happens Anemia usually stems from a fundamental misunderstanding of the separation of concerns. Developers often co...

Transactional Consistency in Hexagonal Architecture: The Unit of Work Pattern

  The hardest boundary to maintain in Hexagonal Architecture (Ports and Adapters) is the one between your Application layer and your Persistence layer when   ACID transactions   are involved. You have likely faced this dilemma: The "Dirty" Approach:  You pass a database transaction object (like JPA’s  EntityManager  or a Prisma  tx  client) into your Domain services.  Result:  Your domain is now coupled to your database library. The "Magic" Approach:  You rely on framework decorators like  @Transactional  (Spring/NestJS).  Result:  This often works for simple CRUD, but fails when composing complex Use Cases where the transaction boundary needs to be explicit, or when you are strictly separating your core logic into libraries that do not depend on the framework. In a strict Clean Architecture, the Use Case (Application Service) dictates the transaction boundary, but the Domain layer must remain ignorant of  h...