This post is part of our ‘The Miners’ Guide to Code Crafting’ series, designed to help aspiring developers learn and grow. Stay tuned for more!
Have you ever looked at a coworker’s code — or even your own after a while — and spent hours wondering "What is this variable for?" or "What is this part of the code doing"? If not, don’t celebrate too much; it’s bound to happen sooner or later.
To help you in these situations, this article presents 4 practical tips to keep your code clean and facilitate collaboration and maintenance.
What is Clean Code and Why is It Important?
Even though it had been used by developers for quite some time, the concept “Clean Code” was popularized after the release of the book “Clean Code: A Handbook of Agile Software Craftsmanship” written by Robert C. Martin, aka Uncle Bob, it refers to a set of best practices that aim to improve the quality of the code by making it:
Readable: The code should be easy to understand.
Maintainable: The code should be easy to modify and update as requirements change.
Efficient: The code should perform well without unnecessary complexity.
Consequently, Clean code is an essential practice in a developer’s daily routine, benefiting the individual and the entire development team.
Furthermore, by prioritizing clarity, clean code improves readability and maintainability, making it easier to read, understand, and modify, leading to faster development. Enhanced team collaboration is facilitated by adhering to coding standards, allowing developers to easily grasp each other’s work and collaborate more efficiently.
In addition, clean code simplifies debugging by making it easier to identify and fix issues. Finally, by reducing the likelihood of introducing bugs and errors, clean code contributes to higher software quality and reliability.
1. Use Meaningful Names
Naming variables is undoubtedly one of the most challenging tasks for a programmer. However, to write clean code, it is essential to carefully consider the names chosen for identifiers in the code, as your choices can significantly impact how understandable the code is.
Follow the existing naming conventions in the project, or if it’s a new project, stick to the standards of the programming language being used and ensure consistency throughout the code.
Choose descriptive names for your variables, functions, and identifiers in general. Avoid abbreviations so that your code is clearer and more descriptive. Make sure that the name you choose conveys to the reader what that identifier means and what it is doing there.
This is one of the crucial points for the developer to spend less time understanding your code.
// Bad
function calc(p, amnt, d) {
return (p.price * amnt) - d
}
function createUser(usr) {
const new_user = new User(usr)
...
}
// Better
function calculateTotalWithDiscount(product, amount, discount)
return (product.price * amount) - discount
}
function createUser(userData) {
const newUser = new User(userData)
...
}
2. Avoid Hard-Coded Values
Magic numbers or hardcoded values are numbers, characters or strings that appear in the code without any context, making it difficult for developers who read the code to understand the it. Avoid using these values, by defining them as constant and giving a descriptive name.
// Bad
function validatePassword(password) {
if (password.length < 8) {
throw new Error('Invalid password')
}
...
}
// Better
const MINIMUM_PASSWORD_LENGTH = 8
function validatePassword(password) {
if (password.length < MINIMUM_PASSWORD_LENGTH) {
throw new Error('Password is too short')
}
...
}
3. Use Comments Only When Necessary
Comments should be used as a last resort, as they often serve to compensate for bad code, such as poorly constructed conditionals.
Instead of fixing the underlying issues, developers end up simply add comments to try to make the code more understandable. This can lead to a tangled mess of comments that do little to improve code quality.
When the comment is intended to explain what or how the code is doing something, although they may seem helpful, tend to become inaccurate over time. This is because the function is often updated but the comment is not, consequently conveying a misleading understanding of what is being executed.
The best comment a developer can write in a code is the comment that he found a way not to write.
However, there are cases where it’s impossible to demonstrate your intent with code alone, such as when you need to pause the code’s execution. In these situations, comments are necessary and should be written.
// Bad code that needs a comment
// Verify if page is available to be displayed
if ((page.createdAt > new Date(2025, 1, 1)) && (page.visitors !== 0) && !page.draft)
// Better code
if (page.isAvailable())
// Bad, excessive comments explaining code
// This function receives an object containing email and password and creates an users
function createUser({ email, password }) {
// checks if user password is valid
validatePassword(password)
// saves user to the database
UserRepository.saveUser({ email, password })
// sends user welcome email
UserMailer.sendWelcomeEmail(email)
}
// Better, this code alone would probably cause some confusion to the reader
// Wait to sync with some service X
sleep(FIVE_SECONDS)
doSomething()
4. Apply the Single Responsibility Principle
The Single Responsibility Principle — also known as SRP — is the first principle of the well-known acronym S.O.L.I.D. This principle states that each function or class in your code should have a single responsibility, or as described by Robert C. Martin, each module should have only one reason to change.
But now you may be wondering: “What is a responsibility?” or “What are the reasons for change?”, and that’s why most people don’t understand what this principle means.
The answer is simple: Responsibility is the obligation to perform a task and possess only the information relevant to that task. The reasons for change are requests made by people, typically from departments or stakeholders who utilize the altered functionality.
Imagine you just implemented a feature responsible for creating an user
function createUser({ email, password }) {
if (password.length < MINIMUM_PASSWORD_LENGTH || !password.match(PASSWORD_REQUIREMENTS_REGEX)) {
throw new Error('Password is too short')
}
try {
dbConnection.execute(`INSERT INTO users (email, password) VALUES (${email}, ${password})`)
} catch {
throw new Error('Failed to create user')
}
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
auth: {
user: '1a2b3c4d5e6f7g',
pass: '1a2b3c4d5e6f7g',
}
});
const mailOptions = {
from: 'example@mail.com',
to: email,
subject: 'Welcome!',
body: 'Imagine a really nice welcoming message!'
}
transporter.sendMail(mailOptions)
}
A week later, the marketing team might ask you to change the email text, the IT team might announce an SMTP server host change, or you might need to adjust password validation rules.
This way, any change to the email text, mailer settings, database query, or password validation becomes a reason to change the createUser
function, but they shouldn’t.
When the marketing team asks to change the email, it should be a reason to change the function that is responsible to send emails, not the function that creates the user.
When the IT team says that the SMTP server credentials changed, it should be a reason to change the function that configures the mailer, not the one creating the users.
This code would be much cleaner this way
function createUser({ email, password }) {
validatePassword(password)
UserRepository.saveUser({ email, password })
UserMailer.sendWelcomeMail(email)
}
If you still have questions about responsibilities or reasons to change, see this post by Uncle Bob himself talking about The Single Responsibility Principle.
Conclusion
By following these 4 tips, you can transform your code into something clearer, more organized, and easier to maintain. Writing clean code is an investment that brings significant returns in productivity, collaboration, and software quality. Start applying these practices in your projects and see the difference it makes in your daily development workflow.
We want to work with you. Check out our "What We Do" section!