The Code Review That Changed Everything
My pull request sat there for three days. When feedback finally came, it was brutal: "This code is impossible to maintain." My JavaScript worked perfectly, passed all tests, but was a tangled mess of nested callbacks, cryptic variable names, and functions doing five things at once.
That humbling moment forced me to learn clean code principles. Over the next 7 parts, I'll share the practices that transformed my JavaScript from "it works" to "it's beautiful."
This 7-Part Series Covers:
- Part 1 (Today): Naming & Variables
- Part 2: Functions & Arrow Functions
- Part 3: Modern JavaScript Features
- Part 4: Async Patterns & Error Handling
- Part 5: Arrays, Loops & Immutability
- Part 6: Code Structure & Logic Flow
- Part 7: Real-World Refactoring & Tools
Let's start with the foundation: naming things properly.
What Is Clean Code?
Clean code isn't about being fancy—it's about being readable, maintainable, and obvious. Code is read 10x more than it's written.
Clean code:
- Explains itself (minimal comments needed)
- Does one thing well
- Can be understood by junior developers
- Makes bugs obvious, not subtle
- Is easy to modify 6 months later
Practice 1: Use Meaningful and Pronounceable Variable Names
The Problem: Cryptic abbreviations make code look like alphabet soup.
❌ Bad: Cryptic Names
const d = new Date();
const y = d.getFullYear();
const m = d.getMonth();
const usr = { n: 'John', a: 25, e: 'john@example.com' };
function calc(a, b, t) {
if (t === 'a') return a + b;
if (t === 's') return a - b;
if (t === 'm') return a * b;
return a / b;
}
✅ Good: Descriptive Names
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth();
const user = {
name: 'John',
age: 25,
email: 'john@example.com'
};
function calculate(firstNumber, secondNumber, operationType) {
if (operationType === 'add') return firstNumber + secondNumber;
if (operationType === 'subtract') return firstNumber - secondNumber;
if (operationType === 'multiply') return firstNumber * secondNumber;
return firstNumber / secondNumber;
}
Why It Matters: You read currentYear once and know exactly what it is. With y, you have to trace back to understand.
Pro Tip: If you can't pronounce a variable name in a code review, it's a bad name.
Practice 2: Use const and let, Never var
The Problem: var has function scope and hoisting issues that cause subtle bugs.
❌ Bad: Using var
var user = 'Alice';
if (true) {
var user = 'Bob'; // Overwrites outer user!
console.log(user); // 'Bob'
}
console.log(user); // 'Bob' - unexpected!
// Hoisting confusion
console.log(count); // undefined (not error!)
var count = 10;
✅ Good: Using const and let
const user = 'Alice'; // Can't be reassigned
if (true) {
const user = 'Bob'; // New block-scoped variable
console.log(user); // 'Bob'
}
console.log(user); // 'Alice' - as expected!
// Block scoping prevents hoisting issues
console.log(count); // ReferenceError: Cannot access before initialization
const count = 10;
Rule of Thumb:
- Use
constby default (90% of the time) - Use
letonly when you need to reassign - Never use
var
Practice 3: Avoid Magic Numbers and Strings
The Problem: Hardcoded values have no meaning and are hard to change.
❌ Bad: Magic Values
function calculateDiscount(price, userType) {
if (userType === 1) {
return price * 0.9;
} else if (userType === 2) {
return price * 0.8;
} else if (userType === 3) {
return price * 0.7;
}
return price;
}
setTimeout(() => {
console.log('Delayed');
}, 86400000); // What is this number?!
✅ Good: Named Constants
const USER_TYPES = {
REGULAR: 'REGULAR',
PREMIUM: 'PREMIUM',
VIP: 'VIP'
};
const DISCOUNTS = {
[USER_TYPES.REGULAR]: 0.10, // 10%
[USER_TYPES.PREMIUM]: 0.20, // 20%
[USER_TYPES.VIP]: 0.30 // 30%
};
function calculateDiscount(price, userType) {
const discountRate = DISCOUNTS[userType] ?? 0;
return price * (1 - discountRate);
}
// Time constants
const TIME = {
SECOND: 1000,
MINUTE: 60 * 1000,
HOUR: 60 * 60 * 1000,
DAY: 24 * 60 * 60 * 1000
};
setTimeout(() => {
console.log('Delayed');
}, TIME.DAY); // Clear what this means!
Pro Tip: Use SCREAMING_SNAKE_CASE for constants that never change.
Practice 4: Boolean Variables Should Ask Questions
The Problem: Boolean names that don't indicate true/false states.
❌ Bad: Unclear Boolean Names
const enabled = true;
const login = false;
const admin = user.role === 'admin';
✅ Good: Question-Based Names
const isEnabled = true;
const hasLoggedIn = false;
const isAdmin = user.role === 'admin';
const canEdit = user.permissions.includes('edit');
const shouldShowModal = !hasSeenWelcome && isFirstVisit;
Prefixes for Booleans:
-
is- State:isActive,isValid,isLoading -
has- Possession:hasPermission,hasChildren,hasError -
can- Ability:canEdit,canDelete,canAccess -
should- Recommendation:shouldUpdate,shouldRender
Practice 5: Use Searchable Names
The Problem: Single-letter variables are impossible to search.
❌ Bad: Single Letters
const a = ['John', 'Alice', 'Bob'];
for (let i = 0; i < a.length; i++) {
const u = a[i];
console.log(u);
}
// Try searching for "i" in a 1000-line file!
✅ Good: Searchable Names
const userNames = ['John', 'Alice', 'Bob'];
for (let index = 0; index < userNames.length; index++) {
const userName = userNames[index];
console.log(userName);
}
// Even better with array methods
userNames.forEach(userName => {
console.log(userName);
});
Exception: Loop counters in small scopes (< 10 lines) can use i, j, k.
Quick Wins Checklist for Part 1
Before moving on, refactor your code with these checks:
✅ Can I pronounce all variable names?
✅ Do I have any var declarations? (Replace with const/let)
✅ Are there magic numbers/strings? (Extract to named constants)
✅ Do boolean variables start with is/has/can/should?
✅ Can I search for my variable names? (No single letters except loops)
Part 1 Conclusion: Names Matter More Than You Think
Good naming is 50% of clean code. When you see code like this:
const usr = data.u[0];
if (usr.a > 18 && usr.s === 1) {
proc(usr);
}
You have to decode it like a cryptic puzzle. But with proper naming:
const user = userData.users[0];
if (user.age > 18 && user.status === ACTIVE) {
processUser(user);
}
The code explains itself.
Time Investment: Spend an extra 30 seconds thinking about names. Save 30 minutes debugging later.
Coming Up in Part 2: Functions & Arrow Functions 🚀
In the next article, we'll tackle:
- Writing small functions that do ONE thing
- When to use arrow functions (and when NOT to)
- Function naming conventions that self-document
- The single responsibility principle in practice
You'll learn how to transform 100-line god functions into clean, testable, 10-line masterpieces.
Did meaningful names transform your code? 👏 Give this article a clap! (You can clap up to 50 times!)
Don't miss Part 2! 🔔 Follow me to get notified when the next part drops.
Have naming conventions that work for you? 💬 Share in the comments - I read every response and love learning from the community!
Help your teammates write better code! 📤 Share this series - clean code makes everyone's job easier.
Quick Challenge: Open your current project and find 3 badly named variables. Refactor them right now. Notice how much clearer the code becomes?
Post your before/after in the comments! 🎯
This is Part 1 of the 7-part "JavaScript Clean Code Mastery" series.
Next: Part 2 - Functions & Arrow Functions
Tags: #JavaScript #CleanCode #WebDevelopment #Programming #CodingBestPractices #ES6 #Tutorial #SoftwareEngineering
Top comments (0)