© Giuliana Carullo 2020
G. CarulloImplementing Effective Code Reviewshttps://doi.org/10.1007/978-1-4842-6162-0_7

7. Naming and Formatting Conventions

Giuliana Carullo1 
(1)
Dublin, Ireland
 

There is nothing more deceptive than an obvious fact.

—Sherlock Holmes in Sir Arthur Conan Doyle’s “The Boscombe Valley Mystery” (1891)

In theory, declaring a variable is a child’s play:
i_am_a_var = 10

Sure enough it gets the job done: having a variable ready for use as you wish.

However, picking naming right can add (or remove) a lot from the overall quality of the code you write. A clear and consistent naming scheme, as subtle it might seem at first, will play you well in the short, medium, and long run. Indeed, haphazard names lead to confusion, highly impacting readability and maintainability of the codebase.

This chapter quickly describes common dos and don’ts and guidelines on how to look at naming when building clean code. It is not a matter of “you have to” approach. But it takes less effort to implement these good practices than reviewing or trying to understand the code later on. Thus, “you really should” implement them.

We are also going to quickly introduce good practices around the use of parameters and access modifiers as well as spacing since they all contribute to a well-rounded readable code.

Naming

As human beings, we all get a name at our birth. Our parents chose our names with love to welcome us in the world. Our name affects our life and how we interact with the world. We need to do the same with our baby code.

We already agreed that a lot of times we get so emotional with our baby code, and we want to take care of it. And choosing the right naming is just another way to show our code some love: “welcome on board, my code!” Choose wisely.

Note

Bob, Mary, and Joe are wonderful names. When I speak about baby code, let’s avoid these names for code, okay?

You Should Be... What?

Ambiguous names make the code hard to read. Not too short. Not too long. But you should be able to tell what they do at glance.
my_dict = dict()

In this example, there is no context that can help your future self, and other programmers, understand what the purpose of the dictionary is.

Hence, a first check is to ensure that chosen names are meaningful within the considered context. If names are meaningful and context oriented, they are easier to remember and eventually to look after.

Back to our example. Suppose you are modeling the age of a set of people, a more meaningful declaration would be
users_age = dict()
How not to do context orientation:
  • Don’t try to be funny. If you are happy, you can’t name your variable lol or rotfl. As much as I am a big believer in having some fun, do not compromise the meaningfulness of a name just for the fun of it. You won’t be laughing later on when you cannot remember the enjoyment at that time, nor when other programmers will enquire you about it. It is also highly probable that it will not make it through any peer review process.

  • Don’t be shy and use single letter variable names. If you feel shy or speechless, you still can’t use a, g, or m. Indexing with i, j, or k is totally okay. That’s it. These are, generally, the only single context-oriented single letter variable names allowed. Bonus: you are allowed to use n for loops.

  • Don’t try to impress other programmers using acronyms to express the context. TVMNTM stands for “this variable means nothing to me.” It is context oriented. Oh well, don’t use it.

Note

Indexes (i, j, k) are okay in loops. Nonetheless, more descriptive names always help, especially for multiple nested loops.

Not You Again

Not the same thing is declared with different names, not same name for different things.

Back to our previous example:
my_dict = dict()

It is not only a matter of readability and longer-term memory. Getting into the habit of not using meaningful names often leads to scattering the same name over and over across the codebase. This would make code readers even more confused and having a harder time to understand what a variable is used for, what is the context, and the scope it lives in.

Takeaway

Always pick meaningful names. It will help readability and maintainability, especially in large-scale software.

Keywords

Certain languages, like Python, allow us to use keywords as variable names. Consider the example in the following. Python offers several built-in functions. type( ) is one of them that given an object as argument returns its type:
type(3)
>>> <type 'int'>
The interpreter would not be mad at you if you use type as variable name; indeed, the following snippet of code is okay and runs with no apparent issue:
type = 5
print (type)
>>> 5
What if at a later stage in your code you remember that you need the built-in function instead? The code won’t work, because now type is referencing an int object instead.
type(3)
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
Takeaway

Long story short, keywords are reserved to the language. Do not use them.

The Good, the Bad, the Ugly

Switching between different languages can make it difficult to follow naming conventions.

In this section, we are going to explore some Python conventions. However, before writing your very first line of code, always go and check the convention for your language.

Let’s go through each one.

Refresher

Private members are only accessible locally (e.g., within a class). Protected members are visible both locally (same class) and by any subclass.

Variables, functions, and packages names should not use camel case, and words should be separated by underscores:
something_like_this
Private methods start with double underscore:
__i_am_a_secret_agent(self, params)
Protected methods start with single underscore:
_i_am_a_protected_method(self, params)
Heads Up

Context specific applies. Always think in advance if a class is meant to be extended (i.e., used for inheritance) and, hence, about its implications on public or private variables. Default behavior should always be to consider a component private, unless clearly needed to be used as protected or public.

Use CamelCase for classes and exceptions:
BrandNewClass(object)
Constants are always all caps separated by underscores:
I_AM_A_CONSTANT = 'whatever whatever'

And always use reverse_notation for multi-worded names used within the same context.

The good:
element_a = 'whatever a'
element_b = 'whatever b'
element_c = 'whatever c'
The bad:
a_element = 'whatever a'
b_element = 'whatever b'
c_element = 'whatever c'

How’s the ugly?

Well, when names are not grouped based on context, it’s ugly.

Bonus Tip

If you can’t find a proper name for a new method, class, and so on, ensure that you are not dealing with a bossy component.

Python Naming Conventions in Short

This section provides a quick recap of naming conventions for Python.1 Specifically
  • Packages and modules names are all lower case. Underscores can be present for readability purposes if multiple words are present. Filenames are treated like a module; hence, same naming conventions apply.

  • Classes are CamelCase. Exceptions are treated as classes and hence follow the same naming convention.

  • Functions and variables are lower case, separated with underscore if multiple words are present. If a variable is local—by definition—it does not need any underscore to signal access type.

  • Constants are all caps, separated with underscores if needed.

Table 7-1 provides a quick reference for the most common naming conventions and their use depending on the desired (if any) visibility.
Table 7-1

Naming Conventions Summary

Type

Convention

Public

Protected

Private

Package

Lower case

lower_case

-

-

Module

Lower case

lower_case

-

-

Filename

Lower case

lower_case.txt

-

-

Class

Camel case

CamerCase()

-

-

Exception

Camel case

CamelCase()

-

-

Function

Lower case

lower_case()

_lower_case()

__lower_case()

Variable

Lower case

lower_case

_lower_case

__lower_case

Local variable

Lower_case

-

-

lower_case

Constant

All caps

ALL_CAPS

_ALL_CAPS

__ALL_CAPS

That’s Magic

MAGIC_NUMBER = 42

Even if 42 is the answer to the ultimate question of life, the universe, and everything, it is not a good practice.

As much as I would love to ignore 42 as a magic number in the code review because I am a geek at heart, magic numbers should be considered with caution and avoided if possible.

They are not a good practice because their meaning is often hard to link back to the actual context.

Suppose that for whatever reason (if you did it, please let me know why) you are trying to put The Hitchhiker’s Guide to Galaxy into code format. A probably better named constant would be
LIFE_UNIVERSE_EVERYTHING = 42
Savage Hardcoding

If you can, avoid hardcoding like the plague. If you really have to use it, make sure it is minimal and easy to locate (i.e., not scattered all over the codebase). Furthermore, any use of hardcoding is tight back to meaningful names.

Parameterization

In simple words, passing too many arguments as input to functions and methods is not a good idea. Here’s an example:
def too_many_params(first, second, third, fourth, ... , nth):
    ...
It makes the code less readable and it might make testing trickier. The suggested options to solve this type of defect are
  1. 1.

    Use optional parameters if possible.

     
  2. 2.

    Consider—if it is sound—to create a new class that contains the input parameters. Thus, pass the single instance as input to the function/method.

     
Consider the following example:
def update_and_store_account(id, name, surname, username, preferences, ...):
   ...
It would be far better designed by specifying an account class that maintains all the parameter:
class Account(object):
...
    def __init__(self, id, name, surname, username,  preferences, ...):
        self._id = id
        self._name = name
        self._surname = surname
        self._username = username
        self._preferences = preferences
        ...
...
Takeaway

When writing or reviewing parameters, look at how many of them are in place for each component. Always consider options to reorganize and reduce their appearance as input for a single component. Too many parameters might be also a signal for a bigger problem to be looked at (i.e., design smells). Indeed, it might be the case of having too many parameters because the code is breaking the single responsibility principle.

Modifiers

Access modifiers also play an important role in readable code as well as maintaining the overall design and architecture sound.

You might be used to Java, where encapsulation dominates everything. Python, au contraire, is less strict on this aspect.

“But wait, Giuliana,” you say, “you told me that for private methods I should use double underscore.”

That is called name mangling, which leads to potentially treating each of the methods as public. But I wouldn’t. If methods have been made private, it means that someone specifically designed them in such a way that signals that you should not access them from the outside. In this case, indeed, the private method might be just temporary; its signature might change in the future or even change its inner behavior. This would cost changes to all the callers and lots of headaches.

Note

If I haven’t convinced you so far, at least, respect the will of previous programmers.

Formatting Code

Spacing properly is also important to achieve uniform and readable code. In the following some guidance on most common practices.

Line Spacing

Like naming, spacing properly helps in achieving readable code. General guidance for Python code includes
  • Two vertical spaces ahead of classes. Since a class gathers together a single behavior, spacing is performed accordingly to place more emphasis on responsibilities separation.

  • One vertical space for class methods.

  • No line separation within the same method.

Note

If you are tempted to add several blank lines into a single method, it might be an early indicator of a method being too long and possibly breaking the single responsibility principle.

Indentation

While line spacing creates visual separation between logically separated behaviors vertically, indentation does it horizontally and deals also with grouping of logical statements. General rule of thumb for Python code is as follows:
  • Always use four whitespaces to define a block (e.g., loop, code at class level, method level, conditional flow)

  • Tabs are generally preferred over spaces. However, consistency is important. If most of the codebase uses already four consecutive spaces instead of tabs, it is okay to keep using them, but strive for consistency.

Whitespace

Readability can be improved even down to a single-line statement. This is the case, for example, of properly spacing boolean operators into a conditional statement. General guidance is the following:
  • Add a whitespace on both sides of boolean, comparison, and assignment operators.

  • Like natural language for parentheses and punctuation. This implies
    • No space immediately after an open parenthesis and no space immediately before a closing parenthesis

    • Space after a comma, but no space before it

  • No space at the end of each line (known as trailing space)

Python Spacing in Short

Properly spacing down to every line of code helps ensure readable code and adds semantic cues of separation to programmers reading the code.

Table 7-2 provides a summary of spacing conventions.
Table 7-2

Spacing Conventions Summary

Type

Convention

Class

Two blank lines before

Function and method

Single blank line before

Block within function

No blank line

Boolean, comparison, and assignment operators

Whitespace both sides

End of line

No space

Code indentation

Tab (four spaces)

Parenthesized expressions

No spaces immediately after and before inside the expression

Comma

No space before, single space after

Here it is a final word on spacing and whitespaces: as almost everything in life, too much of something might cause the opposite effect of the wanted goal. The same applies to spacing. Adding too many whitespaces can decrease readability instead of improving it.

Summary

In this chapter, we provided guidelines and examples around common naming problems and their impact on clean code.

As explained in this chapter
  • Naming has a big impact on the readability of the code.

  • Plenty of factors including parameterization, access modifiers, keywords, and hardcoding need to be considered for a well-rounded code review.

A general takeaway is that conventions are not always strictly enforced. When in doubt, check the reference guide, and if no guidance is provided on a specific aspect, at the very least, ensure that naming choices are consistent across the codebase.

In the next chapter, we will provide more guidance on commenting the code, why it is important and how to make the best use of it.

Heads Up

Many of the guidelines described in this chapter can be automated. Specifically, tools for automated PEP8 checks exist: consider tools already in place within your company or pick the one that best suits your needs and preferences.

Further Reading

If you want a laugh, check out “How To Write Unmaintainable Code” by Andrew Yurisich (https://github.com/Droogans/unmaintainable-code). It is a quick and nice reference on unmaintainable code. PEP8 (www.python.org/dev/peps/pep-0008/#naming-conventions) provides a comprehensive guide on Python guidelines for naming.

Review Checklist

  1. 1.

    Are redundant parameters present in the class (might be the case of instance var instead)?

     
  2. 2.

    Does the code follow the naming conventions of the chosen language (e.g., CamelCase for Java)?

     
  3. 3.

    Are names of variable, methods, and classes meaningful?

     
  4. 4.

    Are names of variable, methods, and classes descriptive?

     
  5. 5.

    Are names consistent across the codebase?

     
  6. 6.

    Are names context oriented?

     
  7. 7.

    Are keywords used for variable naming?

     
  8. 8.

    Can you understand from the function/method/class/variable name what is it expected to perform?

     
  9. 9.

    Are too many parameters in place?

     
  10. 10.

    Are optional parameters adequately used?

     
  11. 11.

    Are modifiers used appropriately?

     
  12. 12.

    Are global variables in place? Are they actually needed?

     
  13. 13.

    Does the code contain magic numbers?

     
  14. 14.

    Is abstraction by parameterization achieved?

     
  15. 15.

    Is parameterization needed to remove redundancies?

     
  16. 16.

    Are generic types used when needed to improve reusability (Java)?

     
  17. 17.

    Is naming giving insights of a bossy component?

     
  18. 18.

    Are private methods called from the outside (Python)?

     
  19. 19.

    Are spacing conventions respected?

     
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.171.121