Lesson 2
Meaningful Naming in C++
Introduction

Welcome to the second lesson of the "Clean Code Basics" course, focused on meaningful naming in C++. In the previous lesson, we introduced clean code and its significance in developing maintainable and efficient software. Now, let's explore the importance of meaningful naming—an essential part of clean code. Selecting appropriate names is vital for creating code that is clear, understandable, and easy to maintain.

Good Naming at a Glance

In this lesson, I'll cover the following naming guidelines:

  • Reveal Intent Through Names: Ensure names clearly convey the role and functionality of variables, classes, and functions. For instance, replacing calc with calculateInterest enhances code clarity. 🧠

  • Avoid Misleading Names: Avoid names that imply incorrect assumptions, such as using usersList for a set, ensuring accuracy and understanding. 🚫

  • Choose Descriptive, Searchable Names: Opt for names like age instead of a, facilitating easy searchability and recognition within the codebase, which enhances maintainability. 🔍

  • Name Interfaces and Implementations Wisely: While C++ doesn't have traditional interfaces, abstract classes often serve this role by defining a contract through pure virtual functions. Use clear names such as AbstractUserService to denote abstract classes and UserService for concrete implementations.

  • Consistent Naming Across the Codebase: Use uniform patterns like getAllUsers instead of varied terms such as fetchAllUsers, maintaining clarity and preventing confusion. 📚

  • Provide Sufficient Context in Names: Include enough context, such as using fileSize instead of size, to eliminate ambiguity, especially when components are used across different contexts. 🌐

Reveal Intent Through Names

Names should clearly express the purpose and functionality of your variables, classes, and functions, leaving no room for ambiguity.

Bad ExampleGood Example
MyClassUserService
collusers
calccalculateInterest
temptemporaryFile
procprocessOrder

Effective names provide immediate insight into what the code does, reducing the need for additional explanations. For example, replacing coll with users instantly conveys the collection's purpose.

Avoid Misleading Names

Avoid using names that may lead others to incorrect assumptions about the type or purpose of a variable or function.

Bad ExampleGood ExampleExplanation
usersListusersThe name suggests a list, but it's actually a set.
saveUsersaveUserAndSendEmailConfirmationThe function name doesn't convey that it also sends an email confirmation.
temptemperatureThe name "temp" could be misinterpreted as "temporary."

You might think if the users' collection is a set, why not name it usersSet? While this is a valid point, the name users is still preferable because it's concise and clear. If the collection's type is crucial, you can add a comment or use a more descriptive name like uniqueUsers. In general, avoid attaching type information to variable names; otherwise, if you change the type later, you'll need to update the name as well, which might affect other parts of the codebase.

Choose Descriptive, Searchable Names

Names should be easily searchable within the codebase. Using short names, even if they might seem descriptive in certain contexts, generally hinders maintainability and readability. For example, opting for numberOfItems instead of num makes the code easier to search and understand.

Name Interfaces and Implementations Wisely

C++ doesn't have traditional interfaces, but pure abstract classes often serve a similar purpose by defining a contract through pure virtual functions. There isn't a universal convention for naming pure abstract classes in C++; some prefer to prefix them with "I" (e.g., IUserService), while others use "Abstract" (e.g., AbstractUserService). Whichever naming convention you choose, ensure it is applied consistently across the codebase. For concrete implementations, use clear names that reflect their purpose, such as DbUserService or InMemoryUserService, to clearly indicate their roles.

Consistent Naming Across the Codebase

Consider method names such as fetchAllUsers, retrieveTasks, loadUsers, and fetchEveryTodoItem. Is anything wrong with these names? They do convey intent and are descriptive, so they appear fine. However, using these varied names within the same codebase is problematic due to inconsistency. In the same codebase, it's beneficial to stick to a single naming pattern, like getAll, to avoid confusion and maintain clarity, e.g., getAllUsers, getAllTasks, getAllTodoItems.

Provide Sufficient Context in Names

When discussing good naming, consider the context in which a name is used. The variable name size might be perfectly acceptable within the resizeArray function. However, in the context of generateReport, the name is too vague, and renaming this variable to something more descriptive like numberOfPages is advisable.

Providing enough context is crucial, but avoid giving too much context. For instance, within the UserService, save is a perfectly acceptable method name, and there's no need for an excessively lengthy name like saveAllUsers.

Summary

Meaningful naming is a critical aspect of writing clean code. By choosing names that clearly express intent, avoiding misleading terms, and maintaining consistency and context, you create code that is easy to read, understand, and maintain. Up next, you'll have the opportunity to refactor code, applying these principles and honing your ability to write intuitive, clean code.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.