“We’ll add tests later” is one of the most reliable predictors of trouble in a software project, and one of the most reasonable-sounding. Skipping tests really is faster in the short term. The feature ships sooner, the deadline is met, and nothing visibly bad happens. The cost is not avoided, though. It is deferred, and it compounds.
The mistake is treating tests as a tax on shipping. For the parts of a system that matter, they are closer to the thing that makes fast shipping possible at all later on.
What the deferred cost actually is
The bill for skipped tests does not arrive as a single event. It accumulates as a set of slow taxes on everything the team does afterwards.
- Manual re-checking. Without automated tests, the only way to know a change broke nothing is to check by hand. That cost is paid on every release, forever, and it grows with the system.
- Fear of changing code. When no safety net exists, every change is a gamble. Teams respond by changing less, and more cautiously, which is exactly the behaviour that lets a codebase calcify.
- Bugs that reach users. A defect caught by a test costs minutes. The same defect caught by a customer costs a support thread, a fix under pressure, an emergency deploy, and some amount of trust that does not fully return.
- Slowing velocity. The combined effect is that an untested system gets harder to change over time, until the team spends most of its effort keeping existing behaviour from breaking rather than adding anything new.
The feature that shipped early bought time from the future at an unfavourable rate. The interest is paid in every subsequent release.
Where tests pay, and where they do not
The answer is not to test everything to an arbitrary coverage figure. Coverage as a target produces tests written to satisfy a number rather than to catch real failures: effort spent, little safety gained. The useful question is where a failure would actually hurt.
Tests earn their cost most clearly on a few things:
- Critical paths: the handful of flows whose failure would directly damage users or the business. These deserve thorough, defended tests regardless of anything else.
- Anything that has broken before. A bug that escaped once will try to escape again, and a test that pins down the fixed behaviour is among the highest-value tests you can write.
- Code you intend to change. Tests are what make refactoring safe. Before reworking a piece of the system, tests around its current behaviour turn a risky rewrite into a routine one.
They pay far less on genuinely throwaway code, on one-off scripts, and on surfaces that change shape constantly, where a test mostly locks in churn and is rewritten as often as the code it guards.
The honest trade-off
Skipping tests is sometimes the right call: for a prototype that may be discarded, for an experiment whose only job is to answer a question. The error is making that emergency choice the permanent default, and doing it silently, so the accumulating cost is never named.
A team that decides deliberately where to invest in testing, and treats the rest as a known and bounded debt, keeps software shippable for the long run: the broader subject of the boring habits that keep software shippable for years. A team that skips by reflex tends to discover the cost all at once, later, when the early signs that a software project is in trouble start to show. That is usually when our project rescue practice gets the call.