Skip to content

Writing Clean Functions in JavaScript

Small, focused functions make code easier to test, read, and maintain without over-engineering.

1 min read

If you need a comment to explain what a block of code does, that block probably wants to be its own function.

Keep functions small

One fat function split into three focused ones

A function that does two things is two functions waiting to be split.

// bad: one function, three jobs
function processUser(data) {
  const user = JSON.parse(data);
  user.name = user.name.trim();
  saveToDatabase(user);
}

// good: each step named and testable
const parseUser = (data) => JSON.parse(data);
const normalizeUser = (user) => ({ ...user, name: user.name.trim() });
const saveUser = (user) => saveToDatabase(user);

Name functions after what they return

A function named getUserData could do anything. A function named fetchActiveUsers tells you the shape and the filter up front.

Push side effects to the edges

Pure functions are easy to test. Network calls, DOM writes, file I/O belong at the outermost layer. Keep the logic pure underneath.

// pure: easy to unit test
const formatPrice = (cents, currency = 'USD') =>
  new Intl.NumberFormat('en', { style: 'currency', currency }).format(cents / 100);

Return early

Nested conditionals add cognitive load. Return early when a condition fails. Flat code is easier to scan than deeply indented code.

function getDiscount(user) {
  if (!user) return 0;
  if (!user.isPremium) return 0;
  return 0.2;
}

Keep reading