Skip to content

Adaptor

An adaptor's purpose is to adapt one Context to another Context. In Domain-Driven Design, this concept is known as an anti-corruption layer that keeps the ubiquitous language of one context from "corrupting" the language of another context. The authors of RIDDL didn't like that term for a variety of reasons so we have renamed the concept as adaptor in RIDDL. Same idea, different name.

Message Translation

Adaptors do their work at the level of messages sent between Contexts. This is done using one or more Handlers. Each handler specifies how messages are translated into other messages and forwarded to the target context.

Target Context

Adaptors are only definable within a containing Context which provides one participant of the translation. The other Context, known as the target context, is specified within the definition of the adaptor.

Adaptation Directionality

Adaptors only translate in one direction, between the containing context and the target context. However, multiple Adaptors can be defined to achieve bidirectional adaptation between Contexts. The directionality of an Adaptor is specified in the definition of the adaptor. This leads to two kinds of adaptors: inbound and outbound.

Inbound Adaptors

Inbound adaptors provide an adaptation that occurs from the Context referenced in the adaptor to the Context containing the adaptor.

Outbound Adaptors

Outbound adaptors provide an adaptation that occurs from the Context containing the adaptor to the Context referenced in the adaptor.

Syntax

context Orders is {
  adaptor PaymentAdapter from context Payments is {
    handler InboundPayments is {
      on paid: event Payments.PaymentCompleted {
        tell command MarkAsPaid(paid.orderId) to entity Order
      }
      on event Payments.PaymentFailed {
        tell command HandlePaymentFailure to entity Order
      }
      on other {
        error "Unrecognized message from the Payments context"
      }
    }
  } with {
    briefly as "Translates payment messages between Orders and Payments"
  }

  adaptor InventoryAdapter to context Inventory is {
    handler OutboundInventory is {
      on command ReserveItems {
        tell command Inventory.ReserveStock to context Inventory
      }
      on other {
        error "Unrecognized outbound message"
      }
    }
  } with {
    briefly as "Translates inventory requests from Orders to Inventory"
  }
}

Note the operand order: tell <message> to <processor>, not the reverse.

The Isolation Seam

An adaptor bridges exactly two contexts: the context that contains it, and the referent context named in its declaration. It is the only sanctioned crossing point between contexts, so it must not traffic in a third context's messages.

Validation

Errors:

  • A message whose owning context is neither the parent nor the referent. This applies both to the message an on clause consumes and to every send/tell target it emits, including those nested inside when, match and foreach bodies.
  • A handler with no on other clause. An adaptor must say explicitly what it does with messages it does not recognize, rather than discarding them silently.

Types defined at domain or root level are shared vocabulary common to both sides and are never flagged.

Options

circuit-breaker (0–2 arguments) is valid on an adaptor, tripping the adaptation when the far side is failing.

When to Use Adaptors

Use an adaptor when:

  • Contexts have different vocabularies: The same concept has different names or structures in each context
  • You need to protect domain integrity: Prevent external concepts from leaking into your bounded context
  • Contexts evolve independently: Changes in one context shouldn't force changes in another
  • Integration with external systems: Translate between your domain model and external APIs

Example scenario: Your Orders context tracks "line items" while the Inventory context uses "stock reservations". An adaptor translates between these models so neither context needs to know about the other's terminology.

Adaptor vs. Direct References

Approach When to Use
Adaptor Contexts have different models, need translation
Direct reference Contexts share the same model, tightly coupled by design

Occurs In

Contains