Shifting Left: Quality Before Code Ships
- Shawn West
- Sep 19, 2025
- 10 min read
Updated: Aug 10
Every bug carries two costs. There is the bug itself — the wrong line, the missing check, the assumption that didn't hold. And there is the cost of when you find it. The first cost is roughly fixed. The second is a curve that climbs steeply as you move left to right across the lifecycle, and it is the one most teams ignore until it has already spent their quarter.
Shifting left is the discipline of catching defects while that second cost is still small. Not a tool. Not a phase. A decision about where in the timeline your team spends its quality energy — and the argument of this piece is that the earliest, cheapest catches are the ones almost nobody staffs, because they don't look like testing at all.
The timeline, and why quality drifted to the right
Picture the lifecycle as a line. On the left: requirements and design — the decisions about what to build and how it should behave. In the middle: code. On the right: testing, release, and production — the system meeting real users and real data.
For decades, quality lived on the right. You built the thing, then threw it over the wall to a QA team whose job was to find what was broken before customers did. That model isn't stupid — it catches real defects — but it catches them at the most expensive possible moment, after the assumptions are already set in code and the cost of unwinding them is highest.
Shifting left moves quality work back toward the origin: prevent the defect in design, catch it in review, verify it in an automated check that runs before merge. Same defects, caught earlier, at a fraction of the cost. If you're still forming a view on why teams test at all — not just when — why we test is the foundation this piece builds on.
Why earlier is cheaper — and where the famous number oversells itself
The direction isn't controversial, and it isn't new. Barry Boehm's Software Engineering Economics (1981) laid out the core finding: the cost to fix a defect rises by roughly an order of magnitude as it moves from requirements to design to code to production. A 2002 NIST study put a national figure on the drag from inadequate software testing infrastructure — an estimated $59.5 billion per year, much of it from defects caught late or not at all.
Here is where honesty matters more than punch. You have probably heard "a bug costs 100x more to fix in production." That number gets repeated with far more confidence than the underlying data supports — the studies behind it vary in method, scope, and era, and the exact multiplier is not something you should quote as fact. What survives scrutiny is the shape of the curve, not its precise slope: fixing a defect late is dramatically more expensive than fixing it early, reliably and across contexts. You don't need "100x" to justify shifting left. You need "steep," and "steep" is well-established.
So the case for shifting left doesn't rest on a single dramatic statistic. It rests on the mechanism: a defect caught in a requirements conversation is a decision; the same defect caught in production is an incident. The next section walks exactly that gap.
One defect, two moments: the refund flow
(Developed example — composite scenario.)
A team is building a refund feature. A customer service agent enters a quantity and the system credits the customer's card. Straightforward.
Moment one — the requirements review. Someone is reading the spec closely and asks a five-word question: "What if the quantity is negative?" The room pauses. Nobody had thought about it. In two minutes they decide: quantities below one are rejected at the form, with a validation message. A product owner notes the rule, an acceptance criterion gets written, and the meeting moves on. Total cost: one question and one decision. Nothing was built, so nothing had to be unbuilt.
Moment two — the same defect, in production. Now imagine nobody asked. The spec said "enter a quantity and issue the refund," and that is exactly what got built. Three weeks after launch, an agent fat-fingers a refund for negative three items. The system does what it was told: it credits the customer for −3 units — money flowing the wrong direction. Here is what that one un-asked question now costs:
Triage. An on-call engineer is paged, pulls logs, and works out that a negative quantity inverted the transaction. That's an hour before anyone even understands the bug.
Hotfix. A validation check is written, reviewed, and shipped under pressure — the riskiest kind of change, because it's urgent and the normal guardrails feel like friction.
Finance reconciliation. Someone has to find every refund since launch, identify the ones with bad quantities, and figure out the real dollar exposure. That work involves people who never touch the codebase.
Post-mortem. An hour of several people's time reconstructing how a known-simple feature shipped without input validation — and what else shipped the same way.
Lost trust. The quieter cost. Leadership now asks harder questions about every release from this team, and that scrutiny is a tax on velocity that outlasts the incident.
The defect was identical in both moments. The code, the fix, the validation rule — all the same. The only variable was when someone asked the question. On the left it was a sentence in a meeting. On the right it was a cross-functional cleanup with a trust penalty attached. That gap — between a conversation and an incident — is the entire economic argument for shifting left, made concrete.
Notice what actually caught it: not a test, not a tool. A person reading the spec for what it didn't say.
The discovery move: read the spec for what it doesn't say
This is the part that separates teams who shift left in name from teams who do it. The expensive defects are rarely in the behavior the spec describes. They live in the behavior the spec forgot — the paths nobody wrote down because nobody imagined them.
So the highest-leverage skill in a requirements review is reading for absence. For every input, every action, every dependency, ask what happens at the edge the spec is silent on:
Empty input. What if the field is blank, zero, negative, or enormous? (The refund flow died here.)
No permissions. What if the user isn't authorized — does the system fail closed, or quietly do the thing anyway?
Downstream timeout. What if the service you call doesn't answer? Do you retry, fail, double-charge, or hang?
These aren't testing questions. They're discovery questions, and they belong before a line of code exists — because once the code assumes the happy path, every one of these becomes a defect to unwind rather than a decision to make. This is the ShiftQuality thesis in one move: projects fail in discovery, not code. The negative-quantity bug was never a coding failure. It was a discovery gap that a coding phase faithfully implemented. Writing these edges down as testable conditions is exactly what acceptance criteria done right is for.
What shifting left looks like in practice
"Shift left" fails as advice when it stays a slogan. It becomes real as four concrete practices, ordered earliest to latest. The earlier ones are cheaper and catch more — and are the ones teams most often skip, precisely because they don't feel like quality work. The table shows what each catches and what it costs if you let that catch slip right instead.
Practice (earliest → latest) | What it catches | Cost to fix here vs. if it slips right |
Requirements review | Missing edge cases, undefined behavior, contradictory rules, unstated assumptions | A sentence in a meeting vs. a production incident + reconciliation |
Design review | Wrong data model, unhandled failure paths, integration mismatches, missing states | A whiteboard redraw vs. a migration and a refactor across services |
Code review / pairing | Logic errors, missing validation, unclear intent, untested branches | A comment on a diff vs. a hotfix and a post-mortem |
Automated tests in CI | Regressions, broken contracts, integration breakage before merge | A red build in 90 seconds vs. a customer bug report |
Each row is a section below, and each ends in something you can run this week.
Requirements review — the cheapest catch there is
This is where shifting left pays the most and gets staffed the least. A defect caught here costs a conversation. The move is the one above: read the spec for what it doesn't say, and turn every silent edge into an explicit, written decision. Empty input, missing permission, downstream failure — name the behavior before it's assumed.
Runnable takeaway: In your next requirements or refinement session, take the single riskiest feature and write down three edge cases the spec doesn't mention — start with empty/negative input, missing permission, and a downstream timeout. Force a decision on each. If the room can't answer, you just found a defect for the price of a question.
Design review — catch the shape before it sets
By design, you're committing to a data model, a set of failure paths, and how components talk to each other. Defects caught here cost a redraw. The same defects caught after implementation cost a migration and a refactor across every service that touched the wrong assumption. Ask the failure-path questions at the diagram stage: What state is the system in if this step fails halfway? What happens to data already written? Where does an error surface, and to whom?
Runnable takeaway: For your next design doc, add a short "Failure paths" section before it's approved. List each external call and dependency, and for each write one line: what the system does when it fails or times out. A design that only describes the happy path isn't finished — it's a happy-path prototype with the hard half missing.
Code review / pairing — intent, not just syntax
Code review catches logic errors, missing validation, and unclear intent while the change is still a diff, not a deploy. Its shift-left value collapses when reviews degrade into style-nitpicking or rubber-stamp approvals. Review for the questions the earlier phases raised: Is the edge case we identified in requirements actually handled here? Is the failure path from the design doc implemented? A review that never references the spec or the design is checking syntax, not quality.
Runnable takeaway: Add one line to your PR template: "Which edge cases and failure paths does this handle, and where?" Make the author answer it and the reviewer check it against the acceptance criteria. Reviews that trace back to a written decision catch defects; reviews that don't just approve typos.
Automated tests in CI — make the catch repeatable
Everything above depends on humans remembering to ask. Automated tests in CI make the earlier catches stick — they turn a decision made in a requirements review into a check that fails a build the moment someone regresses it. This is the rightmost of the shift-left practices, but it's still left of production, and a red build in ninety seconds is far cheaper than a customer bug report. The failure mode here is a suite that's slow, flaky, or tests the wrong layer — so people stop trusting it and route around it. Gate on the checks that encode real decisions, and make sure those gates actually block. Quality gates that actually gate is the difference between a check that informs and one that stops a bad merge.
Runnable takeaway: Take the last defect that reached production and write the automated test that would have caught it — at the lowest layer that reproduces it. Wire it into the check that blocks merge. Do this every time a defect escapes, and your CI suite becomes a growing record of exactly the mistakes your team actually makes.
Where the recommendation bends
Shifting left is a default, not a law, and treating it as absolute is its own failure mode. A few honest exceptions:
You can't shift-left your way out of unknowns. Some behavior can only be learned by running the real system against real data — performance under load, third-party quirks, genuinely novel product bets. Front-loading infinite analysis onto a problem you don't yet understand is analysis paralysis, not quality. Some catches genuinely belong on the right.
The cheapest catch still costs something. Requirements reviews, design docs, and thorough code review take time. On a truly reversible, low-stakes change, that ceremony can cost more than the defect would. The rigor should scale with how expensive the mistake is to reverse — an inline tweak invites experimentation; a payment path or a data migration demands the full left-side treatment.
Shifting left is redistribution, not elimination. You are moving effort from late firefighting to early prevention, and early prevention is real work with real headcount. The payoff is large and well-supported, but it isn't free, and pretending otherwise is how "shift left" becomes a mandate nobody has time to honor. The honest accounting lives in the cost of quality, honestly.
What to do next
Pick your most recent production defect — the last one that actually reached a customer. Walk it backward: at which point in the lifecycle could it have been caught? A requirements question? A design failure-path? A code review comment? A test? You'll almost always find it could have been caught at least one phase earlier than it was, usually several.
That phase is where your team's shift-left investment has the highest return. Not a tool purchase, not a reorg — a habit installed at a specific point in your existing process: a question asked in refinement, a failure-path section in the design template, a line in the PR checklist, a test wired into the gate. Start there, with one defect and one earlier phase, and let the curve do the arguing.
Shifting left, in the end, is not a testing strategy. It's the recognition that the cheapest moment to fix a defect is before it exists — and that the moment is almost always a conversation someone chose not to skip. For where this sits in the broader discipline, see what quality management actually is.
Sources
Boehm, Barry W. Software Engineering Economics. Prentice-Hall, 1981. Origin of the finding that defect-fix cost rises by roughly an order of magnitude across lifecycle phases. The often-repeated "100x in production" figure is cited more confidently than the underlying data supports; the durable, well-established claim is the shape of the curve (steeply rising), not a precise multiplier.
National Institute of Standards and Technology (NIST). The Economic Impacts of Inadequate Infrastructure for Software Testing. 2002. Estimated ~$59.5 billion annual cost to the U.S. economy from inadequate software testing infrastructure, a substantial share attributable to defects found late.
Refund-flow scenario: developed example, composite — not a documented case study. Constructed to illustrate the cost gap between a defect caught in requirements review and the same defect caught in production.
Keep learning. This article is part of the Quality Management Fundamentals path in the ShiftQuality Learning Center.


