DDD is a budget for thinking. First decide where careful modeling pays (strategic design), then model carefully only there (tactical design). This page is the whole path, in the order you walk it.
The problem space is the business as it is: its activities, split into subdomains. The solution space is your response: models drawn inside bounded contexts. They often map one-to-one — but they don't have to, so never force it.
Classify each part of the business before you invest a single design hour. The classification is the budget decision.
Your competitive edge — complex and valuable. The thing you'd never outsource; the reason customers pick you.
Best people, richest modeling. DDD earns its keep here.Necessary and business-specific, but no differentiator. Losing it hurts; having it doesn't win.
Build in-house, modestly. Don't gold-plate.A solved problem everyone has: auth, payments, notifications, search, booking.
Buy or adopt. Hand-modeling this is classic waste.Traps: high-traffic ≠ core (a checkout wrapping Stripe is generic). Mission-critical ≠ core (payments are table stakes). The edge is often the quiet piece — a matching rule, a pricing policy.
A bounded context is the boundary inside which a model and its ubiquitous language stay consistent — every key term has exactly one meaning. The same real-world thing legitimately gets a different model in each context.
Integration patterns follow the relationship between the teams, not the technology. Pick by power dynamic and how much you must protect your model:
Tactical patterns only pay off once boundaries are roughly right — and mostly in core subdomains. A CRUD module in a supporting subdomain is not a failure of DDD; it's DDD working.
Defined by attributes, immutable, no identity. Two with equal attributes are interchangeable.
Identity persists through state changes; equality is by id, not attributes.
A cluster of entities + values changed as one unit. It is the transaction boundary: invariants true at every commit.
A past-tense record that something meaningful happened. The tool for decoupling aggregates and contexts.
Collection-like persistence for aggregates. One per root — not one per table.
Stateless logic that truly spans aggregates (a transfer, a cross-aggregate price).
customerId, never the Customer object.String email, BigDecimal amount everywhere. Reach for EmailAddress, Money.Address with a surrogate id it never semantically needs — that's a value object.