Shift-Left Testing
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). The absence of shift-left practices — tests only running in CI not locally, no pre-commit hooks, security scanning only at deployment — is not caught by a compiler or default linter. Tools like phpstan, phpunit, captainhook, and semgrep can enforce it, but only if someone deliberately sets them up; the gap is typically discovered through code review audits or when bugs regularly surface in production, not automatically flagged.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes moving testing across multiple stages: type checking on save, unit tests on commit, integration tests in CI. This isn't a one-line fix — it requires configuring pre-commit hooks (captainhook), adding SAST (semgrep/phpstan), setting up ephemeral PR environments, and potentially restructuring CI pipelines. It touches dev tooling, CI config, and team workflow simultaneously, making it a multi-file, multi-system effort.
Closest to 'persistent productivity tax' (b5). Shift-left testing applies broadly to both web and CLI contexts. Once adopted (or not adopted), it shapes every developer's daily workflow — slow hooks get bypassed with --no-verify, missing PR environments mean developers can't validate changes in isolation. It imposes an ongoing tax on many work streams (PR reviews, deployments, onboarding) but doesn't fully define the system's shape, placing it at b5 rather than b7.
Closest to 'notable trap' (t5). The misconception field directly identifies the canonical wrong belief: developers assume shift-left means only unit tests run early, missing that SAST, accessibility (axe-core), performance (Lighthouse CI), and contract tests can all shift left too. This is a documented, well-known gotcha that most developers eventually learn, but it leads to incomplete adoption — e.g., security scanning only before release rather than on every PR — which is a real and costly mistake.
Also Known As
TL;DR
Explanation
Traditional testing pyramid deferred integration and security testing to late stages. Shift-left brings it forward: pre-commit hooks run linting and unit tests locally, PRs trigger full CI (unit, integration, static analysis, SAST), feature branches deploy to ephemeral environments, and security scanning runs before merge. Cost of fixing a bug: $1 at commit time, $10 in PR review, $100 in staging, $1000 in production. Shift-left tools: pre-commit hooks, GitHub Actions, PHPStan, SAST scanners, contract tests.
Common Misconception
Why It Matters
Common Mistakes
- Slow pre-commit hooks — hooks over 10 seconds get bypassed with --no-verify.
- Only linting in pre-commit — include fast unit tests for immediate feedback.
- No ephemeral PR environments — developers cannot test their changes in isolation.
- Security scanning only before release — SAST should run on every PR.
Code Examples
// All testing deferred to staging:
// Developer commits → pushed to main → deployed to staging
// QA tests manually → finds bug after 3 days
// Developer context-switched to other work
// Fixing: 1 hour of relearning + 30 min fix
// Cost: 1.5 hours + delayed release
// Shift-left: caught immediately:
// pre-commit: phpcs + phpstan (10 seconds)
// PR: full CI in 5 minutes:
// unit tests, integration tests
// static analysis at level 8
// SAST scan (SonarQube)
// Lighthouse CI for performance
// Ephemeral environment deployed
// Developer still has full context
// Fixing: 10 minutes