Stockio

Code Review Checklist for Focused, Evidence-Based Reviews

Use a risk-first code review checklist to examine correctness, security, tests, and maintainability while separating merge blockers from optional suggestions.

By Ravi Desai

DevOps & Security Engineer ·

On this page

A useful code review answers a small set of consequential questions: does this change solve the stated problem, what could it break, and what evidence supports merging it? Reviewing every line with equal intensity wastes attention. A checklist provides coverage, but the reviewer still needs judgment about the paths that carry the greatest risk.

Establish context and choose the review depth

Read the issue, acceptance criteria, and pull-request description before opening the diff. State the expected behavior in your own words. If the goal is unclear, ask the author to clarify it before discussing implementation details. Intent before syntax prevents a beautifully reviewed solution to the wrong problem.

For structured payload changes, use the JSON formatter with synthetic or redacted before-and-after examples. Compare keys, nesting, nullability, and omitted values without the distraction of compressed data. This supports visual inspection; it does not prove schema compatibility or validate authorization rules. Keep private customer data out of shared tools.

Classify the change by consequences rather than line count. A one-line permission change can deserve more scrutiny than a large mechanical rename. Identify affected users, persistence, public interfaces, external services, and failure recovery. Request a separate patch when unrelated refactoring obscures the actual behavior change.

Review correctness through complete execution paths

Choose one successful scenario and trace it from input to output. Then choose a failure scenario and follow it with equal care. Check branches, early returns, default values, and state transitions. Boundary cases often reveal the real defect: zero items, missing input, duplicate submission, expired state, or a response arriving after the user navigated away.

Use a concrete checklist rather than asking whether the code “looks right”:

  • Are input assumptions enforced where untrusted data enters?
  • Do callers handle the function's actual return and error behavior?
  • Can retries repeat a side effect that should happen only once?
  • Are resources and subscriptions released after failure or cancellation?
  • Does the change preserve compatibility for existing consumers?

Consider this superficially tidy example:

async function savePreferences(input: unknown) {
const preferences = parsePreferences(input);
const response = await fetch("/api/preferences", {
  method: "PUT",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(preferences),
});
if (!response.ok) {
  throw new Error("Saving preferences failed");
}
}

The reviewer still needs to inspect the parser, server-side authorization, caller error handling, and behavior under concurrent saves. Checking response.ok matters because HTTP error statuses do not normally reject the fetch promise; consult the MDN Fetch guide for exact behavior. A short function is not necessarily a small review surface.

Inspect security and data handling separately

Make trust boundaries an explicit pass instead of hoping security problems stand out during general reading. Identify which values originate from users, remote systems, stored records, or environment configuration. Follow those values into database operations, HTML output, filesystem paths, logs, and network destinations.

Check that permissions are enforced on the server for the requested resource, not merely hidden in the interface. Verify that validation does not silently convert a dangerous value into an apparently acceptable one. Avoid logging tokens, personal information, or complete request bodies just because a debugging helper makes it easy.

Use the OWASP Code Review Guide as a source of deeper security questions when the change touches sensitive behavior. A checklist is not a replacement for specialist review of authentication, cryptography, payment handling, or significant access-control changes. Escalation is a sign of correct risk assessment, not reviewer failure.

Inspect dependency and configuration changes too. A new package, broadened permission, or modified installation script can matter more than the application code. Confirm why the dependency is needed and whether existing project utilities already cover the requirement.

Evaluate tests as evidence, not decoration

Start with the defect or requirement and ask which test would fail if the implementation were wrong. Regression evidence is stronger than a screenshot of a green suite unrelated to the changed behavior. For a bug fix, confirm that the new test fails against the prior implementation when practical.

Look for meaningful assertions about observable results. A test that only checks a mock was called may miss an incorrect payload or a swallowed error. Conversely, tests tightly coupled to private helper order can block harmless refactoring without protecting users. Favor the public behavior at the narrowest useful testing level.

Read the failure cases: rejected requests, invalid input, partial results, cancellation, and repeated actions. For interface changes, include a manual keyboard pass and inspect focus after errors. The accessible interface guide offers concrete prompts beyond checking whether an automated scan is green.

Record which commands ran and what was not exercised. Distinguish a flaky test, an unavailable external service, and a genuine regression. Do not normalize unexplained failures just because they occurred before this pull request; document ownership and determine whether they undermine the evidence needed for this change.

Leave actionable feedback and close the loop

Separate merge blockers from optional improvements. A blocker should name the violated requirement, explain the consequence, and propose a way to demonstrate a fix. A suggestion should be clearly optional. This reduces guesswork and avoids turning personal preferences into unofficial policy.

For example, replace “this is unsafe” with “the server accepts another user's record identifier; please add an ownership check and a test showing a forbidden response.” Replace “clean this up” with a specific duplication concern and the existing helper that addresses it. Ask questions when context is missing rather than asserting motives or competence.

Automate formatting and routine lint decisions so human attention goes to behavior. The Google engineering review practices provide a useful model for balancing code health with timely progress. Keep team-specific conventions documented alongside the repository, with supporting material in your developer-tool workflow resources.

After revisions, review the new diff and the surrounding behavior, not only the comment resolution markers. Approval is a decision about the current patch. If a major redesign arrives after approval, take another pass. Capture any accepted follow-up as a tracked task with an owner rather than an indefinite promise in a resolved conversation.

Key takeaways

  • Start with intent, consequences, and the riskiest execution paths.
  • Review correctness, trust boundaries, and test evidence in separate passes.
  • Prefer observable behavior over implementation-shaped assertions.
  • Label blockers and suggestions so authors can act without guessing.
  • Recheck revisions and make remaining risk explicit before approval.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in Dev Tools & AI Coding
Dev Tools & AI Coding

8 Best AI Code Review Tools

Compare eight AI-assisted code review tools for pull requests, security checks, and repository workflows, with practical cautions about false alarms, context, and human responsibility.

Includes: JSON formatterSofia MarchettiSofia Marchetti
Dev Tools & AI Coding

15 Best VS Code Extensions for Web Development

Find useful VS Code extensions for formatting, debugging, writing and remote work. This practical list explains what each add-on does, who benefits, and when built-in features are enough.

Includes: JSON formatterSofia MarchettiSofia Marchetti
Dev Tools & AI Coding

Turborepo Monorepo With pnpm Workspaces

Set up pnpm workspace boundaries and Turborepo task caching with explicit package dependencies, reliable outputs, and a structure that stays understandable as teams grow.

Includes: JSON formatterSofia MarchettiSofia Marchetti
Dev Tools & AI Coding

Chrome DevTools Performance Panel: From Trace to Fix

Record focused Chrome Performance traces, identify expensive main-thread work, and verify targeted fixes with repeatable scenarios instead of guessing from a flame chart.

Includes: JSON formatterRavi DesaiRavi Desai
Dev Tools & AI Coding

direnv and .env Files: Managing Local Environment Variables

Make local project configuration predictable with .env templates, explicit loading rules, direnv approval, and checks that catch missing values before startup.

Includes: JSON formatterRavi DesaiRavi Desai
Dev Tools & AI Coding

AI Tailwind CSS: Get Clean Styles From AI Assistants

AI assistants can produce a convincing interface quickly, but the stylesheet often reveals how little was specified. Arbitrary spacing, duplicated utilities and brittle positioning accumulate when every prompt.

Includes: JSON formatterRavi DesaiRavi Desai