Rule
Use early returns and guard clauses.
Deep nesting and late parameter validation
make functions harder to read and maintain.
Supported languages: 45+Introduction
Guard clauses validate preconditions at the start of a function and return immediately if conditions aren't met. This flattens nesting by handling error cases upfront, leaving the main logic unnested and easy to read. Functions that validate parameters halfway through or nest success paths inside multiple conditionals force readers to track context across many indentation levels.
Why it matters
Code readability: Guard clauses make the happy path visible at the end of the function without nesting. Readers see all error conditions upfront, then read the main logic at a single indentation level without mentally tracking multiple nested conditions.
Maintenance and modification: Adding new validation or error conditions to deeply nested code requires careful placement to avoid breaking existing logic. Guard clauses at the top allow adding new checks without touching the main logic, reducing the risk of introducing bugs.
Code examples
❌ Non-compliant:
function processPayment(user, amount) {
if (user) {
if (user.isActive) {
if (amount > 0) {
if (user.balance >= amount) {
user.balance -= amount;
return { success: true, newBalance: user.balance };
} else {
return { success: false, error: 'Insufficient funds' };
}
} else {
return { success: false, error: 'Invalid amount' };
}
} else {
return { success: false, error: 'Inactive user' };
}
} else {
return { success: false, error: 'User required' };
}
}Why it's wrong: Four levels of nesting hide the main logic (balance deduction) deep inside the function. Each error condition adds another indentation level, making the happy path hard to find and understand at a glance.
✅ Compliant:
function processPayment(user, amount) {
if (!user) {
return { success: false, error: 'User required' };
}
if (!user.isActive) {
return { success: false, error: 'Inactive user' };
}
if (amount <= 0) {
return { success: false, error: 'Invalid amount' };
}
if (user.balance < amount) {
return { success: false, error: 'Insufficient funds' };
}
user.balance -= amount;
return { success: true, newBalance: user.balance };
}
Why this matters: Guard clauses validate all preconditions with early returns, keeping the function at a single indentation level. The happy path (balance deduction) is clearly visible at the end without nesting, making the function easy to read and modify.
Conclusion
Validate inputs and handle error cases at the start of functions with guard clauses. Return early when conditions fail rather than nesting the success path. This keeps code flat, readable, and easy to modify without breaking existing logic.
.avif)
