What does "Domain Driven Design (DDD)" mean?

Domain-Driven Design (DDD) means designing software around the business domain – not around databases, frameworks, or technology. At its core is a precise, shared domain model, developed collaboratively by domain experts and developers. This model structures the code, the team's communication, and the interfaces. The goal: to make complex business logic manageable, reduce risks, and deliver changes faster and more securely.

What DDD is really about

DDD is a way of working and an architectural approach. You build software the way the domain thinks. Every important rule, every term—from "customer credit limit" to "order approval"—is reflected as a clear term and operation in the code. Instead of an "OrdersTable" with 50 columns, there's a living model: an order with items, a payment attempt , a delivery order . Everything is clearly defined, with clean bounded contexts and no implicit magic.

Key ideas and concepts

Ubiquitous Language: A common, precise business language used identically in conversation, tickets, and code. Don't say "CustomerLimit" in code when "credit limit" is used in the business context.

Domain and subdomains: The business area (e.g., retail) is divided into sub-areas: core ( competitive advantage – ), supporting and generic subdomains. DDD helps to isolate the core so that quality and speed are paramount there.

Bounded Context: A clearly defined semantic space. "Customer" in sales means something different than "customer" in accounting. Each context has its own model, its own rules, and often its own data persistence. Communication between contexts occurs through explicit translations.

Context Map: A map of contexts and their relationships. Shows where translations are needed, who depends on whom (e.g., upstream/downstream), and where protection layers are established.

Anti-Corruption Layer (ACL): A protective layer that safeguards a clean model from a "foreign" model. In practical terms, this is a translation: "Legacy language" enters on the outside, while your ubiquitous language remains clean on the inside.

Tactical patterns: Building blocks in the code: Entity (has identity), Value Object (identical in value, immutable; e.g., amount of money with currency), Aggregates (consistency boundaries and invariants), Domain Service (business logic without a natural home), Repository (storage for aggregates), Domain Events ("Order Released" – something significant has happened). Application Services orchestrate use cases but do not contain core logic.

Transaction and consistency boundaries: An aggregate ensures invariants atomically. Between aggregates, you often accept "eventual consistency"—in return, you gain scalability and clear boundaries.

An example from practice

Imagine an online shop. In the subdomain "Order," an aggregate "Order" is responsible for line items, total amount, and approval. The invariant: An order may only be approved if all line items are available and the total amount is covered. The approval process triggers a domain event "OrderApproved." Another context, "Payment," listens and initiates the debit. Yet another context, "Logistics," reacts and creates a shipping order. Each context has its own model—no gigantic god object, no all-powerful table.

In a credit context, the situation is similar: The aggregate "credit line" ensures that a new loan will only be below the approved limit. This decision is embedded in the model, not in a user interface (UI) validation. This ensures consistent application of the rule.

Practical approach – step by step

Start by talking to people. Bring developers and subject matter experts together and gather terms, rules, and exceptions. Listen for small words ("actually," "except if"). That's where the tricky invariants are hidden. Visualize processes and events. You don't need a perfect picture, just enough to sketch out the first model.

Cut through bounded contexts. Examine: Where do terms change their meaning? Where do rules become contradictory? Two small, clear models are preferable to one large, vague one. Draw the context map with directions (who supplies, who consumes) and define interfaces. Where a strong legacy system dominates, add an anti-corruption layer.

Define aggregates with clear invariants. Formulate them as sentences: "An order may only be released if...". Then implement methods that reflect these sentences. Make Value objects truly immutable and rich in logic (e.g., adding price, checking currency), instead of scattering primitive types everywhere.

Work with domain events. Name events using domain terminology. Use them to decouple between contexts. Internally, they help you handle side effects more effectively. Accept that not everything has to happen synchronously – as long as the business guarantees are met.

Iterate. DDD isn't a big bang. Start with the riskiest area, learn, refine the language, and then define the boundaries. Good models emerge from conversations and feedback in real-world production situations.

Typical mistakes – and how to avoid them

Oversized units: If a unit is constantly locking up or needs to be loaded everywhere, it's too large. Trim it down, check for invariants, and coordinate the rest via events.

Ubiquitous language only on slides: If the code uses different words than the daily stand-up, the model breaks down. Use consistent terminology.

DDD without real domain experts: Without subject matter expertise, you're modeling technology, not business. Regularly involve the business side in the conversation – with examples, edge cases, and real data.

Contexts as a folder structure rather than as spaces of meaning: A module is not a bounded context. The crucial point is that terms within it are consistent and translated outside of it.

"Everything synchronous, everything transactional": Strict consistency across context boundaries sounds secure, but makes things slow and fragile. Better: strict invariants within an aggregate, otherwise clear domain guarantees and asynchronous coupling.

When DDD makes sense – and when it doesn't

DDD is worthwhile if your business logic is complex, dynamic, or business-critical. When rules change frequently, new products are developed, or multiple teams work in parallel, clear contexts and strong language are incredibly helpful. DDD is less beneficial if you're only building simple CRUD management without complex logic. In that case, the overhead outweighs the benefits.

Frequently asked questions

What does Domain Driven Design (DDD) mean in one sentence?

You model software along the business domain: common language, clear boundaries (Bounded Contexts), focused building blocks (Aggregates, Entities, Value Objects) – so that complex business logic remains understandable, modifiable and reliable.

What are the specific benefits for companies and startups?

DDD reduces errors and coordination efforts because everyone is on the same page. Teams deliver faster because it's clear where each rule applies. The result: shorter time-to-market, fewer production errors, better handling of changes – especially where business logic is your competitive advantage.

What is a bounded context – and how do I recognize it?

A bounded context is an area where terms and rules are consistent. You can recognize it when the meaning of a word changes (customer in sales vs. in accounting) or when a team can deliver independently. Practically speaking: examine changes – if a change constantly affects many parts, the boundary is incorrect; if changes remain localized, it's well-defined.

Entity, Value Object, Aggregate – how do they differ?

Entities have identity over time (e.g., Customer #4711). Value objects are defined by values ​​and are immutable (e.g., a monetary amount of €10,00). An aggregate groups entities/value objects and defines invariants and transaction boundaries. Only the aggregate root is modified externally, ensuring that rules remain centralized.

How do I get started with DDD without rebuilding the entire system?

Choose a risky or frequently changing subdomain. Define the language and rules, establish a bounded context, place an anti-corruption layer in front of existing systems, and implement an initial aggregate with clear invariants. Gather feedback and expand incrementally. This way, you minimize risk and learn quickly.

Do I need microservices for DDD?

No. DDD is independent of microservices. . You can start in a monolith . You can start with cleanly separated contexts. Later, contexts can be extracted as services—if it makes sense. Architecture follows the model, not the other way around.

How do I deal with legacy systems that "pollute" my model?

Place an anti-corruption layer between your clean model and the legacy system. This layer translates terms and data formats. This keeps your ubiquitous language intact while you modernize gradually, without a big bang.

How do I ensure consistency across contexts?

Hard invariants remain transactional within an aggregate. Across contexts, you use domain events and asynchronous responses. Plan business guarantees ("delivery order only after order release"), implement compensation for error cases, and monitor flows. Eventual consistency is acceptable if business rules permit it.

What organizational changes does DDD support?

DDD fosters autonomous, domain-oriented teams along bounded contexts. Business and tech teams collaborate more closely, meetings become shorter because terminology is clearly defined. Handoffs are reduced because responsibility is divided along the contexts – this accelerates releases.

Isn't DDD too "heavyweight" for small teams?

The toolbox is extensive, but you don't need to use everything. Two things make an immediate difference: consistently using a common language in your code and creating clear contexts. Both cost little but bring a lot of structure and speed – even in small teams.

How do I measure whether DDD works for us?

Pay attention to indicators: Are changes becoming more localized? Is the number of technical error scenarios decreasing? Is less time elapsed from idea to go live? Can new colleagues understand the domain more quickly? If so, your model is viable.

Which typical anti-patterns should I avoid?

“Anemic” domain models (logic in services, data in objects), oversized aggregates, hidden coupling via shared tables, inconsistent terminology in code and conversations, and the “everything must be synchronized” reflex. Remedies: Express invariants in aggregates, clearly separate contexts, utilize events, and maintain disciplined language.

How do I deal with reporting and reading models?

Separate write and read models where it helps: The domain model optimizes rules and consistency, while the read model optimizes queries and presentation. Think in projections fed by domain events. This keeps the business logic lean and results in fast reports.

Conclusion and recommendation

DDD isn't dogma, but an invitation to build software the way your business truly operates. Start small: clarify language, define contexts, implement an initial aggregate with a hard invariant. Observe, learn, and adjust. If you need sparring or a second perspective on your context map, Berger+Team can provide pragmatic support – focusing on clear terminology, clean interfaces, and practical solutions.

Florian Berger
Similar expressions Domain Driven Design (DDD), Domain Driven Design, DDD
Domain-Driven Design (DDD)
Bloggerei.de