LearnThatStack Ace your next interview

Domain-Driven Design (DDD).
Interview cheat sheet.

Quick reference for Domain-Driven Design (DDD) - sectioned for fast scanning. Skim the part you're shaky on, walk in confident.

System Design Concepts 10-section reference ~6 min read

Summary

Master Domain-Driven Design for technical interviews. Covers bounded contexts, aggregates, entities, value objects, and ubiquitous language. Essential for designing complex business applications with clear domain models and maintainable architecture.

Core Concepts

What is DDD?

  • Definition: An approach to software development that focuses on the core domain and domain logic
  • Goal: Create software that reflects complex business domains through collaboration between technical and domain experts
  • Key Principle: The structure and language of software code should match the business domain

Ubiquitous Language

  • Definition: A common language shared by developers and domain experts
  • Purpose: Eliminate translation between business and technical terms
  • Example: Use "Customer" not "User", "Order" not "Transaction" if that's what the business calls them

Bounded Context

  • Definition: A logical boundary within which a domain model is defined and applicable
  • Purpose: Isolate models to avoid conflicts and maintain clarity
  • Example: "Customer" in Sales context vs "Customer" in Support context may have different attributes
// Sales Context
class Customer {
    private CustomerId id;
    private CreditLimit creditLimit;
    private List<Order> orderHistory;
}

// Support Context  
class Customer {
    private CustomerId id;
    private SupportTier tier;
    private List<Ticket> tickets;
}

Building Blocks (Tactical Patterns)

1. Entity

  • Definition: Object with unique identity that persists over time
  • Key: Identity matters more than attributes
  • Example: User, Order, Product
public class Order {
    private final OrderId id; // Identity
    private OrderStatus status;
    private List<OrderItem> items;
    
    @Override
    public boolean equals(Object o) {
        // Equality based on ID only
        return id.equals(((Order) o).id);
    }
}

2. Value Object

  • Definition: Object without identity, defined by its attributes
  • Key: Immutable, replaceable
  • Example: Money, Address, Email
public final class Money {
    private final BigDecimal amount;
    private final Currency currency;
    
    public Money(BigDecimal amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }
    
    // No setters - immutable
    public Money add(Money other) {
        return new Money(
            amount.add(other.amount), 
            currency
        );
    }
}

3. Aggregate

  • Definition: Cluster of entities and value objects with defined boundaries
  • Key: Consistency boundary, accessed through Aggregate Root
  • Example: Order (root) with OrderItems
public class Order { // Aggregate Root
    private OrderId id;
    private List<OrderItem> items;
    
    public void addItem(Product product, int quantity) {
        // Business logic enforced at aggregate level
        if (items.size() >= 10) {
            throw new OrderLimitExceededException();
        }
        items.add(new OrderItem(product, quantity));
    }
}

4. Repository

  • Definition: Interface for accessing aggregates
  • Key: Abstracts data persistence
  • Example: OrderRepository
public interface OrderRepository {
    Order findById(OrderId id);
    void save(Order order);
    List<Order> findByCustomer(CustomerId customerId);
}

5. Domain Service

  • Definition: Business logic that doesn't belong to any entity
  • Key: Stateless operations
  • Example: PricingService, PaymentService
public class PricingService {
    public Money calculateDiscount(
        Customer customer, 
        Order order
    ) {
        // Complex logic involving multiple aggregates
        if (customer.isVip() && order.getTotal() > 1000) {
            return order.getTotal().multiply(0.2);
        }
        return Money.ZERO;
    }
}

6. Domain Event

  • Definition: Something important that happened in the domain
  • Key: Immutable, past tense
  • Example: OrderPlaced, PaymentProcessed
public class OrderPlacedEvent {
    private final OrderId orderId;
    private final CustomerId customerId;
    private final Instant occurredAt;
    
    // Constructor and getters...
}

7. Factory

  • Definition: Encapsulates complex object creation
  • Key: Ensures valid object creation
  • Example: OrderFactory
public class OrderFactory {
    public Order createOrder(
        CustomerId customerId, 
        List<OrderItemData> items
    ) {
        // Complex creation logic
        validateCustomer(customerId);
        Order order = new Order(generateId(), customerId);
        items.forEach(item -> 
            order.addItem(item.product, item.quantity)
        );
        return order;
    }
}

🗺️ Strategic Patterns

Context Mapping Patterns

  1. Shared Kernel: Shared subset of domain model between contexts
  2. Customer-Supplier: Upstream team provides for downstream needs
  3. Conformist: Downstream conforms to upstream model
  4. Anti-Corruption Layer (ACL): Translation layer between contexts
  5. Open Host Service: Well-documented service protocol
  6. Published Language: Well-documented exchange language

Anti-Corruption Layer Example

// External system model
class ExternalCustomer {
    String custId;
    String fullName;
}

// ACL Translator
class CustomerTranslator {
    Customer translate(ExternalCustomer ext) {
        String[] names = ext.fullName.split(" ");
        return new Customer(
            new CustomerId(ext.custId),
            new Name(names[0], names[1])
        );
    }
}

📋 Implementation Patterns

Layered Architecture with DDD

┌─────────────────────────┐
│   Presentation Layer    │ (Controllers, Views)
├─────────────────────────┤
│   Application Layer     │ (Use Cases, DTOs)
├─────────────────────────┤
│     Domain Layer        │ (Entities, VOs, Services)
├─────────────────────────┤
│  Infrastructure Layer   │ (Repositories, External Services)
└─────────────────────────┘

Application Service Example

@Service
public class OrderApplicationService {
    private OrderRepository orderRepo;
    private CustomerRepository customerRepo;
    private EventPublisher eventPublisher;
    
    @Transactional
    public OrderId placeOrder(PlaceOrderCommand cmd) {
        Customer customer = customerRepo.findById(cmd.customerId);
        Order order = new Order(customer.getId());
        
        cmd.items.forEach(item -> 
            order.addItem(item.productId, item.quantity)
        );
        
        orderRepo.save(order);
        eventPublisher.publish(
            new OrderPlacedEvent(order.getId())
        );
        
        return order.getId();
    }
}

🎪 Common Patterns & Best Practices

1. Specification Pattern

public interface Specification<T> {
    boolean isSatisfiedBy(T t);
    
    default Specification<T> and(Specification<T> other) {
        return t -> isSatisfiedBy(t) && other.isSatisfiedBy(t);
    }
}

// Usage
Specification<Order> highValue = 
    order -> order.getTotal().isGreaterThan(1000);
Specification<Order> rush = 
    order -> order.isRush();

var complexSpec = highValue.and(rush);

2. Domain Validation

public class Email {
    private final String value;
    
    public Email(String value) {
        if (!isValid(value)) {
            throw new InvalidEmailException(value);
        }
        this.value = value;
    }
    
    private boolean isValid(String email) {
        return email.matches("^[^@]+@[^@]+\\.[^@]+$");
    }
}

3. Aggregate Design Rules

  • Keep aggregates small
  • Reference other aggregates by ID only
  • Update one aggregate per transaction
  • Use eventual consistency between aggregates

Interview Tips & Common Questions

Key Questions to Prepare

  1. "What is DDD and when should you use it?"

    • Use for complex domains with significant business logic
    • Not for CRUD applications
    • When domain experts are available
  2. "Entity vs Value Object?"

    • Entity: Has identity, mutable
    • Value Object: No identity, immutable
  3. "How do you handle transactions across aggregates?"

    • Domain Events + Eventual Consistency
    • Saga/Process Manager pattern
    • Two-phase commit (avoid if possible)
  4. "What makes a good aggregate?"

    • Small and focused
    • Consistency boundary
    • Low coupling with other aggregates

Red Flags to Avoid

  • ❌ Anemic Domain Model (logic in services, not entities)
  • ❌ Large aggregates loading too much data
  • ❌ Direct references between aggregates
  • ❌ Domain logic leaking to other layers

Design Smells

  • Bidirectional relationships between aggregates
  • Services with too many dependencies
  • Entities without behavior
  • Value objects with identity

🔧 Practical Examples

E-commerce Domain Model

// Aggregate Root
public class ShoppingCart {
    private CartId id;
    private CustomerId customerId;
    private List<CartItem> items;
    private Money totalAmount;
    
    public void addProduct(ProductId productId, int quantity) {
        // Invariant: Max 50 items
        if (items.size() + quantity > 50) {
            throw new CartLimitExceededException();
        }
        
        items.add(new CartItem(productId, quantity));
        recalculateTotal();
    }
    
    public Order checkout() {
        if (items.isEmpty()) {
            throw new EmptyCartException();
        }
        return new Order(customerId, items);
    }
}

// Value Object
public class CartItem {
    private final ProductId productId;
    private final int quantity;
    private final Money unitPrice;
    
    // Constructor, getters, equals/hashCode
}

Event Sourcing with DDD

public abstract class AggregateRoot {
    private List<DomainEvent> changes = new ArrayList<>();
    
    protected void raiseEvent(DomainEvent event) {
        changes.add(event);
        apply(event);
    }
    
    public List<DomainEvent> getUncommittedChanges() {
        return new ArrayList<>(changes);
    }
    
    public void markChangesAsCommitted() {
        changes.clear();
    }
    
    protected abstract void apply(DomainEvent event);
}

📚 Quick Reference

DDD Building Blocks Comparison

Pattern Identity Mutable Example
Entity Yes Yes User, Order
Value Object No No Money, Address
Aggregate Yes (via root) Yes Order + Items
Domain Event No No OrderPlaced

When to Use What

  • Entity: When identity matters across time
  • Value Object: When only attributes matter
  • Domain Service: When logic doesn't fit in entities
  • Repository: To abstract persistence
  • Factory: For complex object creation
  • Domain Event: To communicate between aggregates

Architecture Checklist

  • Domain layer has no dependencies
  • Repositories return domain objects, not DTOs
  • Application services orchestrate, don't contain business logic
  • Each bounded context has its own model
  • Aggregates enforce invariants
  • Value objects are immutable
  • Domain events are past tense

Interview Scenario Solutions

Scenario: Design a Banking System

// Bounded Contexts: Account Management, Transactions, Fraud Detection

// Account Aggregate
public class Account {
    private AccountId id;
    private CustomerId owner;
    private Money balance;
    private AccountStatus status;
    
    public void withdraw(Money amount) {
        if (!status.isActive()) {
            throw new InactiveAccountException();
        }
        if (balance.isLessThan(amount)) {
            throw new InsufficientFundsException();
        }
        balance = balance.subtract(amount);
        raiseEvent(new MoneyWithdrawnEvent(id, amount));
    }
}

// Transaction Context
public class TransferService {
    @Transactional
    public void transfer(
        AccountId from, 
        AccountId to, 
        Money amount
    ) {
        // Orchestrate between aggregates
        Account fromAccount = accountRepo.find(from);
        Account toAccount = accountRepo.find(to);
        
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        
        accountRepo.save(fromAccount);
        accountRepo.save(toAccount);
        
        eventBus.publish(new TransferCompletedEvent(
            from, to, amount
        ));
    }
}

Remember: DDD is about modeling the business domain accurately, not just using patterns!

Found this useful? Pass it on.
Pro · $10/mo

The sheet is free. Pro goes deeper.

Pro opens the full question library behind every sheet, every refresher and a monthly AI allowance. One subscription, all formats.

Full question library All refreshers Cancel anytime