The Refactoring That Made Everything Worse
I had a working 50-line function. Then I read Clean Code and split it into 9 tiny functions across 3 files. My teammate’s review: “What the hell did you do? This used to be simple.”
I’d followed the rules. But I’d made the code worse.
Principles That Actually Matter
1. Code Should Tell a Story
// Good: Explains what's happening
function calculatePrice(quantity, unitPrice) {
const basePrice = quantity * unitPrice;
const priceAfterDiscount = basePrice * 0.8;
if (priceAfterDiscount > 100) {
return priceAfterDiscount * 0.9; // Bulk discount
}
return priceAfterDiscount;
}
2. Names Should Reveal Intent - activeUsers > au. But don’t go crazy: arrayOfActiveUserObjectsThatAreCurrentlyLoggedIn is worse than activeUsers.
3. Functions Should Do One Thing - Getting a user profile IS one thing, even if it requires multiple database calls.
4. Comment the WHY, Not the WHAT
// Good: Explains business logic
function calculateDiscount(user, cart) {
// Per marketing: Loyal customers (>10 orders) get 15% off
if (user.orderCount > 10) return 0.15;
if (user.orderCount === 0) return 0.10;
return 0;
}
Bad: const total = price * quantity; // Multiply price by quantity (obvious)
5. Don’t Duplicate Prematurely - Wait until code is needed 3+ times. First time: write it. Second time: wince but duplicate. Third time: refactor.
6. Small Functions Are Good, NOT at All Costs - A 10-line function in one place beats 4 functions of 2 lines each scattered across files.
7. Use Constants for Magic Numbers
const VOTING_AGE = 18;
if (age >= VOTING_AGE) { /* ... */ }
But: const ZERO = 0 in a loop is overkill.
8. Handle Errors Properly - Don’t swallow them. Log, throw, or return errors explicitly.
9. Keep It Simple (KISS) - Fancy patterns are fun. Simple code is maintainable code.
10. Consistency > Perfection - Follow your team’s patterns, even if you don’t like them.
Real Examples
Over-engineered API client:
// 50+ lines of class, interceptors, builders
class ApiClient { /* ... */ }
// Pragmatic version: 10 lines
async function apiRequest(endpoint, options = {}) {
const response = await fetch(API_BASE_URL + endpoint, {
...options,
headers: { 'Authorization': `Bearer ${getToken()}`, ...options.headers }
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
return response.json();
}
Same result. 80% less code.
When to Break the Rules
- Performance matters
- Clarity suffers
- Team disagrees
- Premature abstraction hurts readability
- Shipping working code > perfect code
The Real Goal
Can the next developer understand and modify this code easily?
That’s it. Not line counts. Not design patterns. Not whether you used a trendy framework.
Clean Code Checklist
- Can someone unfamiliar understand this in 5 minutes?
- Are names clear?
- Are functions focused (without obsessive extraction)?
- Is complex logic commented?
- Are errors handled?
- Is it consistent with the codebase?
Write code for humans first, compilers second.
Perfect is the enemy of shipped.
Clean code is a tool, not a religion. Use judgment. Ship code that works. Make it better over time.
That’s real clean code.