Clean Code for Top Developers 🚀

Fernando Prieto
Huawei Developers
Published in
5 min readAug 6, 2020

--

Photo by Victor Garcia

The ultimate, top priority as a developer should be writing the best possible code. At times, good practices may mean pushing back against deadlines, client demands, management demands, and fatigue. Business conditions often set boundaries on what’s “possible” but a developer always has at least some control over the quality of what he or she writes.

With that being said, software carried out well benefits everyone in the long run — clients, users, companies, and devs. That’s why I consider it to be really important to explain some of the most valuable clean code insights that I’ve been applying throughtout my career:

Clear interface/class/function/variable names

Making meaningful distinctions is key!

One of the reasons to make a distinction is because the dev can end up having redundancy in the chosen class names, such as TeamInfo or TeamData.

Which of those terms gives you a different meaning of what you want to identify? — Neither of them. Indeed they’re called Noise words, because of this reason.

Another reason could be to avoid using number-series naming(b1,b2,b3 .. bN), because those are noninformative, which means that the reader is not going to understand the author’s intention.

Number-series naming

Coming back to the redundancy problem, another potential issue that has been highlighted is including the word variable in the variable name. (e.g. surnameString). How is surnameString better than simply surname? The fact is that surnameString is indinstinguishable from surname.

Extra point: avoid Hungarian Notation. Back in the day, when everything was an integer handler or a long pointer or a void pointer, Hungarian Notation was considered very important, because the compiler did not check types and only programmers needed something to help them remember the types.

Check out: Naming at Developer Android

Avoid Util/Helper/Manager names

Be specific!

It’s really common to find classes and objects with names like Manager, Processor, Data, Helper, Util, etc.

The first point to note is that a class name should not be a verb.

A typical example is Utility Class, also known as Helper class. It is a class, which contains only static methods; it is stateless and cannot be instantiated. It contains a bunch of related methods, so they can be reused across the application. It is a more convenient class to use, as there’s no need to instantiate them, less code and overall much simpler. However the downsides are that this class in not flexible, not mockable and not injectable.

Avoid comments by better naming

Understanding that this topic relates to a non API development, which is expected to be well documented, there are some points that will be interesting to understand:

  • TODO comments should not be acceptable. Strictly speaking, as they’re comments that relate to the future, they may or may not happen in the end. In general they are reminders, which in most of the cases can be missed (luckily Android Studio has got an option to locate those TODOs within the project). But the way the dev works is based on the present, obviously keeping the system flexible enough to make future changes and always keeping a foundation in the code base that allow other developers to refactor it easily.
  • Informative comments can be avoided by using a better function name. For example:
// Returns an instance of an EmailResponder for SMTP protocol
private fun EmailResponderInstance(): EmailResponder

Instead what could be used is a better name of the function without comments:

private fun SmtpEmailResponder(): EmailResponder
  • Clarification can be risky. Finding a complex piece of code with a clarification in a comment might look nice for the developer understanding, but is it 100% necessary? The dev should take care that there’s no better way and then take even more care that the comments are actually accurate. This could be a good example:
assertTrue(a.compareTo(a) == 0)    // a == aassertTrue(a.compareTo(b) != 0)    // a != bassertTrue(a.compareTo(b) == -1)   // a < b

Avoid indentation when possible

Indentation increases the cognitive effort. It means you need to remember more complex contextual scope.

Whenever the code starts to grow and it requires special attention in the indentation point, the developer should check whether that function does more things than it should (breaking the single responsability principle).

Having one line long blocks within any if, else, while statement (probably that line should be a function call), keep the enclosing function small and it even adds documentary value, because the function called within the block can have a nicely descriptive name.

The code still looks a bit redundant, so it potentially could be refactored and reduced massively (it’s out of this article scope).

Single responsibility

This might be the least well understood from the SOLID principles, or the worst applied in practice.

“A module should be responsible to one, and only one, actor”(the simplest definition of module is just a source file).

The single responsibility principle provides another substantial benefit. Classes, software components and microservices that have only one responsibility are much easier to explain, understand and implement than the ones that provide a solution for everything. This reduces the number of bugs, improves your development speed, and makes your life as a software developer a lot easier. That’s why it could avoid adding unnecessary comments within the code base, as the pieces of code are smaller and the understanding is good enough without them.

Keep code short

The ultimate ideal scenario is: “The developer writes the code once, but he/she will read it many times”

Keep variables immutable

Java generally isn’t explicit about immutability. While there’s the final operator that can help, it isn’t always used consistently. Given that immutable programming is often simpler and less error prone, it makes sense to get into the habit of making everything immutable, and only reverting to mutable objects when absolutely necessary.

In Kotlin, in general, seeing var in code should raise a red-flag. There are times where it’s necessary, but the majority of use cases can be refactored to be immutable.

Dependency inversion

This SOLID principle tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions.

The concept of this principle is that instead of saying that your class requires a specific object, such as a class that can only verify passwords (e.g. PasswordVerifierImpl), that you have an interface (PasswordVerifier) contract that defines how a password should be verified and then use that as a dependency.

Conclusion

Bearing in mind these metioned key points won’t only make your work easier whenever you need to refactor or making any changes from that code, but also will facilitate other developers work in code reviews and whenever they need to work on top of your code.

Sources

Clean Code — Robert C. Martin

Clean Architecture — Robert C. Martin

https://stackify.com/solid-design-principles/

https://batchofcode.com/2018/04/13/kotlin-best-practices.html#1-embrace-immutability

--

--