Skip to main content

Automated Checks as Part of Design Hygiene

What This Concept Is

Automated checks in CI are the background hygiene that keeps human review focused on human things. A sane minimum set:

  • Formatter (Prettier, Black, Ruff-format, gofmt, spotless) -- runs on every commit; failure never reaches review.
  • Linter / static analyzer (ESLint, ruff, golangci-lint, pylint, mypy/pyright for types) -- enforces rules the team agreed to.
  • Unit and integration tests -- required green on every PR.
  • Security / dependency checks (pip-audit, npm audit, Dependabot, or similar) -- run on a schedule or on PRs touching dependencies.

These are not a substitute for review. They are the condition that makes review useful. A review that spends fifteen comments on indentation is a review that missed a design problem somewhere.

Why It Matters Here

Review time is scarce. If it is consumed by style nits, real design issues get thirty seconds of attention. Moving style and mechanical correctness to CI is a design decision about your review process. It is also why pattern overuse and bad naming survive in teams without automated hygiene -- reviewers are too exhausted from style correction to catch them.

Concrete Example

Minimal pre-commit config for a Python service:

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
hooks:
- id: ruff # lint
- id: ruff-format # format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
additional_dependencies: [pydantic, sqlalchemy]

Minimal CI job (GitHub Actions):

name: ci
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install -e ".[dev]"
- run: ruff check .
- run: ruff format --check .
- run: mypy src/
- run: pytest -q --maxfail=1

Once this is in place, no human ever comments on spacing, import order, or "this function is untyped." The machine says so.

Common Confusion / Misconception

"The tools will find the bugs." They will not. Lint finds a small class of bug. Type checkers find a larger class. Neither finds design problems, race conditions, domain errors, or bad names that happen to be consistently spelled. Humans still matter.

"More rules are better." Past a threshold, strict rules produce noise and disabled rules. Pick a small, enforced set. Rules are negotiated with the team, not piled on.

"CI is slow, let's skip it on drafts." Skipping on drafts is fine; skipping on the merge branch is how prod breaks. Keep the required-check policy explicit.

"We have tests; we don't need a formatter." A formatter is not about bugs. It is about not wasting review time on whitespace debates. Teams without one spend that time.

"Coverage = quality." High coverage can hide shallow tests; low coverage can mask well-tested code that simply also has a lot of code. Use coverage as a weak indicator, not a gate.

"Pre-commit hooks slow me down." They slow the commit. They do not slow the team, because they catch the things the reviewer would have stopped on anyway.

How To Use It

For any repo you own or can influence:

  1. Pick a formatter and turn it on. Non-negotiable. Run once on the whole repo in a chore: apply formatter commit.
  2. Pick a linter with a small enforced rule set. Expand over time.
  3. Require tests to pass for merge.
  4. Wire the same checks into pre-commit so contributors get fast feedback locally.
  5. Add a CONTRIBUTING.md or similar that explains the policy and how to run checks locally.

For review: if a reviewer is about to comment on indentation or import order, they should instead ask "why is the formatter not catching this?" That question is the real fix.

Check Yourself

  1. What is a formatter, and what is the review-time argument for one?
  2. Why are "more lint rules" not automatically better?
  3. Give an example of a class of bug static analysis will not catch.

Mini Drill or Application

Pick a small repo (yours or a fork). Do all four:

  1. Add a formatter and apply it to the repo.
  2. Add a lint configuration with at least three enforced rules.
  3. Wire both into CI on PRs.
  4. Write two PR review comments on the resulting workflow that you no longer need to write by hand.

Read This Only If Stuck