How To Keep Code Quality Under Control In 7 Steps
These 7 Steps Of Code Quality Control Process will show you what to do to improve the Code Quality in the software that you build.
Join the DZone community and get the full member experience.Join For Free
In the article Code Quality Control And Why You Need It I described shortly importance of keeping high quality of code. This time, you will learn what are the 7 crucial elements that should be a foundation of any Automated Code Quality Control Process. This process can help you to keep your head calm and focus on important things.
The mentioned essential areas of the code quality control process are:
- Code Review
Let’s try to have a closer look at each of these.
1. Code Style
“Clean code is simple and direct.
Clean code reads like well-written prose.”Grady Booch
Have you ever thought about how stylish is your code? Does your code read like well-written prose? Why is it so important?
Well, the way your code looks, shows how much you care about:
- Craftsmanship — This is how you build your personal brand as a developer,
- Teammates — You create code once but people will be reading it many times. So it is much more important for code to be easily readable rather than easily writeable,
- Yourself — Lack of care always bites back. Sooner or later.
Even something as simple as inconsistent indentation can make code analysis a nightmare. And not to mention annoying and unnecessary merge conflicts.
Luckily, we can automate code style checking and correcting. Modern IDEs (Idea/Eclipse) can help you keep the code style correct by amending your code automatically.
Just remember to make the code style consistent across the team members. Each developer should use the same code style definition. Let it be a shared .editorconfig file or IDE-specific configuration.
Sharing the code style definition with your team is the first step. But, as long as we are talking about the process we need a way to check if everyone is following the code style rules.
The easiest way to achieve that is to integrate style checking into your build process. We can use Checkstyle and run it every time we push a code change to the repository. This can be achieved by using the Jenkins plugin or Maven/Gradle script.
2. Code Correctness
So we have code style under control. But stylish code is definitely not enough to say that our code is solid.
Often, when we are working hard on solving a challenging problem and trying to meet deadlines, we may fail on following all the best practices.
Unfortunately, violating best practices can lead to serious consequences like:
- Infinite loops — Seemingly easy to identify but not always. If you are reviewing hundreds of lines of code daily, it is not that hard to miss something like this. I had the questionable pleasure of missing one during the code review. Somehow the code passed the testing phase too. Guess what happened next.
- Unintentional state modifications — Difficult to identify during code review and testing.
- Race conditions — Even more unpleasant type of error than the previous one.
Luckily, we do not have to spend hours scanning our code in search of simple, yet difficult to spot errors.
We can use one (or all) of the free tools that can do that for us:
Some of these tools can also identify duplicated code and find potential performance issues.
Similarly to Checkstyle, we can integrate these tools into our IDE and make code flaws checking a breeze.
There is one more option to make our code more robust. You can use the Checker Framework that enhances the Java type system and allows to add checks in code to prevent potential issues in the future. Requires some extra manual work while coding but it pays off.
But, again, we should always remember to make it run during the project building process. In case we forget to run it before we push our code to the repository.
3. Code Complexity
In the previous section, we focused on finding common programming flaws in our code.
In this section, we will take a look at the code complexity. Code that is difficult to reason about is difficult to maintain and extend. And no one wants to work with such code.
Popular metrics for checking code complexity are:
- Cyclomatic and NPath complexity — Calculates the complexity of the method’s control flow. In other words, it shows the number of different paths that we should cover by tests (testability). Doesn’t actually tell how difficult it is to understand the code for human.
- Cognitive complexity — Shows how difficult the code is to understand for humans (readability).
To automate the process of code complexity checking, you can use the following tools:
- Checkstyle, SpotBugs, or PMD for Cyclomatic/NPath complexity,
- SonarQube (and SonarLint IDE plugin) for Cognitive one.
4. Code Design
Now let’s take a look at the design of your code and design flaws that static code analysis tools can identify.
Poor design (within the meaning of Object-Oriented Design) can cause the same problems as the high code complexity. Similarly, poorly designed software is difficult to understand, troubleshoot and change. So the cost of software development will be unnecessarily higher.
Again, do not expect a simple solution to resolve all the design issues. But, many Object-Oriented Design best practices have been converted into automatic source checks. These checks can prevent our code from becoming overcomplex (e.g. too high inheritance hierarchy) or oversimplified (e.g. God class).
Everything should be made as simple as possible,
but no simpler.Albert Einstein
There are many different rules for design checking but I recommend starting with those related to size violations.
Checkstyle and PMD offer a nice set of checks related to the excessive length of:
These rules might seem trivial. But you should focus on basics and ensure your code follows basic design rules first before you move on to the advanced ones.
Beyond The Basics
So, we have covered basic design checks. But there is more our favorite static analysis tools can offer. Find some examples of the most useful rules below:
- PMD’s LawOfDemeter — Law of Demeter is a simple rule that can help in reducing tight coupling between classes.
- Checkstyle’s DesignForExtension — based on Effective Java 3rd Edition book by Joshua Bloch, Item 17: Design and document for inheritance or else prohibit it.
- PMD’s CouplingBetweenObjects — detects tightly coupled classes that are difficult to test, analyze and extend by measuring its number of unique attributes, local variables and return types.
- jPeek — you can use this tool to measure the cohesion of our classes and as a result, help to keep the high cohesion of classes, modules, packages.
Besides, SonarQube has many size-related metrics and nice visualization of those.
Far Beyond The Basics
If you are looking for a more advanced analysis of design problems, you can check the following tools:
- embold — Includes a great number of advanced design flaws checks targeting coupling and cohesion.
- CodeScene — Allows not only finding potential design issues but also development bottlenecks by analyzing historical code changes in Version Control System. CodeScene has evolved from the open-source project Code Maat.
Please note that these free for open-source projects only.
5. Code Security
We all know that developers care about the security stuff. They do the code review with OWASP TOP 10 in hand. Moreover, they check the CVE database every day to make sure none of the 3rd party dependencies have any security vulnerabilities.
Is that OK? Definitely NOT.
We are responsible for making our code secure to the same extent as we are for making it extendable, maintainable, performant, etc.
The problem is that it is not that exciting as building new stuff, analyzing design challenges, or trying out new, shiny technology.
Code Security Checking
So, how should we do that? How can we make our code secure with the least possible effort?
Should we really check the code with an OWASP 10 list in hand? Well, unfortunately, it is not that easy. It requires deep knowledge in the security field. Besides, you need to know the internal workings of the technology used well.
To clarify, I am not a secure coding expert and probably will never be. Simply because I am focused on different areas of software development craftsmanship. But, it doesn’t mean I am not responsible for creating a secure code and delivering software that is free from known vulnerabilities.
Below you can find basic security-specific knowledge resources that every developer should know:
- General secure coding rules (OWASP TOP 10)
- Technology specific secure coding rules (Oracle Java Secure Coding guidelines)
- Most common security vulnerabilities (Mitre CWE Top 25, SANS TOP 25)
But before you become Secure Coding Master, let’s add some automation to the code security checking.
Below you will find 2 tools that can automate the security checking process:
- FindSecBugs — SpotBugs plugin for security audits of Java (mostly web) applications. You can integrate it into your build process (Maven, Gradle) and also use it while coding thanks to IDE plugins.
- SonarQube — an all-in-one tool like this must include a decent set of security-related checks. Also, SonarSource (the company behind SonarQube) acquired RIPS Technologies in 2020. This will take Sonar’s security checking capabilities to the next level.
There are two more, security-related topics, that should also be part of every Code Quality Control process. These are 3rd Party Dependencies and Docker Images security scanning. But, as these are not strictly related to our code, and to make this article shorter, I will discuss these topics in a separate article(s).
6. Code Coverage
Now, when our confidence level of code quality is high, the time has come to check your code coverage.
You can’t keep a calm head without a decent number of automatic tests, which you can run often and fast, to check if your code still works as expected. Furthermore, you can’t safely refactor your code quality without automatic regression testing.
“Code without tests is bad code. It doesn’t matter how well written it is. It doesn’t matter how pretty or object-oriented or well-encapsulated it is.”Michael C. Feathers
Unfortunately, sometimes we do not write proper tests that cover our code. This may happen e.g. when we struggle to deliver another release on time. Or we write tests but not covering all the possible flows. Because of that, we need some metrics to check if our code has been sufficiently tested or not.
There are many different test coverage metrics. But the most important are:
- Statement/Instruction coverage — How many of the statements in the program have been executed?
- Line coverage — How many lines of source code have been tested (a superset of instructions coverage)?
- Branches coverage — How many of the branches of the control structures (if statements for instance) have been executed?
- Method/Function coverage — How many of the methods defined have been called?
To calculate the coverage of your code you can use your IDE features. Two popular options are Coverage in IntelliJ IDEA and JaCoCo in Eclipse.
Using coverage tools inside your IDE gives you the opportunity of seeing which parts you have covered and which not right in your code editor.
Of course, we can’t forget to integrate Code Coverage calculation into our build process. This will ensure we are not falling short on testing our code by checking the metrics continuously.
- JaCoCo — The most popular code coverage tool in the Java world. You can integrate it into the build process using Maven, Gradle, or even Ant. JaCoCo has out-of-the-box support for collecting coverage information from remote processes. This can be helpful if we want to include End-to-End testing into the final code coverage report.
- OpenClover — A young project created by guys from Atlassian. Apart from a standard set of coverage metrics and integrations, it contains a nice set of extra code metrics that highlights the code that needs coverage improvement the most. Definitely worth having a closer look.
- Cobertura — Used to be the most popular code coverage tool for Java. But seems not to be an actively maintained project anymore.
JaCoCo is also used by Sonar which allows for monitoring how your code coverage changes in time. You can also define alerts if a new code coverage level is too low (Quality Gates notifications).
7. Code Review (Semi-Automatic)
Alright, we’re getting closer to the end of a list of crucial elements of the Code Quality Control Process. The last element to cover is Code Review.
Code review is the most complex and problematic element in the whole process because:
- It is difficult to automate (at least fully).
- Its results may be inconsistent (depending on the skills, seniority, attitude, etc., of the reviewer).
- It is error-prone (due to its manual nature).
Let’s take a quick look at each of these problems.
Automation by Static Analysis
I do not know any tool that can completely automate the process of code review. But all the steps we have covered so far are actually kind of automation of the Code Review process.
In other words, the more elements of the process we cover by automatic analysis the less we will have to do during a Code Review.
And this is actually very good news as the fewer things you have to think about at the same time the better the results should be. And the whole process becomes less error-prone at the same time.
So now, you can do a proper Code Review by focusing only on the elements that automatic code analysis did not cover:
- Functional requirements review
- Project-specific requirements review (if you can’t automate it by writing custom rules in Checkstyle or PMD)
- Advanced design or architecture review.
More on Code Review Automation
Merge/Pull Request Decoration is something you should has a closer look at if you are looking for more automation in the Code review process. This feature is very convenient if there is a lot on your shoulders and you strive to cut unnecessary actions.
It is much easier to log into your SCM and see the static code analysis results right in the code when you open a Merge Request.
You can find this feature in SonarQube (available in paid options only).
Developers conduct Code Review in various ways.
One focuses mostly on a design side while the other is a performance freak and analyzes the time and space complexity of every line of code.
On one side it’s good as there are different views on Code Quality in a team. But on the other side, the result of Code Review might be different depending on who performs it.
And that is not that good at all.
So to make the code review process more consistent it is good to have a Code Review checklist. Such a list should show what to check during the manual code verification process.
I like Google’s Code Review Developers Guide. It is a bit long read but you can always prepare a shortlist out of What to look for in the Code Review section so that every developer in your team knows how to approach Code Review consistently.
So that would be it. We have covered 7 elements of the solid Code Quality Control Process. It might seem like something very complex and difficult to implement. Even unachievable. But you don’t have to build the whole process at once.
If you haven’t used any of the tools described in this article before, then adding one of them should make a difference.
Of course, there are other aspects of implementing the Code Quality Control process. If you are starting a new project then building such a process shouldn’t be a problem as the technical debt is probably not that big. But, if want to start controlling the quality of the code in the legacy system, then you should prepare yourself for war with technical debt first. It may take a while before the static analysis tool that you chose, shows no warnings at all (assuming you haven’t turned most of the rules off…).
Whether you like this article or not I encourage you to leave a comment.
Thank you for reading and till the next time!
Published at DZone with permission of Artur Kluz. See the original article here.
Opinions expressed by DZone contributors are their own.