Engineering

From Sticky Notes to Architecture

Reading bounded context signals and translating them into architectural decisions

Learning Objectives

By the end of this module you will be able to:

  • Identify bounded context candidates by reading three types of signals in the event timeline: pivotal events, ubiquitous language shifts, and aggregate cohesion patterns.
  • Apply the aggregate formation technique to group related commands, events, and policies into coherent consistency units.
  • Map bounded contexts to context mapping patterns and reason about appropriate inter-context coordination mechanisms.
  • Translate bounded context boundaries into candidate microservice or module boundaries in decomposition and modernization scenarios.
  • Recognize the implementation gap and articulate what additional work is needed between Event Storming output and actionable architectural decisions.

Core Concepts

The Wall is Not the Architecture

After an Event Storming session, you have a timeline of orange sticky notes spanning a wall, annotated with commands, actors, policies, and aggregates. That wall represents shared understanding — but it is not, by itself, an architecture.

The translation work begins here. The raw output contains the signals you need to identify bounded contexts, reason about aggregate boundaries, and make principled decomposition decisions. But those signals must be read deliberately.

What is a Bounded Context?

A bounded context is a discrete area of the domain within which a specific model is consistent and valid. Inside a bounded context, terms have precise meanings; the same word used in a different bounded context may mean something subtly or entirely different.

Bounded context boundaries simplify organizational scaling by distributing model ownership and maintenance responsibility. Each bounded context can be independently owned, evolved, and — when appropriate — deployed.

Three Signals of a Boundary

Event Storming surfaces boundary candidates through three categories of observable signal:

1. Pivotal Events

Pivotal events are the most significant business events that mark transitions between major business phases. They are placed deliberately on the timeline to emphasize major state transitions. When you see a pivotal event, you are likely looking at the edge of one bounded context and the beginning of another. An Order Placed event that triggers a completely different set of actors and policies than everything preceding it is a reliable candidate for a boundary line.

2. Language and Ownership Shifts

As participants from different departments contribute sticky notes, watch for vocabulary collisions. The word "customer" in a sales context may carry entirely different meaning and attributes than "customer" in an accounting context.

3. Aggregate Cohesion

At the aggregate level, observe which commands and events cluster around shared data and shared business rules. Where that cohesion breaks down — where a group of events seems to belong to a different set of concerns — a boundary is often present.

What is an Aggregate?

An aggregate is a transactional consistency boundary.

All parts of an aggregate must be consistent according to business rules when changes are committed. Aggregates enforce invariants: rules that must not be violated, such as "cannot refund more than paid."

Aggregates identified through Event Storming represent consistency and decision boundaries within bounded contexts, and they directly shape decisions about transaction scope, optimistic locking strategies, and eventual consistency patterns.

Context Mapping

Once bounded contexts are identified, they must be related to one another. Context mapping describes the relationships between bounded contexts and the patterns that govern those relationships.

At enterprise scale, coordinating communication and dependencies between multiple bounded contexts represents a significant architectural and organizational challenge. Managing contracts between contexts, data ownership, and synchronization points requires explicit governance. DDD provides patterns for this:

  • Anti-Corruption Layer: Translate between models at the boundary to prevent a downstream context from being distorted by an upstream one.
  • Open Host Service: Define a published protocol that other contexts can integrate against without coupling to internals.
  • Shared Kernel: Two contexts share a small, explicitly agreed-upon subset of their model — high coordination cost, but sometimes appropriate.

Core vs. Supporting Domains

Not all bounded contexts carry equal business weight.

  • Core domains represent the highest-value business capabilities with competitive advantage. Invest heavily here.
  • Supporting domains are necessary but not differentiating. Use standard patterns; avoid over-engineering.
  • Generic subdomains are commodity concerns. Buy or adopt off-the-shelf solutions.

This classification directly informs where to direct engineering investment, which contexts to extract first in a decomposition, and where to tolerate technical debt.

Conway's Law


Step-by-Step Procedure

This procedure applies after a Big Picture or Process Level Event Storming session, when you have a populated timeline and want to extract architectural signals.

Step 1: Mark the Pivotal Events

Walk the timeline and identify the pivotal events — the orange stickies that represent the most significant state transitions. Draw a vertical line through the timeline at each pivotal event. These lines are your first-pass boundary candidates. Do not commit to them yet.

Step 2: Look for Language Collisions

Ask the room: "Does this word mean the same thing in the section before this line as it does after?" Look at actors, aggregate names, and event names. Where the vocabulary shifts, or where ownership transfers from one group to another, reinforce the boundary line. Where vocabulary is consistent across the line, the boundary may not be real.

Step 3: Group into Aggregate Clusters

Within each candidate bounded context, move to aggregate identification.

Cluster business rules that operate on similar data. Position related commands and events near one another. When two business rules touch the same data, place them on top of each other spatially. The clusters that emerge are aggregate candidates.

Decision point: If a cluster is hard to separate from another and they seem to share a consistency requirement, they may belong to the same aggregate. If they can tolerate eventual consistency between them, they likely belong to separate aggregates.

Step 4: Name the Aggregates — After Structure is Clear

Step 5: Draw the Bounded Context Boundaries

Combine the signals: pivotal event lines, language collision lines, and aggregate clustering patterns. Draw the bounded context boundaries around cohesive clusters of aggregates that share language and ownership.

Decision point: A bounded context with only one trivial aggregate and no distinctive language is a candidate to be absorbed into a neighbor. A bounded context with a high density of complex aggregates and distinctive language is a strong extraction candidate.

Step 6: Classify by Domain Type

Label each bounded context as core, supporting, or generic. Use the business value visible in the events — where are the policies most complex? Where is the business logic most differentiated? Where are participants from the domain side most engaged? Those are your core domain signals.

Step 7: Map Inter-Context Relationships

Draw lines between the bounded contexts and label the relationships. Which contexts produce events that other contexts consume? Which contexts depend on shared data? Choose context mapping patterns for each relationship: Anti-Corruption Layer, Open Host Service, Shared Kernel, or simple event publishing.

Step 8: Identify the Implementation Gap

Event Storming models can become disconnected from implementation if not intentionally translated to code, documentation, and testing approaches. Before leaving the room, explicitly name what is still unresolved: What does a team own each context? What data does each context own? Which context mapping patterns require protocol negotiation? What documentation must be written to carry these decisions forward?


Worked Example

Scenario: E-Commerce Platform

Imagine the following partial event timeline, produced in a Big Picture session for an e-commerce platform:

[Product Browsed] → [Product Added to Cart] → [Cart Reviewed] →
[ORDER PLACED] → [Payment Initiated] → [Payment Authorized] →
[PAYMENT CONFIRMED] → [Warehouse Notified] → [Item Picked] →
[Order Packed] → [SHIPMENT DISPATCHED] → [Customer Notified]

All-caps events are pivotal events. They are the first-pass boundary markers.

Step 1 output: Three candidate boundaries after ORDER PLACED, after PAYMENT CONFIRMED, and after SHIPMENT DISPATCHED.

Step 2 output: Participants notice that "Customer" in the catalog section refers to a browsing visitor with no account required, while "Customer" in the payment section refers to a verified account with billing details. "Customer" again takes on a different meaning in the notification section — a recipient contact. Three language definitions of the same word confirm the boundaries.

Step 3–4 output: Within the payment section, two clusters emerge:

  • {Initiate Payment, Payment Initiated, Authorize Payment, Payment Authorized, Payment Failed} — all touching transaction state
  • {Confirm Payment, Payment Confirmed, Refund Requested, Refund Issued} — touching settlement state

These may be two aggregates — PaymentAttempt and PaymentSettlement — or a single Payment aggregate if the invariant "cannot refund more than authorized" requires them to be consistent as a unit. The team decides on a single Payment aggregate because the refund invariant requires access to the original authorization amount.

Step 5 output: Three bounded contexts emerge:

  • Catalog & Cart (browsing, selection, cart management)
  • Payments (authorization, settlement, refunds)
  • Fulfillment (warehouse, picking, packing, dispatch)

A fourth candidate emerges for Customer Notifications — it appears after dispatch but also after payment confirmation, suggesting it is a cross-cutting supporting context.

Step 6 output: Payments is identified as a core domain (complex invariants, regulatory risk, competitive sensitivity). Catalog & Cart is supporting. Fulfillment is supporting. Notifications is generic.

Step 7 output: Payment Confirmed is an event that both Fulfillment and Notifications consume. The relationship is a published event with an Anti-Corruption Layer in Fulfillment to translate payment concepts into fulfillment vocabulary.


Annotated Case Study

Decomposing a Monolith at a Financial Services Firm

A financial services team ran a Big Picture Event Storming session across their core loan origination monolith. The system had grown over eight years and contained interleaved concerns across loan application, credit assessment, document management, and regulatory reporting.

What the session revealed:

The timeline surfaced a pivotal event: Loan Application Submitted. Everything before it involved the applicant-facing interface, and everything after involved internal credit analysts. The vocabulary shift was stark: applicants became "borrowers" on one side and "credit files" on the other. This was the first confirmed boundary.

A second pivotal event, Credit Decision Made, separated the credit assessment workflow from the downstream document management and disbursement workflow. Further examination showed that "document" meant different things in the assessment phase (supporting evidence submitted by the applicant) and in the post-decision phase (legally-binding agreements generated by the firm). Two more confirmed boundaries.

What aggregate clustering showed:

Within the credit assessment bounded context, the team found three aggregate clusters:

  1. CreditApplication — receiving the submitted file, routing to analysts
  2. CreditAssessment — analyst workflow, scoring, decision
  3. RegulatoryRecord — immutable log of decisions for compliance

The third caused debate: should it live in the credit assessment context or be its own context? The team noticed that RegulatoryRecord used language from the compliance team, not the credit team, and was consumed by a reporting pipeline the credit team had no ownership over. They extracted it as its own Compliance Reporting bounded context — a supporting domain with different ownership and change cadence.

The architectural decisions that followed:

The "as-is" domain model

The team identified that credit scoring logic represented genuine essential complexity — a core domain business rule, not an implementation artifact. They preserved it. Complex data transformation logic between two internal report formats was revealed to exist only because of an early database schema decision that no longer applied. That was accidental complexity. They eliminated it.

The implementation gap they named:

The session produced four bounded context candidates and a context map. What remained unresolved: data ownership for the shared borrower entity across contexts, the team assignment for the new compliance context, a protocol definition for the event that Fulfillment would consume from Payments, and three ADRs (Architectural Decision Records) that needed to be written before extraction work could begin.


Boundary Conditions

When Bounded Context Signals Conflict

Sometimes the three signals disagree. A pivotal event lands in the middle of a cluster of aggregates that share consistent language and ownership. In this case, prioritize aggregate cohesion and invariants over the pivotal event line. Pivotal events are strong heuristics, not guarantees. The consistency requirements of the aggregates take precedence.

When the Organization and the Domain Disagree

Conway's Law implies that aligning bounded contexts with team structures reduces coordination cost. But sometimes the domain model suggests a boundary that cuts across organizational lines.

Strategic Domain-Driven Design remains the most neglected aspect of DDD in practice — many teams jump directly into tactical implementation without the conversations that give meaning to bounded context decisions. When domain and org structure diverge, do not automatically bend the domain model to fit the org. Consider whether the organizational structure itself is the source of friction. This is a systemic question that may require management engagement.

When a Bounded Context is Too Large

A bounded context that contains many dense aggregate clusters, multiple competing vocabularies, and multiple ownership groups may actually be several bounded contexts that have not yet been separated. Signs of this: the team cannot agree on a name for the context, or the name they choose is very generic ("Order Management," "Platform"). Run a dedicated Design Level session on that section of the timeline.

When a Bounded Context is Too Small

A context with a single trivial aggregate, no distinctive language, and no independent change cadence is a candidate for absorption. A microservice boundary carries operational overhead — deployment, observability, inter-service contracts.

The Strangler Pattern and Extraction Order

The strangler pattern enables teams to transform a monolith by gradually extracting business capabilities into independent services while the original system continues to serve traffic. But not all bounded contexts are equally safe to extract first. Domain boundaries that show low coupling with the rest of the system are where modernization can safely begin. Generic domains (notifications, audit logging) with few inbound dependencies are typically the lowest-risk first extraction targets. Core domains, despite their business importance, are often extracted later — after teams have proven out the extraction pattern on lower-risk contexts.

The Distance Between Model and Code

The workshop produces a shared domain understanding visualized as sticky notes, but this does not automatically translate to software architecture, code organization, or testing strategy. The model will drift from reality as implementation decisions are made. Plan for this: name the translation artifacts you will produce (context maps, ADRs, team charters), assign owners, and schedule a re-storming session within a defined time window to reconcile the model with what was actually built.


Thought Experiment

You have just completed a Big Picture Event Storming session for a healthcare company. The timeline runs from patient appointment booking through clinical consultation, lab testing, diagnosis, treatment planning, and billing. You have identified five candidate bounded contexts.

As you begin to draw the context map, you notice the following:

  • Booking and Clinical Consultation share the concept of "patient" but define it completely differently — Booking cares about contact details and scheduling preferences; Consultation cares about medical history and clinical notes.
  • Lab Testing is consumed by both Clinical Consultation (for diagnosis) and Billing (for cost coding) but owns its own vocabulary for test results.
  • Billing is a generic domain by domain classification, but it is the only context with a clear team owner and the most stable codebase.

Now consider:

The organization wants to begin extraction immediately and has pressure to show a "win" in the first quarter. An engineering manager proposes starting with Billing because it is well-understood and team ownership is clear.

Is this the right extraction target? What signals from the Event Storming output would you use to evaluate this argument? What would you need to know about the inter-context relationships before committing? What is the risk if you extract Billing first, and what is the risk if you wait?

There is no single correct answer. Reason through the tradeoffs using what the Event Storming session revealed.

Key Takeaways

  1. Three signals identify boundaries. Pivotal events, language and ownership shifts, and aggregate cohesion patterns each independently point to bounded context candidates. When all three align, the boundary is strong.
  2. Aggregates are consistency units, not just groupings. An aggregate enforces invariants. Grouping by convenience rather than by consistency requirement produces aggregates that will fight you in implementation. Name aggregates only after their structure -- and specifically their invariants -- are clear.
  3. Context mapping is a governance decision, not just a diagram. The relationship patterns between bounded contexts (Anti-Corruption Layer, Open Host Service, Shared Kernel) determine coordination costs and team autonomy. Naming them explicitly forces the team to commit to a contract, not just a concept.
  4. Domain classification drives investment and extraction order. Knowing which contexts are core, supporting, and generic tells you where to invest engineering depth, what to buy or adopt, and which contexts to extract first versus last in a decomposition strategy.
  5. The implementation gap is predictable and must be named. The model on the wall is not architecture until it is translated into team ownership, data ownership decisions, API contracts, and written documentation. Name the translation artifacts before the session closes and assign owners to each.