bene : studio is a global consultancy, helping startups, enterprises and HealthTech companies to have better product
Principles of wiriting clean code
At bene : studio we love knowledge sharing to help the community of professionals. With 10+ years and over 100 projects behind us, we have a vast amount of experience. This is why we have launched a knowledge base on our blog with regular updates of tutorials, best practices, and open source solutions.
These materials come from our internal workshops with our team of developers and engineers.
Clean code to give quality to clients
Robert C. Martin: Clean Code (ISBN: 9780136083238), is a book summarizing decades of software development best practices, which became a standard in the IT industry. It is strongly recommended to read at least Chapter 1 for all non-technical readers of this document since this chapter has no tech requirements.
Writing software is like any other kind of writing. When you write a paper or an article, you get your thoughts down first, then you massage it until it reads well. The first draft might be clumsy and disorganized, so you wordsmith it and restructure it and refine it until it reads the way you want it to read. Master programmers think of systems as stories to be told rather than programs to be written.
Why does clean code matter? Basically, to avoid this:
Teams that were moving very fast at the beginning of a project can find themselves moving at a snail’s pace. Every change they make to the code breaks two or three other parts of the code. No change is trivial. Every addition or modification to the system requires that the tangles, twists, and knots be “understood” so that more tangles, twists, and knots can be added. Over time the mess becomes so big and so deep and so tall, they can not clean it up. There is no way at all. As the mess builds, the productivity of the team continues to decrease, asymptotically approaching zero.
Naming things in software is so important that several sources state it as one of the most important things: There are only two hard things in Computer Science: cache invalidation and naming things. — Phil Karlton
The hardest thing about choosing good names is that it requires good descriptive skills and shared cultural background. This is a teaching issue rather than a technical, business, or management issue. As a result many people in this field don’t learn to do it very well.
General rule: take care with your names and change them when you find better ones!
Renaming is usually a single operation in popular code editors. If you don’t find proper names in the code you are working with, consider renaming it. Consult with the author if the name was not introduced by yourself. The same applies to file names – just make sure that versioning systems will know about the rename, too.
Use Intention-Revealing Names
General rule: If a name requires a comment, then the name does not reveal its intent. Good names and comments are inversely proportional to each other. If you are tempted to write a comment in your code, consider using better names first, until the code lines become nice sentences without necessary explanation.
Consider this instead:
Consider this instead:
General rule: avoid words whose entrenched meanings vary from our intended meaning!
For example, if we see a variable with name itemCount, we expect that this is a number, and holds the number of items (with some specific criteria). We will be surprised if we discover that it is an object with many fields.
Make Meaningful Distinctions
Because you can’t use the same name to refer to two different things in the same scope, you might be tempted to change one name in an arbitrary way. Don’t do this. Try to rename them in the way that the programmers will know which name belongs to what kind of object. For example, if we have a payment function like this,
we don’t know which customer should send and receive payment. Consider rename like
Pick one word per concept
Pick one word for one abstract concept and stick with it. For example, if you are using fetchItems for an API call which is fetching items, do not use getUsers for fetching users. Use fetchUsers instead.
Several other examples can be found in the book, like
- Use Pronounceable Names
- Use Searchable Names
- Avoid Encodings
- Avoid Mental Mapping
- Don’t be cute
Functions are the smallest building blocks of source code.
When the function code lines grow over 10, you should check the possibility of extracting some functionality. Usually, it will improve readability. Do not write functions that have more than a few dozen lines.
Do one thing without side effects
Functions should do one thing. They should do it well. They should do it only!
One way to know that a function is doing more than “one thing” is if you can extract another function from it with a name that is not merely a restatement of its implementation. Another way is to check the level of abstraction per function. If the level of abstraction is more than one, you should try to reduce it to one, and extract low level abstractions to another function.
For example, we usually use filter, map, and reduce functions on arrays to transform the original data according to the business logic. Although their callback functions can be written in-line, it is always a good idea to consider extracting the callback function if it is not a trivial one-liner.
If you follow the rules herein, your functions will be short, well-named, and nicely organized.
Have not too many arguments (no more than two)
If the function arguments are parts of one single concept, wrap them into an object and pass that one to the function. Instead of
Consider wrapping x and y into a single object
Don’t use flag arguments. Passing a boolean into a function immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing. It does one thing if the flag is true and another if the flag is false!
Have no side effects
Side effects are lies. Your function promises to do one thing but also other hidden things. Sometimes it will make unexpected changes to the variables of its own class or data structure, often resulting in strange temporal couplings and order dependencies.
Check the following code snippet. We expect that this function will check the password validity. In fact it does, but as a side effect it invalidates user token if password validation is not successful.
Command Query Separation
Functions should either do something or answer something, but not both. Either your function should change the state of an object, or it should return some information about that object. Doing both often leads to confusion.
DRY (Don’t Repeat Yourself)
Duplication may be the root of all evil in software. Many principles and practices have been created for the purpose of controlling or eliminating it. It would appear that since the invention of the subroutine, innovations in software development have been an ongoing attempt to eliminate duplication from our source code…
If you are tempted to copy code from other sources inside the project, consider the possibility of extracting it into a single entity that can be reused in multiple places.
According to the book, “comments are, at best, a necessary evil. If our programming languages were expressive enough, or if we had the talent to subtly wield those languages to express our intent, we would not need comments very much—perhaps not at all.” It is clearly making a difference between good (like legal and todo) and bad (commented out code) comments.
The proper use of comments is to compensate for our failure to express ourselves in code. Note that I used the word failure. I meant it. Comments are always failures. We must have them because we cannot always figure out how to express ourselves without them, but their use is not a cause for celebration.
Strong words, especially if you are working with a code quality tool which warns you if you don’t comment enough. But in the long term I agree with it. But before we start to blame all types of comments, take a look at the list of good comments according to the book:
- Legal comments: Copyright, Released under MIT or any kind of license
- Documentation of public APIs (for example with JsDoc)
- TODO comments
Whenever you comment because you think that it is not clear what the code itself does, consider another solutions:
Remember the chapter about naming things. We found that proper names are inversely proportional with bad comments. It is not surprising that therefore we can eliminate some ugly comments by choosing better names.
Instead of commenting
We can use descriptive names
If your logic is doing something not trivial and you want to clarify it by a comment, consider extracting that into a function. For example if the above calculation of benefits is a part of a large calculateSalary function, you can extract it out as a compensateWithBenefits function. Note: if we remember that functions should do one thing, the isEligibleForBenefits and compensateWithBenefits should be 2 different functions, one is checking another is modifying the employee object.
“You should take care that your code is nicely formatted. You should choose a set of simple rules that govern the format of your code, and then you should consistently apply those rules. If you are working on a team, then the team should agree to a single set of formatting rules and all members should comply. It helps to have an automated tool that can apply those formatting rules for you.”
The book recommends to obey the following (soft) rules:
- Vertical: File length max. 500 lines (but average is not above 200 lines)
- Horizontal: Row length max. 100-120 Characters
It is a good practice to use automatic formatting and lint tools. These tools should be running automatically before committing code.
“Clean code is readable, but it must also be robust. These are not conflicting goals. We can write robust clean code if we see error handling as a separate concern, something that is viewable independently of our main logic.”
Wrong error handling: if it is nearly impossible to see what the code does because of all of the scattered error handling. Error handling is important, but if it obscures logic, it’s wrong.
Boundaries (3rd party software)
“Code at the boundaries needs clear separation and tests that define expectations. We should avoid letting too much of our code know about the third-party particulars. It’s better to depend on something you control than on something you don’t control“
“Tests are as important to the health of a project as the production code is. Perhaps they are even more important, because tests preserve and enhance the flexibility, maintainability, and reusability of the production code. So keep your tests constantly clean. Work to make them expressive and succinct. Invent testing APIs that act as domain-specific language that helps you write the tests. If you let the tests rot, then your code will rot too. Keep your tests clean.”
“The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change. This principle gives us both a definition of responsibility, and guidelines for class size. Classes should have one responsibility—one reason to change.”
We should use independent static code analysis tools to find out problems in our codebase. Flaws which could be part of the codebase in spite of code reviews, can be pointed out of an automatic analysis. We show an example analysis done with Sonarqube, one of the popular static code analysis tools.
The overall result is passed, you can see that there are 6 code smells. Clicking on issues, you can check the details of the problem and how to fix it. It is worth adding Sonarlint extension to your IDE if it is available.
Read the book!
These were the main concepts of Clean Code best practices in a nutshell. We highly recommend reading the full book: Robert C. Martin: Clean Code, and practicing it every day.
Join our team, we are hiring!
Read moreSee all open source
Using Schedulers and Cron in Node.JS
Follow out tutorial and learn about scheduling in Node JS
Why we love Next.js and server-side rendering
You should use Next.js because of its benefits in SEO, Integrated routing, pre-rendering and styling.
Integrating Garmin into a running app
Learn how we integrated Garmin library into the Coopah running companion app and what challenges we came accross.
Functional programming in Java with examples
See examples if this style of programming, to make code more concise and less complex.
How to become a VSCode power user
In this article, we are going through some of our most commonly used extensions, key bindings, and best practices.
Let bene : studio enhance
your digital product!