Mastering Clean Code Principles: The Art of Naming Variables and Functions

Md. Saddam Hossain
6 min readJul 31, 2023

--

As developers, we constantly strive to write code that is not just functional but also easy to read, understand, and maintain. One of the most influential books that guides us on this quest is “Clean Code” by Robert Cecil Martin. In this article, we will delve into a crucial topic covered in the book — “The Art of Naming.” We will explore the key takeaways from the book and provide examples in JavaScript to illustrate each principle. Embracing these principles will elevate our code quality, enhance team collaboration, and make debugging and refactoring a breeze.

1️. Use Intention-Revealing Names: Names should reveal the purpose and intent of variables and functions. Choose descriptive names that make the code self-documenting.

// Bad naming
const x = 10; // What does 'x' represent?

// Good naming
const numberOfStudents = 10; // Clearly states the purpose of the variable

2️. Avoid Disinformation: Avoid using names that may mislead or confuse other developers. Be accurate and consistent in your naming conventions.

// Disinformative name
const getAge = () => {
// This function doesn't actually get the age
return calculateBirthYear();
};

// Accurate name
const calculateAge = () => {
// Now the function name reflects its actual purpose
return getCurrentYear() - calculateBirthYear();
};

3. Make Meaningful Distinctions: In addition to using intention-revealing names, it’s crucial to make meaningful distinctions between variables and functions. Avoid using names that are too similar, as this can lead to confusion and potential bugs in your codebase. By making clear and distinct naming choices, you ensure that each element serves a unique purpose and contributes to the overall clarity of your code.

// Unclear distinction
const getUserData = () => {
// Function that retrieves user data
};

const getUserDetails = () => {
// Function that also retrieves user data?
};

// Better distinction
const fetchUserData = () => {
// Function to fetch user data from the server
};

const calculateUserDetails = () => {
// Function to process and calculate specific user details
};

4. Use Pronounceable Names: When choosing names for variables and functions, opt for names that are easy to pronounce and say out loud. Pronounceable names promote better communication within the development team, especially during discussions and code reviews. If names are hard to pronounce or ambiguous, it might lead to misunderstandings and miscommunications.

// Not easily pronounceable
const xvr = 42;

// Easily pronounceable and meaningful
const numberOfStudents = 42;

5. Use Searchable Names: When choosing names for variables and functions, opt for names that are easy to search for within your codebase. This means using descriptive and specific names that reflect the purpose of the element. Searchable names facilitate navigation and understanding of the code, especially in larger projects with numerous files and functions.

// Not easily searchable
let s = 0;
const t = [/* Fill in your array 't' elements here */];
for (let j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}

// Easily searchable and meaningful
const realDaysPerIdealDay = 4;
const WORK_DAYS_PER_WEEK = 5;
const NUMBER_OF_TASKS = /* Replace with the actual number of tasks */;
const taskEstimate = [/* Fill in your array of task estimates here */];

let sum = 0;
for (let j = 0; j < NUMBER_OF_TASKS; j++) {
const realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
const realTaskWeeks = Math.floor(realTaskDays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}

6. Avoid Encodings: When naming variables and functions, it’s best to avoid using encoding prefixes or tags that indicate the type or purpose of the element. Encoding prefixes like “str” for strings, “num” for numbers, or “arr” for arrays can clutter the code and make it less readable. Instead, use descriptive names that clearly convey the purpose and meaning of the variables and functions.

  • Avoid Hungarian Notation: Hungarian Notation is a specific type of encoding where prefixes are used to indicate the variable’s data type. For example, “strName” might be used to indicate a variable that holds a string value, “numCount” for a numeric counter, or “arrFruits” for an array of fruits. Avoid using Hungarian Notation and opt for descriptive names that convey the purpose rather than the data type.
// Avoid Hungarian Notation
const strName = 'John'; // Not recommended
const numCount = 42; // Not recommended
const arrFruits = ['apple', 'banana', 'orange']; // Not recommended

// Prefer Descriptive Names
const userName = 'John'; // Recommended
const itemCount = 42; // Recommended
const fruits = ['apple', 'banana', 'orange']; // Recommended
  • Avoid Member Prefixes: Member prefixes, like “m_” or “m”, are sometimes used to indicate class member variables. However, modern development practices often discourage this practice, as it adds unnecessary noise to the code. Instead, rely on your IDE or editor’s syntax highlighting or other conventions to distinguish between member variables and local variables.
// Avoid Member Prefixes
class Employee {
constructor() {
this.m_employeeId = 123; // Not recommended
this.m_firstName = 'John'; // Not recommended
this.m_lastName = 'Doe'; // Not recommended
}
}

// Prefer Direct Naming
class Employee {
constructor() {
this.employeeId = 123; // Recommended
this.firstName = 'John'; // Recommended
this.lastName = 'Doe'; // Recommended
}
}
  • Avoid Interfaces and Implementations in Names: When creating interfaces and their implementations, avoid including the interface name in the implementation class name. For example, instead of naming the implementation class “MyInterfaceImpl,” use a more meaningful and context-specific name. This ensures better separation of concerns and makes it easier to refactor or swap implementations in the future.
// Avoid Interface and Implementation in Names
class IUser { /* Interface code here */ }
class UserImplementation extends IUser { /* Implementation code here */ }

// Prefer Separated Names
class IUser { /* Interface code here */ }
class User extends IUser { /* Implementation code here */ }

7. Avoid Mental Mapping: When naming variables, choose names that don’t require readers to mentally translate them into other known terms. Avoid single-letter variable names unless they serve as traditional loop counters with limited scope. Using descriptive names enhances code clarity and readability, promoting better collaboration and maintainability. Prioritize clarity over demonstrating mental prowess, and remember that professionals prioritize code that others can understand.

8. Class Names: Classes and objects should have noun or noun phrase names like “Customer,” “WikiPage,” “Account,” and “AddressParser.” It is essential to avoid using words like “Manager,” “Processor,” “Data,” or “Info” in the name of a class. Instead, class names should reflect the entities or objects they represent within the problem domain. Using nouns helps establish a clear and logical relationship between the class and its responsibilities.

9. Method Names:

  • Use Verb or Verb Phrase Names: Methods should have names that are verbs or verb phrases, reflecting the action they perform.
  • Follow JavaBean Standard: Accessors (get), mutators (set), and predicates (is) should be named for their value and follow the JavaBean naming conventions.
// Method with verb phrase name
function postPayment() {
// Implementation code here
}

// Accessor method following JavaBean standard
function getName() {
// Implementation code here
}

// Mutator method following JavaBean standard
function setName(name) {
// Implementation code here
}

// Predicate method following JavaBean standard
function isPosted() {
// Implementation code here
}
  • Use Static Factory Methods: For overloaded constructors, use static factory methods with descriptive names for improved code readability.
class Complex {
constructor(realNumber) {
// Implementation code here
}

// Static factory method with descriptive name
static fromRealNumber(realNumber) {
// Implementation code here
}
}

10. Be Explicit and Pronounceable: Clear and pronounceable names facilitate communication among team members and contribute to a collaborative coding environment.

// Not explicit and hard to pronounce
const df1 = ['apple', 'banana', 'orange'];

// Explicit and pronounceable
const fruits = ['apple', 'banana', 'orange'];

11. Think About Scope: Ensure that the scope of a variable is apparent from its name. Avoid ambiguous names that might lead to unintended side effects.

// Ambiguous variable name
let data = fetchData();

// Better naming with clear scope
let userData = fetchUserData();

12. Favor Clarity Over Cleverness: While clever names might seem fun, code maintainability should be our top priority. Choose clarity over cleverness.

// Clever but unclear
const x = (a, b) => a + b; // What does 'x' do?

// Clear and straightforward
const addNumbers = (a, b) => a + b; // Clearly states the function's purpose

Conclusion

Applying the principles of clean code, specifically “The Art of Naming,” can greatly improve code readability and maintainability. Using intention-revealing names, avoiding disinformation, being explicit and pronounceable, thinking about scope, and favoring clarity over cleverness will lead to a more collaborative coding environment and a joy to work with. Remember, writing clean code is an ongoing journey, and embracing the teachings from “Clean Code” will undoubtedly bring clarity and elegance to your projects. Happy coding! 💻🚀

--

--