A practical guide to writing readable, maintainable code — from naming conventions to function design, inspired by Robert C. Martin's Clean Code.
Code is read far more often than it is written. Studies suggest developers spend 10x more time reading code than writing it. Clean code isn't a luxury — it's the foundation of a sustainable codebase.
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." — Martin Fowler
Names should reveal intent. If a name requires a comment to explain it, rename it.
// Bad
const d = 86400; // seconds in a day
const u = getUser(1);
// Good
const SECONDS_IN_A_DAY = 86400;
const currentUser = getUserById(1);
Rules of thumb:
userList, orderTotal)fetchUser, calculateTax)isActive, hasPermission)usr, cnt, tmpThe Single Responsibility Principle applied to functions: a function should do one thing, do it well, and do it only.
// Bad — does too much
async function processOrder(orderId) {
const order = await db.orders.findById(orderId);
order.total = order.items.reduce((sum, item) => sum + item.price, 0);
await db.orders.update(orderId, order);
await emailService.send(order.userEmail, 'Order confirmed');
await analyticsService.track('order_processed', { orderId });
}
// Good — each function does one thing
async function processOrder(orderId) {
const order = await fetchOrder(orderId);
const updatedOrder = calculateOrderTotal(order);
await saveOrder(updatedOrder);
await notifyUser(updatedOrder);
await trackOrderEvent(orderId);
}
A comment that explains what code does is usually a sign that the code needs to be rewritten. A comment that explains why is often invaluable.
// Bad — the code already says this
// Loop through users
for (const user of users) { ... }
// Good — explains non-obvious reasoning
// Using a 400ms debounce to avoid hammering the search API
// while the user is still typing (measured optimal UX delay)
const debouncedSearch = debounce(search, 400);
Every piece of knowledge should have a single, authoritative representation in the system. Duplication leads to bugs — fix it in one place, forget to fix it in three others.
// Bad — validation duplicated in two places
function createUser(email) {
if (!email.includes('@')) throw new Error('Invalid email');
// ...
}
function updateUser(email) {
if (!email.includes('@')) throw new Error('Invalid email');
// ...
}
// Good
function validateEmail(email) {
if (!email.includes('@')) throw new Error('Invalid email');
}
function createUser(email) { validateEmail(email); /* ... */ }
function updateUser(email) { validateEmail(email); /* ... */ }
"Always leave the code better than you found it."
You don't need a refactoring sprint. Every time you touch a file, make one small improvement: rename a confusing variable, extract a long function, delete a dead comment. Over time, these micro-improvements compound into a dramatically cleaner codebase.