DDD vs MVC: Practical Trade‑offs, Pitfalls, and When to Keep It Simple
This article compares Domain‑Driven Design and MVC, outlines the architectural changes such as dependency inversion and layer separation, examines common drawbacks in real projects, and offers concrete guidance on when to adopt DDD, blend it with MVC, or stick to a lightweight CRUD‑centric approach.
Evolution from MVC to DDD
Since Domain‑Driven Design (DDD) became popular, many projects have migrated from classic MVC to a DDD‑style architecture. The migration mainly applies the Dependency Inversion Principle and separates business logic into distinct Application and Domain layers.
1. Dependency Inversion
Changes introduced
The Infrastructure layer defines interfaces that higher layers depend on; concrete implementations live in Infrastructure.
Typical scenario: the Domain layer declares a Repository interface, Infrastructure provides a concrete repository class, and the Application layer no longer references Infrastructure directly.
Drawbacks
The Application layer must go through the Domain layer to reach Infrastructure, which adds extra data‑transfer objects and conversion steps.
Developers accustomed to a straight API → Business Logic → DB flow find the additional indirection harder to adopt, especially when the simple flow is efficient.
Benefits
Clearer boundaries between layers.
The business‑logic layer no longer depends on Infrastructure, making unit testing easier.
// Domain layer – repository contract
public interface OrderRepository {
Order findById(Long id);
void save(Order order);
}
// Infrastructure layer – concrete implementation
public class JpaOrderRepository implements OrderRepository {
private final JpaRepository<OrderEntity, Long> jpaRepo;
public Order findById(Long id) { /* map Entity → Domain */ }
public void save(Order order) { /* map Domain → Entity */ }
}
// Application layer – uses only the abstraction
public class OrderService {
private final OrderRepository repository;
public OrderService(OrderRepository repository) { this.repository = repository; }
public void placeOrder(Command cmd) { /* business rules */ repository.save(order); }
}2. Splitting Business Logic into Application and Domain Layers
Changes introduced
Add a dedicated Domain layer.
Move domain‑specific business rules from the Application layer into the new Domain layer.
Drawbacks
Domain objects often need conversion when crossing layer boundaries.
Large‑scale modifications or high‑performance scenarios become less friendly.
DDD emphasizes aggregate lifecycles; full‑object updates can cause ABA problems under high concurrency.
Team members must have solid DDD knowledge; otherwise the code may look like MVC while being more complex.
Benefits
Improved code design quality once the DDD pattern is mastered.
Consistent design and code, raising overall engineering quality.
Better decoupling of business logic from infrastructure, facilitating unit testing.
Common reasons DDD projects fail
1. Frequent requirement changes and tight schedules
Rapid requirement shifts and shallow communication between developers and business stakeholders often lead teams to skip proper domain modeling. The resulting models are inaccurate or incomplete, diverging from real business needs.
2. Insufficient DDD knowledge within the team
Some developers interpret DDD merely as a layered architecture, ignoring core concepts such as bounded contexts and rich domain models. Under delivery pressure, DDD is applied superficially, producing over‑engineered or misaligned designs.
3. Technology‑driven decisions that couple domain logic to infrastructure
Projects sometimes prioritize micro‑service frameworks, ORM tools, or other technologies before understanding the domain. Consequently, bounded contexts are poorly defined, and domain logic becomes entangled with data storage and service interfaces.
4. CRUD‑heavy scenarios make DDD feel cumbersome
When the core functionality is simple CRUD (e.g., admin panels, data entry systems), a full DDD stack adds unnecessary complexity, bloating code and slowing development.
Recommendations
For simple, CRUD‑centric business, use a traditional layered architecture (Controller → Service → Repository) to avoid over‑design.
If the domain is complex but CRUD still dominates, apply DDD only to the critical, intricate parts while keeping the rest lightweight.
Combine MVC and DDD where appropriate, and reach a consensus within the team on the hybrid approach.
Conclusion
The core value of DDD lies in handling complex domain problems and slowing code decay. For projects whose primary operations are CRUD, forcing DDD leads to low efficiency, high maintenance cost, and team resistance. The right approach is to weigh design methods against actual requirements and avoid theory‑driven development.
Further reading
DDD Layered Architecture Practice: https://mp.weixin.qq.com/s?__biz=Mzk0NDI1NzI2Mw==∣=2247485769&idx=1&sn=11be934c2dfeb2cc2dc713fd2bd51df1
Alibaba COLA 4.0 Best Practices: https://mp.weixin.qq.com/s?__biz=Mzk0NDI1NzI2Mw==∣=2247485055&idx=1&sn=e32bd459769022f55c9ec2f1a24a3a2c
Appendix
DDD engineering code sample:
Eric Tech Circle
Backend team lead & architect with 10+ years experience, full‑stack engineer, sharing insights and solo development practice.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
