Clean Code Tip 3: Write understandable code

Readable code alone does not guarantee comprehension. Consider the following example:
incomeTax = calculateTax(income)
The code above is highly readable and appears clean. However, do we truly understand it? For instance, the units of income and incomeTax are not specified. This lack of clarity prevents complete understanding. To achieve fully understandable code, every detail must be explicit so that the reader has no uncertainties. Let’s revise the previous example to enhance its clarity:
incomeTaxDollars = calculateTax(incomeDollars)
Unclear code is often the result of poor naming for things like variables, functions, and their parameters. If these names are not completely clear, it becomes hard to fully understand the code. You need to understand the code well before making changes, because changing code you don’t fully understand can be risky.
If you want your code to be easy to understand, focus on making it self-documenting. This means your code should be clear on its own, without needing extra comments. When you do use comments, they should explain why something is done, not just what is happening. Here’s an example of code that isn’t self-documenting because it needs a comment to explain it:
incomeTax = calculateTax(income) // income must be in dollars
However, the below version is self-documenting code:
incomeTaxDollars = calculateTax(incomeDollars)
Some practitioners argue that code with fewer, longer functions is preferable, as it reduces indirection and is therefore easier to read. Indirection, in this context, refers to the process of navigating between a function caller and its corresponding called function. Frequent navigation of this kind is said to hinder code readability. However, when code is structured with clear and understandable abstractions, such navigation becomes unnecessary. Clean code enables readers to comprehend and trust abstractions without examining their implementation details. Although code may appear to contain significant indirection, in practice, this is minimal. Accessing the implementation of an abstraction is typically required only in two scenarios: when a bug is suspected in the abstraction, or when a modification to the implementation is necessary. In well-maintained codebases, bugs are infrequent, and adherence to the open-closed principle further reduces the need for changes to existing implementations. The open-closed principle will be discussed in a subsequent section.
Consider the following Java example that demonstrates a payroll service:
class Payroll {
// ...
void pay(final Employee employee, final double amountDollars) {
// ...
final var incomeTaxDollars =
incomeTaxCalculator.calculateIncomeTax(amountDollars)
// ...
}
}
In the example above, when reviewing the code within the pay method and encountering the call to the calculateIncomeTax method, it is unnecessary to examine the internal logic of calculateIncomeTax. The abstraction should be trusted to accurately compute the income tax amount. The implementation of calculateIncomeTax should only be reviewed if a defect is suspected or modifications are required. Confidence in the correctness of the abstraction arises from thorough testing. A comprehensive suite of unit tests should exist for the calculateIncomeTax method, ensuring that all scenarios are covered and that the function returns correct values for all possible inputs.
In some cases, achieving highly understandable code necessitates the use of lengthy variable or function names. However, such long names can impede readability, as they require more time to process. It is often not possible to maximize both readability and understandability simultaneously. Therefore, a compromise is required: selecting shorter names may enhance readability at the expense of some clarity, while longer, more descriptive names may improve understanding but reduce readability.
Understandability, particularly the metric of time-to-understand, serves as a primary indicator of code clarity. A reduced time-to-understand corresponds to cleaner code.
If you are interested in reading more about clean code, grab yourself a copy of my 140 Tips For Clean Code booklet.




