#Setting coding standards a team will follow
AddedA coding standard is the set of decisions a team makes once so nobody has to make them again in every file and every review: how code is formatted and named, which patterns are preferred, how errors are handled, what a pull request must contain. Its value isn't that the chosen style is better than another; it's that the argument is over. Review time goes to design and correctness instead of quote marks, and code written by six people in two countries reads like one person wrote it.
The mental model: standards are the team's paved road. You can still walk off it when you have a reason, but the road is where everything is easy: the linter is configured, the templates exist, the examples are there, and reviewers wave you through. A standard that's only a wiki page is a sign by the side of a dirt track; nobody reads it, and the review becomes the place where it's enforced, one argument at a time.
What makes standards stick, in practice:
- Adopt, don't invent. Start from a published guide (Google publishes style guides for TypeScript, JavaScript, HTML/CSS, Java, Shell and more at google.github.io/styleguide; the ESLint and typescript-eslint recommended configs encode another set) and write down only your deviations.
- Automate everything a tool can check (see Enforcing standards with tooling, not meetings). The written standard is then short: the judgement calls a tool can't make.
- Give the reason next to each rule. "Use
===because==coerces types" gets followed; "use===" gets argued with. - Make it changeable. Anyone can propose a change through a pull request to the standards file or an ADR; the team decides; the tooling is updated in the same PR.
- Apply it to new and touched code, not by rewriting the codebase in one go.
Google's code review guide states the principle that makes this work ("The Standard of Code Review", Google Engineering Practices, checked October 2026): "On matters of style, the style guide is the absolute authority," and any purely style point the guide doesn't cover is a matter of personal preference. A reviewer may suggest, but not block, on preference. Here's what a short, enforceable standards file can look like for a TypeScript web UI and Node API team:
# Engineering standards
Tooling enforces most of this; this page covers what it can't. To change a
standard, open a PR against this file (and the config that enforces it).
## Formatting and lint (enforced in CI, not in review)
- Prettier formats everything. Don't comment on formatting in review.
- ESLint `recommendedTypeChecked` + our rules in `eslint.config.js`.
Warnings fail CI. Disabling a rule needs a reason:
`// eslint-disable-next-line <rule> -- <why>`
## TypeScript
- `strict: true`. No `any` in new code; use `unknown` and narrow.
- Validate every external input at the boundary (HTTP bodies, device
responses, env vars) with a schema; trust types only after that.
## Errors and logging
- API errors use RFC 9457 problem details (`application/problem+json`).
- Log with the request id; never log tokens, passwords or personal data.
## Pull requests
- One concern per PR, ideally under 400 changed lines. Title in
Conventional Commits form (it becomes the squash commit).
- Tests for every behaviour change; a bug fix starts with a failing test.
- Changes under `src/api/` update `openapi.yaml` in the same PR.
## Decisions
- Significant or hard-to-reverse choices get an ADR in `docs/adr/`.- The first paragraph sets the rule about the rules: tooling enforces what it can, this page covers the rest, and the way to change a standard is a pull request to this file plus the config. That makes the standard a living, versioned artefact with history, instead of a decree.
- "Don't comment on formatting in review" is the single most valuable line. Once Prettier runs in CI, formatting comments are noise; saying so explicitly gives reviewers permission to stop and authors permission to ignore them.
- Escape hatches are allowed but visible:
eslint-disable-next-line <rule> -- <why>keeps the reason next to the exception. ESLint (10.13.0, as tested) also warns about disable comments that no longer suppress anything, so stale exceptions surface on their own. - The TypeScript and error sections are judgement rules a linter only partly checks: "validate external input at the boundary" and "use problem details" are design standards, so they live here, with the concrete mechanism named.
- The PR section links standards to the workflow: size, title format, tests, and the API-first rule, which a CI script can check (see the PR policy model in Enforcing standards with tooling, not meetings). It's short enough to read in two minutes, which is the point: a 40-page standard is a standard nobody has read.
- Formatting: all at once. Reformat the whole repository in one commit that contains nothing else, and add that commit's hash to a
.git-blame-ignore-revsfile sogit blameskips it (git config blame.ignoreRevsFile .git-blame-ignore-revs; GitHub's blame view also reads that file name). Doing it file by file mixes formatting noise into every real change for months. - Lint rules: ratchet. A new strict rule on an old codebase can produce a thousand violations. Record them as a baseline and fail only when the count goes up; ESLint has this built in as bulk suppressions (shown with real output in Enforcing standards with tooling, not meetings).
- Architecture rules: through ADRs. "New services use the shared auth middleware" is a decision with context and consequences; record it as an ADR and link it from the standards page.
- Boy-scout rule, with limits. Improve what you touch, but put clean-ups in their own commit or PR so reviews stay readable.
Reviewing a PR, you see (a) a function named getData that actually deletes stale records, (b) a for loop you'd personally write as .map(), and (c) a 30-line block that Prettier would format differently. Which do you block on?
Show answer
Only (a).
- (a) is a correctness and readability problem, not a style preference: a function whose name says "get" but which deletes data will mislead the next caller and could cause data loss. Block, and suggest a name like
deleteStaleRecords. - (b) is personal preference. Unless the standards say "prefer array methods", it's a suggestion at most, labelled as such ("nit:" or "optional:"), and the author can decline it. Google's review guide puts it plainly: a purely style point that isn't in the style guide is personal preference.
- (c) shouldn't reach a human at all. If CI runs
prettier --check, the PR can't be merged until it's formatted; if it doesn't, the fix is to add that check, not to leave a comment. - The general rule: block on correctness, security, design and agreed standards; suggest on preference; automate formatting.