Top 6 Code Quality Metrics to Empower Your Team

Perfecting code quality is a goal that most software developers share, but while the intention is straightforward, the strategy for achieving it can be complex. How and what you measure are key factors in improving the outcomes of the review process.

This is especially true for teams that adopt principles of continuous improvement, ongoing attention to technical excellence, and regular reflection. With over 20 years of experience in software development, JetBrains has gathered insights to share about which metrics can be most effective for teams.

Practical code quality metrics, and how to measure them

1. Cyclomatic complexity (CYC)

CYC is a measure of the complexity of a program’s code flow based on the number of independent paths through the source code. This is an important metric because as complexity increases, code becomes more difficult to understand, test, and maintain.  If you’re following an Agile approach, sustainability and maintainability are key. This is where CYC can give you insight into where you might need to simplify.

Let’s demonstrate how this metric works with a simple example. Consider a snippet of code that only executes statements sequentially, without any conditions or branches:

public int sum(int a, int b) {
   System.out.println("Adding two numbers: " + a + " + " + b);
   return a + b;

Because there are no branches in the code, with any combination of the parameter values, all of the statements in the function will be executed. Hence, the CYC result for this code is 1. 

If we introduce a conditional statement for checking the input, the CYC will double, as our code will contain two possible execution paths instead of a single branch:

public int sum(int a, int b) {
   if(a < 0) throw new IllegalArgumentException("Parameter a should be positive");
   System.out.println("Adding two numbers: " + a + " + " + b);
   return a + b;

Adding another condition to test the second parameter increases the CYC result to 3:

public int sum(int a, int b) {
   if (a < 0) throw new IllegalArgumentException("Parameter a should be positive");
   if (b < 0) throw new IllegalArgumentException("Parameter b should be positive");
   System.out.println("Adding two numbers: " + a + " + " + b);
   return a + b;

Any conditional statement or loop block would add to the CYC metric of a method, thus contributing to the number of tests needed to execute through all the code branches.

While a high CYC value doesn’t immediately indicate that the code is buggy or broken, it’s definitely an indication that the code might be hard to maintain, making it easier to break with new changes. IntelliJ IDEA can notify you about overly complex methods right in the editor. The threshold for the Overly complex method inspection can be configured in Settings | Editor | Inspections:

Duplication analysis with JetBrains Qodana, to find duplicate code.

By default, the threshold value is set to 10. However, if we change this metric to 2, the editor will highlight the code in the example above:

Example of static code analysis.

How to enable this inspection for your entire project

If you’re using Qodana for server-side code analysis (to track code quality for the entire team, not just locally), you can check CYC automatically. Select the Recommended profile and check that it is enabled for the language you’re coding in.

Enabling code complexity check with JetBrains Qodana.

Interpreting the results

In his presentation Software Quality Metrics to Identify Risk, for the Department of Homeland Security [download], Tom McCabe Jr. says that if the CYC metric value of a method is less than 10, then the code is considered simple enough.

If the metric exceeds 50, the code is considered overly complex and untestable. In practice, however, you should aim for values below 6 and set a warning if the result is over 10. This indicates that it is time to simplify the function to prevent complexity from growing.

Our suggested ranges for the CYC score are as follows:

  • 1–5 – Simple code, easy to test and debug
  • 6–10 – More complex, moderate risk
  • 10–20 – High risk, be careful
  • 20+ – Very complex code, hard to understand and maintain

2. Code duplication percentage

The code duplication percentage helps you identify how much of the same or similar code appears in multiple places in the codebase. This is an important metric because high levels of code duplication can lead to increased maintenance, a higher chance of introducing bugs, and decreased code readability. 

With Qodana, duplication checks are enabled by default, but you can also configure duplicate detection in IntelliJ IDEA and other IDEs such as WebStorm and Rider.

Qodana duplication percentage check.
Checking for duplicates with Qodana.

Interpreting the results

Ideally, you should keep your code duplication percentage lower than 5%. This can help you avoid unnecessary refactoring – changing many parts of your code for a single improvement or issue. Be sure to monitor code duplication on an ongoing basis, either locally or on the server side with tools like Qodana.

3. Code (test) coverage

Writing test cases with maximum coverage can help you verify that your software executes as expected before manual testing. With more effective testing, you’ll likely get a high-quality product to market faster.

Plus, high test coverage bolsters maintainability and can alert you to redundant code, since it is measured on the assumption that higher coverage results in fewer code defects.

The most common method for gauging code test coverage is to measure by the number of lines of code:

Code coverage percentage = (the number of lines of code tested by the algorithm / the total number of lines of code in a system component) * 100

However, there are two other strategies:
1) Measuring by statement
2) Measuring by branch, which is better connected to the cyclomatic complexity metric, as the complexity shows how many tests you need to implement to cover the code.

Assessing code coverage

If you have a Qodana Ultimate or Ultimate Plus license, with Qodana for the JVM, JS, or PHP, you can run a code coverage test in your qodana.recommended or qodana.starter profile. Find out how to set up a code coverage measurement here.

Code coverage testing with JetBrains Qodana.

4. Number of possible bugs

We obviously want to keep the number of bugs in our code as close to zero as possible, and code analysis is capable of flagging all sorts of them. One example is NullPointerExceptions, which are raised when we’re trying to perform an operation where an object is required. This is often the result of using a method on an object instance that is null at runtime or trying to access variables of that instance.

It’s important to catch these problems early to avoid releasing a buggy version of your product, especially since you might not immediately notice them in your code or even during the peer review process. Qodana can easily gate problems related to incorrect resource handling, such as database connections not being closed safely after use.

5. Code smells

Measuring code smells, such as deprecated API usage, is important for maintaining the health of a software codebase. Though deprecated API usage can be assessed manually, allowing reviewers to identify and suggest alternatives to deprecated APIs, the most common approach is to employ static code analysis tools like Qodana.

6. Number of vulnerabilities

Vulnerabilities in code refer to security weaknesses or issues that could lead to security breaches, data leaks, or other security-related problems. 

Even one vulnerability can lead to a major security breach. We just need to look at the examples of X (formerly Twitter), CloudFlare, and AWS, which have been drastically affected by a Log4J vulnerability. These vulnerabilities can manifest in various forms, such as security vulnerabilities, configuration errors, access control problems, dependency vulnerabilities, and more.

Security vulnerabilities with the JetBrains Qodana Cloud dashboard.

Above, you can see a check in Qodana Cloud that will flag vulnerable dependencies with the aid of Checkmarx functionality. You can also check for dependency licenses with Qodana data.

Once you’ve established the number of vulnerabilities in your code, you can assess which of them are critical and present the most risk. From there, you can start working on the highest priority issues immediately and save the less critical ones to the Baseline to be addressed later.

Simplify code quality measurement with static code analysis

Code quality metrics help guide you toward cleaner code that is more efficient and maintainable. These metrics offer a holistic view of a project’s health over time, giving you a strategic advantage in improving your products and collaborating in teams.

If you’re looking to implement these metrics into your delivery process, Qodana can help. It fits perfectly into any CI/CD workflow, giving your entire team a single source of truth for code quality. On top of that, its scan results are available in JetBrains IDEs out of the box, which enables you to fix the issues quickly.

Try it today and let us know which metric you rely on most. Click on the button below to get started. Or get in touch with us if you want to find out more about how to measure code quality.

Try Qodana for free!

image description