Writing clean code is more than just an aesthetic or intellectual exercise. It makes our software more robust, easier to maintain, and more efficient in the long run. In a professional context, it makes our work easier for others to understand, review, debug, and modify. As software developers, we don’t merely write code for machines; we write for humans, too.
What is Clean Code?
Clean code has a few defining characteristics:
Readability : Code should be easy to read and understand at a glance. This includes not only the use of clear, descriptive variable and function names, but also the proper use of white space, indentation, and line breaks to guide the reader’s eye.
Simplicity : Code should be as simple as possible, with no unnecessary complexity. This means avoiding clever but obscure solutions, keeping functions and modules small and focused, and minimizing dependencies between different parts of your code.
Expressiveness : Code should clearly express the programmer’s intent. This means avoiding “magic numbers” and cryptic shorthand, and instead using well-named constants and functions that clearly describe what they do.
Testability : Code should be easy to test. This means designing your code in a modular, loosely-coupled way that allows individual functions or modules to be tested independently. It also means writing tests for your code and using those tests to guide your development process.
Now, let’s dive into the 12 Tips for Writing Clean Code. For simplicity, the code examples use JavaScript.
1: Pursuing Better Naming
Computer science faces two major challenges — cache invalidation and naming. Regarding the naming challenge, we can adhere to the following strategies:
- Consistent naming conventions
Adopt intuitive and meaningful naming conventions that ensure your code is more readable and understandable. In JavaScript, it is common to use a camel case for naming variables and functions, while PascalCase is used for naming classes.
// Bad practice
let firstname = 'John';
let LastName = 'Doe';
function calculateage(birthYear) {...}
class people {}
// Good practice
let firstName = 'John';
let lastName = 'Doe';
function calculateAge(birthYear) {...}
class People {}
- Start function names with verbs
Starting function names with verbs can make your code clearer and more comprehensible. It indicates that the function performs an action.
// Not recommended
function name() {...}
// Recommended
function getName() {...}
- Use meaningful names
Your code should strive to be self-explanatory. Using clear and descriptive names for variables, functions, and modules will make your code more readable and understandable. For example, instead of writing:
// Not recommended
let d = new Date();
let y = d.getFullYear();
// Recommended
let currentDate = new Date();
let currentYear = currentDate.getFullYear();
2: Keep Your Functions Small and Focused
A good rule of thumb is that a function should do one thing and do it well. If a function is performing multiple tasks, it’s a sign that it needs to be broken down into smaller, more focused functions.
// Not recommended
function handleDeveloper() {
// code to validate developer data
// code to save developer data
// code to send a welcome email
}
// Recommended
function validateDeveloperData() {...}
function saveDeveloperData() {...}
function sendWelcomeEmail() {...}
3: Avoid Deep Nesting
Deeply nested code can be difficult to read and understand. Try to keep your code as flat as possible.
// Bad practice
if (condition1) {
if (condition2) {
if (condition3) {
// Do something
}
}
}
// Good practice
if (!condition1) return;
if (!condition2) return;
if (!condition3) return;
// Do something
4: Use Comments Sparingly
While comments can be helpful, they should not be used as a crutch to explain complex or poorly written code. Good code should be self-explanatory. However, when used appropriately, comments can clarify the purpose and functionality of your code.
// Bad practice
let x = 10; // setting x to 10
// Good practice
// If we reach this point, the user is eligible for the discount
let isDiscountEligible = true;
5: Keep Your Functions Pure
A pure function always produces the same output for the same input and has no side effects. Pure functions make your code easier to test and debug.
// Bad practice
let age = 25;
function incrementAge() {
age++;
}
// Good practice
function incrementAge(age) {
return age + 1;
}
6: Limit Scope of Variables
Avoid using global variables as they can introduce dependencies between different parts of your code. Instead, keep your variables scoped as closely as possible.
// Bad practice
let counter = 0;
function incrementCounter() {
counter++;
}
// Good practice
function createCounter() {
let counter = 0;
function incrementCounter() {
counter++;
}
return incrementCounter;
}
7: Handle Errors Gracefully
Error handling is an essential part of writing clean, robust code. It’s always better to anticipate potential errors and handle them gracefully.
// Bad practice
function divideNumbers(x, y) {
return x / y;
}
// Good practice
function divideNumbers(x, y) {
if (y === 0) {
throw new Error('Cannot divide by zero');
}
return x / y;
}
8: Use the Principle of DRY (Don’t Repeat Yourself)
Avoid duplicating code. If you find yourself writing the same code in several places, consider creating a function.
// Bad practice
let x = y * 10;
let z = w * 10;
// Good practice
function multiplyByTen(num) {
return num * 10;
}
let x = multiplyByTen(y);
let z = multiplyByTen(w);
9: Use Constants for Magic Numbers and Strings
“Magic” numbers or strings are values with unclear meanings. It’s better to store them in constants.
// Bad practice
if (status === 1) {
// Do something
}
// Not recommended
const salary = 40 * 15.50;
// Good practice
const ACTIVE_STATUS = 1;
if (status === ACTIVE_STATUS) {
// Do something
}
// Recommended
const HOURS_PER_WEEK = 40;
const HOURLY_RATE = 15.50;
const salary = HOURS_PER_WEEK * HOURLY_RATE;
10: Limit Function Parameters
Avoid using excessive parameters in a function as it can make your code confusing and harder to maintain. If you need to pass multiple values, consider using an object or an array instead. For example:
// Not recommended
function displayDeveloper(firstName, lastName, address, phoneNumber, email) {...}
// Recommended
function displayDeveloper(developer) {...}
By passing a single Developer
object, we encapsulate related information and simplify the function call.
11: Keep Dependencies to a Minimum
Excessive dependencies can make your code harder to maintain and test. Keep your dependencies to a minimum, and manage them properly.
// Not recommended
class MyService {
constructor() {
this.dep1 = new Dependency1();
this.dep2 = new Dependency2();
this.dep3 = new Dependency3();
}
// ...
}
// Recommended
class MyService {
constructor(dep) {
this.dep = dep;
}
}
12: Refactor Regularly
Code can quickly become messy without regular maintenance. Take the time to refactor your code regularly, improving its structure and removing unnecessary parts.
// Before refactoring
function processOrder(order) {
validateOrder(order);
calculateTotal(order);
printReceipt(order);
}
// After refactoring
function processOrder(order) {
if (!isValid(order)) {
throw new Error('Invalid order');
}
const total = calculateTotal(order);
printReceipt(order, total);
}
Conclusion
Writing clean code requires a deliberate and disciplined approach. It’s not just about making your code work — it’s about making your code work well, both now and in the future.
If you find this helpful, please consider subscribing to my newsletter for more insights on web development. Thank you for reading!
Top comments (1)
My coding usually starts with a text processor. Having a clear concept is the first step to write clean code.