Alpha Version: You are viewing the ALPHA documentation. This is an experimental version and may contain breaking changes.
Skip to main content

Choosing an approach: Aggregate, DCB, or Hybrid

The online shop is implemented three times — once with each plugin style. Before following the walkthrough, it helps to know which style you would reach for, and why this tutorial uses the Hybrid one.

The three styles in one table

Aggregate-basedDCB-basedHybrid
Event storageOne event log per aggregate instanceOne shared, tag-filtered log per pluginBoth — per-aggregate logs and a shared DCB log
Consistency boundaryPer aggregate instancePer command (optimistic)Per entity type
Cross-entity decisionsNot directly supportedSupported (slices read across entities)Supported for the DCB entities
Best whenEntity lifecycles are independentYou need consistency across entities in one commandSome entities are independent, others are interdependent

How to decide, per entity

For each entity in your plugin, ask:

  1. Does its decision need to see other entities' events? → DCB.
  2. Does a read model need to combine its events with another entity's events? → both entities should share a DCB log.
  3. Is its lifecycle fully independent? → Aggregate.

If every entity points the same way, use that pure style. If the answers are mixed — which is common — use Hybrid, modelling each entity with the approach that fits it.

Two App Guide pages go deeper: What is a DCB? defines the vocabulary (tag, partition, fence, decision model) and the decision guide works the same question with the trade-offs written out, for when you are choosing for your own domain rather than reading about this one.

Why this tutorial uses Hybrid

The shop has both kinds of entity:

  • IndependentCustomer is a self-contained lifecycle: registering, updating contact details, deactivating and reactivating. No other entity's events take part in those decisions → aggregate.
  • InterdependentCategory, Product, ProductDemand, Order, and CatalogProduct all decide on events other entities produced. AddProduct reads CategoryAdded / CategoryArchived to reject a product in a category that does not exist or has been withdrawn; PlaceOrder reads CatalogProductSynced to reject an order for a product Ordering has never heard of. Those reads only work if the entities share a tag-filtered log → DCB.

Note how the rule plays out for Category: on its own it is a plain Add/Rename/Archive lifecycle and would make a perfectly good aggregate. It is DCB here because another entity's decision has to read its events — the question is never "is this entity simple?" but "does any decision need to see it alongside something else?".

Hybrid is the most representative of a real application, so it is the spine of this tutorial. The two pure styles are kept as alternates for comparison.

Alternate implementations


Next: walk through the recommended implementation in the Hybrid walkthrough →