@booklib/skills 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/animation-at-work/SKILL.md +246 -0
- package/animation-at-work/assets/example_asset.txt +1 -0
- package/animation-at-work/references/api_reference.md +369 -0
- package/animation-at-work/references/review-checklist.md +79 -0
- package/animation-at-work/scripts/example.py +1 -0
- package/bin/skills.js +85 -0
- package/clean-code-reviewer/SKILL.md +292 -0
- package/clean-code-reviewer/evals/evals.json +67 -0
- package/data-intensive-patterns/SKILL.md +204 -0
- package/data-intensive-patterns/assets/example_asset.txt +1 -0
- package/data-intensive-patterns/references/api_reference.md +34 -0
- package/data-intensive-patterns/references/patterns-catalog.md +551 -0
- package/data-intensive-patterns/references/review-checklist.md +193 -0
- package/data-intensive-patterns/scripts/example.py +1 -0
- package/data-pipelines/SKILL.md +252 -0
- package/data-pipelines/assets/example_asset.txt +1 -0
- package/data-pipelines/references/api_reference.md +301 -0
- package/data-pipelines/references/review-checklist.md +181 -0
- package/data-pipelines/scripts/example.py +1 -0
- package/design-patterns/SKILL.md +245 -0
- package/design-patterns/assets/example_asset.txt +1 -0
- package/design-patterns/references/api_reference.md +1 -0
- package/design-patterns/references/patterns-catalog.md +726 -0
- package/design-patterns/references/review-checklist.md +173 -0
- package/design-patterns/scripts/example.py +1 -0
- package/domain-driven-design/SKILL.md +221 -0
- package/domain-driven-design/assets/example_asset.txt +1 -0
- package/domain-driven-design/references/api_reference.md +1 -0
- package/domain-driven-design/references/patterns-catalog.md +545 -0
- package/domain-driven-design/references/review-checklist.md +158 -0
- package/domain-driven-design/scripts/example.py +1 -0
- package/effective-java/SKILL.md +195 -0
- package/effective-java/assets/example_asset.txt +1 -0
- package/effective-java/references/api_reference.md +1 -0
- package/effective-java/references/items-catalog.md +955 -0
- package/effective-java/references/review-checklist.md +216 -0
- package/effective-java/scripts/example.py +1 -0
- package/effective-kotlin/SKILL.md +225 -0
- package/effective-kotlin/assets/example_asset.txt +1 -0
- package/effective-kotlin/references/api_reference.md +1 -0
- package/effective-kotlin/references/practices-catalog.md +1228 -0
- package/effective-kotlin/references/review-checklist.md +126 -0
- package/effective-kotlin/scripts/example.py +1 -0
- package/kotlin-in-action/SKILL.md +251 -0
- package/kotlin-in-action/assets/example_asset.txt +1 -0
- package/kotlin-in-action/references/api_reference.md +1 -0
- package/kotlin-in-action/references/practices-catalog.md +436 -0
- package/kotlin-in-action/references/review-checklist.md +204 -0
- package/kotlin-in-action/scripts/example.py +1 -0
- package/lean-startup/SKILL.md +250 -0
- package/lean-startup/assets/example_asset.txt +1 -0
- package/lean-startup/references/api_reference.md +319 -0
- package/lean-startup/references/review-checklist.md +137 -0
- package/lean-startup/scripts/example.py +1 -0
- package/microservices-patterns/SKILL.md +179 -0
- package/microservices-patterns/references/patterns-catalog.md +391 -0
- package/microservices-patterns/references/review-checklist.md +169 -0
- package/package.json +17 -0
- package/refactoring-ui/SKILL.md +236 -0
- package/refactoring-ui/assets/example_asset.txt +1 -0
- package/refactoring-ui/references/api_reference.md +355 -0
- package/refactoring-ui/references/review-checklist.md +114 -0
- package/refactoring-ui/scripts/example.py +1 -0
- package/storytelling-with-data/SKILL.md +238 -0
- package/storytelling-with-data/assets/example_asset.txt +1 -0
- package/storytelling-with-data/references/api_reference.md +379 -0
- package/storytelling-with-data/references/review-checklist.md +111 -0
- package/storytelling-with-data/scripts/example.py +1 -0
- package/system-design-interview/SKILL.md +213 -0
- package/system-design-interview/assets/example_asset.txt +1 -0
- package/system-design-interview/references/api_reference.md +582 -0
- package/system-design-interview/references/review-checklist.md +201 -0
- package/system-design-interview/scripts/example.py +1 -0
- package/using-asyncio-python/SKILL.md +242 -0
- package/using-asyncio-python/assets/example_asset.txt +1 -0
- package/using-asyncio-python/references/api_reference.md +267 -0
- package/using-asyncio-python/references/review-checklist.md +149 -0
- package/using-asyncio-python/scripts/example.py +1 -0
- package/web-scraping-python/SKILL.md +259 -0
- package/web-scraping-python/assets/example_asset.txt +1 -0
- package/web-scraping-python/references/api_reference.md +393 -0
- package/web-scraping-python/references/review-checklist.md +163 -0
- package/web-scraping-python/scripts/example.py +1 -0
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
# Domain-Driven Design — Patterns Catalog
|
|
2
|
+
|
|
3
|
+
Complete catalog of patterns from Eric Evans' *Domain-Driven Design: Tackling
|
|
4
|
+
Complexity in the Heart of Software*, organized by part and chapter.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Part I — Putting the Domain Model to Work
|
|
9
|
+
|
|
10
|
+
### Ubiquitous Language
|
|
11
|
+
**Problem:** Developers and domain experts use different vocabularies, leading to
|
|
12
|
+
translation overhead, misunderstandings, and models that diverge from reality.
|
|
13
|
+
|
|
14
|
+
**Solution:** Establish a shared language rooted in the domain model. Use this
|
|
15
|
+
language in all communication — conversations, documentation, code, diagrams.
|
|
16
|
+
Class names, method names, and module names should all reflect the Ubiquitous
|
|
17
|
+
Language. When the language changes, the model changes, and vice versa.
|
|
18
|
+
|
|
19
|
+
**Key rules:**
|
|
20
|
+
- One language per Bounded Context
|
|
21
|
+
- Language appears in code — not just documents
|
|
22
|
+
- Changes to the language are changes to the model
|
|
23
|
+
- If a concept has no name in the language, the model is incomplete
|
|
24
|
+
|
|
25
|
+
### Model-Driven Design
|
|
26
|
+
**Problem:** Analysis models and design models diverge. The conceptual model
|
|
27
|
+
doesn't map to the code, creating a disconnect that undermines the model's value.
|
|
28
|
+
|
|
29
|
+
**Solution:** The design model IS the analysis model. The code directly reflects
|
|
30
|
+
the domain model. No separate "analysis model" that gets translated into a
|
|
31
|
+
"design model." Model-Driven Design requires that the model work as both
|
|
32
|
+
an analysis tool and as the basis for the code.
|
|
33
|
+
|
|
34
|
+
**Key rules:**
|
|
35
|
+
- Every design decision reflects a modeling decision
|
|
36
|
+
- If the code can't express the model, revise the model
|
|
37
|
+
- If the model doesn't serve the design, revise the model
|
|
38
|
+
- Hands-on modelers: the people writing code must participate in modeling
|
|
39
|
+
|
|
40
|
+
### Hands-On Modelers
|
|
41
|
+
**Problem:** When modelers don't code and coders don't model, the model
|
|
42
|
+
degrades. "Ivory tower" architects produce models that don't work in practice.
|
|
43
|
+
|
|
44
|
+
**Solution:** The modeler must also be a hands-on implementer. Modeling
|
|
45
|
+
and implementation feed back into each other. Anyone responsible for changing
|
|
46
|
+
code must learn to express a model through code. Any developer who touches
|
|
47
|
+
the code must be empowered to refactor the model.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Part II — Building Blocks of Model-Driven Design
|
|
52
|
+
|
|
53
|
+
### Layered Architecture
|
|
54
|
+
**Problem:** Domain logic mixed with UI, database, and application concerns
|
|
55
|
+
becomes tangled and impossible to reason about.
|
|
56
|
+
|
|
57
|
+
**Solution:** Separate the system into four layers:
|
|
58
|
+
|
|
59
|
+
| Layer | Responsibility |
|
|
60
|
+
|-------|---------------|
|
|
61
|
+
| **User Interface (Presentation)** | Display information, interpret user commands |
|
|
62
|
+
| **Application** | Coordinates tasks, delegates to domain objects. Thin layer — no business logic. Manages transactions, security, and use case flow |
|
|
63
|
+
| **Domain** | Heart of the software. Business concepts, rules, information. This is where DDD patterns live |
|
|
64
|
+
| **Infrastructure** | Technical capabilities: persistence, messaging, UI frameworks. Supports all other layers |
|
|
65
|
+
|
|
66
|
+
**Key rules:**
|
|
67
|
+
- Each layer depends only on layers below it
|
|
68
|
+
- Domain layer has NO dependencies on other layers
|
|
69
|
+
- Infrastructure implements interfaces defined in the domain layer (Dependency Inversion)
|
|
70
|
+
- Application layer orchestrates but contains no business rules
|
|
71
|
+
|
|
72
|
+
### Entity
|
|
73
|
+
**Problem:** Some objects are defined by their identity and continuity, not by
|
|
74
|
+
their attributes. A Person isn't defined by their name (which can change) but by
|
|
75
|
+
a persistent identity.
|
|
76
|
+
|
|
77
|
+
**Solution:** Model objects with identity and lifecycle as Entities. Define
|
|
78
|
+
equality based on identity (ID), not attributes. Maintain continuity through
|
|
79
|
+
a lifecycle of changes.
|
|
80
|
+
|
|
81
|
+
**Key rules:**
|
|
82
|
+
- Each Entity has a unique identifier
|
|
83
|
+
- Equality is based on ID, not attributes
|
|
84
|
+
- Strip Entity classes down to the most intrinsic characteristics — identity and lifecycle behavior
|
|
85
|
+
- Attributes can change; identity persists
|
|
86
|
+
- Define what "same" means clearly (e.g., same database row, same SSN, same order number)
|
|
87
|
+
|
|
88
|
+
### Value Object
|
|
89
|
+
**Problem:** Not every object needs identity. Modeling everything as an Entity
|
|
90
|
+
adds unnecessary complexity.
|
|
91
|
+
|
|
92
|
+
**Solution:** When you care only about the attributes of an element, model it as
|
|
93
|
+
a Value Object. Make it immutable. Define equality based on attribute values.
|
|
94
|
+
|
|
95
|
+
**Key rules:**
|
|
96
|
+
- No identity — two Value Objects with the same attributes are equal and interchangeable
|
|
97
|
+
- Immutable — all operations return new instances, no state modification
|
|
98
|
+
- Side-effect-free — methods on Value Objects are pure functions
|
|
99
|
+
- Can be freely shared, passed, and copied
|
|
100
|
+
- Rich behavior — don't make them anemic. Put computation and domain logic on Value Objects
|
|
101
|
+
- Examples: Money, Address, DateRange, Color, Coordinates, PhoneNumber
|
|
102
|
+
|
|
103
|
+
**Design preference:** Favor Value Objects over Entities. They are simpler,
|
|
104
|
+
safer (immutable, no aliasing bugs), and easier to test.
|
|
105
|
+
|
|
106
|
+
### Domain Service
|
|
107
|
+
**Problem:** Some domain operations don't naturally belong to any Entity or Value
|
|
108
|
+
Object. Forcing them onto an Entity makes the Entity bloated and unclear.
|
|
109
|
+
|
|
110
|
+
**Solution:** Model these operations as stateless Services in the domain layer.
|
|
111
|
+
Name them using the Ubiquitous Language. They operate on domain objects but
|
|
112
|
+
live as standalone operations.
|
|
113
|
+
|
|
114
|
+
**Three characteristics of a good Domain Service:**
|
|
115
|
+
1. The operation relates to a domain concept not a natural part of an Entity or Value Object
|
|
116
|
+
2. The interface is defined in terms of other domain model elements
|
|
117
|
+
3. The operation is stateless
|
|
118
|
+
|
|
119
|
+
**Distinguish from other service layers:**
|
|
120
|
+
| Layer | Service examples |
|
|
121
|
+
|-------|-----------------|
|
|
122
|
+
| Application Service | Transfer between accounts (orchestration), Send notification |
|
|
123
|
+
| Domain Service | Calculate transfer fee, Determine overdraft policy |
|
|
124
|
+
| Infrastructure Service | Send email, Log to file, Query external API |
|
|
125
|
+
|
|
126
|
+
### Module (Package)
|
|
127
|
+
**Problem:** As models grow, developers need a way to organize and navigate
|
|
128
|
+
large numbers of classes.
|
|
129
|
+
|
|
130
|
+
**Solution:** Use Modules to group highly cohesive domain concepts. Modules
|
|
131
|
+
are part of the model — they tell a story about the domain, not the technology.
|
|
132
|
+
|
|
133
|
+
**Key rules:**
|
|
134
|
+
- Low coupling between Modules, high cohesion within
|
|
135
|
+
- Module names are part of the Ubiquitous Language
|
|
136
|
+
- Don't organize by pattern type (all Entities in one package). Organize by domain concept
|
|
137
|
+
- Refactor Modules as the model evolves — don't let packaging become rigid
|
|
138
|
+
|
|
139
|
+
### Aggregate
|
|
140
|
+
**Problem:** Complex associations between objects make it impossible to maintain
|
|
141
|
+
consistency. If any object can change any other, invariants break.
|
|
142
|
+
|
|
143
|
+
**Solution:** Cluster Entities and Value Objects into Aggregates. Each has a
|
|
144
|
+
root Entity and a boundary. External objects can only hold references to the root.
|
|
145
|
+
The root enforces all invariants for objects within the boundary.
|
|
146
|
+
|
|
147
|
+
**Key rules:**
|
|
148
|
+
- Root Entity has global identity; internal entities have local identity only
|
|
149
|
+
- Nothing outside the Aggregate boundary can hold a reference to an internal object (except transient references)
|
|
150
|
+
- Only the root can be obtained directly from a Repository. All other objects are reached by traversal from the root
|
|
151
|
+
- Objects within the Aggregate can hold references to other Aggregate roots
|
|
152
|
+
- Deletion of the root removes everything within the boundary
|
|
153
|
+
- When a change to any object within the Aggregate is committed, all invariants of the whole Aggregate must be satisfied
|
|
154
|
+
- Keep Aggregates small — prefer references by ID to other Aggregates over large clusters
|
|
155
|
+
- One transaction per Aggregate. Cross-Aggregate consistency is eventual
|
|
156
|
+
|
|
157
|
+
### Factory
|
|
158
|
+
**Problem:** Creating complex Aggregates or objects with many invariants is
|
|
159
|
+
cumbersome and leaks construction details into client code.
|
|
160
|
+
|
|
161
|
+
**Solution:** Encapsulate creation logic in Factories. A Factory creates an
|
|
162
|
+
object in one atomic operation, enforcing all invariants.
|
|
163
|
+
|
|
164
|
+
**When to use a Factory vs. constructor:**
|
|
165
|
+
- Constructor: Simple creation, few arguments, no invariants
|
|
166
|
+
- Factory Method on Aggregate root: Creating internal elements of the Aggregate
|
|
167
|
+
- Standalone Factory: Complex creation crossing multiple objects, reconstitution from persistence
|
|
168
|
+
|
|
169
|
+
**Key rules:**
|
|
170
|
+
- Each creation method is atomic — yields a consistent product or throws
|
|
171
|
+
- Factory is not part of the domain model. It's a design element serving the model
|
|
172
|
+
- Reconstitution Factories (from persistence) don't assign new IDs or run validation that only applies to new objects
|
|
173
|
+
- Factory abstracts away the concrete classes created — client depends on interfaces/abstract types
|
|
174
|
+
|
|
175
|
+
### Repository
|
|
176
|
+
**Problem:** Clients need to obtain references to existing domain objects.
|
|
177
|
+
Direct database queries scatter persistence logic throughout the domain.
|
|
178
|
+
|
|
179
|
+
**Solution:** Provide a collection-like interface for accessing domain objects.
|
|
180
|
+
Repositories encapsulate the technology used for data retrieval. To the client,
|
|
181
|
+
it feels like an in-memory collection of domain objects.
|
|
182
|
+
|
|
183
|
+
**Key rules:**
|
|
184
|
+
- Repositories exist only for Aggregate roots
|
|
185
|
+
- Provide add/remove/query operations using the Ubiquitous Language
|
|
186
|
+
- Encapsulate all storage and retrieval technology
|
|
187
|
+
- Reconstitute full Aggregates (not partial objects)
|
|
188
|
+
- Repository interface is defined in the domain layer; implementation is in infrastructure
|
|
189
|
+
- Delegate to Factories for reconstitution when complex
|
|
190
|
+
- Keep queries focused — query specifications can help for complex searching
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Part III — Refactoring Toward Deeper Insight
|
|
195
|
+
|
|
196
|
+
### Specification Pattern
|
|
197
|
+
**Problem:** Business rules like "is this customer eligible?" combine multiple
|
|
198
|
+
predicates. Embedding them in Entities bloats the Entity; putting them in the
|
|
199
|
+
application layer drains behavior from the domain.
|
|
200
|
+
|
|
201
|
+
**Solution:** Create explicit Specification objects that encapsulate boolean
|
|
202
|
+
business rules. Each Specification has an `isSatisfiedBy(candidate)` method.
|
|
203
|
+
Specifications can be combined with AND, OR, NOT.
|
|
204
|
+
|
|
205
|
+
**Three use cases:**
|
|
206
|
+
1. **Validation** — Does this object satisfy the specification?
|
|
207
|
+
2. **Selection** — Find objects matching the specification (query)
|
|
208
|
+
3. **Building to order** — Create an object that satisfies the specification
|
|
209
|
+
|
|
210
|
+
**Key rules:**
|
|
211
|
+
- Each specification is a Value Object — immutable and side-effect-free
|
|
212
|
+
- Combinators (and, or, not) enable composition without modifying existing specifications
|
|
213
|
+
- The specification expresses a domain concept, named in the Ubiquitous Language
|
|
214
|
+
- Can be used to generate database queries (specification-to-query translation)
|
|
215
|
+
|
|
216
|
+
### Intention-Revealing Interfaces
|
|
217
|
+
**Problem:** If a developer must read the implementation to understand what a
|
|
218
|
+
component does, the design has failed.
|
|
219
|
+
|
|
220
|
+
**Solution:** Name classes and operations to describe their effect and purpose,
|
|
221
|
+
not their implementation. Write method signatures so the return type and
|
|
222
|
+
parameters tell the story. Clients should be able to use a component correctly
|
|
223
|
+
by reading the interface alone.
|
|
224
|
+
|
|
225
|
+
### Side-Effect-Free Functions
|
|
226
|
+
**Problem:** Operations that modify state create hidden complexity. Combining
|
|
227
|
+
them creates unpredictable results.
|
|
228
|
+
|
|
229
|
+
**Solution:** Place as much domain logic as possible in pure functions —
|
|
230
|
+
operations that return results without modifying any observable state. Value
|
|
231
|
+
Objects are the natural home for side-effect-free functions.
|
|
232
|
+
|
|
233
|
+
**Key rules:**
|
|
234
|
+
- Commands (modify state) and queries (return values) should be separate
|
|
235
|
+
- Move complex logic to Value Objects that compute and return new Value Objects
|
|
236
|
+
- Commands on Entities should be simple state changes; heavy computation goes to Value Objects
|
|
237
|
+
|
|
238
|
+
### Assertions
|
|
239
|
+
**Problem:** When side effects are buried in complex method chains, developers
|
|
240
|
+
can't predict what will happen.
|
|
241
|
+
|
|
242
|
+
**Solution:** State post-conditions of operations and invariants of classes and
|
|
243
|
+
Aggregates. Document or enforce what must be true after an operation completes.
|
|
244
|
+
Use assertion-based testing to verify invariants.
|
|
245
|
+
|
|
246
|
+
### Conceptual Contours
|
|
247
|
+
**Problem:** Object boundaries that don't match domain concepts lead to
|
|
248
|
+
awkward APIs — splitting what should be together or coupling what should be separate.
|
|
249
|
+
|
|
250
|
+
**Solution:** Align object boundaries with the conceptual contours of the domain.
|
|
251
|
+
Find the natural seams where concepts divide. Operations that change together
|
|
252
|
+
belong together. A change in the domain should require changes in only one place.
|
|
253
|
+
|
|
254
|
+
### Standalone Classes
|
|
255
|
+
**Problem:** Every dependency makes a class harder to understand. A web of
|
|
256
|
+
dependencies can make simple concepts unmanageable.
|
|
257
|
+
|
|
258
|
+
**Solution:** Actively minimize dependencies. Low coupling is fundamental to
|
|
259
|
+
object design. Where possible, create classes that can be understood in isolation.
|
|
260
|
+
|
|
261
|
+
### Closure of Operations
|
|
262
|
+
**Problem:** Introducing new types for every operation result increases
|
|
263
|
+
complexity.
|
|
264
|
+
|
|
265
|
+
**Solution:** Where it fits, define operations so the return type is the same
|
|
266
|
+
as the type of the argument(s). Example: adding two Money objects returns Money.
|
|
267
|
+
Combining two Specifications returns a Specification.
|
|
268
|
+
|
|
269
|
+
### Strategy / Policy Pattern (in Domain Context)
|
|
270
|
+
**Problem:** A process or rule needs to vary by context but the overall algorithm
|
|
271
|
+
structure remains the same.
|
|
272
|
+
|
|
273
|
+
**Solution:** Factor out the varying part into a separate Strategy object
|
|
274
|
+
(called a "Policy" in domain terms). The Strategy encapsulates an alternative
|
|
275
|
+
algorithm or business rule, expressed in domain language.
|
|
276
|
+
|
|
277
|
+
**Example:** Different shipping cost policies (FlatRate, WeightBased, ZoneBased)
|
|
278
|
+
implement a ShippingPolicy interface.
|
|
279
|
+
|
|
280
|
+
### Composite Pattern (in Domain Context)
|
|
281
|
+
**Problem:** Domain concepts have a natural recursive, nested structure where
|
|
282
|
+
individual elements and groups should be treated uniformly.
|
|
283
|
+
|
|
284
|
+
**Solution:** Define an abstract type for the domain concept. Both individual
|
|
285
|
+
items and groups implement this type. Operations on the group delegate to
|
|
286
|
+
all children.
|
|
287
|
+
|
|
288
|
+
**Example:** A Route composed of Legs. Each Leg is itself a Route. Operations
|
|
289
|
+
like calculateDistance work identically on simple and composite routes.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Part IV — Strategic Design
|
|
294
|
+
|
|
295
|
+
### Bounded Context
|
|
296
|
+
**Problem:** In any large system, a single unified model is impractical.
|
|
297
|
+
Different parts of the organization have different meanings for the same terms.
|
|
298
|
+
"Account" means one thing to billing and another to authentication.
|
|
299
|
+
|
|
300
|
+
**Solution:** Explicitly define the boundary within which a particular model is
|
|
301
|
+
defined and applicable. Within a Bounded Context, keep the model strictly
|
|
302
|
+
consistent. Don't try to apply a model outside its context.
|
|
303
|
+
|
|
304
|
+
**Key rules:**
|
|
305
|
+
- Each Bounded Context has its own Ubiquitous Language
|
|
306
|
+
- The same real-world concept may be modeled differently in different contexts
|
|
307
|
+
- Code for one context should not be mixed with another
|
|
308
|
+
- Context boundaries often align with team boundaries
|
|
309
|
+
- A Bounded Context is not a Module — it's an explicit boundary around a model
|
|
310
|
+
|
|
311
|
+
### Continuous Integration
|
|
312
|
+
**Problem:** Within a Bounded Context, models fragment as multiple developers
|
|
313
|
+
make independent changes.
|
|
314
|
+
|
|
315
|
+
**Solution:** Institute Continuous Integration within each Bounded Context:
|
|
316
|
+
frequent merging of all code, automated tests exercising the model, and constant
|
|
317
|
+
communication. The goal is model-level integration, not just code compilation.
|
|
318
|
+
|
|
319
|
+
### Context Map
|
|
320
|
+
**Problem:** Without a global view of contexts, integration is ad hoc and teams
|
|
321
|
+
make incompatible assumptions.
|
|
322
|
+
|
|
323
|
+
**Solution:** Draw a Context Map — a document identifying each Bounded Context
|
|
324
|
+
and the relationships between them. The map is descriptive (what IS), not
|
|
325
|
+
prescriptive. It shows upstream/downstream relationships, shared models,
|
|
326
|
+
and translation layers.
|
|
327
|
+
|
|
328
|
+
**Relationship patterns on a Context Map:**
|
|
329
|
+
- Shared Kernel
|
|
330
|
+
- Customer/Supplier
|
|
331
|
+
- Conformist
|
|
332
|
+
- Anticorruption Layer
|
|
333
|
+
- Open Host Service / Published Language
|
|
334
|
+
- Separate Ways
|
|
335
|
+
|
|
336
|
+
### Shared Kernel
|
|
337
|
+
**Problem:** Two teams need to share a subset of the model. Without explicit
|
|
338
|
+
agreement, changes in one team break the other.
|
|
339
|
+
|
|
340
|
+
**Solution:** Designate a small subset of the domain model that both teams agree
|
|
341
|
+
to share. This shared code can't be changed without consulting the other team.
|
|
342
|
+
Include CI tests that both teams run.
|
|
343
|
+
|
|
344
|
+
**Key rules:**
|
|
345
|
+
- Keep the shared kernel as small as possible
|
|
346
|
+
- Both teams must agree to any change
|
|
347
|
+
- Automated tests run by both teams validate consistency
|
|
348
|
+
- Larger than necessary shared kernels become Big Balls of Mud
|
|
349
|
+
|
|
350
|
+
### Customer/Supplier Development
|
|
351
|
+
**Problem:** One system (downstream/customer) depends on another
|
|
352
|
+
(upstream/supplier). The downstream team has no influence over the upstream API.
|
|
353
|
+
|
|
354
|
+
**Solution:** Establish a clear customer/supplier relationship. The downstream
|
|
355
|
+
team communicates their needs. The upstream team negotiates and commits to
|
|
356
|
+
supporting them. Automated acceptance tests, written by the downstream team
|
|
357
|
+
and run in the upstream CI, validate that needs are met.
|
|
358
|
+
|
|
359
|
+
### Conformist
|
|
360
|
+
**Problem:** The upstream team has no motivation or ability to support the
|
|
361
|
+
downstream team's needs. The Customer/Supplier relationship has failed.
|
|
362
|
+
|
|
363
|
+
**Solution:** The downstream team conforms to the upstream model. Eliminates
|
|
364
|
+
the complexity of translation at the cost of limiting the downstream model.
|
|
365
|
+
Use when the upstream model is good enough and translation isn't worth the cost.
|
|
366
|
+
|
|
367
|
+
### Anticorruption Layer (ACL)
|
|
368
|
+
**Problem:** Integrating with a legacy system, external service, or different
|
|
369
|
+
Bounded Context whose model is unsuitable for your domain.
|
|
370
|
+
|
|
371
|
+
**Solution:** Build a translation layer — the Anticorruption Layer — that
|
|
372
|
+
isolates your model from the external model.
|
|
373
|
+
|
|
374
|
+
**Components:**
|
|
375
|
+
- **Façade** — Simplified interface to the external system (optional — use when the external API is complex)
|
|
376
|
+
- **Adapter** — Translates between the external system's interface and your domain's interface
|
|
377
|
+
- **Translator** — Converts data between the external model and your domain model
|
|
378
|
+
|
|
379
|
+
**Key rules:**
|
|
380
|
+
- Your domain layer never imports external system types
|
|
381
|
+
- The ACL is infrastructure, implementing domain-defined interfaces
|
|
382
|
+
- Testing the ACL validates the translation, not the external system
|
|
383
|
+
- The ACL can be thin or thick depending on how different the models are
|
|
384
|
+
|
|
385
|
+
### Separate Ways
|
|
386
|
+
**Problem:** Integration with another context is too costly relative to the
|
|
387
|
+
benefit.
|
|
388
|
+
|
|
389
|
+
**Solution:** Declare the two contexts to have no integration. The teams go
|
|
390
|
+
their separate ways. This is a legitimate strategic choice when the cost of
|
|
391
|
+
integration exceeds the value.
|
|
392
|
+
|
|
393
|
+
### Open Host Service
|
|
394
|
+
**Problem:** One system needs to expose functionality to many other systems.
|
|
395
|
+
Building custom translations for each consumer doesn't scale.
|
|
396
|
+
|
|
397
|
+
**Solution:** Define a protocol (Open Host Service) that gives access to your
|
|
398
|
+
system as a set of well-defined services. When a new integration need arises,
|
|
399
|
+
add to the protocol. For special cases, build one-off translators.
|
|
400
|
+
|
|
401
|
+
### Published Language
|
|
402
|
+
**Problem:** Direct translation between two domain models is complex and
|
|
403
|
+
tightly couples them.
|
|
404
|
+
|
|
405
|
+
**Solution:** Use a well-documented shared language (Published Language) as
|
|
406
|
+
a common medium for communication between Bounded Contexts. Often combines
|
|
407
|
+
with Open Host Service. Examples: iCalendar for scheduling, XBRL for financial
|
|
408
|
+
reporting, JSON Schema for APIs.
|
|
409
|
+
|
|
410
|
+
### Core Domain
|
|
411
|
+
**Problem:** In a large domain model, not everything is equally important. If
|
|
412
|
+
developers spread equal effort across all parts, the most valuable and complex
|
|
413
|
+
part gets insufficient attention.
|
|
414
|
+
|
|
415
|
+
**Solution:** Identify the Core Domain — the part of the model that is the
|
|
416
|
+
fundamental competitive differentiator. Assign the best developers. Focus
|
|
417
|
+
modeling effort here. Invest in deep modeling and supple design for the Core.
|
|
418
|
+
|
|
419
|
+
**Key rules:**
|
|
420
|
+
- Core Domain is what makes the system worth building
|
|
421
|
+
- It's the hardest part to model and the most valuable
|
|
422
|
+
- If you can buy it off-the-shelf or outsource it, it's not the Core Domain
|
|
423
|
+
- Write a Domain Vision Statement: a short document describing the Core Domain and its value
|
|
424
|
+
|
|
425
|
+
### Generic Subdomain
|
|
426
|
+
**Problem:** Parts of the model are necessary but not distinctive. Building
|
|
427
|
+
custom, polished solutions for them wastes effort that should go to the Core.
|
|
428
|
+
|
|
429
|
+
**Solution:** Identify Generic Subdomains — areas that can be handled with
|
|
430
|
+
off-the-shelf solutions, outsourced development, or simpler implementations.
|
|
431
|
+
Don't invest in deep modeling here.
|
|
432
|
+
|
|
433
|
+
**Options for Generic Subdomains:**
|
|
434
|
+
1. Off-the-shelf solution (buy it)
|
|
435
|
+
2. Outsource to external team
|
|
436
|
+
3. Published design/model from existing literature
|
|
437
|
+
4. In-house implementation — but with minimal investment
|
|
438
|
+
|
|
439
|
+
### Domain Vision Statement
|
|
440
|
+
**Problem:** The Core Domain lacks a clear, concise description that guides
|
|
441
|
+
decision-making.
|
|
442
|
+
|
|
443
|
+
**Solution:** Write a short document (about one page) describing the Core Domain
|
|
444
|
+
and the value it provides. Focus on what distinguishes the system from others.
|
|
445
|
+
Use this to guide model refinement and to communicate with new team members.
|
|
446
|
+
|
|
447
|
+
### Highlighted Core
|
|
448
|
+
**Problem:** Even when the Core Domain is defined, it may not be obvious in a
|
|
449
|
+
large codebase which elements belong to it.
|
|
450
|
+
|
|
451
|
+
**Solution:** Two complementary techniques:
|
|
452
|
+
1. **Distillation Document** — A short document (3-7 pages) that describes the
|
|
453
|
+
Core Domain's essential concepts and interactions. Not comprehensive — just
|
|
454
|
+
enough to point developers to the most critical parts
|
|
455
|
+
2. **Flagged Core** — Mark Core Domain elements directly in the code with
|
|
456
|
+
annotations, package naming conventions, or documentation tags
|
|
457
|
+
|
|
458
|
+
### Cohesive Mechanism
|
|
459
|
+
**Problem:** Complex computations or algorithms clutter the domain model with
|
|
460
|
+
implementation details.
|
|
461
|
+
|
|
462
|
+
**Solution:** Extract complex mechanisms into separate lightweight frameworks or
|
|
463
|
+
utility classes. The domain model delegates to the mechanism. The mechanism is
|
|
464
|
+
generic and reusable; the domain model remains expressive.
|
|
465
|
+
|
|
466
|
+
**Example:** A complex graph traversal algorithm for routing. The routing domain
|
|
467
|
+
model expresses what routes mean; the mechanism handles how to compute them.
|
|
468
|
+
|
|
469
|
+
### Segregated Core
|
|
470
|
+
**Problem:** The Core Domain is tangled with supporting code and Generic
|
|
471
|
+
Subdomains within the same Bounded Context.
|
|
472
|
+
|
|
473
|
+
**Solution:** Refactor to separate the Core Domain into its own Module or package.
|
|
474
|
+
Reduce coupling to the supporting code. The Core Domain Module should have
|
|
475
|
+
minimal dependencies. Supporting elements depend on the Core, not vice versa.
|
|
476
|
+
|
|
477
|
+
### Abstract Core
|
|
478
|
+
**Problem:** Even within a Segregated Core, there may be so much detail that the
|
|
479
|
+
essential model is hard to see.
|
|
480
|
+
|
|
481
|
+
**Solution:** Identify the most fundamental abstract concepts in the Core Domain.
|
|
482
|
+
Place these into a separate Module. This abstract core consists of abstract
|
|
483
|
+
classes and interfaces that capture the essence of the model. Specialized
|
|
484
|
+
implementation Modules depend on and extend the abstract core.
|
|
485
|
+
|
|
486
|
+
### Responsibility Layers
|
|
487
|
+
**Problem:** In a large system, it's hard to understand how the major parts
|
|
488
|
+
relate to each other and what role each subsystem plays.
|
|
489
|
+
|
|
490
|
+
**Solution:** Organize large-scale structure using Responsibility Layers.
|
|
491
|
+
Each layer has a broad responsibility within the domain:
|
|
492
|
+
|
|
493
|
+
| Layer | Responsibility |
|
|
494
|
+
|-------|---------------|
|
|
495
|
+
| **Potential** | What could be — resources, capabilities, capacity |
|
|
496
|
+
| **Decision Support** | Analysis, forecasting, projections |
|
|
497
|
+
| **Policy** | Rules, goals, constraints that guide operations |
|
|
498
|
+
| **Operations** | What is happening now — day-to-day activities |
|
|
499
|
+
|
|
500
|
+
**Key rules:**
|
|
501
|
+
- Layers depend downward only (Operations depends on Policy, not vice versa)
|
|
502
|
+
- This is a domain-concept structuring, not a technical layering
|
|
503
|
+
- Not every system needs all layers
|
|
504
|
+
- Let the structure evolve — impose it gently
|
|
505
|
+
|
|
506
|
+
### Knowledge Level
|
|
507
|
+
**Problem:** A domain has rules that users need to configure. Hard-coding
|
|
508
|
+
the rules forces code changes for what should be configuration. But making
|
|
509
|
+
everything configurable creates complexity.
|
|
510
|
+
|
|
511
|
+
**Solution:** Create a Knowledge Level — a group of objects that describes
|
|
512
|
+
how another group of objects should behave. It's a meta-model. The Knowledge
|
|
513
|
+
Level defines the rules; the operational level follows them.
|
|
514
|
+
|
|
515
|
+
**Example:** In an employee scheduling system, the Knowledge Level defines what
|
|
516
|
+
types of shifts exist, what qualifications are required, and how assignments
|
|
517
|
+
work. The operational level has actual employees, shifts, and assignments
|
|
518
|
+
that follow the Knowledge Level's rules.
|
|
519
|
+
|
|
520
|
+
### Pluggable Component Framework
|
|
521
|
+
**Problem:** Multiple implementations of a subsystem need to be interchangeable
|
|
522
|
+
in a mature ecosystem.
|
|
523
|
+
|
|
524
|
+
**Solution:** Define interfaces and a protocol for interaction so that
|
|
525
|
+
different implementations can be substituted. All components conform to the
|
|
526
|
+
interfaces defined by the Abstract Core.
|
|
527
|
+
|
|
528
|
+
**Key rules:**
|
|
529
|
+
- Requires a mature, well-distilled Abstract Core
|
|
530
|
+
- Components interact only through the framework's defined interfaces
|
|
531
|
+
- Don't attempt this too early — it requires deep domain understanding first
|
|
532
|
+
|
|
533
|
+
### Evolving Order
|
|
534
|
+
**Problem:** Imposing too much structure too early constrains the design.
|
|
535
|
+
No structure at all leads to chaos.
|
|
536
|
+
|
|
537
|
+
**Solution:** Let large-scale structure evolve gradually. Don't impose it on
|
|
538
|
+
day one. As patterns emerge, gently formalize them. Be willing to abandon
|
|
539
|
+
or change the structure as understanding deepens.
|
|
540
|
+
|
|
541
|
+
**Key rules:**
|
|
542
|
+
- Structure should make development easier, not harder
|
|
543
|
+
- If the structure is getting in the way, simplify or remove it
|
|
544
|
+
- A bad structure is worse than no structure
|
|
545
|
+
- Favor minimalism — the least structure that helps
|