5 JavaScript Patterns I’ve Seen Senior Developers Use (And Why They Matter)



This content originally appeared on DEV Community and was authored by Priyanshi Jain

My code used to work… but it wasn’t good. Through pair programming and countless PR comments, I started noticing patterns that separated beginner code from production-ready code.

Pattern 1: Early Returns (Guard Clauses)

❌ How I used to write it:

function processUser(user) {
  if (user) {
    if (user.isActive) {
      if (user.hasPermission) {
        // actual logic here
        return doSomething(user);
      } else {
        return null;
      }
    } else {
      return null;
    }
  } else {
    return null;
  }
}

✅ What I learned from seniors:

function processUser(user) {
  if (!user) return null;
  if (!user.isActive) return null;
  if (!user.hasPermission) return null;

  return doSomething(user);
}

💡 Why it matters:

  1. Reduces nesting – No more “pyramid of doom
  2. Improves readability – Each condition is clear and isolated
  3. Easier to maintain – Adding/removing conditions is simple
  4. Lower mental load – You can scan the guards quickly

Don’t over-engineer simple logic.

Pattern 2: Object Lookup Instead of Switch/If-Else Chains

❌ How I used to write it:

function getStatusMessage(status) {
  if (status === 'pending') {
    return 'Your order is pending';
  } else if (status === 'processing') {
    return 'We are processing your order';
  } else if (status === 'shipped') {
    return 'Your order has been shipped';
  } else if (status === 'delivered') {
    return 'Your order has been delivered';
  } else {
    return 'Unknown status';
  }
}

✅ What I learned from seniors:

const STATUS_MESSAGES = {
  pending: 'Your order is pending',
  processing: 'We are processing your order',
  shipped: 'Your order has been shipped',
  delivered: 'Your order has been delivered'
};

function getStatusMessage(status) {
  return STATUS_MESSAGES[status] || 'Unknown status';
}

💡 Why it matters:

  • More scalable – Adding new statuses is just one line
  • Better performance – O(1) lookup vs O(n) with if-else chains

Pattern 3: Optional Chaining & Nullish Coalescing

❌ How I used to write it:

function getUserCity(user) {
  if (user && user.address && user.address.city) {
    return user.address.city;
  }
  return 'Unknown';
}

const limit = config.limit !== null && config.limit !== undefined 
  ? config.limit 
  : 10;

✅ What I learned from seniors:

function getUserCity(user) {
  return user?.address?.city ?? 'Unknown';
}

const limit = config.limit ?? 10;

💡 Why it matters:

  1. ?. safely accesses nested properties – No more undefined errors
  2. ?? only defaults on null/undefined – Preserves 0, false, and ” as valid values
  3. Modern JavaScript – Supported in all modern browsers (2020+)

Pattern 4: Destructuring with Defaults

❌ How I used to write it:

function createUser(options) {
  const name = options.name || 'Anonymous';
  const age = options.age || 18;
  const role = options.role || 'user';

  return { name, age, role };
}

✅ What I learned from seniors:

function createUser({ 
  name = 'Anonymous', 
  age = 18, 
  role = 'user' 
} = {}) {
  return { name, age, role };
}

💡 Why it matters:

  • Cleaner function signature – Parameters are self-documenting
  • Handles missing object – The = {} prevents errors if nothing is passed
  • Avoids falsy value issues – Same problem as Pattern 3 with ||

Pattern 5: Composition Over Complex Conditionals

❌ How I used to write it:

function processData(data, shouldValidate, shouldTransform, shouldLog) {
  let result = data;

  if (shouldValidate) {
    result = validate(result);
  }

  if (shouldTransform) {
    result = transform(result);
  }

  if (shouldLog) {
    console.log(result);
  }

  return result;
}

✅ What I learned from seniors:

const pipe = (...fns) => (value) => 
  fns.reduce((acc, fn) => fn(acc), value);

const processData = pipe(
  validate,
  transform,
  log
);

// Usage
const result = processData(data);

💡 Why it matters:

  • Single responsibility – Each function does one thing
  • Easy to modify – Add/remove/reorder steps without touching logic

I’m still learning every day. If you’re a senior developer reading this, what patterns would you add? If you’re early in your journey like me, which of these resonates most with you?

Let’s learn together in the comments. 👇


This content originally appeared on DEV Community and was authored by Priyanshi Jain