10 · Patterns in the model
When you finish this lesson you should be able to:
- Steal a named analysis pattern (account, posting, interest) instead of inventing a worse local dialect
- Use Strategy as Policy and Composite when the model is a tree of meaning
- Reject Flyweight-as-habit for values
- Say “this pattern is in the ubiquitous language” or not use it
Analysis patterns are prior art
Section titled “Analysis patterns are prior art”Deep models are expensive. Sometimes an experienced person looks at a domain and sees a familiar shape. Fowler-style analysis patterns (and the domain’s own literature) are knowledge to draw on, not homework to implement in full.
Evans’s banking-shaped examples: accounts, interest, postings, nightly batch. The insight is not “always use Account.” It is:
- The nightly batch was not “just a job.” It was a temporal concept in the domain (when value is recognized).
- Interest was not a stored number; it was a rule with a duration.
- Once those names exist, the batch and the online path stop being two programs that happen to write the same table.
Your analog: a “nightly send” of emails is often an implicit DeliveryWindow or Digest, not a cron. A “ledger” of experiment exposures might be an Entry you should not overwrite. A “balance” of remaining messages in a quota is an account-like pattern whether or not you are a bank.
How to use this as a strong engineer:
- Hear a job, report, or batch.
- Ask: is this a concept with a name in this industry?
- Try that name with experts. If they light up, you found prior art. If they stare, do not force Fowler into a chat app.
Relating GoF patterns to the model
Section titled “Relating GoF patterns to the model”Design patterns are not a badge. They belong when they express the model.
Strategy (aka Policy)
Section titled “Strategy (aka Policy)”When experts talk about interchangeable rules—“retry policy,” “holdout policy,” “quiet hours policy”—the model is a Strategy. The word in the language is Policy.
const quietHoursPolicy = { allows: (ctx, at) => quietHoursAllows(ctx.quietHours, at) };const alwaysAllow = { allows: () => true };The application picks a policy; the domain does not switch(type) across the whole codebase.
Composite
Section titled “Composite”When the domain is truly a tree of the same kind of meaning (a route made of legs, a spec that is AND/OR of specs, a notification rule that is nested groups), Composite is the model. Nested ifs that happen to look like a tree in one function are not yet Composite—you have not named the node.
Why not Flyweight (as a reflex)
Section titled “Why not Flyweight (as a reflex)”Sharing a single object instance to save memory is an implementation trick. Values are already small and immutable. Do not introduce identity and caches to “Flyweight” QuietHours. You will accidentally create entities.
What not to do
Section titled “What not to do”- Implement a pattern because a blog said DDD + Strategy + CQRS + Event Sourcing.
- Name a class
CompositeSpecificationAbstractFactorywhen experts say “eligible.” - Copy Evans’s interest-accrual example into a product that has no interest.
Drill (20 minutes)
Section titled “Drill (20 minutes)”- Find one batch, cron, or report. Propose an analysis-pattern-shaped name. Test it in a sentence with a fake expert.
- Find one
switch(type)on behavior. Extract a Policy object. Name it in product words. - Find a nested boolean. Either it is a Specification Composite, or it is two concepts. Pick.
- Write one sentence: “We are not using Flyweight because…”
Further reading
Section titled “Further reading”- Domain-Driven Design — Chapter 11, Applying Analysis Patterns
- Domain-Driven Design — Chapter 12, Relating Design Patterns to the Model