This chapter covers Domain-Driven Design (DDD) as applied to cloud architecture on Microsoft Azure, specifically for the AZ-305 exam. You will learn how DDD principles like bounded contexts, ubiquitous language, and aggregates guide the design of microservices and event-driven systems. While DDD is not a dominant topic on the exam, it underlies several design patterns tested in the 'Design for Migration, Integration, and Infrastructure' domain (objective 4.4). Expect 1–2 questions applying DDD concepts to Azure services like Event Grid, Service Bus, and API Management.
Jump to a section
Imagine you are the chief architect of a sprawling metropolis. The city has many districts: residential, commercial, industrial, and government. Each district has its own planning department, building codes, and infrastructure. The residential district cares about parks and schools; the industrial district focuses on logistics and waste management. These departments do not share the same blueprints—they use their own models. A 'building' in residential means a home with a garden; in industrial, it's a factory with loading docks. If the residential department tried to use the industrial code, chaos would ensue. To collaborate, they agree on a 'city map' (shared kernel) showing major roads and boundaries, but each district's internal details remain private. When a new business district is created, the city issues a 'translation service' (anti-corruption layer) to convert between the commercial and residential models. This is exactly how Domain-Driven Design works: bounded contexts are like districts, each with its own ubiquitous language. The city map is the context map. The translation service handles integration. You never force a single model across the whole city; you let each context evolve independently, preserving integrity and reducing complexity.
What is Domain-Driven Design and Why Does It Matter for Cloud Architecture?
Domain-Driven Design (DDD) is a software design methodology introduced by Eric Evans in his 2003 book. It emphasizes modeling software to reflect the real-world domain—the business problem you are solving. In cloud architecture, DDD helps you decompose complex systems into manageable, loosely coupled components. The AZ-305 exam tests your ability to apply DDD principles to design reliable, scalable, and maintainable solutions on Azure.
Core Concepts of DDD
#### Ubiquitous Language A common language shared by domain experts and developers. Every term has a precise meaning within the bounded context. For example, in an e-commerce system, 'Order' means a customer's purchase request, not a database row. This language is used in code, documentation, and conversations.
#### Bounded Context A bounded context is a logical boundary within which a particular domain model applies. Each bounded context has its own ubiquitous language, entities, and business rules. Microservices are often mapped one-to-one with bounded contexts. For example, 'Inventory Management' and 'Order Fulfillment' are separate bounded contexts, each with its own model of 'Product'.
#### Entities, Value Objects, and Aggregates - Entity: An object with a distinct identity that runs through time and different states (e.g., a customer with a customer ID). - Value Object: An immutable object that describes aspects of the domain with no identity (e.g., an Address). - Aggregate: A cluster of domain objects that can be treated as a single unit. An aggregate has a root entity (aggregate root) that ensures consistency of changes within the aggregate. For example, an 'Order' aggregate root contains order items and ensures that adding an item updates the total.
#### Domain Events Something that happened in the domain that domain experts care about. For example, 'OrderPlaced' is a domain event. In cloud architecture, domain events are often implemented using Azure Event Grid or Service Bus.
Applying DDD to Azure Cloud Architecture
#### Microservices Decomposition Use bounded contexts to define microservice boundaries. Each microservice owns its data store and communicates via events or APIs. Azure Service Fabric, Azure Kubernetes Service (AKS), or Azure App Service can host these microservices.
#### Event-Driven Architecture Domain events drive communication between bounded contexts. For example, when an order is placed, the 'Order' context publishes an 'OrderPlaced' event to Azure Event Grid. The 'Inventory' context subscribes and updates stock levels. This decouples services and improves scalability.
#### Anti-Corruption Layer (ACL) When integrating with legacy systems or external services, an ACL translates between models. In Azure, you can implement an ACL using Azure API Management or a dedicated microservice that maps between the legacy model and your domain model.
#### Shared Kernel A shared subset of the domain model that two teams agree to share. In Azure, this could be a common library or a shared database schema, but it is generally discouraged because it creates coupling.
#### Context Map A diagram showing the relationships between bounded contexts. Common relationships include: - Partnership: Two contexts collaborate to achieve a common goal. - Shared Kernel: Shared subset of the model. - Customer-Supplier: One context (upstream) provides data that another (downstream) consumes. - Conformist: Downstream context conforms to the upstream model. - Anticorruption Layer: A translation layer protects the downstream context. - Open Host Service: A context provides a service that others can use via a published protocol. - Published Language: A well-defined, shared language (e.g., a JSON schema) that multiple contexts use. - Separate Ways: No integration; contexts are independent. - Big Ball of Mud: A poorly structured system with no clear boundaries.
DDD and Azure Services
#### Azure Service Bus Used for reliable messaging between bounded contexts. Supports topics and subscriptions for publish-subscribe patterns. For example, the 'Order' context publishes an 'OrderSubmitted' message to a topic, and multiple downstream contexts (Billing, Shipping) subscribe independently.
#### Azure Event Grid A fully managed event routing service. It uses a publish-subscribe model where publishers emit events (domain events) and subscribers react. Event Grid is ideal for high-throughput, low-latency event-driven architectures.
#### Azure API Management Can serve as an anti-corruption layer or open host service. It allows you to expose a consistent API facade, translating between external protocols and internal domain models.
#### Azure Functions and Logic Apps Can be used to implement domain event handlers or sagas (long-running processes). For example, a Function can listen to an Event Grid event and trigger a workflow in Logic Apps.
#### Azure Cosmos DB Often used as the data store for microservices. Its change feed can be used to publish domain events when data changes, aligning with event sourcing.
DDD Patterns Relevant to AZ-305
#### Event Sourcing Stores the state of an aggregate as a sequence of domain events. The current state is derived by replaying events. Azure Cosmos DB change feed or Azure SQL temporal tables can support this pattern.
#### Command Query Responsibility Segregation (CQRS) Separates read and write models. Often combined with event sourcing. In Azure, you might use Azure SQL for writes and Cosmos DB for reads, or use Azure Cache for Redis as a read model.
#### Saga Pattern Manages distributed transactions across multiple microservices. Each step publishes a domain event; if a step fails, compensating actions are triggered. Azure Service Bus or Durable Functions can implement sagas.
How DDD Interacts with Related Technologies
Containerization: Docker and Kubernetes (AKS) enable deployment of bounded contexts as independent containers.
API Gateways: Azure API Management can enforce bounded context boundaries by routing requests to the appropriate microservice.
Monitoring: Azure Monitor and Application Insights track domain events and service health.
DevOps: CI/CD pipelines deploy microservices independently, aligning with bounded context autonomy.
Common Pitfalls
Anemic Domain Model: A model with only data and no behavior—violates DDD.
Over-engineering: Applying DDD to simple CRUD applications adds unnecessary complexity.
Wrong Bounded Context Boundaries: Splitting by technical layers (e.g., UI, business, data) rather than business domains leads to high coupling.
Exam Relevance
AZ-305 does not require deep DDD knowledge, but you must recognize when to apply these patterns. Questions may present scenarios where you need to recommend a microservices architecture, event-driven integration, or a migration strategy. Knowing DDD helps you justify your choices.
Summary
DDD provides a strategic approach to designing cloud-native applications. Bounded contexts, ubiquitous language, domain events, and aggregates are the building blocks. Azure services like Event Grid, Service Bus, and API Management naturally support DDD patterns. For the exam, focus on identifying bounded contexts and choosing appropriate integration patterns.
Identify Core Domains
Start by understanding the business problem and identifying the core domain—the area that provides competitive advantage. For example, in an e-commerce system, the core domain might be 'Order Processing'. Subdomains include 'Inventory', 'Shipping', and 'Billing'. Each subdomain becomes a candidate for a bounded context. This step involves domain experts and stakeholders to define the ubiquitous language and scope.
Define Bounded Contexts
For each subdomain, define a bounded context with its own ubiquitous language, entities, and business rules. Document the context map showing relationships between contexts (e.g., partnership, customer-supplier). In Azure, each bounded context often maps to a separate microservice or Azure service (e.g., App Service, AKS). Ensure contexts are loosely coupled and communicate via events or APIs.
Design Aggregates and Entities
Within each bounded context, identify aggregates and their roots. An aggregate root is the only object that external clients can reference. For example, an 'Order' aggregate root contains order items and ensures invariants (e.g., total must equal sum of item prices). Use Azure Cosmos DB to store aggregates as documents, ensuring transactional consistency within the aggregate.
Model Domain Events
Identify domain events that represent meaningful state changes. For example, 'OrderPlaced' event includes order ID, customer ID, and total. Use Azure Event Grid to publish these events. Configure event subscriptions for downstream contexts (e.g., Inventory, Shipping). Ensure events are idempotent and versioned to handle schema evolution.
Implement Integration Patterns
Choose integration patterns based on the context map. For partnership contexts, use shared kernel or open host service. For legacy systems, implement an anti-corruption layer in Azure API Management or a dedicated microservice. Use Azure Service Bus for reliable messaging with topics and subscriptions. Test the integration with domain events and ensure eventual consistency.
Enterprise Scenario 1: E-Commerce Platform Migration
A large retailer migrated from a monolithic ERP to a microservices architecture on Azure. They identified bounded contexts: Catalog, Cart, Order, Payment, and Shipping. Each context was deployed as an Azure App Service with its own Azure SQL Database. The Order context emitted 'OrderPlaced' events to Azure Event Grid, which triggered a Function in the Payment context to process payment. The Shipping context subscribed to 'PaymentConfirmed' events. Initially, they misidentified the Cart context boundary, including inventory checks, which caused tight coupling. After refactoring, they used an anti-corruption layer in API Management to integrate with the legacy ERP for inventory. Performance: Event Grid handled 10,000 events/sec with sub-second latency. Misconfiguration of event retry policies led to duplicate orders; they implemented idempotency keys.
Enterprise Scenario 2: Healthcare Claims Processing
A health insurance company used DDD to modernize claims processing. Subdomains: Claims, Providers, Members, and Payments. They used Azure Service Bus topics for domain events: 'ClaimSubmitted', 'ClaimApproved', 'ClaimDenied'. Each context had its own Azure Cosmos DB, with aggregates like 'Claim' containing claim line items. The Claims context used a saga pattern with Durable Functions to coordinate approval workflows. They faced a challenge: the Provider context needed to update provider data when a claim was approved, but the models differed. They implemented an anti-corruption layer in a Function that transformed the 'ClaimApproved' event into a 'ProviderUpdate' command. Scale: 1 million claims per day. Common mistake: using a single shared database for all contexts, which caused contention and violated bounded context autonomy.
Enterprise Scenario 3: Financial Trading System
A fintech company designed a trading platform using DDD. Bounded contexts: Order Management, Market Data, Risk, and Settlement. They used Azure Kubernetes Service (AKS) for each context, communicating via gRPC and Azure Event Hubs for high-throughput market data. Domain events like 'TradeExecuted' were published to Event Hubs with partitions based on instrument ID. The Risk context subscribed and ran real-time risk calculations. Misconfiguration: they initially used a shared kernel for 'Trade' entity across contexts, leading to versioning conflicts. They refactored to separate models with an anti-corruption layer. Performance: Event Hubs ingested 100,000 events/sec. Key lesson: maintain strict bounded contexts even for shared concepts.
What AZ-305 Tests on DDD
The AZ-305 exam covers DDD under objective 4.4: 'Design for Migration, Integration, and Infrastructure'. Specifically, you need to:
Identify appropriate integration patterns (e.g., event-driven, messaging) based on bounded contexts.
Recommend Azure services (Event Grid, Service Bus, API Management) for implementing DDD patterns.
Recognize when to use anti-corruption layer, shared kernel, or open host service.
Understand the relationship between DDD and microservices decomposition.
Common Wrong Answers and Why Candidates Choose Them
Choosing a shared database for multiple bounded contexts: Candidates think it simplifies data sharing. Wrong because it violates bounded context autonomy and creates coupling. The correct answer is to use event-driven communication with separate data stores.
Using Azure Functions without Event Grid for domain events: Candidates may choose direct HTTP calls between services. Wrong because it creates synchronous coupling. Event Grid or Service Bus decouple services.
Selecting 'Big Ball of Mud' as a valid integration pattern: This is a trap—it is an anti-pattern. Candidates might think it's a pattern name. Actually, it describes a system with no clear boundaries.
Assuming DDD requires a single database: Candidates may think DDD is about data modeling. In reality, DDD is about business logic boundaries, not data storage.
Specific Numbers and Terms on the Exam
Event Grid: Supports up to 10 million events per second per region, with 64 KB max event size.
Service Bus: Premium tier supports up to 10000 topics per namespace, 256 GB message size.
API Management: Can be used as an anti-corruption layer with policies for transformation.
Bounded context: Must have its own data store (separate database or schema).
Ubiquitous language: Must be consistent within a bounded context.
Edge Cases and Exceptions
When to use shared kernel: Only when two contexts have a legitimate, stable shared subset. Avoid if possible.
Eventual consistency: DDD patterns often accept eventual consistency between contexts. The exam expects you to understand trade-offs.
CQRS and Event Sourcing: These are advanced patterns; the exam may ask when to use them (e.g., high write concurrency, audit trails).
How to Eliminate Wrong Answers
If a solution uses a single database for multiple services, it is likely wrong.
If communication is synchronous (e.g., direct HTTP), consider if asynchronous messaging is better.
If the question involves integrating with a legacy system, look for 'anti-corruption layer' or 'API Management'.
If the question asks about decomposing a monolith, look for 'bounded contexts' as the guiding principle.
Bounded contexts are the fundamental unit of decomposition in DDD; each context has its own ubiquitous language and data store.
Domain events represent meaningful business occurrences and are implemented with Azure Event Grid or Service Bus.
Anti-corruption layer (ACL) is used when integrating with legacy systems; Azure API Management can serve as an ACL.
The context map defines relationships between bounded contexts; know the patterns: Partnership, Shared Kernel, Customer-Supplier, Conformist, ACL, Open Host Service, Published Language, Separate Ways.
Aggregate root ensures consistency within an aggregate; external references only go through the root.
Eventual consistency is acceptable between bounded contexts; the exam expects you to choose asynchronous communication.
Avoid 'Big Ball of Mud'—it is an anti-pattern, not a valid integration pattern.
For the exam, recognize when to use Event Grid (event routing) vs. Service Bus (reliable messaging) based on requirements.
These come up on the exam all the time. Here's how to tell them apart.
Event Grid
Publish-subscribe model with topics and subscriptions.
Best for high-throughput, low-latency event routing (up to 10 million events/sec).
Events are not persisted after delivery (unless using dead-letter).
No ordering guarantee per topic (unless using event domains).
Ideal for reactive, event-driven architectures with many subscribers.
Service Bus
Supports topics, queues, and sessions for messaging.
Supports ordered delivery with sessions and partitioning.
Messages are persisted until consumed (up to 14 days).
Supports exactly-once delivery with duplicate detection.
Best for reliable, transactional messaging with complex routing.
Mistake
DDD is only for object-oriented programming.
Correct
DDD is a design methodology that applies to any programming paradigm. In cloud architecture, it is used to design microservices and event-driven systems regardless of the underlying language.
Mistake
Bounded contexts must correspond to one database per context.
Correct
While each bounded context should have its own data store, that store could be a separate schema within a shared database, but this is discouraged due to coupling. The exam expects separate databases or schemas to enforce boundaries.
Mistake
Domain events are the same as system events (e.g., 'DatabaseUpdated').
Correct
Domain events are meaningful to the business (e.g., 'OrderShipped'), not technical implementation details. System events like 'RowInserted' are not domain events. The exam tests this distinction.
Mistake
The 'Big Ball of Mud' is a valid DDD integration pattern.
Correct
It is an anti-pattern describing a system with no clear boundaries. The exam includes it as a distractor. The correct patterns are Partnership, Shared Kernel, Customer-Supplier, Conformist, Anticorruption Layer, Open Host Service, Published Language, and Separate Ways.
Mistake
DDD requires CQRS and Event Sourcing.
Correct
CQRS and Event Sourcing are advanced patterns that complement DDD but are not mandatory. The exam may ask when to use them, but DDD itself is broader.
Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.
A bounded context is a logical boundary within a domain model, while a microservice is a deployment unit. Ideally, one microservice maps to one bounded context, but a bounded context could be implemented by multiple microservices if needed (though not recommended). The exam tests the relationship: bounded contexts guide microservice decomposition.
Use Event Grid for high-throughput, low-latency event routing where events are fire-and-forget and subscribers are independent. Use Service Bus when you need reliable, ordered delivery, duplicate detection, or support for sessions and transactions. Service Bus also supports queues for point-to-point messaging.
An anti-corruption layer (ACL) translates between two bounded contexts to prevent one model from corrupting the other. In Azure, you can implement an ACL using Azure API Management (with policies to transform requests/responses) or a dedicated microservice (e.g., Azure Function) that maps between models.
Technically yes, but it violates the principle of bounded context autonomy. The exam expects you to recommend separate databases or schemas per bounded context to avoid coupling. If a single database is used, it should be with strict schema separation and no cross-context queries.
A domain event is something that happened in the domain that domain experts care about (e.g., 'OrderPlaced'). An integration event is a domain event that is published to other bounded contexts. In practice, they are often the same event, but the term 'integration event' emphasizes its use for communication between services.
No, DDD can be applied to brownfield projects to refactor legacy systems. Start by identifying bounded contexts in the existing system and gradually extract them into microservices. The exam may present a migration scenario where you need to recommend DDD-based decomposition.
A shared kernel is a shared subset of the domain model that two teams agree to use. Use it only when there is a stable, common part of the model that changes infrequently and both teams have a strong need to share. Avoid it otherwise because it creates coupling. The exam expects you to prefer other patterns like open host service or published language.
You've just covered Domain-Driven Design for Cloud Architecture — now see how well it sticks with free AZ-305 practice questions. Full explanations included, no account needed.
Done with this chapter?