Code Quality & Linting
Automated code-quality tools catch bugs before runtime and keep a codebase consistent without bikeshedding about style. The win is leverage: a linter flags a real bug in milliseconds, and a formatter ends every "tabs vs spaces" debate by making it not a choice.
The mature setup combines a linter (bugs/anti-patterns), a formatter (style), and a type checker (type errors), enforced in CI so standards can't silently slip — and auto-fixed in the editor so they're painless.
TL;DR
- Use linters to catch bugs and formatters for consistent style.
- Add a type checker (TypeScript, mypy) for an extra safety net.
- Enforce in CI and auto-fix on save in the editor.
- Configure to match team conventions; commit the config.
Quick Example
The four kinds of static analysis, and the standard tools per language:
Core Concepts
- Linting — detects likely bugs and anti-patterns (unused vars,
==misuse). - Formatting — enforces consistent style mechanically (indentation, quotes).
- Type checking — catches type errors before runtime.
- Security scanning — flags vulnerable dependencies and risky patterns.
Configuration
Pre-commit Hooks
Run fast checks before code is even committed:
CI Integration & Editor
Gate merges on quality in CI, and make fixes automatic locally:
Best Practices
- Lint + format + type-check — they're complementary, not redundant.
- Run checks in CI (block on failure) and on save locally.
- Commit the config (
.eslintrc,pyproject.toml) so the whole team is consistent. - Keep rules pragmatic — too many noisy rules get ignored or disabled.
Common Mistakes
Linter and formatter fighting
Quality checks only locally
FAQ
What's the difference between a linter and a formatter?
A linter analyzes code for likely bugs and anti-patterns (unused variables, unreachable code, misuse of ==); a formatter only rewrites style (indentation, quotes, line breaks) deterministically. Use both — and let the formatter own style so the linter doesn't fight it.
ESLint or Prettier — do I need both?
Yes, they do different jobs: ESLint catches bugs/anti-patterns, Prettier formats. Use eslint-config-prettier to turn off ESLint's stylistic rules so they don't conflict, letting Prettier handle all formatting.
Should quality checks run in CI or locally?
Both. Editor/pre-commit checks give fast feedback and auto-fixes; CI is the enforcement gate that blocks merges when something slips through. Relying only on local checks lets standards drift; relying only on CI makes feedback slow.
What's a good Python setup in 2026?
Ruff for linting and formatting (fast, replaces flake8/black/isort), plus mypy or pyright for type checking, wired into pre-commit and CI. It's the modern, low-config default.
Related Topics
- TypeScript — Type checking
- CI/CD Pipelines — Where quality gates run
- Testing — The other half of quality
- Git Fundamentals — Pre-commit hooks
- Python — Ruff/mypy ecosystem