The Stable Interface
A function signature is a promise.
You agree: give me these inputs, and I will give you this output. That promise lets everyone downstream build something real. They can write tests against it. They can integrate it into their own systems. They can go to sleep trusting it will still be there in the morning.
The moment you break that promise — silently, for good reasons, with the best intentions — you’ve done something that propagates. Every caller now has a latent bug. Every integration has a hidden assumption that is no longer true. The ripple is invisible until it isn’t.
The Cost of Surprise
Stability is underrated because it’s invisible when it’s working. Nobody celebrates the API that didn’t change. Nobody writes a postmortem about the migration that didn’t need to happen.
But remove stability from a codebase and you feel it immediately. Every change becomes an archaeology expedition. You’re not just writing new code — you’re auditing everything that touches what you changed. You’re reading test output with suspicion. You’re checking commit history before trusting any assumption.
The opposite of a stable interface isn’t a flexible one. It’s a suspicious one.
What Stability Actually Requires
Stable interfaces don’t require rigid thinking. They require discipline at the boundary.
Inside a module, you can refactor constantly. Rename variables, reorganize logic, swap out data structures. The interior of an implementation is private territory — you can redecorate as often as you like. What you must not do is move the front door.
The habit to build is: treat every public function signature, every exported type, every documented behavior as load-bearing until proven otherwise. The burden of proof sits with the change, not the interface.
Versioning as Honesty
When a break is unavoidable — and sometimes it is — the right response is to name it. Increment a version. Write a migration guide. Give callers time.
Versioning isn’t bureaucracy. It’s honesty in a format that machines can check. It says: something changed, and I’m telling you about it, and I’m giving you a way to adapt. That’s exactly the behavior you want from a collaborator.
The Invisible Contract
Most of the interfaces we work with daily are undocumented. The function that returns a list has never promised what order the list is in. The config file that takes a path hasn’t said whether it expands tildes. The error message has never guaranteed it won’t change.
These implicit contracts accumulate. Code learns to depend on behavior that was never stated. And then the day comes when someone changes the thing that was never promised, and something breaks, and nobody can explain why.
The discipline is to make the implicit explicit — at least for the things that matter. Write down what you’re promising. And then keep that promise.
A function signature is a promise. Keep the ones you make.