Naming Modules or Classes

The thinking in this post is applicable to the class as well as modules. However, in this post, I’ll use the word class.

Photo by rawpixel on Unsplash

Let me walk you through some of the bad and good examples first and show you the useful notes at the end of the post.

Uglier ways of naming modules or classes

  • myClass: Lazy ways of naming classes. Does it answer it’s purpose clearly?
  • Anything that is suffixed by general words like Manager, Helpers, Info, Data, Details, Utility.
    • CSVHelper: Is it formatting, serializing, converting data into CSV? Are you sure it is answering the questions?
    • XMLUtility: Same as above.
    • JSONManager
    • AppointmentEntity: Is this a Transfer object?
    • AppointmentBO BO: Business object; doesn’t your programming language have namespace or package?
    • Common, Utility, Helpers: Wow! Put all the garbage here. The magnet class that attracts all lazy developers. They do their sins in this class.
    • Processor
    • StudentData, StudentDetails, StudentInfo, StudentInformation: What will happen if I simply give a name:`Student`? It is also a piece of student information, isn’t it?
  • QC: Avoid abbreviations. We are here to solve the problem and make collaboration easy within the team. Avoid abbreviations.
  • BatchJob: This was a base class for all jobs that can be queued in a batch. Does that convey anything related to base class?
  • JWTAuthentication: Are you yelling at others about implementation?
Photo by Hutomo Abrianto on Unsplash

Let’s go through some of the good examples of naming classes.

Cleaner ways of naming classes:

  • Appointment: You have ways to locate your classes using namespace so instead of appending general words like Entity, or BO, or AppointmentEntity, use namespaces wisely.
  • DateFormatter: It formats the date based on the given format. Makes more sense than DateHelper or DateUtility, right?
  • MeetupSerializer: It serializes the meetup object into a string representation. Intuitive?
  • DocumentFileStorage: It tells you about its central purpose like Reading/Writing a document to a file system.
  • UserRepository: It tells you that it’s a repository pattern for User. If your language supports generics, then Repository<User> could be a better solution.
  • MoneyFormatter: It formats the money.
  • ColorCodeProvider.getColorCode(value). It gives you a color code for a given value.
  • QualityCheck is better than QC
  • StudentProgramSearch, The search entity that contains fields related to a student and his education program.
  • StudentValidator.
  • Logger
  • ControllerFactory: It creates controllers.
  • Sanitizer
    • UpdateCommandSanitizer: It should ignore some of the fields from user input like CreatedAt and UpdatedAt fields and prepare update command for updating other fields.
    • PersonDataSanitizer: It clears some of the person fields like phone, email, address and sends data for remaining fields.

Giving a name to a class is art. To learn that art, I would recommend you to read, understand and apply: Abstraction, Cohesion, and Single responsibility principle. You will also need to understand the conventions of the framework you are using e.g. MVC as well as learn design patterns.

Don’t forget to ask these questions while naming the class.

  • Does your class name describe its central purpose? and doing those things only? Example: Abstract data types like Stack, Queue, etc.
  • Does your class answer your questions like what it is doing? Rather than how is it doing?
  • Name your classes using a noun, according to their domain and architectural meaning.
  • What do you want to achieve? Ask repeated questions. For e.g. Formatting? what kind of formatting? Money? Then the name should be MoneyFormatter…. Similarly, Converting document into JSON? OK, but why are you doing it? Do you want to serialize document? Then it should be named DocumentSerializer rather than JsonConverter.
  • Can a class be treated as a black box? Visibility of the members? Use class diagrams for clarity.
  • Does class make assumptions about the consumer of that class?
  • Does your class name feel more generic or specific?

Don’t use abbreviations while naming variables

A few months ago, Technogise had conducted a Code Retreat session for engineering graduates. I was one of the volunteers for this activity.

We asked students to solve a simple problem.

We asked them to write a program which calculates the final price of product items in a shopping cart, when the initial price of each item, the category in which each item falls, their quantity and the GST (goods & services tax) slab applicable to each category was given.

Going through the code for some of the students led me to write this post.

Please read the code below:


using System;
using System.Collections.Generic;
using System.Linq;
namespace Assignment
{
internal class Program
{
private static Dictionary<string, int> CGR = new Dictionary<string, int>();
private static Dictionary<string, string> iCat = new Dictionary<string, string>();
private static void Main(string[] args)
{
CGR.Add("Food-grains", 0);
CGR.Add("Furniture", 5);
CGR.Add("Electronics", 18);
CGR.Add("Cosmetics", 28);
iCat.Add("Rice", "Food-grains");
iCat.Add("Wheat", "Food-grains");
iCat.Add("Sofa", "Furniture");
iCat.Add("Chairs", "Furniture");
iCat.Add("TV", "Electronics");
iCat.Add("Mobile", "Electronics");
iCat.Add("Shampoo", "Cosmetics");
iCat.Add("Perfume", "Cosmetics");
Console.WriteLine("Welcome to NMart store");
Console.WriteLine("***************************");
Console.Write("Enter name of item: ");
string iName = Console.ReadLine();
Console.Write("Enter quantity of item: ");
int iQnt = int.Parse(Console.ReadLine());
Console.Write("Enter rate per product item: ");
int iRate = int.Parse(Console.ReadLine());
string cName = "";
foreach (var cat in iCat)
{
if (cat.Key == iName)
{
cName = cat.Value;
break;
}
}
int cPercentage = 0;
foreach (var c in CGR)
{
if (c.Key == cName)
{
cPercentage = c.Value;
break;
}
}
double fPrice = iQnt * (iRate + iRate * cPercentage / 100.0);
string output = "*******************************************\n" +
"Billing Details for " + iName + ":\n" +
"*******************************************\n" +
"Quantity: " + iQnt +
"\nPrice per unit: " + iRate +
"\nFinal rate: " + fPrice;
Console.WriteLine(output);
Console.WriteLine("\n*********************************\n");
}
}
}

Were you able to understand the code? After a few minutes of repeated reading, you could.

It’s difficult to know the meaning of the variables like CGR, iCat, iName, iQnt, cPercentage, fPrice and so on?

It creates a complicated mapping in your brain. You need to scroll up and down to understand the intention of everything, isn’t it?

Now let’s see the same code after giving little better names.


using System;
using System.Collections.Generic;
namespace NMart.Billing
{
internal class NMartStore
{
private static Dictionary<string, int> CategoryGstRatesInPercentage = new Dictionary<string, int>();
private static Dictionary<string, string> ItemsInCategory = new Dictionary<string, string>();
private static void Main()
{
CategoryGstRatesInPercentage.Add("Food-grains", 0);
CategoryGstRatesInPercentage.Add("Furniture", 5);
CategoryGstRatesInPercentage.Add("Electronics", 18);
CategoryGstRatesInPercentage.Add("Cosmetics", 28);
ItemsInCategory.Add("Rice", "Food-grains");
ItemsInCategory.Add("Wheat", "Food-grains");
ItemsInCategory.Add("Sofa", "Furniture");
ItemsInCategory.Add("Chairs", "Furniture");
ItemsInCategory.Add("TV", "Electronics");
ItemsInCategory.Add("Mobile", "Electronics");
ItemsInCategory.Add("Shampoo", "Cosmetics");
ItemsInCategory.Add("Perfume", "Cosmetics");
Console.WriteLine("Welcome to NMart store");
Console.WriteLine("***************************");
Console.Write("Enter name of item: ");
string itemName = Console.ReadLine();
Console.Write("Enter quantity of item: ");
int itemQuantity = int.Parse(Console.ReadLine());
Console.Write("Enter rate per product item: ");
int ratePerUnitItem = int.Parse(Console.ReadLine());
string categoryName = "";
foreach (var item in ItemsInCategory)
{
if (item.Key == itemName)
{
categoryName = item.Value;
break;
}
}
int gstPercentageForItem = 0;
foreach (var categoryGstRate in CategoryGstRatesInPercentage)
{
if (categoryGstRate.Key == categoryName)
{
gstPercentageForItem = categoryGstRate.Value;
break;
}
}
double finalPrice = itemQuantity * (ratePerUnitItem + ratePerUnitItem * gstPercentageForItem / 100.0);
string output = "*******************************************\n" +
"Billing Details for " + itemName + ":\n" +
"*******************************************\n" +
"Quantity: " + itemQuantity +
"\nPrice per unit: " + ratePerUnitItem +
"\nFinal rate: " + finalPrice;
Console.WriteLine(output);
Console.WriteLine("\n*********************************\n");
}
}
}

Do you see how simple it becomes as soon as you write meaningful names?itemName, itemQuantity, ratePerUnitItem, gstPercentageForItem, finalPrice and so on. Now the variables are conveying their intent, better than the first snippet? (I agree I could use a better data structure or use LINQ. However, I am simulating what students had written. They used different programming languages too. This code is for demo purpose.)

Now, you don’t need to scroll up and down to understand the intention of the variables. This is an impact of giving meaningful names to variables.

Don’t use abbreviations for variable names

Hence, we should spend little more time on giving meaningful names to variables (same thing is applicable to the class, namespace, methods, and so on) so that when you or maintenance developer revisits your code to fix a bug or add a feature, she/he could do it very easily. It should be flawless. Avoid using abbreviations while giving names to variables throughout the project. It would be a nightmare to maintain such code.

Dattatray Kale: Crafting Software Excellence for Over a Decade

Introduce explaining variable

While doing pair programming with developers, I have experienced that some of them are hesitant to introduce the explaining variable. They worry more about other devs thinking about that extra variable.

Will it be redundant to have an extra variable? Well, let’s see:

Before

In the above code snippet (…even though it’s a simple one), checking file size against an arbitrary number does not convey any business rule clearly. You can’t predict easily about the meaning of ‘10000000’ or size whether it is in Bits, Byte, KB, MB or something else. One who visits this snippet needs to spend some time to figure out the intent.

Well, let’s introduce explaining variable and see if it helps.

Better way:

I know, I have increased the line of code here. However, don’t you think the introduction of explaining variable made it expressive and understandable?

Now it reads like:

When file size exceeds maximum allowed size (10000000 Bytes!), then just exit!

Another example:

Before

PHP code doing some matching on phone.

It’s really difficult for me when I read it the first time.

Better way:

Divided into multiple parts so that it could express itself very easily.

Now at least, you know that there is a regular expression for valid phone number pattern. It is used to determine if the phone number is valid or not and take appropriate action.

Introduce the explaining variable to convey your intent. This is one of the ways to express yourself via code.


Why giving meaningful names to things in programming is important

Everything in this world has meaningful names. It helps our brain to understand and remember the things very easily. It means less mental mapping.

Let us take real-world examples of meaningful names given to things like hand wash (of course, you don’t use it to wash your face), face wash, shaving cream, aftershave and so on.

Similarly, in the programming, everything needs to have a meaningful name because we as a developer spend our most of the time reading the code than we do writing it.

As a developer, our daily job is to give a solution to the problem at hand.

To solve the problem at hand, we sometimes create a project, an assembly, a namespace,  directories, class files, classes, fields, methods, other members, UI elements, their translation files, translation keys and so on.

All of these things should have the meaningful name so that they convey their intent and you realize what they are doing by just looking at their name.

Perhaps they answer all the big questions that you or future maintenance developers would have.

Let’s go through the following code snippet. It is written in js.

  downld(recs){ 
        const cols = ['Name', 'Age', 'Gender'];
        let d = `data:text/csv;charset=utf-8,${cols.join(',')}rn`;
        recs.each((r) => {
            const row = [
                r.get('name'),
                r.get('age'),
                r.get('gender')
            ].join(",");

            d += `${row}rn`;
        });
        const u = encodeURI(d);
        const lnk = document.createElement("a");
        lnk.setAttribute("href", u);
        lnk.setAttribute("download", "users.csv");
        document.body.appendChild(lnk);
        lnk.click();
  }

I hope you understood what it is doing.

The above example shows that a simple code snippet could be difficult to understand when meaningful names are NOT given to variables, functions and so on.

Now think about a project that has 100+ classes and thousands of lines.

Don’t you think it will be painful for the maintenance developer as well as an original developer to read it again in the future?

This could have been easy to understand when good names would have been given.

Let us try to give the meaningful name in the code snippet.

  downloadAsCsv(users){ 
        const columnNames = ['Name', 'Age', 'Gender'];
        const csvHeader = `data:text/csv;charset=utf-8,${columnNames.join(',')}rn`;
        let csvDataRows = "";
        const newlineAndCarriageReturn = `rn`;
        users.each((user) => {
            const currentRow = [
                user.get('name'),
                user.get('age'),
                user.get('gender')
            ].join(",");

            csvDataRows += currentRow + newlineAndCarriageReturn;
        });

        const csvFileContent = csvHeader + csvDataRows;
        const encodedUri = encodeURI(csvFileContent);
        const newlink = document.createElement("a");
        newlink.setAttribute("href", encodedUri);
        newlink.setAttribute("download", "users.csv");
        document.body.appendChild(newlink);
        newlink.click();
  }

Now, do you think it’s a little better than the previous version?

The good names encourage you to write clean and good code. You can go one step ahead and split above function.

    downloadAsCsv(users){
        const csvFileContent = this.generateCsvContent(users);
        const encodedUri = encodeURI(csvFileContent);
        const newlink = document.createElement("a");
        newlink.setAttribute("href", encodedUri);
        newlink.setAttribute("download", "users.csv");
        document.body.appendChild(newlink);
        newlink.click();
    }

    generateCsvContent(users) {
        const columnNames = ['Name', 'Age', 'Gender'];
        const csvHeader = `data:text/csv;charset=utf-8,${columnNames.join(',')}rn`;
        let csvDataRows = "";
        const newlineAndCarriageReturn = `rn`;
        users.each((user) => {
            const currentRow = [
                user.get('name'),
                user.get('age'),
                user.get('gender')
            ].join(",");

            csvDataRows += currentRow + newlineAndCarriageReturn;
        });

        return csvHeader + csvDataRows;
    }

I hope you agree with me that meaningful names will make everyone (including you) more than happy after reading it.

In case of methods, when you failed to give a name to a method, you may realize it’s doing more than one thing. It is really helping you.

Even when you are able to give a meaningful name to a method, you may realize that the method doesn’t belong to this class.

I often realized that this practice of giving meaningful names helped me a lot about understanding the solutions, separations of concerns and even responsibility of the classes, methods, assembiles and so on.

Suppose your boss comes to you and asks you to fix value against gender column in generated CSV (from above example) on priority. Instead of debugging and finding the location of the code, just ask IDE to show you “generateCsvContent” routine.

Thus, help your IDE to help you by giving meaningful names to everything in programming so that you can figure out everything very easily.

Consequently, giving meaningful names will help you in some way or other.

When you revisit your code after 4 hours or 4 weeks, or 4 years, and you think you could give more meaningful names now then

DO NOT hesitate to rename it if it’s not breaking anything and has less impact on other features.

REMEMBER!

https://blog.beingcraftsman.com/datta/