Better Practices With Clean Code
Why should we care about clean code?
The main reason to care about clean code is due to the developer team's speed to maintain and deliver more functionalities in an existing project. It's not just about aesthetics, the people involved in the project will have more ease and less stress to work on it.
Roadmap to achieve a cleaner code:
- The boy scout rule
- Variables
- Functions
- Comments
- Formatting
- Unit Tests
- Refactoring
Introduction
One thing all developers should perceive is that they are writting not only for machines to interpret their code, but for humans either. It's important because not only others will need to understand the code, but himself too, because he may have started working on other projects or features in the future, and when he comes back, the developer will be out of context.
So, when we are coding, we should consider the order and "Human" meaning of the classes/functions/variables/components. It must not be just a procedural "cake recipe".
The boy scout rule
Leave your code better than you found it
That may seem like a obvious advice, and it is! But it's not about when we leave our project we need to make it perfect. Instead, it advices us to gradually and frequently refactor our code. That way, it won't slow us down, it will just speed us up when we get back to that code, and since we are not trying to achieve the holy grail, most unrealistic perfect code, it shouldn't take too long to do it.
Variables
Rules that can significantly improve the code:
- Meaningful names
- Pronounceable/Searchable names
Dirty Example
Note that "x", "y" , "r", "special", "anmals", "f" and "a" have names that doesn't mean anything for humans, they just store values that we need to look in the code for their meaning.
Clean Example
Now we know what each variable does in its context. And we don't have the magic number "0.5" floating arround, we can see why it is there.
Functions
Rules that can significantly improve the code:
- Function names (follow the same principle as variables)
- Size of the function (Vertically and Horizontally)
Usually when a functions is too big, it is probably not following the principles of “Single Responsibility Principle” (SRP) or “Don't Repeat Yourself” (DRY). - It shouldn't have more than 3 parameter
This one is debatable, but one thing we can all agree is that less parameters is better for testing (since there are less combinations of inputs and expected outputs), understanding and use of the function.
Dirty Example
Here we can't scale the function if we had more loans and we have duplication of codes in lines 19–22 and 26–29.
Clean Example
4. Indenting
Since the indenting guides us when we are reading, it should always make sense. Content of functions, conditions, classes should match their opening and closing brackets, giving a sense that the code inside the bracket "belongs" to that section.
5. Have no side effects
In this function, it says to us that it will "check the password passed", but if you look at line 3, you will see that it has a second responsibility to "startAdminSession" if the password is "Admin". That is certainly an side effect that this function should not be responsible of.
7. Guard clauses
I started really to notice this when I learned swift language, because it has a "guard (condition) else { return }" statement that really started to make sense for code cleanness for me and check for null variables of course.
Dirty Example
Clean example
Comments
If you feel the need to write a comment, try to refactor your code first, in a way that it will be self-explanatory. There are cases that they are really hard, but try to minimize the most you can. And there is always a risk that your comment will be left behind in terms of updated to your code, leading to confusion afterwards.
Good comments
- Warning of consequences: This one should be used moderately, but it could prevent unwanted consequences from happening.
- TODO/FIXME: They can be used as reminder, but if written in the project must be prioritized to not accumulate all over the project. Usually that is better controlled outside of the project.
- JSDoc like comment: They can be used to document more complex code.
Bad Comments
- Redundant
- Comments vs Variable/Functions
Usually well named variables and functions gives a good notion of what it does. Think about our previous example function "checkAdmin", is it a good name? it could be better, a clearer definition would be "IsAdminAuthenticated". - Commented-out code
This one a caught myself falling into it. The problem is if you comment a code and let it stay in your project, no one except you will know if they can delete that code, because it certainly has a reason to being there instead of deleted. If we keep doing that practice, we will overload our project with undesired polution of commented code (of course, there are exceptions for this).
Unit Tests
Best practices of TDD always tells us to write our code first, and then our production code. There are four things you should consider when dealing with tests:
- The three Laws of TDD
1. You may not write production code until you have written a failed unit test.
2. You may not write more of a unit test than is sufficient to fail and not compiling is failing.
3. You may not write more production code than is sufficient to pass the currently failing test. - One assert per test (similar to the DRY principle, don't do too much in a single test)
- F.I.R.S.T
- FAST: tests should fast, because slow tests will discourge us to run it frequently.
- INDEPENDENT: tests should not be dependent because they can cause a chain effect of failures that is hard to deal.
- REPEATABLE: tests should be able to run in any enviroment, develop, homlog, production, it doesn't matter which environment it is running.
- SELF-VALIDATING: tests should alway output a boolean, because it will speed up the reading of the result of the tests.
Restructring vs Refactoring
Restructuring is any rearrangement of parts of a whole. It’s a very general term that doesn’t imply any particular way of doing the restructuring.
Refactoring is a very specific technique, founded on using small behavior-preserving transformations (themselves called refactorings)
— Martin Fowler
Why refactoring is important?
- Improves the Design of the software
- Boosts programming speed
- It makes code easier to read
- It helps find bugs
- It helps to understand better the code you are working on
I won't explore in this article techniques of refactoring, because it would get too long for that. But I just wanted to mention it because it really help us as developers to make a more maintanable project and grow as professionals.
If you want to know more about this kind of content, try reading the books that are in the "References" section, I used them to learn and write this article. Since there is a lot of content there, I just made a synthesis of things that impacted me the most .
References:
Robert Cecil Martin, Clean Code (Prentice Hall, 2008).
Kent Beck and Martin Fowler, Refactoring: Improving the Design of Existing Code ( Addison-Wesley Professional, 2018).