Platform Engineering: Local First

中文翻译即将推出

Background

The main loop for a developer is to make a change and find out quickly whether it works. In this post I’ll discuss why developers should be able to run the entire service in isolation on their own machine, in a dedicated local mode, with minimal discrepancies between local and the shared environments, and what to do about the dependencies that make this hard.

The benefit is confidence. When a developer can exercise a change locally, they validate it before it ever touches shared infrastructure, and they do not need to reason about whose other work they might break to do so.

Scope

This should hold across every stage of the platform CLI lifecycle: compile, build, test, package, deploy. Each stage should behave the same locally as it does in the pipeline. If build and deploy work one way on a laptop and a different way on a CI agent, you have reintroduced the “works on my machine” gap that the local mode was supposed to close; this is the same unified interface argument I have made before, applied to the developer’s own machine.

The exception: external dependencies

Some dependencies cannot reasonably run locally: third-party APIs, managed databases, other services holding external state. For these, provide mocks or stubs that a developer can configure easily, including the ability to set up different scenarios and routes so they can reproduce the case they care about.

The service exposes a local mode flag. When it is set, the service detects that it is running locally and routes to the mocked externals; in the shared environments it routes to the real ones.

service --local-mode   # routes externals to mocks/stubs
service                 # routes externals to the real dependencies

The important part is that the developer does not swap configuration by hand. The service behaves correctly based on where it is running, because manual configuration swapping is the step everyone eventually forgets, and a forgotten swap is a bug that only shows up somewhere expensive.

It is not just for humans anymore

There is a second beneficiary now, and it changes how much this is worth. A coding agent has the same need as a developer: make a change, then validate it before it goes anywhere shared. A local mode gives the agent a place to do that on its own. It can run build, test and deploy against the mocked externals, read the result, and decide whether the change is good, all without a human shepherding it through a shared environment and without the risk to shared infrastructure that a deploy carries.

This raises the return on the local mode considerably. The mocks and the local mode flag were already worth building for the developer inner loop; once an agent can drive that same loop unattended, the same investment now buys you a validation loop that runs without a person in it. An agent that can only validate by deploying to a shared environment is slow, disruptive and risky for exactly the reasons a developer in that position is, except it will do it far more often. Local first is what makes an agent safe to let iterate.

The anti-pattern

The failure I want to name is the shared environment as the only test ground. If there are no local mocks or test doubles, a developer can only validate a change by deploying it to a shared environment. This breaks local first in three ways: it slows iteration, because every change now waits on a deploy; it risks destabilising shared infrastructure and disrupting other developers’ work; and it removes the possibility of confident, isolated local testing entirely. The mocks are not a nicety on top of the platform; they are what makes the local loop exist at all.

Share this post: 分享这篇文章:

Comments 评论