Domain-Centric Architecture: The Adapter-First Trap and How to Escape It

The Disconnect Between Theory and Practice

In domain-centric architectures like Clean, Onion, or Hexagonal Architecture combined with Domain-Driven Design (DDD), the business domain model should drive everything. The domain layer is supposed to be the heart of the system — independent of frameworks, databases, or APIs, and technology-agnostic.

Yet, in customer projects, new features are often initiated by designing the database schema or REST API first. I repeatedly see colleagues, despite their commitment to domain-centric principles, beginning with a relational database model or REST resource design. Instead of first defining the domain’s entities and aggregates, they jump straight into technical implementation. In my opinion, this approach often leads to constraints in thinking and execution, as the focus shifts to database normalization or API endpoints rather than the domain’s true needs.

The Reasons Behind the Habit

Starting with the database or API is often a matter of habit. Developers are accustomed to thinking in terms of tables, columns, or REST resources because these concepts are tangible and familiar. The tools we use — ORMs like Hibernate, API generators like OpenAPI, or even IDE templates — reinforce this behavior. They make it easier to design a database schema or API contract than to model a domain.

The human factor also plays a critical role. In many projects, developers are often far removed from the business domain, but drive the design decisions. They default to what they know: databases and APIs. Business analysts, meant to bridge the gap, frequently act as mere "throughput heaters", lacking deep domain expertise themselves. Without true domain knowledge in the team and the will of developers to understand it, the path of least resistance leads straight to adapter-first design.

Additionally, there’s time pressure. For example, another team might be waiting for a new API to integrate with. A REST endpoint or a database table can be implemented quickly, providing immediate, visible progress. Domain modeling, on the other hand, requires discussions, iterations, and a deeper understanding of the business logic — things that don’t always yield instant results.

Finally, lack of practice plays a role. Many developers understand DDD in theory but struggle to apply it in practice. Terms like Aggregate RootsValue Objects, or Domain Events sound great in books, but translating them into real-world code is a different challenge. We often overlook the business side of things entirely.

The Consequences: Technology Dictates the Domain

When we let technical concerns drive the design, the technology begins to dictate how we model the domain. A classic example is object-relational mapping (ORM). ORMs often require a one-to-one mapping between domain objects and database tables. This forces developers to flatten complex domain concepts into a tabular structure, which may not align with the domain’s natural boundaries.

Consider a domain where an Order can exist in multiple states (DraftSubmittedFulfilledCancelled), each with its own rules and behaviors. A database-first approach might lead to a single Order table with a status column, while a domain-centric design could model each state as a separate class with its own logic. The former simplifies storage but complicates the domain logic, making it harder to enforce business rules and maintain clarity.

image

Domain-Centric vs. Adapter-Driven: The Impact of Traditional Habits

The result? Technical debt accumulates as the domain logic becomes entangled with the persistence or API layer. Developers feel the need to keep their structures in sync to maintain conceptual "consistency" — where no such consistency is actually needed. Worse, we might build the business model for a relational database schema, only to later switch to a document-based database. Now what? Do we change the domain model together with the adapter, simply because we realize the domain could be represented better? 

In domain-centric architectures, changing an adapter should only affect the adapter layer — and nothing else.

The Solution: Let the Domain Lead

To avoid these pitfalls, the domain should lead the way. This doesn’t mean ignoring databases or APIs entirely — it means ensuring they serve the domain, not the other way around.

Start by defining the domain’s building blocks: entities, value objects, and aggregates. Ask: What are the core concepts in our business? What rules govern them? Use the ubiquitous language of the domain to name and describe these elements, ensuring clarity and consistency across the team. But this only works if the team includes people with genuine domain expertise — not just developers or analysts who think they understand the business. Domain-centric design demands real domain knowledge, or it fails.

Only after the domain model is clear should you consider the technical implementation. How will the domain model be persisted? How will it be exposed to clients? These decisions should be guided by the domain’s needs, not by the limitations of the database or API framework.

For example, if the domain requires complex state transitions for an Order, model those states explicitly in the domain layer. Then, design the database schema or API to support this model, even if it means using patterns like Event Sourcing or CQRS to handle the complexity.

Practical Guidelines

  • Guideline 1: Avoid designing the database schema or API before the domain model is defined.
  • Guideline 2: Use the domain’s ubiquitous language to name classes, methods, and variables.
  • Guideline 3: If you find yourself thinking in tables or endpoints, pause and refocus on the domain.
  • Guideline 4: Include domain experts in your team (common sense). Without them, the domain model will reflect technical biases, not business needs.

Tool Recommendations:

  • Explore the business side of new features using Domain Storytelling.
  • Use whiteboard sessions or collaborative tools like Miro to model the domain visually.
  • Enforce architectural boundaries with tools like ArchUnit.

The Conclusion: Let the Domain Unfold Its Potential

Domain-centric architecture can only unfold its full potential when the domain model is allowed to drive the design and when the team has the domain expertise to let it. Starting with the database or API often leads to a system where technical constraints overshadow the business logic. By prioritizing the domain, teams can build systems that are not only technically sound but also aligned with the business’s true needs.


You'll only receive email when they publish something new.

More from Luc Weinbrecht
All posts