20 Advanced Domain-Driven Design (DDD) Interview Questions and Answers

An in-depth list of advanced Domain-Driven Design (DDD) interview questions for senior engineers and architects, covering strategic patterns like Bounded Contexts and tactical patterns like Aggregates and Entities.
Domain-Driven Design (DDD) Q&A Component

Jump to Category

🗺️ Strategic Design 🧱 Tactical Design: The Building Blocks
🗃️ Aggregates & Data Management 🏗️ Architecture & Implementation

Strategic Design

1. What is a Bounded Context and why is it considered the most important pattern in DDD?

A **Bounded Context** is a conceptual boundary within which a specific domain model is defined and consistent. Inside this boundary, every term in the Ubiquitous Language has a precise meaning. For example, a “Product” in the `Sales Context` is different from a “Product” in the `Inventory Context`.

It’s the most important strategic pattern because it allows large, complex domains to be broken down into smaller, more manageable pieces. It provides the logical frame for a microservice and is the key to creating loosely coupled, highly cohesive systems. It explicitly defines where one model ends and another begins.

Read Martin Fowler’s article on Bounded Context.

2. Explain the purpose of a Ubiquitous Language.

A **Ubiquitous Language** is a shared, rigorous language developed by the team, including both developers and domain experts. This language is used in all forms of communication—code, documentation, diagrams, and conversations—to describe the domain.

Its purpose is to eliminate ambiguity and misunderstanding between technical and non-technical stakeholders. By using the same terms for domain concepts in the code as in business discussions, it ensures that the software model is a direct reflection of the business domain, reducing the risk of incorrect implementations.

3. What is a Context Map and what patterns would you use to integrate two Bounded Contexts?

A **Context Map** is a diagram that shows the relationships and integration points between different Bounded Contexts. It’s an explicit map of the political and technical connections in a system.

Common integration patterns include:

  • Shared Kernel: Two teams share a common subset of the domain model (code). This creates tight coupling and should be used sparingly.
  • Customer-Supplier: One team (the “supplier”) provides an API for another team (the “customer”). The supplier’s priorities are influenced by the customer’s needs.
  • Conformist: The downstream team conforms to the model of the upstream team without trying to influence it.
  • Anti-Corruption Layer (ACL): The downstream team creates a translation layer that isolates its own model from the upstream model, protecting it from changes. This is a key defensive pattern.
Explore Context Mapping patterns.

4. Differentiate between Core, Supporting, and Generic Subdomains.

  • Core Domain: This is the part of the business that provides a competitive advantage. It’s the most complex and valuable area. The most talented developers and resources should be focused here.
  • Supporting Subdomain: A part of the business that is necessary for the solution to work but is not a competitive differentiator. It’s typically developed in-house but is not the primary focus.
  • Generic Subdomain: A part of the business that is a “solved problem,” such as authentication or sending emails. The best strategy here is to use off-the-shelf software or a third-party service, not to build it from scratch.

5. How does DDD relate to Microservices architecture?

DDD provides the strategic design tools necessary to do microservices well. The most common and effective way to define the boundaries of a microservice is to align it with a **Bounded Context**.

A system designed without DDD principles can easily devolve into a “distributed monolith,” where services are tightly coupled through shared databases or chatty communication, defeating the purpose of the architecture. DDD helps ensure that services are truly autonomous and loosely coupled by defining clear, domain-driven boundaries.

Read about decomposing by Bounded Context.

Tactical Design: The Building Blocks

6. What is the fundamental difference between an Entity and a Value Object?

The key difference is their concept of **identity**.

  • An **Entity** has a distinct identity that runs through its entire lifecycle, even if its attributes change. Two entities are different if they have different IDs. Examples include a `Customer` or an `Order`.
  • A **Value Object** has no conceptual identity. It is defined solely by the value of its attributes. Two value objects are considered the same if all their attributes are equal. They should be immutable. Examples include a `Money` object (with amount and currency) or a `DateRange`.
Read Martin Fowler’s article on Value Objects.

7. Why should Value Objects be immutable?

Immutability makes Value Objects easier and safer to work with. Since their identity is based on their value, changing their value would mean it’s no longer the “same” object, which is confusing. By making them immutable, they can be freely passed around and shared without fear of side effects or inconsistent state. If you need a different value, you create a new Value Object instance instead of modifying the existing one.

8. What is a Domain Event and what is its purpose?

A **Domain Event** is an object that represents something significant that has happened in the domain. It’s a statement of fact about the past (e.g., `OrderPlaced`, `CustomerAddressChanged`).

Its primary purpose is to decouple different parts of your domain. When a state change occurs in one part of the system (e.g., an Order is placed), it can publish a Domain Event. Other parts of the system (e.g., a Notifications service) can then subscribe and react to this event without the Order service needing to know about them. This is a key pattern for handling side effects and integrating Bounded Contexts.

Read about Domain Events.

9. What is the role of a Repository? How does it differ from a DAO?

  • A **Repository** mediates between the domain and data mapping layers. Its interface is defined in terms of the domain model and speaks the Ubiquitous Language. It acts like an in-memory collection of Aggregates, providing methods like `findById` or `save`. It encapsulates all the logic for retrieving and persisting Aggregates.
  • A **DAO (Data Access Object)** is a lower-level pattern that is an abstraction over a specific data source (like a database table). Its API is often very CRUD-centric and reflects the structure of the database table, not the domain model.

In practice, a Repository might *use* one or more DAOs under the hood to implement its logic.

10. When should you use a Factory instead of a simple constructor?

You should use a Factory when the creation of an object, especially an Aggregate, is a complex process that doesn’t fit neatly into a constructor. A Factory can encapsulate complex creation logic, such as:

  • Creating an Aggregate from multiple source objects.
  • Enforcing complex invariants that must be true upon creation.
  • Reconstituting an object from a database or a DTO.

A Factory’s method name can also be more descriptive than a constructor (e.g., `OrderFactory.createFromShoppingCart(…)`).

11. What is a Domain Service?

A Domain Service is used when a piece of domain logic does not naturally belong to any single Entity or Value Object. This often occurs when an operation involves coordinating between multiple domain objects.

For example, transferring money between two `Account` entities is not the sole responsibility of either account. A `MoneyTransferService` could be created to encapsulate this logic. Domain Services should be stateless.

Aggregates & Data Management

12. What is an Aggregate and what is the role of the Aggregate Root?

An **Aggregate** is a cluster of associated domain objects that are treated as a single unit for the purpose of data changes. It acts as a transactional consistency boundary.

The **Aggregate Root** is a specific Entity within the Aggregate. It is the single entry point for all modifications to any object within the Aggregate boundary. External objects are only allowed to hold a reference to the Aggregate Root, never to the internal entities. This ensures that the Aggregate Root can enforce all invariants and business rules for the entire cluster of objects before any state change is committed.

Read Martin Fowler’s article on Aggregates.

13. What are the rules for designing Aggregates?

  1. Protect Business Invariants: The primary purpose of an Aggregate is to enforce consistency rules within its boundary.
  2. Reference Other Aggregates by ID: To maintain loose coupling, an Aggregate should not hold a direct object reference to another Aggregate Root. It should only hold its ID.
  3. Keep Aggregates Small: Smaller aggregates are more performant and less prone to concurrency conflicts. If an aggregate is too large, it may be a sign that the boundary is drawn incorrectly.
  4. Update in a Single Transaction: Changes to a single Aggregate should be persisted within one atomic transaction.

14. Why should you reference other Aggregates only by their ID?

Holding a direct object reference to another Aggregate creates tight coupling and makes it difficult to define clear consistency boundaries. If you load one Aggregate, you might be tempted to load its entire graph of related aggregates, leading to poor performance.

By referencing only by ID, you treat other Aggregates as external. This forces you to consider transactional boundaries explicitly. If you need to perform an operation that involves two Aggregates, you must do so through an Application Service or Domain Service, often using eventual consistency via Domain Events rather than a single ACID transaction.

15. How do you handle a business rule that spans multiple Aggregates?

This is a common challenge. Since a single transaction should only modify a single Aggregate, you cannot enforce immediate consistency across them. The solution is to use **eventual consistency**.

For example, if a business rule states that a customer cannot have more than 3 open orders, when a `PlaceOrder` command is received, the `Order` Aggregate might be created and an `OrderPlaced` event is published. A separate process or “Saga” would then listen for this event, check the customer’s total open orders, and if the rule is violated, it would initiate a compensating action, such as dispatching a `CancelOrder` command. The system is temporarily inconsistent but eventually corrects itself.

Architecture & Implementation

16. Compare Layered Architecture with Hexagonal Architecture (Ports and Adapters).

  • A **Layered Architecture** typically has layers like UI, Application, Domain, and Infrastructure. The dependency rule is that a layer can only depend on layers below it. A key drawback is that the Domain Layer can become coupled to the Infrastructure Layer (e.g., persistence concerns leaking into domain models).
  • A **Hexagonal Architecture** inverts this dependency. The Domain is at the center and has no outward dependencies. It defines “Ports” (interfaces) for its needs, like a `OrderRepository` port. External concerns like the UI, database, or message queues are “Adapters” that implement these ports and are plugged into the core. This keeps the domain pure and isolated from technology concerns.
Explore Hexagonal Architecture.

17. What is the role of an Application Service in a DDD architecture?

An Application Service orchestrates the execution of a specific use case or user story. It is a thin layer that sits between the presentation/API layer and the domain model. Its responsibilities are to:

  1. Receive a request (often as a DTO).
  2. Use a Repository to fetch the relevant Aggregate(s).
  3. Invoke methods on the Aggregate Root to perform the domain logic.
  4. Use the Repository to persist the changed Aggregate.
  5. Handle transactional boundaries and cross-cutting concerns.

It should not contain any business logic itself; that belongs in the domain model.

18. How do CQRS and Event Sourcing complement a DDD approach?

They complement DDD very well, especially for complex domains.

  • CQRS (Command Query Responsibility Segregation) aligns with DDD by separating task-based operations (Commands) that modify Aggregates from the read-side (Queries). This allows you to have a rich, behavior-driven domain model for writes, and separate, optimized read models for queries, avoiding a one-size-fits-all model.
  • Event Sourcing is a natural way to persist DDD Aggregates. Instead of saving the Aggregate’s current state, you persist the sequence of Domain Events that it has produced. The Aggregate’s state can be rebuilt at any time by replaying its events. This provides a perfect audit log and makes publishing Domain Events a first-class, reliable part of the persistence mechanism.
Read about CQRS and Event Sourcing.

19. What is an Anemic Domain Model and why is it considered an anti-pattern in DDD?

An Anemic Domain Model is one where the domain objects are simple data bags with only getters and setters, and all the business logic is located outside of them in separate service or manager classes. This is an anti-pattern because it’s just a procedural design and completely misses the point of object-oriented design and DDD, which is to encapsulate data and the behavior that operates on that data together. It leads to a domain model that cannot enforce its own invariants and business rules.

20. How would you start applying DDD to a legacy brownfield project?

You would not try to refactor the entire application at once. A good approach is to apply the **Strangler Fig Pattern**:

  1. Identify a well-defined **Bounded Context** within the monolith that is a good candidate for extraction.
  2. Create an **Anti-Corruption Layer (ACL)** to act as a translation layer between the legacy system and the new Bounded Context.
  3. Begin building the new context using proper DDD principles (Aggregates, Entities, etc.).
  4. Use the ACL to gradually redirect calls from the monolith to the new service until the old functionality can be decommissioned.

Remote hiring made easy

75%
faster to hire
58%
cost savings
2K+
hires made

Our Offices

415 Mission St, San Francisco,
CA 94105, United States

320 Serangoon Road #13-05, Centrium Square, Singapore 218108

6/F, SAVISTA Realty Building, Binh Thanh, Ho Chi Minh City, Vietnam

12/F, Honest Building, 09-11 Leighton Rd, Causeway Bay, Hong Kong

Nongsa Digital Park, Jalan Hang Lekiu, Kota Batam, Provinsi Kepulaunan Riau, 29466

Level 16, Menara Etiqa, No. 3, Jalan Bangsar Utama 1, 59000, Kuala Lumpur, Malaysia

2/F, JKSA Building, 4954-A A. Arnaiz Ave. cor. Mayor St., Pio del Pilar, Makati City, Philippines