Application Architecture — Scoping and Domain Decomposition
Before writing code, ask the right questions.
Let's study the case of an order placement application. This application allows users to browse a product catalog, verify immediate inventory availability to add items to their cart, and securely pay for the cart to convert it into a confirmed order (triggering stock decrement and fulfillment).
Through this concrete scenario, let's explore fundamental application architecture questions and their answers.
Essential Questions (and Answers)
❓ What are the business objectives and critical scenarios?
Before writing a single line of code, collaborate with domain experts to deeply understand the product's purpose. Identify the primary user journey—the one delivering maximum value or that must never fail. Next, define strict business invariants that must always hold true in the system.
🛒 In our example:
- 🎯 Business objective: Allow customers to purchase items online autonomously, smoothly, and securely, while guaranteeing real-time inventory accuracy.
- ⚡ Critical scenarios (Use Cases):
- Add to cart: Select a catalog item, check instant stock availability, and temporarily reserve the requested quantity.
- Secure payment: Send the exact amount to the payment gateway and await confirmation without risk of duplicate charges.
- Order creation: Convert the paid cart into a binding order, decrement physical inventory, and notify logistics for dispatch.
- 🛡️ Strict business rules (Invariants):
- Zero overselling: Cannot validate a cart or place an order if requested quantity exceeds available stock.
- Price integrity: The price charged must match the price displayed when added to cart (price lock window of 15 minutes).
- Order atomicity: No order created without successful payment confirmation, and conversely no payment captured without immediate order persistence.
❓ How should the business domain be partitioned?
Avoid dumping everything into a single monolithic model. In Domain-Driven Design (DDD), we partition the application into Bounded Contexts. Each domain owns its specific rules, its ubiquitous language, and its dedicated data model. This ensures that changes in one area do not inadvertently break others.
🛒 In our example — Domain breakdown:
- 📦 Catalog Domain:
Definition: Manages product listings, categories, descriptions, public prices, and available stock levels. - 🛒 Cart Domain:
Definition: Handles temporary customer item selection, promo code validation, and real-time subtotal calculations. - 💳 Payment Domain:
Definition: Orchestrates the financial transaction with external payment gateways (Stripe, PayPal, banks), verifies receipt, and issues proof of payment. - 📋 Order Domain:
Definition: Materializes the binding commercial contract once payment is approved. Freezes purchase history, tracks statuses (created, processing, shipped, delivered), and drives invoicing.
🛠️ Practical Tools for Scoping and Domain Design
To align engineering and business teams, clarify concepts, and formalize domain boundaries unambiguously, I rely on a pragmatic toolkit:
A rapid, collaborative workshop using sticky notes (or Miro/Mural). Business experts, developers, and architects lay out key domain events on a timeline ("ItemAddedToCart", "PaymentAccepted", "OrderPlaced"). It is the premier technique for uncovering natural domain boundaries.
👉 Explore EventStorming examplesConcise sheets detailing each domain's responsibilities, ubiquitous language, internal invariants, and upstream/downstream relationships (Customer/Supplier, Partnership, Anti-Corruption Layer) to prevent semantic drift across teams.
👉 Explore Bounded Context CanvasWriting Given / When / Then scenarios validated with domain experts. They turn invariants into unambiguous acceptance criteria before writing the first unit test.
👉 Explore Gherkin BDD examplesLightweight Diagrams-as-Code versioned in Git. They visualize high-level flows between bounded contexts and external systems without falling into stale documentation traps.
👉 Explore C4 Diagram examples