Skip to content

Why DDD with Ironflow

Ironflow’s core primitives — entity streams, projections, sagas, and event-driven functions — map directly to the tactical patterns of Domain-Driven Design. If you already practice DDD, this section shows you exactly how Ironflow implements each pattern. If you’re new to DDD, you’ll find collapsible concept definitions alongside every mapping.

Ironflow PrimitiveDDD PatternPage
Entity StreamsAggregate RootsAggregates & Entity Streams
appendToStream() eventsDomain Events (persisted)Commands, Events & Reactions
ProjectionsRead Models (CQRS)CQRS with Projections
SagasDistributed SagasSagas & Process Managers
emit() / event triggersCommands & Domain EventsCommands, Events & Reactions
publish() / subscriptionsIntegration EventsCommands, Events & Reactions

While Ironflow’s strongest alignment is with tactical DDD patterns, its architecture naturally supports strategic concepts too.

A bounded context defines a boundary within which a particular domain model applies. In Ironflow, bounded contexts emerge naturally from:

  • Function scoping — each function subscribes to specific event types, creating natural context boundaries. An order-processing function only reacts to order.* events.
  • Entity stream namespacing — entity types like order, customer, and inventory each define their own event vocabulary and consistency boundary.
  • Environments — Ironflow’s multi-environment support can model separate deployment contexts (e.g., payments-service vs shipping-service).

DDD emphasizes using consistent domain terminology across code and conversation. Ironflow’s event-driven model reinforces this:

  • Name events in past tense using domain language: order.placed, payment.captured, shipment.dispatched — not order_table_insert or handle_order_v2.
  • Name entity streams after domain concepts: order-123, customer-456 — not row_42 or entity_abc.
  • Name functions after business processes: process-order, fulfill-shipment — not handler-1 or background-job.

Bounded contexts need to communicate. Ironflow provides two integration mechanisms:

  • emit() — publishes events that trigger workflows within a context. These are domain events: internal, rich, and tightly coupled to the context’s model.
  • publish() — publishes events to topics for cross-context communication. These are integration events: leaner, designed for external consumers, and decoupled from internal models.

This distinction maps directly to the DDD concept of domain events vs integration events. Keep domain events rich and context-specific; keep integration events slim and stable.

When integrating with external systems or bounded contexts that have different models, use an Anti-Corruption Layer to translate between schemas. In Ironflow, this is a function that:

  1. Subscribes to integration events from the external context
  2. Transforms the event schema to your domain model
  3. Emits domain events in your context
// ACL: Translate legacy "OrderCreated" to our domain's "order.placed"
export const legacyOrderACL = ironflow.createFunction(
{
id: "legacy-order-acl",
triggers: [{ event: "legacy.orders" }], // External system events
},
async ({ event, step }) => {
// Transform legacy schema → domain schema
await step.run("translate-and-emit", async () => {
await ironflow.emit("order.placed", {
orderId: event.data.order_id, // snake_case → camelCase
customerId: event.data.customer_ref,
items: event.data.line_items.map((li: any) => ({
sku: li.product_code,
qty: li.quantity,
price: li.unit_price,
})),
total: event.data.order_total,
});
});
},
);

The ACL protects your domain model from external schema changes. When the legacy system changes, you update the ACL — not your core domain logic.

For integration events shared across contexts, define a Published Language — a stable, versioned schema contract. In Ironflow:

  • Use topics with explicit versioning: notifications.order.v1, analytics.revenue.v2
  • Document the schema in a shared location (e.g., a schema registry or API spec)
  • Version integration events independently from domain events
  • Use upcasters for backward compatibility when evolving schemas

New to DDD? Read these pages in order — each builds on the previous:

  1. Aggregates & Entity Streams
  2. Commands, Events & Reactions
  3. CQRS with Projections
  4. Sagas & Process Managers
  5. Putting It All Together

Experienced with DDD? Jump directly to the pattern you need from the mapping table above.