Introduction
The most important concept to remember when writing code is that we write code for other developers, not just computers.
If you haven’t looked at your code in a few months and didn’t write it cleanly, remembering which function does what and how everything fits together can take a long time.
Now Consider looking at someone else’s messy and unclean code. Isn’t it a nightmare?
Refactoring code is changing the structure of a piece of code without changing its behavior.
What is a clean function ?
It’s function that another developer can read, understand and easily extend.
A function is clean when it is:
- Readable
- Searchable
- Understandable
How to achieve clean function ?
- Write small functions
- Clean Organization (Spacing and Returns)
- Eliminate Boolean flags (Should do one thing)
- Naming and standardization
- Limiting parameters
- Encapsulating conditions
1. Write small function
“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.”
—
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship
Small functions are easy to understand and have a clear purpose.Generally a function should be between 20 to 30 lines, any more than that is considered lengthy function and can be refactored in to smaller functions.
2. Clean Organization (Spacing and Returns)
All the initializations , logic and return part of a function should have space between them, check the code bellow and compare the two.
The one without spacing is more difficult to understand, while the one with spacing is easier to read.
// With no spacing
function addUser(user) {
const userData = {...user, type: 'Admin'};
if(userData) { }
return userData;
}
// With appropriate spacing
function addUser(user) {
const userData = {...user, type: 'Admin'};
if(userData) {
}
return userData;
}
3. Eliminate Boolean flags (Functions should do one thing)
One function should only do one thing. If a function does more than one thing, it should be divided into separate functions.
Looking for Boolean flags in our code is an easy way to tell if a function is doing more than one thing.
Take a look at the bellow function.
const displayUsers = (isNewUser, email, usersList) => {
// Only runs when we deleted a user
if (email) {
// remove the user having 'email' from the list.
}
if(isNewUser){
// only runs when a new user is added.
}
return defaultThing;
}
The above function does three different things using the Boolean flags. We can simply refactor the function and put each functionality into a separate function of itself.
- removeUserFromList()
- addUserToList()
Now instead of calling displayUsers()
function with different Boolean flags to do the task, we can call its own specific functions. This way our code is more readable and future developers don’t have to open the displayUser()
function to decipher what each flags does.
4. Naming and standardization
Descriptive Name
The name of a function should explain what it does. Nothing less and nothing more. Functions with names like “add,” “do” aren’t very useful because we don’t know what they’re supposed to do and there are several possibilities.
Look at the code below; the function addUser()
can add any type of user and there is no way to tell just by their name.
// Descriptive Names - BAD
function addUser(user) {
const userData = {...user, type: 'Admin'};
// adds user to DB
}
In the above code we add users of type ‘Admin’ so a better name for this function would be like this.
// Descriptive Names - GOOD
function addAdminUser(user) {
const userData = {...user, type: 'Admin'};
// adds user to DB
}
Standardize your naming
Standardize your naming; for example, functions that return or retrieve something should begin with get
, while functions that update a value should begin with set
.
// Standardization of Naming
function getAdminById(id) {
// gets admin
}
function getUserById(id) {
// gets user
}
5. Limiting parameters
Functions with more than 2 arguments should be avoided whenever possible. When the number of arguments start to growth to more than 2 arguments, we need to start thinking on how to shorten it.
One way to do it is to wrap them in specific class or Object that describe their meaning better.
Bellow is the example of bad and good practices.
// Limit Params - BAD
function getUsersFullName(first, middle, last, nickName) {
return `${first} ${middle} ${last} - AKA: ${nickName}`
}
// Limit Params - GOOD
function getUsersFullName2(userName) {
return `${userName.first} ${userName.middle} ${userName.last} - AKA: ${userName.nickName}`
}
In the above code we see that all the parameters can be wrapper in an Object that can better describe their meaning.
6. Encapsulating conditions
Whenever the condition logic of the if
or else if
statement is too long. We should encapsulate the condition and its logic in to separate function.
Have a look at the bellow code.
function getNonPrimaryUsers(user) {
if(user.isActive === true && user.isPrimaryAccount === true) {
return user.subMembers;
} else {
return new Error('User is not Primary Account Holder.');
}
}
In the condition of the if
statement we check for two things, first if the user is active and second if the user is primary account.
To make this function more readable, we can separate the conditions to their own functions with a descriptive names to precisely describe what is does.
function getIsUserPrimaryActiveAccount(user) {
const isPrimaryAccount = user.isPrimaryAccount === true;
const isActive = user.isActive === true;
return isActive && isPrimaryAccount;
}
After applying it our code it will look something like this.
function getNonPrimaryUsers(user) {
if(getIsUserPrimaryActiveAccount(user)) {
return user.subMembers;
} else {
return new Error('User is not Primary Account Holder.');
}
}
function getIsUserPrimaryActiveAccount(user) {
const isPrimaryAccount = user.isPrimaryAccount === true;
const isActive = user.isActive === true;
return isActive && isPrimaryAccount;
}
Summary
The important thing that you need to remember is that clean code is subjective . Different developers may have different opinions and ideas on what is clean code.
Go for what works for you and your team.
Clean functions are:
- Readable
- Searchable
- Understandable
How to write clean functions?
- Write small functions
- Leave spaces between declarations, logic and return statement
- Eliminate Boolean flags - your function should do only one thing
- Give descriptive names to your functions
- Limit the number of parameters
- Separate complex conditions into their own functions with descriptive names