Clean Code Session 2: Naming, Methods & Formatting


Hello everybody, once again we are on the topic of clean code and how to begin writing beautiful code. In the previous article – Clean Code Session 1: Bad Code & Motivation – I explained my motivation why keeping your code clean is vital and what you need to re-think in order to begin looking at your code as a piece of art, not simply a list of machine instructions.

In this article we are going to have a look over the first bunch practical tips and tricks I have gained through the years (in the usual circle – daily practice, book reading, daily practice and so on) and which I think are crucial for everybody who writes code. So, let’s get straight to the point and go ahead with what you need to do in order to make your code clean, well structured and…simply beautiful.

Proper naming

We can definitely state that programming is 50% naming – we name everything you can think of – files, directories, classes, methods, variables, namespaces, etc. So, you can imagine it is essential that we do name all entities throughout our code correctly, so that the person reading the code after us can grasp what we wanted to do. So, always use intention-revealing names – give that variable a name which answers the questions why it exists, what it does and how it is used. Furthermore, pay attention not to accidentally provide disinformation or no information whatsoever. If you name a variable, e.g. hp, what does this stand for? Hypotenuse, horsepower, an instance of a class called Company which you have created to store information about Hewlett-Packard? I believe you already got my point. Also, never obscure a data structure type in the variable name – if you have a map of properties, don’t declare a variable propertiesList to hold it – this is truly misleading, since the structure is a map, not a list.

Keep in mind that all entities throughout your code should bear pronounceable names – otherwise the future discussion will be really tough and you and your partner may waste time tying your tongues. Avoid using encoded characters as well, although today’s programming languages and compilers allow that – it may happen once in a while, but your code will break. Furthermore, visually, can you make the difference between Latin small letter e (U+0065) and Cyrillic small letter е (U+0435)? I believe you cannot. Also, avoid using general entity prefixes for all the entities in your code – this will slow down the reader (if your project bears the name “Smart Home System”, declaring e.g. a class such as SHSUser just makes it necessary for the reader to remove the “SHS” prefix every time he/she wants to read an entity name).

Try to stick to a single word per logical concept. What this means is that, if you have decided all your getter methods to begin with the word “get”, apply this convention for the whole project and don’t arbitrary use e.g. “fetch”, “retrieve” or other synonyms. However, although this approach is pretty good for consistency, always keep in mind that semantics is more important and has greater impact on your code than consistency! If, for example, at a certain place it makes more sense and is suitable to use “insert” instead of “add” (although the whole project already makes use of the word “add” for this action), change it bravely!

And finally, never use humor, jokes, slang or uncensored words – you can always forget to remove these and they can easily reach production code. I once tried to system-out some test strings with the text “Alex is cool!” and, admittedly, had forgotten to delete them. Somehow, none of my colleagues proved to be eagle-eyed as well and you can image my gazing face when I saw “Alex is cool!” on the screen during the (thankfully) internal demo. So don’t purposely put the shame on you!

Perfect methods

We all know nothing in this world can be perfect, but our methods at least should be, because they are the moving parts of our code. So, since the main goal of methods is to eradicate code duplication, they should be small, properly named and do only one thing. It is recommended that methods are no more than 20 lines of code long and do not accommodate more than two nested constructs inside them (so, two nested if-statements and that’s it). You may now be wondering why it is so important for methods to be of such small size? Well, we said it is a must that methods have a single responsibility and do one thing, so that they are focused and tight. In order to make them do one thing, we need to limit their length, so, if a method is too long, it must be fragmented into several smaller methods. It is a good practice to declare a public caller method which consecutively calls the separated smaller private methods. Considering method naming – I am pretty sure you got this in the previous point. Anyway, never forget that, considering a function’s length, name and actions it performs, you should always remember that a method must do something or answer something, but never both at the same time!

// A simple example showing several private methods
// via which the initializeDevice(String deviceID) method
// logic is separated, thus making it much more readable
// and doing one thing - initializing the device, not doing
// updates of different device features.

public void initializeDevice(String deviceID) {
    updateDeviceInfo(new DeviceInfo(deviceID));
    updateDeviceLEDState(LED_STATE_ON);
    updateDeviceStatus(STATUS_ONLINE)
}

private void updateDeviceInfo (DeviceInfo deviceInfo) {
    // logic for device info update
}

private void updateDeviceLEDState(String ledState) {
    // logic for device led state update
}

private void updateDeviceStatus(String status) {
    // logic for device status update
}

Something else that is important to know about methods is that it is a good practice they have as little parameters, respectively arguments, as possible, for clarity and readability at least. If you pass one argument to a method, think twice if you are modifying and then returning the same argument as an output of the function. The only thing a method should modify is a class instance variable and, in such case, why passing an argument, modifying it and returning it, when you can simply use the this keyword to refer the instance variable? Two arguments and more is not a good practice at all besides the case in which the two arguments are homogeneous values of a single entity – width and height of resolution for example, or x and y coordinates of a point.

Maybe you are now asking yourself – okay, but what if I cannot go without these exact five parameters? Well, such a big number of parameters needed for your method designates that you have to create a separate class, declare all of these as its instance variables and pass an instance of this class as a single argument to your method. Simple as that! And one more thing as well – never ever pass or return null value! By doing so, you only accumulate more work for yourself, because you have to always check if an argument value is null, or you have to always check if the method’s return value is null when calling it. The result when you somehow forget to do these checks – our beloved NullPointer Exception.

And while we are on the topic of exceptions, prefer throwing exceptions rather than using error codes. By exploiting error codes thrown by a method, you automatically force the caller method to always be ready for error code handling. So, why not just make use of the straightforward error handling flow exceptions provide us with?

Finally, when writing methods, always pay attention for unexpected side effects, or, in other words, if your function is implicitly modifying class field it should not touch whatsoever. Also, your function must be structured in such a way it is open for extension but closed for modification. A quick example – if you have a method which checks if a string contains only letters, when you decide to extend the method to check if the string contains only Cyrillic letters, you should be able to do this without modifying the already written function code.

Proper comments

It is a well-known fact commenting is good – it clarifies the intentions of the developer who wrote a piece code. That’s fine, but if we use comments extensively, they can become uncontrollable, because a comment’s aim is to clarify, not to explain! So, there is nothing worse than a badly written comment and you have better write self-documenting code instead of sloppy, long, meaningless comments. Which do you prefer is a better approach – having this?

// check if the device can be reached
if (device.status != null && device.status.equals(STATUS_ONLINE) && device.allPropertiesSet())

Or just supply the class for the device instance with a method isReachable() and just do this?

if (device.isReachable())

Evan a really long but meaningful name is always better than a comment. However, you should keep in mind license and authorship comments must be present in your project and you should always put them in the top-most part of the files (respectively classes). Also, don’t let yourself leave many TODOs here and there, because TODOs are good only if you depend on some external factor – a colleague committing his or her changes shortly, a third-party API being provided in the future, or a feature being finished in a few days. However, writing TODO just for yourself means you are delaying your work and – we already mentioned it – later equals never.

To finish our piece of advice for commenting, always delete commented-out code – it reduces readability and why do you need it at ll? We’ve got source control systems, you can always revert and check what the code used to look like. Also, when commenting, never give global information locally – if, for example, the piece of information you want to specify is applicable for the whole class, don’t put it in one of the getter methods.

Correct Formatting

I will go short here – formatting equals communication. Formatting is your beautiful handwriting for the next person to read your code. During the project development, your code may change a number of times together with the functionalities and requirements, but formatting is forever. Statistically, it is proved that successful projects fit in the following limits, so pay attention to the numbers:

  • Each file is around 200 lines long and is no longer than 500 lines.
  • Each line of every file is no more than 120 characters long.
  • Your project consists of no more than 50 000 files in total.

Furthermore, you may be wondering how often and where to use blank lines? Take the following approach: one line of code is equal to on expression, one clause. A few lines (expressions) represent one thought and thoughts must be separated with a blank line (as you actually do when you speak – you make logical pauses between your thoughts). Cool, huh? However, once again, always think of the context and don’t get too far with empty lines, because sometimes two thoughts should be said together, right? So, always think!

It is advisable that concepts that share the same or close logic should be located so that they  are neighbors in your code. Also, variables must be declared as close to their initial usage as possible, while similar methods should be grouped together (e.g. a public caller and all the private methods it calls afterwards, structured in an alphabetical order).

Avoid long chains of method calls – these are nasty long statements like the following:

final String thingStatus = handler.getThing().getProperties().get("status");

Also known as “train wrecks”, these expressions can sometimes be really long, so you’d better split them (every next method call to be assigned to a new variable) or, at least, put a new line for every call.

final String thingStatus = handler.getThing()
.getProperties()
.get("status");
// Or even better
Thing thing = handler.getThing();
List<String> properties = thing.getProperties();
String thingStatus = properties.get("status");

All in all, do not forget that formatting style is a decision of the team! All of the mentioned practical tips and tricks are good to follow, but if your team has decided to, e.g. use a blank line before every return statement, you have to comply with this. Team rules considering formatting are always a first priority!

So, this is it for now – you already know the basics of clean code – how to name the entities properly, how to format them, when to add comments and what the real aim of methods is. See you in the next clean code session!


If you find yourself looking for extended information considering clean code, it is recommended that you have a deeper look over the following book, which has served as one of the main motivational sources for summing up the information given above: Clean Code: A Handbook of Agile Software Craftsmanship, Robert C. Martin, ISBN-13: 978-0132350884.

Alex

Leave a comment

Your email address will not be published. Required fields are marked *