Pages

Clean Code Series #2 - Naming

 


Part 2 - Meaningful Names


Continuing in the amazing world of the concepts of software design, organized in the book written by Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, let's talk about some topics related to names.


Thoughtfully Naming

You, as the storyteller of your solution, must have the proposal to care about code. That means you must define meaningful names to represent your variables, classes, and modules.

As Grady Booch said in his book, Object-Oriented Analysis, and Design for Applications:

   "clean code is simple and direct. clean code reads like well-written prose"


Reveal your Intent

Classes, methods, variables, properties, and many other parts of the code are identified using names. All of these elements must reveal their respective intents by themselves.

As Uncle Bob said:

"if you need to put a comment that describes the name, then it's a bad name"

and
"If you must read the code in order to understand the name, it's a bad name"
 
In other words, the code must be self-described. Check this example:
    
int d; // elapsed time in days
      
The variable d doesn't represent the intent of the code. There are different meaningful variable names that could be used, based on the actual business context, e.g.:
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
      
The true cost of the software is in the maintenance, so make it as descriptive as possible, using variable names that show real intent.

This is another example:

public List<string> get()
{
	var list1 = new List<string>();
    
    for(var i = 1; i < 10; i++)
		list1.Add($"User {i}.");
	
    return list1;
}
See, we have no clue about the intentions of this method based on its signature. The variable  list1 doesn't tell us anything.

The refactored method, based on one specific intention:

public List<string> getUsers()
{
	var users = new List<string>();
	
	for (var i = 1; i < 10; i++)
		users.Add($"User {i}.");

	return users;
}

Avoid Disinformation

Names that give you a false clue about their intentions are an example of the Disinformation concept. When such things happen, the code itself becomes more obscure, making it hard to understand the goal of the method.

Variables like: asx, prsr, l02 (it's L or I, and it's O or zero), d, accountList.

In the case of an account list, you can consider that the List is a technical term, so avoid it. Instead, you can use something like:

accountGroup
accounts

Another problem is names that vary in a small way:
XYZControllerForEfficientHandlingOfStrings
XYZControllerForEfficientStorageOfStrings


Use Pronounceable Names

The use of acronyms and prefixes can lead you to errors:
    
DateTime genymdhms; 
DateTime modymdhms;
int pszqint;
        
Instead, you can use more easily pronounceable names, like the examples below:  
    
DateTime generationTimestamp;
DateTime modificationTimestamp;
int record;
	
Avoid Encodings

The Hungarian notation was useful in the '90s when you should help who was reading the code to identify the elements you were developing. Now, IDEs can do it easily for you. So avoid things like CUser (class), IUser (for interface), sName (for name property). They are just distractions for you.

In the case of interfaces, it's even preferable to leave the interfaces without the "I", adding the Imp suffix instead (ex: IShapeFactory -> ShapeFactory, with the concrete class ShapeFactoryImpl).

You can avoid the use of prefix member variables with m_: 
    
private String m_dsc;
	
Just using a simple approach is enough:
    
String description;
	

Choose Parts of Speech Well

  • Class Names: should have a noun or noun phrase (e.g. Customer, WikiPage, Account). Avoid words like Manager, Processor, Data.
  • Method Names: use verbs or verb phrases (e.g. deletePage, save). Use set and get as prefixes for setters and getters (e.g. setName, getName).
  • Constructors: when overloaded, give preference to static factory methods with a more descriptive approach:
    
Complex fulcrumPoint = new Complex(23.0); // incorrect way
Complex fulcrumPoint = Complex.FromRealNumber(23.0); //proposed way
	
  • Booleans: give preference to add the prefix "is" (e.g. isEmpty, isValid).
Also, try to avoid some mistakes like the example below:
    
public boolean set(string name, string value){...}
	
The intent of the code is to set a specific value for the name. At the same time, it's returning a boolean. We are talking about two routines here, right?

The correct approach would be to divide this method into two, one void method with a set and another one that returns the boolean if the value was correct defined:
    
public void set(string name, string value){ 
  throws NotSetException ...
}

public boolean set(string name){ 
  ...
}
	
The Scope Rule

Think about what you read above and look at this example:
foreach (var tr in testResults)
{
  var e = createElement(tr);
  rootElement.Append(e);
}
	
You can infer that there are some problems here, regarding the variables like tr or e. But there are some interesting definitions about it. Uncle Bob calls "The Scope Rule":

"For variables, the longer is the scope, the longer the name. Variables in the short scope should have short names. If the scope is larger, the name tends to be the larger the same way."

In the code above, we can consider that it's fine to use short variable names because we know that the variable tr is referring to the list of testResults, as well the e variable is the result of the createElement method.

Now look at this example:
public void serve(Socket s)
{
    try
    {
        tryProcessInstructions(s);
    }
    catch (Exception e) { ... }
    {
        closeServiceInSeparateThread();
    }
}
	
Here the story is different, as you can see in this Uncle Bob's definition:

"For functions and classes, the longer the scope, the shorter the names should be. The shorter the scope, the longer the names should be."

He's saying that a public method named serve is good, in a way that it'll be simple and meaningful to be used outside by other classes. On the other hand, we do have some private methods executing specific behaviors. The scope is smaller, so the names are longer and more focused.

The same occurs for classes and subclasses like, for example, class Account (more general) and the subclass SavingsAccount (more specific). 


The Conclusion

Don't belittle your capacity of doing things better. You can refactor a code and turn it into something better if you know some principles. Remember that the Scout Rule state that you should leave the place you were better than it was before you got there. So be sure you have a good foundation, so you can perform better during your work.

These are some basic rules. There are more rules, so be aware and continue improving during the time. The final goal is to have more readability in your code, so everybody can win with it.


The Entire List of Chapters

---------------------------------------------------------------------------------------------------------------------

References:

I'd like to leave with you some references that can be helpful for your development as a software engineer, part of what we talked about above:


Links for books to buy in the USA: 

                 



Links for books to buy in Europe:

                 


Help us to maintain the MyLifeInDev running:

Fabio Ono

No comments:

Post a Comment