Map Your Business Domains to Code: Bounded-Context Discovery, Automated
How to use Kiro specs, Steering files, and Hooks to make bounded context boundaries enforceable.
A quick primer on Domain-Driven Design
Domain-Driven Design (DDD) is a software development philosophy introduced by Eric Evans in his 2003 book Domain-Driven Design: Tackling Complexity in the Heart of Software. The central premise is simple: the biggest source of complexity in large systems isn't the technology—it's the business domain itself. So the model your code uses should reflect how the business actually thinks and operates, not how a database schema or an API response happens to be shaped.
DDD splits into two layers:
Strategic DDD — the big-picture design. This is where you carve up a large problem domain into smaller, manageable pieces called bounded contexts. Each context has a clear owner, a defined responsibility, and its own internal model. Strategic DDD also defines how contexts relate to each other using context maps, which name the integration patterns between teams and services.
Tactical DDD — the code-level design. This covers the building blocks you use inside a context: entities (objects with identity that change over time), value objects (immutable descriptors like a money amount or an address), aggregates (clusters of entities treated as a single transactional unit), repositories (the abstraction over how you load and save aggregates), and domain events (records of something significant that happened).
The glue between the two layers is the ubiquitous language — a shared vocabulary that domain experts and engineers use consistently in conversations, documentation, and code. When the code uses the same words the business uses, misunderstandings surface early instead of after the code ships.
What bounded-context discovery actually involves
Before getting into the Kiro workflow, let's be precise about the problem. Bounded-context discovery is a three-part exercise:
- Linguistic analysis — Identify where the same word means different things to different teams. "Order" in the warehouse context (a pick list) is not the same as "Order" in the payment context (a financial transaction). Surfacing those semantic seams is the first step.
- Behavioral clustering — Group capabilities that change together and for the same reasons. This is Eric Evans's original insight: a bounded context is not about nouns, it's about change velocity and ownership. Code that changes together for the same business reason belongs in the same context.
- Relationship mapping — Once you have candidate contexts, you need to name the integration patterns between them: shared kernel, customer-supplier, anticorruption layer, open-host service, published language. These relationships determine how teams couple and decouple.
Doing this manually against a large codebase is expensive. Doing it against a requirements document that hasn't been written yet is speculative. Kiro lets you do it iteratively, in code, as you build.
Kiro's spec-driven model as a DDD accelerator
Kiro's core workflow is spec-driven development: you describe what you want to build in structured natural language, and Kiro generates requirements, a technical design, and sequenced implementation tasks before writing a single line of code. For DDD practitioners, this is a native fit.
The spec is the ubiquitous language made executable. When you write a spec in Kiro, you're forced to name things. That naming discipline surfaces context boundaries earlier than any amount of whiteboard sketching.
Here's the key insight: Kiro specs are bounded-context boundaries made explicit. Each spec lives in
.kiro/specs/, scoped to a feature. When you scope a spec to a specific domain capability rather than a technical layer, you're doing strategic DDD—you're defining the problem before you define the solution.A concrete walkthrough: e-commerce domain decomposition
Let's walk through discovering and implementing bounded contexts for an e-commerce platform. This is intentionally a domain engineers know well, so the DDD decisions are visible rather than buried in unfamiliar business logic.
Step 1: Start with a domain narrative, not a data model
Open Kiro and start a new spec. Instead of describing a technical system, describe the business domain:
1
2
3
4
5
6
7
8
9
10
I'm building an e-commerce platform. The business has three core
capabilities:
1. A customer browses and selects products (catalog and search)
2. A customer places and pays for an order (checkout and payment)
3. A warehouse fulfills and ships the order (fulfillment and logistics)
These three capabilities have different owners, different change rates,
and different failure modes. I want to design the system so these
capabilities can evolve independently.Kiro will generate a requirements document that surfaces the natural nouns in each domain. Watch what it does with the word "product":
- In the catalog context: a product has a name, description, images, and attributes for search and display
- In the checkout context: a product has a price, a SKU, and tax classification
- In the fulfillment context: a product has a weight, dimensions, and a bin location
These are three different models of the same real-world thing. That's a bounded context signal.
Step 2: Let Kiro generate the context map as a design artifact
In the design phase of the spec, prompt Kiro to make the context relationships explicit:
1
2
3
4
5
Based on these requirements, generate a technical design that:
1. Names each bounded context and its owning team
2. Identifies the shared concepts across contexts (Product, Customer, Order)
3. Defines the integration pattern for each context boundary
4. Specifies what data each context owns vs. what it reads from other contextsKiro will generate a design document that looks something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
## Bounded Contexts
### Catalog Context
**Owner:** Discovery Team
**Core model:** Product (with search attributes, media, taxonomy)
**Integration pattern:** Published Language — exposes a ProductView read model
**Owns:** Product catalog, search index, category hierarchy
### Order Context
**Owner:** Commerce Team
**Core model:** Order, LineItem, PricedProduct (value object, snapshot at time of purchase)
**Integration pattern:** Customer-Supplier with Catalog (Catalog is upstream)
**Owns:** Order lifecycle, pricing rules, promotions
### Fulfillment Context
**Owner:** Operations Team
**Core model:** ShipmentOrder, PickList, PhysicalItem
**Integration pattern:** Anticorruption Layer over Order Context
**Owns:** Warehouse state, carrier integrations, trackingThis isn't just documentation—it's the input to the next phase of Kiro's workflow: task generation.
Step 3: Generate implementation tasks that respect context boundaries
When Kiro breaks the design into tasks, it naturally scopes tasks to contexts. Each task becomes a bounded unit of work:
1
2
3
4
5
6
7
8
9
10
11
12
13
Task 1: Scaffold Catalog bounded context
- Create /catalog package with its own domain model
- Define Product aggregate with catalog-specific attributes
- Expose ProductView as published language via read model
Task 2: Scaffold Order bounded context
- Create /orders package with its own domain model
- Define PricedProduct as a value object (snapshot, not a reference)
- Define integration contract with Catalog context
Task 3: Implement anticorruption layer for Fulfillment
- Translate Order domain events into Fulfillment's ShipmentOrder model
- Isolate Fulfillment from Order model changesNotice that Task 3 generates an anticorruption layer automatically because Kiro reasoned from the design document that Fulfillment needs to be insulated from Order's churn rate. That kind of architectural decision usually lives only in a senior engineer's head.
Using Steering files to enforce DDD conventions
Kiro's Steering system lets you embed architectural constraints that apply to every spec in the project. For DDD-disciplined teams, this is where you codify the rules that don't survive code review alone.
Create
.kiro/steering/ddd-conventions.md:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# DDD Architectural Conventions
## Bounded Context Rules
- Each bounded context lives in its own top-level package or service
- No direct imports between bounded context domain models
- Cross-context communication happens through domain events or explicit ACL adapters
- Each context defines its own representation of shared concepts (no shared entity classes)
## Ubiquitous Language
- All domain model class names must match the language used in the spec
- If a concept has different names in different contexts, use the context-specific name
(e.g., `Product` in Catalog, `PricedProduct` in Order, `PhysicalItem` in Fulfillment)
## Aggregate Rules
- Aggregates are transactional boundaries — only one aggregate per transaction
- Aggregate roots are the only entry point for external modification
- References between aggregates use IDs, not object references
## Anti-Corruption Layer
- Any integration with a legacy system or external service requires an ACL
- ACL lives in the consuming context, not the producing context
- ACL translates the external model into the consuming context's ubiquitous languageNow every spec Kiro generates for this project will produce code that follows these constraints. When a developer asks Kiro to add a feature that would create a cross-context entity reference, Kiro will surface the constraint and suggest the correct integration pattern instead.
Hooks for context boundary enforcement
Beyond spec generation, Kiro's hook system lets you automate architectural guardrails as you code. Here's a hook that fires whenever a file is saved in a bounded context package and checks for cross-context imports:
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"name": "Check Context Boundary Violations",
"version": "1.0.0",
"description": "Flags direct imports between bounded context packages",
"when": {
"type": "fileEdited",
"patterns": ["src/*/domain/**/*.ts", "src/*/domain/**/*.java"]
},
"then": {
"type": "askAgent",
"prompt": "Review the saved file for bounded context violations: check if any imports reference domain models from a different bounded context package. If a violation exists, suggest the correct integration pattern (domain event, ACL adapter, or read model). Reference the DDD conventions in .kiro/steering/ddd-conventions.md."
}
}This runs after every save. It's not a linter rule—it's a reasoning agent that can suggest the right architectural fix, not just flag a line number.
Context maps as living documents in your repo
One thing that distinguishes Kiro-assisted DDD from ad-hoc AI code generation is that the design artifacts live in the repository, not in a chat history. Your
.kiro/specs/ directory becomes the authoritative record of architectural decisions.For context maps specifically, consider keeping a top-level spec that documents the relationships:
1
2
3
4
5
6
7
8
9
10
11
.kiro/
specs/
context-map.md # Strategic view: all contexts and their relationships
catalog/
product-catalog.md # Catalog context feature specs
orders/
order-lifecycle.md # Order context feature specs
fulfillment/
shipment-tracking.md # Fulfillment context feature specs
steering/
ddd-conventions.md # Architectural rules applied to all specsWhen a new engineer joins the team, they read
context-map.md and understand the architecture. When a team wants to add a feature, they write a spec in the relevant context directory and Kiro generates code that fits the established model.This is the loop that DDD has always needed: a way to keep the strategic design synchronized with the code as the system evolves.
What this changes for staff engineers
If you're a staff engineer, your leverage is architectural. You set the patterns that the whole team follows. The traditional problem is that architectural constraints are fragile — they live in documentation, in tribal knowledge, and in code review comments that arrive too late.
Kiro shifts when architectural decisions get made and who has access to them. A mid-level engineer writing a spec for a new payment feature will get the correct integration pattern suggested before they write any code, because the context map and DDD conventions are in the Steering files they're working against.
That changes your job. You spend less time catching violations in code review and more time refining the constraints that Kiro enforces. You write the steering files. You curate the context-map spec. You review the designs Kiro generates for correctness, not for whether the engineer understood the architecture at all.
The whiteboard and the codebase finally share a source of truth.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article