Bounded Contexts in Python — Core Concepts

What a bounded context is

A bounded context is a boundary within which a particular domain model is defined and applicable. The term comes from Eric Evans’ Domain-Driven Design. It solves a fundamental problem: in any non-trivial system, the same concept means different things to different teams or subsystems.

An Account in the authentication context is a username, password hash, and login history. An Account in the billing context is a payment method, balance, and invoice history. Forcing both meanings into one class creates a bloated, fragile model that serves neither purpose well.

Why bounded contexts matter

Avoiding the “God model”

Without explicit boundaries, teams tend to build a single shared model that tries to represent everything. This “God model” grows until:

  • Every change requires coordinating across teams
  • Simple features take weeks because of unexpected side effects
  • Nobody fully understands the model anymore

Bounded contexts prevent this by giving each subdomain its own focused model.

Enabling team autonomy

Each bounded context can be owned by a different team, developed at its own pace, and deployed independently. The only contract between contexts is the communication protocol at the boundary.

How to identify bounded contexts

Follow the language

When the same term means different things to different groups, you have found a boundary. If the warehouse team and the customer support team argue about what “order status” means, they are in different contexts.

Follow the data

When two parts of the system need different attributes for the same concept, they belong in different contexts. Catalog needs product descriptions and images. Warehouse needs product dimensions and bin locations.

Follow the teams

Conway’s Law suggests that system architecture mirrors team structure. Bounded contexts often align with team boundaries — and when they do not, friction appears.

Bounded context patterns

Shared Kernel

Two contexts share a small common model. Both teams agree on the shared definitions and coordinate changes. Use sparingly — it creates coupling.

Customer-Supplier

One context (supplier) provides data that another (customer) consumes. The supplier designs the interface; the customer adapts. Example: the catalog context supplies product data that the search context indexes.

Anti-Corruption Layer

A translation layer that protects one context from another’s model. Used when integrating with legacy systems or external APIs. The ACL translates foreign concepts into your domain language.

Published Language

Contexts communicate through a well-documented, versioned data format — like a shared event schema or API contract. Neither context exposes its internals.

Implementing bounded contexts in Python

As packages in a monolith

src/
  catalog/          # Bounded context 1
    models.py
    services.py
    events.py
  warehouse/        # Bounded context 2
    models.py
    services.py
    events.py
  shared/           # Shared kernel (minimal)
    events.py
    types.py

Each package has its own models.py with its own Product class. Import rules prevent catalog from importing warehouse internals and vice versa.

As separate services

Each bounded context becomes a microservice with its own database, deployed independently. Communication happens through HTTP APIs, message queues, or event streams.

The monolith approach is usually better to start with. Extract into services later when the boundaries are proven stable.

Context mapping in practice

Context maps visualize how bounded contexts relate to each other. For a Python project, document this in your architecture decisions:

[Catalog] --publishes--> ProductCreated event
[Search] --subscribes--> ProductCreated event (anti-corruption layer translates)
[Warehouse] --customer of--> [Catalog] (reads product dimensions via API)
[Billing] --shared kernel--> [Identity] (both use CustomerId value object)

Common misconception

“Each bounded context must be a microservice.” This is the most damaging misconception. Bounded contexts are a logical design concept. They can be packages in a monolith, modules in a monorepo, or separate services. The boundary is about model separation, not deployment topology.

When to introduce bounded contexts

  • Early signs: Different teams argue about what a concept means. A model class has 30+ fields serving different purposes. Changes in one area frequently break another.
  • Right time: When you can identify at least two distinct subdomains with different vocabularies.
  • Too early: A small project with one team and one clear domain. Adding boundaries where none are needed creates unnecessary complexity.

The one thing to remember: Bounded contexts draw clear lines between different parts of your domain, letting each part have its own model and vocabulary without contaminating the others.

pythonarchitectureddd

See Also

  • Python Aggregate Pattern Why grouping related objects under a single gatekeeper prevents data chaos in your Python application.
  • Python Bulkhead Pattern Why smart Python apps put walls between their parts — like a ship that stays afloat even with a hole in the hull.
  • Python Circuit Breaker Pattern How a circuit breaker saves your app from crashing — explained with a home electrical fuse analogy.
  • Python Clean Architecture Why your Python app should look like an onion — and how that saves you from painful rewrites.
  • Python Connection Draining How to shut down a Python server without hanging up on people mid-conversation — like a store that locks the entrance but lets shoppers finish.