Skip to content
Developer Experience

Day 8: Find Problems Early. Fix Them Cheaply.

The bug that costs a comment in code review costs an incident in production. Shift left is the discipline of moving quality, security and feedback as early as possible — not a testing phase, a mindset.

Thamunkpillai 5 min read

Draw the traditional software lifecycle as a straight line: plan, code, build, test, deploy, operate. Now mark where problems actually get found on most teams — and they cluster hard on the right-hand side, in test or worse, in production. That's not a coincidence, it's a direct consequence of where the checks live. If security scanning happens at the end, security problems get found at the end. If the only tests are the ones QA runs before a release, that's where bugs surface — after the code's been written, reviewed, and half-forgotten.

Shift left means moving those checks toward the left of that line: earlier in planning, earlier in coding, earlier in the pipeline. Not because early checks are inherently better tests, but because of what a defect costs at each point it could have been caught.

Warning

The number that gets quoted for this is something like "a bug found in production costs 10-100x what the same bug costs in code review." The exact multiplier isn't the point and it's certainly not from a peer-reviewed study you should cite in a doc. The direction is what's real and worth internalizing: every stage a defect survives, it gets more expensive to fix, because more has been built on top of the wrong assumption.

What actually gets shifted left

"Shift left" gets used loosely enough to mean almost nothing, so it's worth being concrete about what moves and to where:

  • Security — SAST and secrets scanning in the IDE and pre-commit hook, not a pentest the week before launch.
  • Quality — code review and static analysis on every PR, not a QA pass after "feature complete."
  • Testing — unit and contract tests that run on git push, not a manual regression suite run once a sprint.
  • Observability — logging and tracing designed in from the first commit, not bolted on after the first production incident makes clear you can't see anything.
  • Infrastructure — terraform validate and policy checks in CI, not discovered when apply fails against a locked-down account.
  • Feedback — a teammate's opinion on the approach before three days of implementation, not a design objection raised in review after the PR is already open.

The pattern across all six: the check used to be a gate near the end. Now it's a habit near the beginning.

A real pipeline, shifted

YAML
# .github/workflows/ci.yml — checks run on every push, not before a release
name: ci
on: [push, pull_request]
jobs:
  shift-left-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Lint and static analysis
        run: npm run lint && npm run typecheck
      - name: Unit tests
        run: npm test -- --coverage
      - name: Secrets scan
        run: trufflehog filesystem . --fail
      - name: Dependency vulnerability scan
        run: npm audit --audit-level=high
      - name: IaC policy check
        run: tflint && conftest test infra/ --policy policy/

Every one of those steps runs in seconds to a few minutes, on every push, before a human reviews anything. The bug, the vulnerable dependency, and the policy violation all get caught while the context is still in the author's head — not three weeks later when someone else has to reconstruct what the code was even trying to do.

The part people get wrong: shift left isn't "add more gates"

The failure mode with shift left isn't skipping it — it's implementing it as a wall of new required checks that make every commit slower without making anything meaningfully safer. A pre-commit hook that takes four minutes doesn't get run, it gets skipped with --no-verify. A PR template with fifteen mandatory checkboxes gets filled in on autopilot.

The actual mindset shift

Shift left works when the early check is easier than the late one, not just earlier. A linter that auto-fixes on save is shift left done right — it removes friction. A mandatory 40-minute security review before every merge is shift left done wrong — it just moved the bottleneck two days earlier and made it everyone's problem.

Why yesterday's article makes this one work

Immutable infrastructure and shift-left testing depend on each other in a way that's easy to miss: shift left only pays off if the artifact you tested in CI is exactly the artifact that reaches production. If someone can SSH into a box after the pipeline runs and change something, then every early check you ran was validating something that no longer exists by the time users touch it. Immutability closes that gap — what passed the pipeline is, byte for byte, what's running. Without it, "shift left" becomes theater: rigorous testing of an artifact, followed by silent, untested changes to the thing actually serving traffic.

The teams that get real value from shift left aren't the ones with the most checks. They're the ones where the checks are cheap enough to run constantly and the artifact those checks validate is the one that actually ships.

Written by Thamunkpillai · Have a question or a correction? Reach out via email.

Get the useful stuff, not the noise.

Occasional notes on engineering, Platform Engineering, AI, cloud and things I’m learning along the way.

No spam. Unsubscribe anytime.