04 · Isolate the domain
When you finish this lesson you should be able to:
- Place a behavior in UI, application, domain, or infrastructure and defend the placement
- Explain Evans’s shipping-destination example: five technical jobs, one business job
- Treat Smart UI as a legitimate pattern for simple places and a trap for complex domains
- Keep the domain from importing your ORM, HTTP types, or vendor SDKs
Why isolation is in a DDD book
Section titled “Why isolation is in a DDD book”Only a small fraction of the code is domain, but that fraction is where you need to apply the best thinking. You must see the model as a system, not pick constellations out of a night sky of widgets, queries, and network calls.
This ground is well-trodden (layers, hexagonal, ports and adapters). Evans reviews it because without isolation, chapters 5–17 have nowhere to live.
The shipping-destination lesson
Section titled “The shipping-destination lesson”To let a user pick a cargo destination, software must: draw a widget, query cities, interpret input, associate city with cargo, commit. All of that is one program. Only the association is shipping. If that rule is written inside the widget or the SQL, you will never get a model of Cargo.
Your analog: picking a plan during onboarding is drawing UI, loading plans, validating the POST, asserting the session may select a plan, committing. Only the assertion is domain.
Layered architecture (from a domain point of view)
Section titled “Layered architecture (from a domain point of view)”| Layer | Responsibility | Allowed to know |
|---|---|---|
| UI | Render, collect intent | Application API, view models |
| Application | Use case: load, call domain, save, enqueue | Domain, infrastructure ports |
| Domain | Model, invariants, language | Domain only (plus simple types, clocks as ports) |
| Infrastructure | SQL, queues, mail, files, vendor SDKs | Everything messy, hidden behind interfaces the app uses |
Dependencies point inward. Application coordinates; it should not contain if (!verified && plan). That if is the domain.
There are variants (hexagon: domain in the center, adapters outside). The DDD test is the same: can you find the model without grepping controllers?
Smart UI (anti-pattern for complex domains)
Section titled “Smart UI (anti-pattern for complex domains)”Evans is more honest than internet summaries. Smart UI puts logic in the interface. For a simple CRUD admin, it is fast, testable-enough, and honest. Teams that pretend they will “extract a model later” almost never do: every screen copies rules, tests hit the UI, there is no place to hang a ubiquitous language.
Use Smart UI on purpose for generic tools. Do not use it for the core domain (lesson 13) and then wonder why DDD “didn’t work.”
Other isolation
Section titled “Other isolation”- Separate processes / services: isolation by network, costs a context map (lesson 12).
- Separate databases: good if they match aggregates; bad if you still join in your head.
- Published language at the edge: JSON that is the model of a context, not the dumping of tables.
If two teams share a users table, you have not isolated anything. You have a secret unbounded context.
Example
Section titled “Example”Rule in the wrong home:
if (req.body.planId && !user.emailVerified) return res.status(400).end();Isolated:
POST /sessions/:id/plan → Application StartPlanSelection → session.assertCanSelectPlan() // domain → session.select(plan) // domain → repository.add(session) → 200HTTP does not know what “can” means. When “verified” gains “or trusted provider,” one method changes.
flowchart TB ui[User interface] app[Application] domain[Domain] infra[Infrastructure] ui --> app app --> domain app --> infra
Domain defines ports (Clock, IdentityLookup) if it must. Infrastructure implements. If session.ts imports prisma or express, isolation already leaked.
Failure modes
Section titled “Failure modes”- God application service that is the old Smart UI in a hoodie.
- Domain that logs, sends email, and commits. That is infrastructure envy.
- “Clean architecture” folder ritual with the same
ifin three layers.
Drill (20 minutes)
Section titled “Drill (20 minutes)”- List eight behaviors (notify, assign experiment, charge, snooze, verify, …).
- Mark where each rule lives today.
- Move two rules on paper into domain methods. Write application as load / call / save only.
- Find one import in a domain-ish file that is HTTP, SQL, or a vendor. Replace with a port.
- Pick a truly simple admin screen. Write “Smart UI: yes” and one sentence why you will not grow a model there.
Further reading
Section titled “Further reading”- Domain-Driven Design — Chapter 4, Isolating the Domain (layered architecture; domain layer; Smart UI; other isolation)