Clean code and code review habits that make you a better developer

Code is read far more often than it is written. Learn the habits that make code easy to understand, change and review.

Tidy code being reviewed by a teammate

Working code is the minimum. Good code is easy to read, change and trust. Most of a developer's time is spent reading existing code, so writing for the next reader (often future you) is a core skill.

1. Name things well

Names are the biggest part of readability.

  • Use descriptive names that reveal intent: daysUntilExpiry, not d or tmp.
  • Name functions with verbs (calculateTotal, sendInvoice) and values with nouns.
  • Booleans read like questions: isActive, hasPermission.
  • Avoid misleading or vague names (data, info, manager, handleStuff).
  • Be consistent: do not mix fetch, get and retrieve for the same idea.
  • Short names are fine for tiny scopes (i in a loop). Longer scope needs a clearer name.

2. Keep functions small and focused

A function should do one thing at one level of detail.

  • If you need "and" to describe it, split it.
  • Aim for few parameters. Many parameters are a sign to group them into an object or split the function.
  • Prefer early returns to deep nesting.
  • Avoid hidden side effects. A function named getUser should not also change data.
// harder to read
function process(o) {
  if (o) {
    if (o.items.length > 0) {
      if (o.paid) { ship(o); }
    }
  }
}

// clearer
function shipIfReady(order) {
  if (!order || order.items.length === 0 || !order.paid) return;
  ship(order);
}

3. Comments explain why, not what

  • Good code explains what itself through names and structure.
  • Use comments for why: a business rule, a workaround, a link to a bug or a standard.
  • Delete commented-out code. Version control remembers it.
  • Outdated comments are worse than none, so update them with the code.

4. Avoid duplication, but do not over-abstract

  • DRY (don't repeat yourself): repeated logic should live in one place.
  • But do not abstract too early. Wait until you see the same idea three times and understand what really varies. A wrong abstraction is worse than a little duplication.
  • Remove dead code and unused variables.

5. Handle errors on purpose

  • Do not swallow errors silently with an empty catch.
  • Fail early with a clear message when input is invalid.
  • Add context (which ID, which operation) to errors, and log them once at the right place.
  • Do not use exceptions for ordinary control flow.
  • Never expose internal error details to end users.

6. Make data and state simple

  • Prefer immutable values where practical.
  • Limit global variables and shared mutable state.
  • Replace magic numbers and strings with named constants.
  • Keep related data together; use clear types.

7. Write tests

  • Tests document behaviour and give you the confidence to refactor.
  • Test behaviour (inputs and outputs), not private details.
  • Keep tests small, fast and independent.
  • A bug fix should come with a test that fails before the fix.

8. Refactor in small safe steps

Refactoring changes structure without changing behaviour.

  • Have tests first.
  • Make one small change at a time and run the tests.
  • Follow the boy-scout rule: leave the code a little cleaner than you found it.
  • Keep refactoring commits separate from feature changes so reviews stay clear.

Code review: giving feedback

A review is about improving the code and sharing knowledge, not judging the person.

  • Understand the goal first by reading the description.
  • Check correctness and edge cases, security, readability, tests and performance for hot paths.
  • Be specific and kind: explain why, suggest an alternative, ask questions ("what happens if the list is empty?").
  • Separate must-fix issues from suggestions or style preferences (prefix with "nit:").
  • Let tools handle formatting and lint rules so humans focus on logic.
  • Praise good solutions.
  • Review small changes. Large diffs get shallow reviews.

Code review: receiving feedback

  • Do not take it personally. The review is about the code.
  • Ask for clarification if you do not understand a comment.
  • Explain your reasoning, and be willing to change your mind.
  • Thank reviewers. Fix or discuss every comment.
  • Keep pull requests small, focused and well described: what, why, how to test.

A pre-review checklist for your own code

  • Does it do what the task asked, including edge cases?
  • Are names clear and is there dead code or debug output to remove?
  • Are there tests, and do they pass?
  • Did I check security: input validation, permissions, secrets?
  • Could someone new understand this in a few minutes?

Takeaway: write for the reader: clear names, small functions, comments for the why, handled errors and tests. In reviews, be specific and kind, keep changes small, and let tools check style.


Programming roadmaps series, Part 2 (languages and design): 4 of 5. Previous: REST API design best practices: URLs, status codes and errors.

Keep reading