Yes, it’s another article about clean code. Just a quick reminder: according to various sources, the ratio of time spent reading code versus writing it can reach 7:1 or even higher. Whether you’re fixing a bug, adding a feature, or refactoring, you inevitably submerge yourself in logic written by others (or by you, several months ago). This is why readability is far more critical than how fast you typed it out in the first place.
Unreadable code is technical debt that bottlenecks the entire team and inflates development costs in the long run. Period.
The Core Principles of Readable Code
I think it's time to realize that "clean code" isn't a silver bullet or a set of holy, unbreakable laws. Ideal code doesn't exist and cannot exist. It’s more of a philosophy-a set of recommendations to help make code understandable. Ironically, these "unbreakable laws" often lead to people failing to agree on anything, sparking endless debates and conflicting interpretations.
I don't want this to be another "proper code" summary. If you want to write purely academic code (which is impossible anyway), go ahead and read Robert Martin’s Clean Code. This article promotes rational cleanliness. Apply it where it’s actually needed-meaning, in projects that actually need to be maintained.
"The best code is stupidly readable code."
Code that doesn't force your brain to grind gears just to understand the intent. Let’s just walk through the foundation, because without this, "maintainability" isn't even part of the conversation:
-
Clear variable and function names. This has been said 1,000 times, and I’ll say it for the 1,001st. It is the absolute base. A name must reveal intent. If you see a variable named
dorlist1, you’ll have to go hunting through God-knows-where or dive deep into the implementation just to figure out what it is. If it’s calledelapsedTimeInDaysoractiveUsers, the questions disappear. -
Single Responsibility Principle (SRP). A function should do one thing and do it well. When you see a
handleUserDatafunction that fetches form data, validates it, saves it to the database, and sends an email-that’s a red flag. I could tell you to split it intovalidateForm,saveUserToDatabase, andsendWelcomeEmail, but the fact that you had one function doing all that in the first place is the real alarm bell. If you’re stuck with a massive monolith, this is at least a baseline for readability. - Consistent Coding Style. It doesn't really matter if you use tabs or spaces (though tabs take up less memory, but who cares?), or where you put the curly brace. What matters is that the whole team does it the same way. At the very least, try not to write in different paradigms yourself while in a "drunken stupor" working on a microservice meant to handle 1,000,000 RPS. Inconsistent style creates visual noise. Luckily, linters and formatters solved this ages ago. Set them up once and let the robots handle the style.
What? Code Review?
Code review isn't about finger-pointing; it’s one of the most effective tools for collective growth. To keep the review systematic, keep a checklist in mind:
Logic: Does it solve the task? Are edge cases handled?
Readability: Are the names clear? Is the structure too complex?
Architecture: Does it follow the project patterns? Is it extendable?
Tests: Are there tests? Do they cover the "happy path" and the alternatives?
Let the robots work. Humans are inconsistent. Routine checks for duplication, potential bugs, and vulnerabilities should be delegated to automation. Tools like SonarQube built into your CI/CD pipeline will catch 90% of typical issues before a human even sees them.
Focus on teaching, not critiquing. Instead of a directive "Fix this," use dialogue: "What if we tried this approach? I think it might simplify maintenance later." We need to be kinder to our colleagues—and everyone else. The world lacks kindness.
Patterns and Anti-patterns: Explained with Cats
In programming, as in living with cats, there are elegant solutions and there are weird, tangled messes. Some will say, "Meh, this is just a Clean Code summary!" Well, no. I’m calling you to do what’s necessary here and now. If you apply the things below, your future self will thank you.
1. Deep Nesting (Arrow Code)
Imagine your cat wants to relax and get to some catnip. But the path is treacherous.
The Anti-pattern:
if (catWantsToPlay) {
if (isLivingRoom) {
if (blanketOnCouch) {
if (boxUnderBlanket) {
if (catnipInBox) {
// Success, the cat is high!
}
}
}
}
}
This is a pyramid of indents. You have to hold the entire chain in your head.
The "Early Return" Pattern (Guard Clauses):
if (!catWantsToPlay) return;
if (!isLivingRoom) return;
if (!blanketOnCouch) return;
if (!boxUnderBlanket) return;
if (!catnipInBox) return;
// Success, the cat is high!
The code becomes flat and clear-like a cat's direct path to the goal.
2. Mystery Cat Behavior
What if your cat’s behavior is described by numbers?
The Anti-pattern:
if (catState === 1) {
// Pet
} else if (catState === 2) {
// Feed
} else if (catState === 3) {
// Don't touch, the cat is dead
}
What do 1, 2, and 3 mean? These are Magic Numbers. Today you remember, but in a month you'll be digging through documentation (if it even exists...) to decode this message.
The "Named Constants" Pattern:
const STATE_PURRING = 1;
const STATE_HUNGRY = 2;
const STATE_DEAD = 3;
if (catState === STATE_PURRING) {
// Pet
} else if (catState === STATE_HUNGRY) {
// Feed
} else if (catState === STATE_DEAD) {
// Don't touch
}
3. Feeding Two Identical Cats
The Anti-pattern (Copy-Paste):
// Feed Barsik
putInBowl("Barsik", "kibble");
pourInBowl("Barsik", "water");
callCat("Barsik");
// Feed Murzik
putInBowl("Murzik", "kibble");
pourInBowl("Murzik", "water");
callCat("Murzik");
If you add vitamins, you have to change it in two places. If you have ten cats, you will forget one.
The Better Way (DRY):
function feedCat(catName) {
putInBowl(catName, "kibble");
pourInBowl(catName, "water");
callCat(catName);
}
feedCat("Barsik");
feedCat("Murzik");
But please, DO NOT DO THIS WITH DIFFERENT USE CASES! That’s an anti-pattern called "Service Hell." Every use case should be isolated. Otherwise, an error in one place will cause a mysterious crash in another.
Readable Code and Documentation
Good code is self-documenting. But comments are still needed to explain why. If you used a weird workaround for a bug in an external library, leave a link. Otherwise, you’ll get a surprise "prod is down" call on a Friday night. But think before you write: code gets updated, but people are often afraid to touch old comments. Don't overdo it.
Practical Tips
Micro-refactorings. See a bad name? Change it. A function that does everything? Break it up—but into logical blocks, not 3,000 tiny pieces. Leave the code cleaner than you found it. It’s like picking up someone else's trash while staying in your seat.
Pair Programming. Real-time review. A great way to share knowledge or debate the speed of QuickSort vs MergeSort.
Internal Guides. Agree on rules and stick to them. Actually look at them once in a while, or they're useless.
Pragmatism Above All
Readable code speeds up development. Fact. But as we’ve already discussed, "clean code" is not a panacea. Everyone will still fight over what "clean" means anyway. Don't blindly follow Martin if the task doesn't require it. If you’re writing a one-off migration script or a prototype that’s getting tossed tomorrow, spending hours on architecture is counterproductive. Context is everything.
The worst thing you can do is mindlessly apply complex patterns where a simple solution works. Three weeks later, you have a monster that takes longer to start than it does to run. It solves a problem that never existed.
The goal isn't to write clean code for the sake of cleanliness; it's to write maintainable code where it actually matters. Find the balance, think about the future of your project, and always keep learning. (And one more thing: never collaborate with dictatorships. The restrictions and systems you build are exactly what allow them to feel comfortable and wage wars.)
I'm done. Good luck!


Top comments (0)