Bounded Context and Domain Boundaries
Bounded Context (BC) is a clear boundary within which a single Ubiquitous Language, consistent models and invariants operate. Inside the border, the terms are unambiguous ("Bet," "Client," "Limit"), and outside the context communicates with contracts (events/teams) and does not pull inside other people's semantic "tails." Smartly chosen boundaries reduce connectivity, simplify scaling and accelerate product evolution.
1) Why do we need borders
Cognitive load reduction. The team works with one model and one language, not "the whole business at once."
Isolation of invariants. Critical rules (balance ≥ 0, login uniqueness) live in one place and are protected by aggregates.
Change management. The evolution of the scheme/rules within BC does not break the neighbor - there are explicit contracts.
Performance and reliability. Within a BC, a suitable consistency model and storage can be chosen; outside - asynchronous projections.
2) How to identify Bounded Context
Quick method (workshop 2-4 hours):1. Event Storming: write down the domain events "what happened," then the commands "what do you ask to do," then the aggregates "who guarantees the rule."
2. Language clusters: where words and rules consistently match - potential BC. Where the word "Client" means different (payer vs player) - there are clearly different contexts.
3. Invariants and ownership: what cannot be violated and who is responsible? The invariant → inside the BC that can guarantee it.
4. Value flow: Group steps that often change together - these are candidates for one BC.
5. Org structure: if one part is made by a separate team with separate KPIs - this is probably a separate BC (but not vice versa: the organizational structure should not blindly dictate the model).
Boundary signals:- Dispute about terms ("bet," "ticket," "round" - different meanings).
- The hottest invariant "flows" through the services.
- Different SLOs and pace of change.
- "Dual-write" between modules for the sake of atomicity.
3) Typical contexts (domain example)
Identity/KYC - registration, verification levels, restriction statuses.
Wallet/Ledger - balances, transactions, reserves, currencies.
Betting/Orders - reception, quotes, calculation.
Game/Round - round life cycle, results.
Bonus/Promo - accruals, vager, conversion.
Payments - deposits/withdrawals, payment gateway statuses.
Compliance/Reporting - reports, audits, regulatory showcases.
Catalog/Provider Integration - games, versions, statuses of providers.
Analytics/Read Models - projections and materialized views.
4) Context Map: how BCs interact
The context map captures the relationship type:- Customer–Supplier. One BC (Supplier) delivers events/data, the other (Customer) adjusts its models.
- Conformist. Customer accepts the Supplier language and model as is (e.g. regulatory ledger).
- Partnership. Two BCs synchronously evolve language and contracts (often one command/roadmap).
- Shared Kernel. Common minimal sublanguage/library, versioned jointly; use carefully.
- Anti-Corruption Layer (ACL). A protective layer that translates other people's models into their own language.
- Open Host Service / Published Language. Public protocols/schemes, versioned and documented.
Practice: Use ACLs and asynchronous events by default; Conformist - only if the provider dictates the standard, Shared Kernel - minimally and consciously.
5) Bound = language + model + invariants + storage
Inside the BC, define:- Ubiquitous Language. Dictionary of terms with examples.
- Aggregates and invariants. Who "holds" the rules and what operations are allowed.
- Consistency model. Strong/CP for money, EC/causal for storefronts.
- Storage and indexes. Selected for invariants and SLO.
- Exit contracts. Events/commands, schema versions, delivery SLOs.
Outside: no direct SQL/table dependencies. Communication - through a contract.
6) Boundaries and Consistency (PACELC)
Inside BC: choose a model for invariants (Wallet - Strong, Betting - Strong at the reception).
Between BC: Most often eventual through events and projections. If synchronous verification is needed, an explicit command with a deadline and failure when unavailable (not a "hidden" REST call).
7) Anti-corruption layer (ACL)
The task of the ACL is not to let someone else's language and dirty data inside the BC.
Schema mapping: external'PaymentStatus = SETTLED '→ internal'LedgerEntry (type = Credit, reason = PsPSettle)'.
Validation and enrichment: verification of invariants, normalization of timezones, currencies.
Versioning: support for'schema _ version'external contract, backward compatibility.
Idempotence: by 'external _ id '/' operation _ id'.
Observability: trace tags' source ',' schema _ version ',' mapping _ id ', DLQ for' poisonous' messages.
8) Boundaries and data: ownership, projections, API
Ownership: Who owns the "truth"? Only the owner changes the record. The rest of BC - read-models and links.
Projections: denormalized tables for readings; are updated from events.
API: commands (mutate in the owner) and requests (read projections). No "end-to-end" updates of other people's data.
9) Evolution and versions
Events and APIs - with'schema _ version'and compatibility policy (additive + fallback).
Blue/Green by BC: the new contract 'v2' is published parallel to 'v1', traffic is transferred gradually.
Migrations: for major changes - a new projection/service, a "two-phase switch" of readings.
10) Boundary testing
Contract tests: checking that BC complies with the published contract (producer tests) and correctly understands someone else's (consumer tests).
Property-based: invariants of aggregates within BC (balance, limits, uniqueness).
Chaos on integrations: delays, out-of-order, duplicates, schema-evolution; presence of DLQ and safe redrave.
NFR tests: p95/peak load at the border (event server/ACL).
11) Observability and SLO by boundary
Metrics: throughput of events/commands, 'projection _ lag _ ms', 'dlq _ rate', mapping errors, p95 API.
Tracing: mandatory tags' bc ',' tenant _ id ',' event _ id ',' operation _ id ',' schema _ version '.
Alerts: exceeding the projection lag, increasing command failures, schema "flap" (many 'schema _ mismatch').
12) Multi-tenant and regions
'tenant _ id '- in the keys of all events and projections on the border.
Fairness: Publishing/redraw limits per tenant to keep "noisy" from derailing neighbors' SLOs.
Residency: BC data live in a "home" region; cross-regional - aggregates/reports.
13) Anti-patterns (resulting in blurred boundary)
Giant "core-service." Everything in one place → the struggle for transactions, long releases, low autonomy.
Tabular integrations. SELECT lines to foreign tables → fragility and coupling according to the scheme.
Dual-write. At the same time, writing in two BCs "for convenience" → discrepancies and sabotage of invariants.
Conformist by default. "Accepted someone else's model as it is" → leakage of other people's meanings, the impossibility of evolution.
Hidden synchronous calls. REST call "somewhere inside" without an explicit contract and deadline → an unexpected dependence on availability.
14) Example of contours (verbal scheme)
[Wallet/Ledger] <--CP, Leader, Transactions-->
publishes: WalletReserved/Committed v
[Betting] <--CP on bid taking-->
events: BetPlaced/Settled v
[Read Models/Analytics] <--EC projection-->
[Payments] --ACL--> [Wallet/Ledger]
[Provider Integration] --ACL--> [Game/Round]
[Compliance] <-events - [KYC/Identity], -> reports [Reporting]
15) Mini-guide for border selection
1. Formulate invariants and determine who can guarantee them.
2. Describe the dictionary (10-20 terms) and make sure that the team has the same understanding.
3. Draw the Context Map and relationship types.
4. Solve the consistency model within and at the joints.
5. Design contracts (events/commands) and ACLs.
6. Plan for observability (metrics/tracing/alerts) and DLQ/redrive.
7. Run contract-tests and chaos for integrations.
8. Fix governance: who owns the language/scheme, how changes are made.
16) Pre-sale checklist
- Each BC has a vocabulary, aggregates, and invariants.
- Relationships are defined on the Context Map and contracts are documented.
- Integration through events/commands and ACLs, no direct SQL dependencies.
- Command/event idempotency; there are outbox/inbox and DLQ.
- Consistency model (intra/inter BC) fixed and tested.
- Schema versioning and compatibility strategy (v1/v2).
- Lag/error/performance metrics and alerts are configured.
- Multi-tenancy and data-residency policies are enforced.
- Operating playbooks: schema-mismatch, redrive, rebuild projections.
17) Quick recipes
Money and limits: separate BC with CP and transactions, API only commands, events as the outcome of truth for readings.
Feeds/directories: BC with EC, projections and cache, explicit 'freshness'.
Integrations with external providers: always through ACLs, events/commands, schema versioning.
Team growth: One BC is one team, the team has a "language owner" and a "keeper of invariants."
Monolith refactoring: contracts and ACLs first, then physical separation.
Conclusion
Bounded Context is not only a diagram, but a working agreement on language, rules and the way of evolution. Clear boundaries reduce connectivity, speed change, and make the system predictable to operate. Separate by meaning and invariants, protect ACL boundaries and contracts, measure everything with metrics - and your architecture will remain flexible and reliable even with the rapid growth of the domain and team.