Clean Up Your Code by Applying These 7 Rules
Readable code is maintainable code
In this post, I will go over some of the rules that you can apply to improve your code. All code samples are Javascript.
I find that Readable code is maintainable code.
The goal for me as a developer is to write quality code. Every developer on the team, despite his/her skill level, has to be able to understand the code by reading it. This helps young developers to be more confident in writing code.
Remove unnecessary code comments
Of course, some code can be very complex. I know that and I have seen that many times. Here where I would add proper documentation and code comments. Don’t get me wrong. I’m not a fan of code comments or in Javascript JSdoc. Or at least not as long as I don’t need them.
I don’t need any comments to read that this function takes X amount of arrays and merges them together into a new array.
function mergeArrays(...arrays) {
let mergedArray = []
arrays.forEach(array => {
mergedArray = [...mergedArray, ...array]
})
return mergedArray
}
Adding JSdoc to this code does not improve the readability. I expect that my team members know what the spread operator is. And if they don’t, they should ask about it during the code reviews.
And let’s not forget the commented code blocks. Only one solution for that: DELETE THAT CODE. Git has the amazing feature to checkout old code, so why leave it in the comments?
Please stop making a junkyard of your codebase.
Focus on naming
If you look at the name mergeArrays
, it should be very clear that this function combines X amount of arrays into a new one.
I know that naming things is hard. And the more complex the function, the harder the naming part will be… I use a rule to make naming easier for myself. Here’s how I do it.
Imagine a function that merges 2 arrays of numbers and generates a new unique list of numbers. How would you name it? Something like this?
function mergeNumberListIntoUniqueList(listOne, listTwo) {
return [...new Set([...listOne, ...listTwo])]
}
The name is not that bad, because it does what it says. The problem is that the function is doing 2 things. The more a function does, the more difficult it is to name it. Extracting it into 2 separate functions will make it much easier and more reusable at the same time.
function mergeLists(listOne, listTwo) {
return [...listOne, ...listTwo]
}
function createUniqueList(list) {
return [...new Set(list)]
}
if(value === 'duck' || value === 'dog' || value === 'cat') {
// ...
}
Of course, it’s easy to create a beautiful one-liner without calling a new function. But sometimes, one-liners are not that readable.
If statements
I could not find a name for this problem… See! Naming is hard…
But I see this a lot.
if(value === 'duck' || value === 'dog' || value === 'cat') {
// ...
}
By doing this, you create a readable piece of code that looks like an English sentence.
const options = ['duck', 'dog', 'cat'];
if (options.includes(value)) {
// ...
}
If options include value then …
Early exit
There are a dozen ways of naming this principle, but I picked the name “Early exit”. So let me show you a piece of code. I’m sure you saw something like this before.
function handleEvent(event) {
if (event) {
const target = event.target;
if (target) {
// Your awesome piece of code that uses target
}
}
}
Here we are trying to check if the object event
is not falsy and the property target
is available. Now the problem here is that we are already using 2 if
statements.
Let’s see how you could do an “early exit” here.
function handleEvent(event) {
if (!event || !event.target) {
return;
}
// Your awesome piece of code that uses target
}
By applying the “early exit” here, you check if event
and event.target
is not falsy. It's immediately clear that we are sure that event.target
is not falsy. It's also clear that no other code is executed if this statement is falsy.
Destructuring assignment
In Javascript, we can destructure objects and arrays.
According to the documentation, found on developer.mozilla.org, the destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
Some code samples
// Destructuring an object
const numbers = {one: 1, two: 2};
const {one, two} = numbers;
console.log(one); // 1
console.log(two); // 2
// Destructuring an array
const numbers = [1, 2, 3, 4, 5];
const [one, two] = numbers;
console.log(one); // 1
console.log(two); // 2
The problem with destructuring is that it sometimes creates a bad name for a property. The perfect example is fetching data from an API and receiving a response object which has a data property.
const url = "http://localhost:8080/api/v1/organizers/1"
const response = await axios.get(url)
const {name} = response.data
This code sample indicates that you are fetching an organizer with id 1. The organizer object has a name, and you destructure it. Nothing wrong with that.
This code works and is fine. But why is the name still name
? Will that be the only name
property in the whole scope? And from which object is it the name again?
Avoid these questions by renaming the property.
const url = "http://localhost:8080/api/v1/organizers/1"
const response = await axios.get(url)
const {name: organizerName} = response.data
This code becomes more readable. Everyone will know that the variable is the name of the organizer.
The boy scout rule
Ever heard of the phrase: “Leave it better than you found it”?
Well, this is exactly what the boy scout rule is. Leave the code better than you found it. Did you find a code smell? Refactor it! Did you find an unused variable? Remove it!
I like to compare it with a room cleaning situation. Let’s imagine that everyone in your house leaves the dishes on the sink, puts all garbage in the hallway, and leaves all the laundry in the bathroom. But every Sunday, you have to clean up the whole house and it takes well over 4 hours. Would you like that?
I’m sure that the answer is no. So if everyone immediately cleans up little parts of the house, the work will be smaller on Sunday.
This is the same with codebases. If every small code smell is left in the codebase, no one deletes unused variables, the linter is going crazy and has about 77 warnings. There will be a lot of clean-up to do, but if everyone takes his responsibility and applies the boy scout rule, a lot of the problems will be solved.
Code style
Last but not least. Determine a code style in your team.
I don’t care if you like single quotes or double quotes, spaces or tabs, trailing comma or no trailing comma. Pick 1 style and stick to it. You can do this with a linter and/or a prettier.
There are so many tools to use to fix this kind of issue. My favorite is a pre-commit hook using Husky. Prettier also has a page in their documentation about pre-commit hooks.
This pre-commit hook always runs the configured command before every commit. If you configure it in the correct way, it runs the prettier and applies all the rules on all files. This makes sure that the team always has the same code style without any bad code.
Conclusion
I know that some rules are obvious and others are not. But as a full-time developer, I get to work on different codebases. The importance of these rules only become clear in larger codebases. But that doesn’t mean that you should not apply it in your smaller projects. Improving your code quality will help you to be more efficient in your smaller projects. It will also help your team with reading the code and approving your pull requests. As I said, readable code is more maintainable, but it also has many more advantages.
If you wish to learn more about clean code, you should read Clean Code by Robert Martin. If you like my content, make sure to follow me on Twitter where I post all the links to the blogs I release. I try to release 1 every week on various topics.