the ratchet
I have a theory about why software projects slow down and eventually stop: they forget to set the ratchet. Here's what that means, and how to install one.
what a ratchet does
A ratchet only turns one way. The teeth catch. If you slip, if you get tired, if something goes wrong — you don't fall back to zero. You hold where you are.
In mechanical systems this is obvious. In software it requires deliberate installation.
The most common form: a test. Every test you add to a suite is a ratchet tooth. The functionality it describes is now locked in. You can change the implementation freely, but you can't accidentally delete the behavior and ship. The CI run catches it. The tooth holds.
A second form: linting. Once you've turned on the rule that forbids 400-line functions, it holds. The next 400-line function that tries to merge hits a wall. The ratchet holds.
A third form people underestimate: the commit message. Once you've described why a change was made, that context exists permanently. Future maintainers — including you, six months from now — can look back and read it. The knowledge doesn't slip.
ratchets don't accumulate by accident
Here's the failure mode: you build the feature, it works, you're satisfied, you ship it. No test. No lint rule. No note about why the edge case is handled that specific way.
The ratchet isn't set. The next person (or you, three weeks later) comes in without knowing this code is load-bearing. They change something. The feature regresses. The tooth wasn't there to catch it.
What should have happened: ship the feature, immediately write the test that would have caught the regression you just noticed while testing it manually. Set the tooth. Now the next change will catch against it.
This sounds obvious. It is. People still don't do it, for a predictable reason: setting the ratchet adds friction to the commit, and the commit already works, so why add friction?
Because friction is the point. A ratchet without friction isn't a ratchet. It's a wheel.
the scope of one tooth
The failure mode in the other direction: trying to set every tooth at once. The giant refactor that "adds tests for everything." The lint migration that touches 2,000 files. The architectural overhaul that requires the whole team to stop shipping for a sprint.
These usually fail, or cost more than expected, or — worst case — succeed in a way that actually loosens the ratchet. You end up with tests so entangled with the implementation that they don't catch regressions; they just slow refactors. The teeth are set to the wrong thing.
One tooth. Set it. Let it hold. Move on.
The compound interest argument applies: if you add one ratchet tooth per PR, and you ship ten PRs a week, you have fifty teeth a month from now. The project is significantly harder to regress in ways you've already experienced. That's real. It compounds.
If instead you add zero teeth per PR because you're waiting for "the right time to write tests," you have zero teeth indefinitely, and eventually someone removes the feature because they thought it was dead code.
the wrong kind of ratchet
A ratchet that won't let you turn at all is a lock, not a ratchet.
I've seen this with test suites so rigid that every feature change required rewriting fifty tests. The teeth were set too fine. Coupling between tests and implementation was too tight. What was supposed to catch regressions was catching change instead — which is different.
Teeth should hold behavior, not implementation. The test should say "given this input, this output comes out." Not "given this input, this exact function is called with these exact parameters in this exact order." The latter breaks when you refactor. The former survives it.
Design the ratchet around what you don't want to slip. Not everything. Not the details. The behavior you promised.
set it now
If you shipped something last week that doesn't have a test, the ratchet isn't set. Go set it.
Not the full test suite. One test. The one that would catch the bug that will eventually show up. Ten minutes. Commit it separately, with a message that says what it's protecting.
The tooth is set. The next person comes through, they change something, the test catches it, they go "oh, someone already thought about this." That's the ratchet working.
That's the job.