What Change-as-Code is

Change-as-Code means treating the evolution of systems and external dependencies as something explicit, versioned, executable, and verifiable — in the same way we treat application code.

Not as documentation. Not as tribal knowledge. Not as a checklist in a runbook.

As concrete change artifacts that can be reviewed, applied, verified, and reasoned about.

Without this discipline, drift is inevitable. With it, system evolution becomes manageable instead of surprising.

what-is-cac


A concrete example

A payments team ships a schema update to record which payment gateway processed each transaction. Operationally, this matters: different gateways have different settlement timing, fees, and reconciliation logic.

On paper, the change is backward-compatible.

In reality, it must propagate across environments, consumer services, and a reconciliation job that replays historical events.

In staging, everything works.

In production, the reconciliation service hasn’t been updated. It silently ignores the new field — not just for new events, but for every message it replays.

Nothing crashes. Nothing alerts.

Days later, finance notices missing transactions in settlement reports. Revenue recognition is off. Month-end close is delayed.

The data was there. The system just couldn’t see it.

The change worked. The evolution did not.

example-flow

Change-as-Code doesn’t remove complexity. It makes this coordination explicit and reviewable, instead of implicit and fragile.


We solved deployment. We didn’t solve change.

CI/CD taught us that changes should be explicit, versioned, reviewed, and repeatable.

But once application code is deployed, we stop applying those lessons.

Meanwhile, the riskiest changes in modern systems happen elsewhere:

  • database schemas evolve
  • message contracts drift
  • storage layouts change
  • retention rules are tweaked
  • permissions mutate
  • external systems upgrade on timelines we don’t control

All of this still happens. It’s just unmanaged. managed-vs-unmanaged


What Change-as-Code actually requires

Change-as-Code isn’t a tool. It’s a discipline — and it has concrete properties.

A change should be explicit. No hidden mutations or manual clicks. The change exists as an artifact you can point to.

It should be versioned. You know what came before and what comes after.

It should be deterministic in practice. Idempotent and verifiable — you can run it again and confirm the intended state was reached.

It should be replayable. You can reconstruct how the system evolved and verify where it ended up.

And it should be auditable. Months later, you can answer what changed, when, and why.

If evolution doesn’t meet these criteria, you don’t really have Change-as-Code. You have confidence — until you don’t.

five-properties


Why this discipline was missing

In monolithic systems, a change affected one application, one team, one deployment. Coordination was implicit, and it mostly worked.

In distributed systems, the same change ripples across services, teams, and timelines. Coordination must be explicit.

But our tools didn’t evolve with our architectures. We moved to distributed data, asynchronous messaging, and external dependencies — while still managing evolution as if change were rare. monolith-to-distributed

Without a name for the discipline, teams built fragments instead: migration tools, schema validators, scripts, manual SaaS configuration. Each solves a local problem. None govern system evolution as a whole.


Where you can start

You don’t need to fix everything at once.

Look at your last few production incidents that weren’t caused by bad code. A schema shift. A permission change. A contract upgrade. An external dependency behaving differently.

How many of those changes were visible in version control? How many had a clear before-and-after? How many could you have verified before production?

Pick one painful dependency and make its evolution explicit.

That’s not the whole discipline — but it’s how it starts. where-to-start


What comes next

Now that the discipline has a name, the harder question is how to reason about it.

How does system evolution actually behave over time? Why does drift accumulate even when “state looks correct”?

To answer that, we need a mental model.

Next post: The Mental Model of System Evolution