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
- Part 1: The Art of Clean Code
- Part 2: Meaningful Names (you are here)
- Part 3: Functions
---------------------------------------------------------------------------------------------------------------------
Help us to maintain the MyLifeInDev running:
No comments:
Post a Comment