The Art of the Silent Codebase: When to Speak and When to Code
Every developer has seen it: a helpful comment that lies. The code was refactored, the comment remained, and now it actively misleads the next engineer. The root cause is a fundamental truth comments and code live separate lives. When you change code, you rarely remember to update the comment. Over time, this creates a silent swamp of outdated, even dangerous, documentation.
The solution isn’t to ban comments. It’s to treat them as the exception, not the rule. By writing self explanatory code, you eliminate the need for most comments entirely. Your code becomes the single source of truth clean, expressive, and impossible to go out of sync.
In this article, we’ll explore how to write professional, self‑documenting JavaScript. You’ll see concrete examples that make comments redundant and learn patterns that keep your codebase maintainable.
The Cost of Comment‑Dependent Code
Consider this typical snippet:
// Calculate total with tax
// tax rate is 0.08 (8%)
// apply discount if total > 100
function calc(cart) {
let total = 0;
for (let i = 0; i < cart.length; i++) {
total += cart[i].price * cart[i].quantity;
}
// apply discount
if (total > 100) {
total = total * 0.9;
}
// add tax
total = total * 1.08;
return total;
}At first glance, the comments seem helpful. But what happens when the discount logic changes to a tiered system? Or the tax rate becomes dynamic? The comments will almost certainly stay as they are, creating a trap for anyone who trusts them. Worse, the code itself is noisy with boilerplate and magic numbers.
Now let’s rewrite it without a single explanatory comment, using only expressive naming and structure.
Self Explanatory Code in Action
1. Use Descriptive Names
Names are the most powerful tool for self‑documentation. A well‑chosen function or variable name tells you what and why.
const TAX_RATE = 0.08;
const DISCOUNT_THRESHOLD = 100;
const DISCOUNT_RATE = 0.9;
function calculateCartTotalAfterDiscountAndTax(cart) {
const subtotal = calculateSubtotal(cart);
const discountedTotal = applyDiscount(subtotal);
return addTax(discountedTotal);
}
function calculateSubtotal(cart) {
return cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
function applyDiscount(amount) {
return amount > DISCOUNT_THRESHOLD ? amount * DISCOUNT_RATE : amount;
}
function addTax(amount) {
return amount * (1 + TAX_RATE);
}What changed?
- No comments needed. The function names (calculateSubtotal, applyDiscount, addTax) are mini‑documents.
- Constants replace magic numbers.
- Each function does one thing and has a clear, testable boundary.
2. Embrace Small, Pure Functions
When a function does only one thing and its name describes that thing perfectly, comments become unnecessary.
// Needs a comment
// check if user has permission to edit this document
function canEdit(user, doc) {
return user.role === 'admin' || doc.ownerId === user.id;
}
// Self‑explanatory
function isAdmin(user) {
return user.role === 'admin';
}
function isOwner(user, doc) {
return doc.ownerId === user.id;
}
function canEditDocument(user, doc) {
return isAdmin(user) || isOwner(user, doc);
}
Now the code reads like a story. You don’t need a comment to understand the permission logic the function names and composition tell you everything.
3. Use Modern JavaScript to Express Intent
Destructuring, default parameters, and object shorthand can turn cryptic code into clear declarations.
// Before: comment needed to explain what's happening
function createUser(data) {
// extract first and last name from the full name
const fullName = data.fullName.split(' ');
const firstName = fullName[0];
const lastName = fullName[1];
// default role to 'user'
const role = data.role || 'user';
return { firstName, lastName, role };
}
// After: self‑explanatory with modern syntax
function createUser({ fullName, role = 'user' }) {
const [firstName, lastName] = fullName.split(' ');
return { firstName, lastName, role };
}The destructured parameter makes it obvious what inputs are expected. The default value for role is right where you need it. The code is compact yet perfectly clear.
4. Avoid “What” Comments Let the Code Speak
Comments that restate what the code does are noise. The code itself can and should—do that.
// Redundant "what" comments
// loop through products
for (let i = 0; i < products.length; i++) {
// add to total
total += products[i].price;
}
// Code that needs no explanation
const totalPrice = products.reduce((sum, product) => sum + product.price, 0);When you use higher‑order functions like reduce, map, or filter, the intent is embedded in the method name. You no longer need comments to explain iteration.
5. Use Meaningful Constants for Business Logic
Magic numbers are a common source of “what” comments. Turn them into named constants.
// Cryptic
if (user.points > 1000 && user.purchases > 5) {
user.tier = 'gold';
}
// Self‑explaining
const GOLD_TIER_MIN_POINTS = 1000;
const GOLD_TIER_MIN_PURCHASES = 5;
function isEligibleForGoldTier(user) {
return user.points >= GOLD_TIER_MIN_POINTS &&
user.purchases >= GOLD_TIER_MIN_PURCHASES;
}
if (isEligibleForGoldTier(user)) {
user.tier = 'gold';
}Now the condition reads like a business rule. Any future change to the threshold is isolated to the constant, and the function name tells you exactly what’s being checked.
When Do You Use Comments?
Self‑explanatory code doesn’t mean never write comments. It means using comments for things code cannot express:
- Why a certain approach was taken (a trade‑off, a workaround for a bug in a dependency).
- Complex business rules that are not obvious from the code alone.
- Public API documentation (JSDoc) to describe parameters and return types, especially in libraries.
Example of a good comment:
/**
* Fetches user data with retry logic.
* Why: The external user service is unreliable and may fail with 5xx errors.
* We retry up to 3 times with exponential backoff to increase reliability.
*/
async function fetchUserWithRetry(userId) {
// implementation...
}
Conclusion
Comments are not evil, but they are a liability when used as a crutch for unclear code. Every time you write a comment, ask yourself: Can I rewrite the code so this comment becomes unnecessary?
Professional engineers know that code is read far more often than it is written. By investing in self‑explanatory code clear names, small functions, meaningful constants, and expressive modern syntax you build a codebase that is a joy to read, safe to change, and immune to the silent rot of outdated comments.
The next time you’re about to add a comment, let the code speak for itself. Your future self (and your teammates) will thank you.
Happy coding, and may your code always be its own best documentation.

Comments
No approved comments yet.