The Aesthetics of Readable Code
Is Shorter Code Better?
Although reducing code size can improve readability, shortening the time it takes to comprehend the code is what really matters.
Surface-Level Improvements
- Clear naming for methods and variables
- Methods don’t need words like
do - Avoid ambiguous terms when choosing vocabulary, e.g.,
popvs.popItem - Pack more information into method names
- Methods don’t need words like
function getPage() {}
// 對方可能不知道 getPage 的實作方式?爬蟲? ajax?
function fetchPage() {}
// 可能比較清楚是用 ajax 的方式並且回傳 json。
- Find more specific and precise words
- send => deliver, dispatch, announce, route
- find => search, extract, locate, recover
- start => launch, create, begin, open
- make => create, setup, build, generate, add, new, compose
Clarity and precision are more important than being cute
-
Even for
tmpvariables, you can provide a bit more context.- tmpNumber
- tmpFile
- tmpUsrData
-
If loop iterators like
iandjcarry meaning, give them appropriate names, e.g.,row,col,index. -
Choose concrete method names.
-
If a variable represents a measurement with units, include the unit in the name.
- startSec
- delayMs
-
Naming variables with important attributes
- plainData
- entryptedData
-
When a variable’s scope is large, choosing a longer (or more informative) name is better. Conversely, if its scope spans only a few lines and anyone can instantly tell what it does, using a short
aliasis totally fine.
Names That Can’t Be Misunderstood
- Does
filterfilter things out, or keep them? - Using
minandmaxprefixes - Booleans
computeData=> implies running a computationally expensive function
Consistent Formatting
- Maintain consistent formatting
- Make similar code look similar
- Group related code into blocks/paragraphs
- The aesthetics of comments
Why is formatting so important? First, it makes it easier (and more inviting) for others—or future you—to read the code. Second, you spend much less time trying to figure out what your code is doing. Win-win!
Code Quality Tools
-
eslint
-
stylelint
Eliminating Clutter with Methods?
Whenever you feel a task is getting messy or chaotic, it’s time to wrap it in a method.
Deceiving consumers with fancy packaging is human nature (just kidding). Whether you can fool others isn’t the point; what matters is whether you can fool yourself. If you don’t even respect your own code, no one else will.
For example:
assert(checkTime("12:00")) === "12:00"
assert(checkName("kalan", 20)) === { name: "kalan", age: 20 }
assert(checkPaid(20000, true)) === 20000
Looking closely at the code above, it’s not hard to see that they are all doing similar things, with several repeated strings. Moreover, it’s overly verbose—it takes a moment to decipher what these lines are actually doing.
This is when refactoring is needed; we can wrap it in a method.
function checkValue(type, value) {
if (type === "time") {
assert(checkTime(value));
}
if (type === "name") {
assert(checkName(value) === value;
}
if (type === "paid") {
assert(checkPaid(value)) === value;
}
}
// checkValue(type, value);
// [string] [depend]
checkValue("name", kalan);
checkValue("time", 12:00);
checkValue("paid", 20000);
This way, the code becomes much cleaner, and readability improves significantly! Once again, shorter code isn’t inherently good code; code that is easy to understand is good code. Beyond this, there are other benefits:
- Clearly highlights what is being tested.
- Makes it much easier to add new tests!
Break Down by Order and Paragraphs
Long, unbroken walls of code are something neither others nor you will want to look at. When declaring variables or writing statements, break them up based on their behavior or role. It’s the same reason we use paragraphs in writing.
function getUserInfo(userName, age) {}
getUserInfo("kalan", 20)
// getUserInfo(userName, age)
// [string] [number]
getUserInfo("kalan", 20)
If there are repeated function calls, aligning parameters can make them much easier to scan.
command = {
{ "timeout" , null, cmd_spec_timeout},
{ "timestamping" , bull, cmd_adj_boolean},
f
}
When writing comments, don’t overthink it. Just write down your train of thought at the time and what the function is supposed to do. Sometimes, after a while, you’ll forget what that function was even for.
—
2. Comments
Comments exist to help others understand the developer’s intent—and to remind your future self of what you were thinking at the time.
- How to write good comments, and what doesn’t need comments.
- What not to comment on
- Put yourself in the reader’s shoes
Don’t let comments substitute for what the code itself should convey
Avoid the resistance to writing comments. This usually takes some experience to appreciate, but writing comments early before the project architecture becomes complex is definitely a good habit. Otherwise, you’ll end up writing that guilty
// TODO: refactor
and never touch it again.
Summary
- Reasons for choosing a specific implementation
- Known flaws or shortcomings in the code
- Parts that might confuse a reader
Keep Comments Concise
- Describe your code precisely, and avoid using ambiguous pronouns for parameters.
- If parameter behavior is complex, provide concrete examples to make it immediately clear.
3. Control Flow
The most common case is if/else branches. The book suggests a guideline: put positive conditions first, and handle the simpler cases first.
If your function/method returns a value, return as early as possible!
- Make good use of De Morgan’s laws: Anyone with a STEM background probably remembers this! It helps simplify complex logical expressions.
Battling Complex Logic
The book mentions an interesting approach that I’d like to note down.
When implementing a range, we might have an overlapWith method to check whether two ranges overlap. Rather than directly checking if the two ranges overlap, it is often simpler to check if they do not overlap. This is because there are only two non-overlapping conditions: either other’s end comes before this range’s start, or other’s start comes after this range’s end.
Break Down Giant Expressions with Variables
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
// refactor
const $thumbUp = $(".thumb_up")
const highLight = "highlighted"
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
$(".thumb_up").removeClass("highlighted")
//
4. Variables
The longer a variable persists, the harder it is to debug
- Eliminate unnecessary variable declarations.
What qualifies as an unnecessary variable?
- It doesn’t make the code’s meaning clearer or more concise.
- The underlying logic is already simple enough that a separate variable adds no value.
- It is only used once.
- Prefer write-once variables
In functional programming, we prefer functions to be pure and data to be immutable. The same applies to variables—try to make them const or immutable. This not only makes the function easier to understand at a glance, but also makes it much easier to pinpoint bugs.
Turning Thoughts into Code
Describe the intended behavior in plain language first, then translate that behavior into code. This helps developers write more natural and intuitive code.
Avoid Writing Unnecessary Code
- Understand the actual requirements
- Re-examine and question requirements
- Regularly read API documentation to stay familiar with standard libraries
Related Posts
- Dale Carnegie's How to Win Friends and Influence People This book is an absolute classic, and after putting it off for a long time, I finally finished it. The core philosophy of the book essentially boils down to turning yourself into an altruist.
- Outliers by Malcolm Gladwell My thoughts after reading Outliers
- So Good They Can't Ignore You by Cal Newport Passion is overly romanticized. The book opens with Steve Jobs's commencement speech, pointing out that what Jobs actually did was quite different from what he preached. I believe passion shouldn't be something you're expected to force out of thin air; rather, it develops naturally through the process of doing something. You might have a passion for XYZ, but the world usually doesn't care about your passion—it cares about your output.
- Review of MIT OpenCourseWare: Introduction to Computational Thinking with Julia The course might seem eclectic at first glance, covering data science, climate change modeling, ray tracing, PDEs, statistics, and image processing...