The domain is too big to model as one thing
The domain is the entire problem space your software addresses — for this course, “running a small online bookstore’s order fulfillment.” Stated like that, it’s obviously too large to model as a single coherent thing. Placing an order, generating an invoice, and getting a parcel to a doorstep are related, but they are not the same concern, and trying to model them as one undifferentiated blob is how you end up with a 4,000-line OrderService that nobody can safely change.
So the first move in strategic design is to divide the domain into subdomains — and then make a judgment call about which of them deserves your best modeling effort.
Core, Supporting, Generic
DDD gives you three buckets:
- Core Domain — the part that gives the business its actual competitive edge. This is where the differentiated, hard-to-replace logic lives, and it’s where rigorous DDD effort is most justified. For the bookstore, this is order fulfillment and allocation: deciding which warehouse (or combination of warehouses) ships which lines of an order, with a rule like “prefer a single warehouse; only split a shipment when no single warehouse can fill the whole order.” That rule is specific to how this bookstore operates — a competitor might prioritize cost over speed, or vice versa — and it’s complex enough to be worth a real model.
- Supporting Subdomain — necessary to the business, custom-built, but not strategically differentiating. Billing fits here: the bookstore needs to invoice customers correctly, and the rules (when an invoice is generated, how it relates to an order) are specific enough to need custom code, but getting invoicing right isn’t what wins or loses customers.
- Generic Subdomain — a problem every business like this one has, already solved well by someone else. Payment processing and tax calculation are textbook generic subdomains: every e-commerce business needs them, nobody differentiates on having a better Stripe integration, and reaching for an off-the-shelf provider is usually the correct call rather than a shortcut.
Subdomains are about the problem, not the code. You're asking "which clusters of concepts carry the business's hardest, most specific rules" — not "which package is biggest."
Where it gets less clean: Shipping
Real domains rarely sort this cleanly, and Shipping in the bookstore is the honest example. Booking a courier and printing a label is close to generic — most logistics platforms solve it well, and a fair chunk of the Shipping context will end up as a thin wrapper around a carrier’s API (you’ll meet this as an Anticorruption Layer in Module 5). But consolidating a customer’s order into the minimum number of packages, in coordination with the Sales context’s allocation decision, has real, bookstore-specific value — it directly affects shipping cost and customer experience. So Shipping is best described as mostly generic, with a supporting-to-core sliver around shipment consolidation that’s worth deliberate modeling. Reporting this kind of split judgment honestly is more useful than forcing a clean single label onto a subdomain that doesn’t have one.
Heuristics for classifying a subdomain
You won’t find a subdomain’s classification written down anywhere — you infer it by reading the logic and asking:
- Density and specificity of business rules. A cluster where every other line encodes a rule that’s specific to this business, and would need to change if the business strategy changed, leans core. The allocation rule above is a good example: change the business’s priorities and that logic has to change with it.
- Does it mostly wrap a third-party concern? Code that’s mostly plumbing around email delivery, PDF generation, authentication, currency conversion, or payment processing is reaching toward a solved problem — that’s the generic signal.
- Is it bespoke but auxiliary? Reporting, admin screens, and configuration are usually custom-built (so not generic) but don’t carry the business’s differentiating logic (so not core) — that’s the supporting profile, same as
Billing. - Classify with confidence levels, not certainty. “Sales is almost certainly core; Shipping is mostly generic with a supporting sliver around consolidation” is a more honest and more useful statement than forcing everything into exactly one bucket. You’ll revisit and revise these judgments as the model matures — that’s expected, not a sign you got it wrong.
Tip. A quick gut-check: if you swapped this subdomain out for a well-known off-the-shelf product tomorrow, would the business lose its edge? If yes, it’s core. If the business would barely notice, it’s generic. If it’d be painful but not fatal, it’s supporting.
Why the classification matters in practice
This isn’t an academic exercise — it’s a budget. Sales (the core domain) is where the deep modeling work in Modules 6–8 — careful Aggregate boundaries, well-named Value Objects, explicit invariants — pays for itself. Pouring that same level of rigor into Billing is usually wasted effort, and building a custom tax engine instead of buying one is actively worse than wasted: it’s a maintenance burden with no competitive upside.
Subdomains describe the problem space — how the business itself is shaped, independent of any code. The next module turns to the solution space: how you actually draw boundaries in the software, and why those boundaries don’t always line up neatly with the subdomains you just identified.
Next: Module 4 — Bounded Contexts.