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:
- Reduces nesting - No more "pyramid of doom"
- Improves readability - Each condition is clear and isolated
- Easier to maintain - Adding/removing conditions is simple
- 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:
- ?. safely accesses nested properties - No more undefined errors
- ?? only defaults on null/undefined - Preserves 0, false, and '' as valid values
- 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. 👇
Top comments (0)