Programming is becoming more and more domain-oriented. There are hundreds of frameworks and dozens of libraries that help to overcome the complexity of low-level details in order to focus on something more important and even more sophisticated. I’m talking about business logic. And today I’ll try to convince you that static code analysis is the one thing that not only can make your coding life more pleasant but help the business to build more robust processes as well.
Business Goals
Let’s make something clear. What does business value the most in a software system? Is it performance? The modern technologies? Or maybe documentation? Actually, business cares about two things.
- The income the software gets.
- The maintainability.
The first one is pretty obvious. The essential goal of any company is to earn money. And the software should help to reach it either directly or indirectly. For example, the system that allows customers to book a hotel room online and pay in advance earns money directly. While the software that can automatically build the artifact and deploy it on the production stage earns money indirectly. Because it reduces the time that engineers spend on routine tasks and helps them to concentrate on those ones that can bring more benefit.
The second point may seem not so important in comparison to the first one, but not paying attention to it may lead to even worse consequences.
Imagine that you are a CEO of a company that provides B2C service. Let’s assume it is an online book shop. You hired software engineers that keep the development going. They implement new features, fix bugs, and so on. But the time goes by as the employees change. The new developers coming and the old ones leave. Everything is going more or else smoothly. Until the one day.
“Hey Jane. We need to provide our customers with an option to
purchase e-books as weel,” the system analyst claimed.“Actually, we have some problems with implementing the new
features. John you know, the codebase has become so messy that
it’s almost impossible to continue to maintain it. The one that
you asked may take months to implement.”“So, where are going with that?” John suspiciously questioned.
“I think we should start from the beginning and build the system
from scratch again. Otherwise it seems impossible to me to keep
the development going”.
Now your business is in a big danger. The customers will tolerate neither future updates absence nor the fact that you need to rewrite the software to make the process going. They will just leave you and choose the one company that can satisfy their needs right now.
The software applications are being used for many years or even decades. As a manager, you should be aware of the consequences of the poor maintenance level.
By the way, the rewriting system from scratch is not a good option either because of the second system effect. The right way to solve those problems is refactoring but that’s a topic for another article.
Code Checks Automatization
There are some crucial points that define the system’s maintainability. Those are naming strategies, design architecture, unit tests, code style, and etc. If developers take care of that, the code becomes clearer and easier to understand. No doubts here. But there is one caveat. Not all of this stuff can be checked manually in a sufficient way.
For instance, suppose that we want all classes to have no unused imports. Pretty reasonable requirement. How do we check it? Well, the straightforward way is to do it during the code review.
Can you spot an unused import in this class? It’s not an easy task without an IDE.
package com.kirekov.juu.monad;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class Lazy<T> {
private final Supplier<T> supplier;
private Lazy(Supplier<T> supplier) {
this.supplier = supplier;
}
public static <T> Lazy<T> of(Supplier<T> supplier) {
return new Lazy<>(Objects.requireNonNull(supplier));
}
public <U> Lazy<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
return Lazy.of(() -> mapper.apply(supplier.get()));
}
public <U> Lazy<U> flatMap(Function<? super T, ? extends Lazy<? extends U>> mapper) {
Objects.requireNonNull(mapper);
return Lazy.of(() -> mapper.apply(supplier.get()).calculate());
}
public T calculate() {
return supplier.get();
}
}
The answer is in line 6 — java.util.function.Predicate
. And this class is not so big after all. You can imagine how difficult it could be during the real code review.
Let’s assume another example. The manager has decided that we need to increase the test coverage percentage of our system. The solution that we picked is to set the minimum required coverage percentage for the new code (for each pull request). Again, how do we check it? We could ask reviewers to run all tests locally. But even if they do it, how can they distinguish the new code from the one that has already been present? It’s the edge when the result requires so many resources that it’s more reasonable not to do anything.
There could be dozens of other cases. “All comments should be written in English”, “There must be no spelling mistakes in the code”, “The codebase should be formatted according to the predefined code editor file”, and so on. The key point is that we need some sort of automatization to be able to integrate those checks.
Arguments
When I talk about static code analyzers and how important their usage is, I hear many arguments about why one team cannot integrate them within the product.
Our code base is already huge to change the workflow
This seems like a reasonable statement but only under particular circumstances. If your project has no tests and it’s five years old, it’s impossible (or maybe too expensive) to increase the coverage up to 80% instantly. But you don’t have to. Start with a lower bar and then continuously increment it. It can be 5% at the beginning that turns to 25% in a quarter.
Another example can be applied to code quality itself. Most static analyzers are configurable. If you tried to set Checkstyle Google configuration to the mature project, you would probably get hundreds or even thousands of errors. You can start with just one rule. Ar first glance, it seems not so important. But after the moment when the configuration reaches the repository, you can be sure that no one else can violate this rule in the future.
We review pull requests according to the style guide. Static analyzers are redundant for us
Do you remember an example with an unused import? What if you have twenty similar rules? How can you be sure that reviewers spot all these small details? Anyway, you have already declared your style guide in Wiki/Markdown/HTML. Why don’t you transfer it in the format that is understood by one static analyzer? I know that not everything can be automated. But if it is possible, it should be done.
Static analyzers don’t let us implement features fast
If maintainability is not your priority, then I can agree with you. But you should be aware of the consequences. And they can be dramatic as we have seen before.
Our team consists of many Junior developers. The static analyzers slow them down too much
Code static analyzer’s requirements can be a real challenge for the one who has started to program recently. But we grow as professionals when we solve difficult tasks. Anyway, how can you become stronger, if you don’t increase the weight?
We have only Senior guys on our project. Static analyzers are not needed
Suppose that I want to build a skyscraper. I hired a group of professional builders. So, they don’t need belays. Because we all know that highly skilled people don’t make any mistakes, right?
I think you see where I’m going. It does not matter how professional you are. We all make mistakes. And we all need belays.
More than that, it’s my personal belief that the fact that you
want your code to be checked characterizes the real professional.
Tools
The market provides us with lots of static code analyzers. I listed some of the most popular ones.
SonarQube
That’s my personal favorite. It supports 27 programming languages (at the moment of writing). It has predefined recommended code styles for everything and it is easily integrated with Github/Bitbucket/Gitlab. Although it costs money, you can use SonarCloud for your open-source projects absolutely for free.
Checkstyle
One of the most well-known and mature static code analyzers for Java. All you have to do is to add a plugin for your Maven/Gradle project. No CI integrations. No pricy subscriptions. And lots of available configurations.
PVS-studio
It’s a static code analyzer for C, C++, C#, and Java. It can be installed either as a plugin in your IDE or as an addition to existing CI/CD instruments (including SonarQube). Although the variety of supported language is not wide, the product analyzes the code really deep and can find well-masked bugs and vulnerabilities.
EsLint
A Javascript/Typescript linter. It has become so popular, that it’s almost a standard to include it in your React/Angular/Vue project. If you do frontend or backend on NodeJS and never heard about ESLint, you should definitely try it.
Conclusion
I consider that static code analyzers are not the replacement but a great addition to existing processes of writing well-maintained code. If you have any questions or suggestions, please write your comments down below. Thanks for reading!
Top comments (0)