Anti-corruption layer
Eric Evans, Domain-Driven Design
Translate vendor-specific data models at the integration boundary.
MUSES integrates five external SaaS products behind a single REST API with a shared vocabulary. In Reynt, payment adapters perform the same translation for providers. This allowed two providers to be removed without changing the payment domain.
In other stacksThe layer looks the same in every language: one module per vendor that owns its data types and returns domain types. Generated clients (OpenAPI, gRPC) keep the vendor side cheap to update.
What it costsEvery vendor field the domain needs is mapped by hand, and a vendor change means touching its adapter even when the domain stays the same.
Store-and-forward, backoff with jitter
the transactional outbox pattern
Persist requests before calling an external service so they can be retried after an outage.
In MUSES, the ticket service stores incoming requests before calling the external ticket system, then retries failed calls with backoff. The certificate solver also uses timeouts and retries with jitter, and serialises concurrent challenges.
In other stacksThe outbox comes as a library in most stacks — MassTransit or NServiceBus in .NET, Spring Modulith on the JVM — or as a table and a worker anywhere.
What it costsThe caller gets an acknowledgement instead of an answer, and a retried request can arrive twice, so the receiving side has to be idempotent.
Boring infrastructure
choose boring technology, after Dan McKinley
Keep infrastructure dependencies to what the system needs.
Our workflow engine uses Postgres for queues and timers. Elsewhere we use a single database engine, cron for jobs that tolerate a minute of latency, and containers deployed from manifests. This site is static, with one script for cookieless analytics.
In other stacksPostgres-backed queues exist across stacks: pg-boss and graphile-worker in Node, River in Go, Oban in Elixir, Hangfire with a Postgres store in .NET.
What it costsSimple infrastructure still has limits. A Postgres queue that works at thousands of jobs a minute may need replacing at millions. We monitor those limits as usage grows.
Programs as values
declarative over imperative
Represent workflows as data so they can be inspected before execution.
octaflow represents a workflow as a DAG that can be inspected, tested and displayed before execution. The graph declares idempotency keys, deadlines, retries and compensating steps.
In other stacksThe same split runs through the field: code-first engines such as Temporal on one side, declared graphs such as AWS Step Functions or Argo Workflows on the other.
What it costsA declared graph cannot express arbitrary control flow. An imperative engine may be a better fit when the workflow’s structure cannot be known in advance.
GitOps and a signed supply chain
Define infrastructure in version control and sign released container images.
We use Flux and Terraform for declarative infrastructure, with encrypted secrets in Git. Deployments select container image tags produced by CI. Published containers run as non-root on distroless images with read-only filesystems. Images are signed, include SBOM and provenance attestations, and are scanned weekly for vulnerabilities.
In other stacksArgo CD does what Flux does. Sigstore’s cosign, Syft and Trivy sign, inventory and scan images whatever language built them.
What it costsEven a one-line configuration fix goes through a commit and a reconcile loop, and secrets need their own encryption set up before they can live in Git.