Designing Domain-Driven Design Architecture

1. Understanding Strategic Domain-Driven Design

ConceptPurpose
SubdomainSlice of business problem (Core/Supporting/Generic)
Core domainCompetitive differentiator; invest most effort
SupportingCustom but non-differentiating
GenericBuy or use OSS (auth, billing)
Bounded contextCode boundary for one model
Ubiquitous languageShared terms in each context

2. Designing Bounded Contexts

HeuristicApply When
Same term, different meaning"Order" in Sales vs Fulfillment → 2 contexts
Different teamsConway's law alignment
Different lifecycleDifferent deploy cadence
Different storageOLTP vs analytics

3. Designing Context Mapping

PatternRelationship
PartnershipTwo teams succeed/fail together
Shared KernelSmall shared model; high coordination
Customer-SupplierUpstream serves downstream needs
ConformistDownstream conforms with no influence
Anti-Corruption LayerTranslation layer to protect model
Open Host ServicePublic protocol for many consumers
Published LanguageShared schema (Avro, OpenAPI)
Separate WaysNo integration; duplicate as needed

4. Designing Ubiquitous Language

ElementPractice
SourceDomain experts; not engineers alone
GlossaryMaintain per bounded context
Code mirrors languageClass/method names match domain terms
Refactor on renameUpdate code when language evolves

5. Designing Aggregates and Aggregate Roots

RuleDescription
Single rootOne entity is the root; access only via root
Transactional boundaryOne aggregate per transaction
Reference by IDOther aggregates referenced by ID, not object
Small aggregatesReduces contention, lock scope
InvariantsEnforced inside aggregate boundary

Example: Aggregate root (Java)

public class Order { // root
    private final OrderId id;
    private final List<OrderLine> lines = new ArrayList<>();
    private OrderStatus status;

    public void addLine(ProductId pid, int qty, Money price) {
        if (status != OrderStatus.DRAFT) throw new IllegalStateException();
        lines.add(new OrderLine(pid, qty, price)); // invariant managed via root
    }
    public Money total() { return lines.stream().map(OrderLine::subtotal).reduce(Money.ZERO, Money::add); }
}

6. Designing Domain Events

PropertyDescription
Past tense nameOrderPlaced, PaymentCaptured
ImmutableFacts about what happened
Carries dataSelf-contained payload + metadata
VersionedSchema evolution required
Outbox patternPersist event in same DB txn as state

7. Designing Anti-Corruption Layer

ComponentRole
TranslatorMaps external model → domain model
AdapterTalks to external API/legacy
FacadeSimplified domain-friendly interface
Note: Use ACL when integrating with legacy/3rd-party systems whose model would pollute yours. Adds latency and code; worth it for protection.

8. Designing Shared Kernel Pattern

AspectGuideline
ScopeMinimal shared code (value objects, IDs)
OwnershipJoint ownership; changes need consensus
VersioningSemVer; coordinated upgrades
RiskCoupling; prefer Published Language when possible

9. Designing Customer-Supplier Relationships

ElementDetail
Backlog priorityCustomer team gets items in supplier backlog
ContractsAPI contracts agreed upfront
TestsConsumer-driven contract tests (Pact)
DeprecationNotice period + migration support

10. Designing Open Host Service Pattern

ElementDescription
Stable protocolVersioned REST/gRPC/event schema
Self-service docsOpenAPI, AsyncAPI, portal
Backwards compatAdditive changes, deprecation policy
SLA publishedLatency / availability commitments