If I ask you to tell me how much quality your code has, how would you answer it? There’s not a correct answer, and responses vary depending on seniority or past experiences of each one. As there is no consensus of what’s quality, here’s a list of aspects I think your code must have to be considered good (not necessarily in this order):

  • It must work. Whatever the feature is, it should only do what it was designed to do. No more, no less.
  • There must be automated tests to ensure it is working and to describe how it works.
  • The code is well documented (at least as much as it needs).
  • The code is clear and shows its intention by having well-chosen variables, methods, and class names.
  • It is easy to maintain, or in other words, it is easy to change.
  • It has no security breaches.
  • It is fast (at least fast enough for its usage).

Different features may be added depending on the kind of software you’re building. You may need your code to meet some legal issues if you work in a bank or an insurance firm, for instance.

OK, we got attributes of a good code. Why should I measure it?

In my opinion, measuring is the best way of looking at the situation as it is. It is essential to listen to the feelings of developers and your senior developers. They may have a very accurate sense of codebase health status. However, you can’t rely just on it.

Developers are humans, and as humans, they are influenced by emotions, by egos (have you ever heard lines like “my code is beautiful, I’m an artist”?) and also by their experience.

This last aspect, the experience is the most crucial one. Depending on how much messy code has a developer dealt with, its definition of quality changes. That’s why measuring is so important.

You get a standardized view of your code health.

Another great thing about metrics is looking at its history to make questions. For instance, if your number of code smells in September is 33 and October it goes down to 22, you could tell your team “what have we done? Let’s keep doing this because it improved the overall code quality”! Alternatively, in the worst scenario, asking your team, “why are code smells growing so much this month?” may raise important issues, like your team being pressured by the product team to deliver faster and faster without looking to quality.

These numbers allow you to ask questions, understand your process and the impacts of your changes.

OK, I agree that measuring is essential. What should I measure?

Many companies look to the number of bugs as an indicator of code quality, but the fact is that it relates more to the quality of the process than to the health of your codebase. Of course, bad code leads to more bugs, however not every bug is due to bad code.

Well, for me, it is. Moreover, it tends to happen when there’s no one looking for quality in the team. We don’t usually think about quality before writing a new feature, nor we think about quality when done. We only think about quality during the development of a feature where we find a lot of… Let’s say, “what the fuck.”

That’s the reason the most common metric for software development is “WTF/minute,” as illustrated in the cartoon below by Thom Holwerda.

WTF/minutes metric

Despite being funny, it raises the question of how should I measure quality then? Well, there isn’t a right answer to that. However, we’re going to present some ideas.

Here is a list of useful metrics that you may measure. They are simple to calculate and there are automated tools to calculate all of them (there are plenty more if you google for it).

Measuring code complexity

How easy it is to change is directly related to its quality. So, the first health metrics should be related to its complexity. Calculating complexity can be hard, but there are a lot of open-source tools available for this purpose.

It consists of calculating the number of possible lines executed in all possible arrangements for a given piece of code (or throughout your entire code base).

The formula is Cyclomatic Complexity = Edges – Nodes + (Nodes with exit point * 2). Let’s see it in practice. Given the following code, written in Ruby using ActiveModel API:

post_changes = post.changes || {}
if post_changes.present?
  ChangeHistory.create!(entity: 'Post', entity_id: post.id, changes: post_changes)
  if post_changes[:slug].present?
      path: post_changes[:slug].first,
      redirect_to: post_changes[:slug].last

The following image shows the code as nodes and edges of a graph that represents the path of its execution. Notice that it ignores the fact that bang methods (methods ended with an exclamation mark) may raise an exception and it would stop the execution.

In this case, the complexity would be:

Number of edges (E) = 9
Number of nodes (N) = 8
Nodes with exit points (P) = 3

Applying the formula: N - E + (P * 2)
Cyclomatic Complexity = 9 - 8 + (3 * 2)
Cyclomatic Complexity = 7

OK. Now, let’s try to reduce this number by refactoring the code. A good strategy is to reduce the number of nested ifs, and we could achieve this by the following piece of code:

post_changes = post.changes || {}

if post_changes.present?
  ChangeHistory.create!(entity: 'Post', entity_id: post.id, changes: post_changes)
if post_changes[:slug].present?
    path: post_changes[:slug].first,
    redirect_to: post_changes[:slug].last

Just by looking at this code, one could say it is easier to understand and more comfortable to change. Its intention is way more straightforward: save the post, create a ChangeHistory record if post attributes changed and then, if slug has changed, create a redirect rule. Here’s the graph:

Now let’s do the math:

Number of edges (E) = 8
Number of nodes (N) = 8
Nodes with exit points (P) = 2

Applying the formula: N - E + (P * 2)
Cyclomatic Complexity = 8 - 8 + (2 * 2)
Cyclomatic Complexity = 4

As we see, the second piece of code, although it does the same job, is less complicated than the first one. That’s how measurement can help your code to be easier to understand: by knowing where are the most complicated points. So you and your team can work on it until it is acceptable for your rules. Yeah, acceptable is the word, since there is not a magic number. To determine it, you need first to understand your context.

A good practice is: doesn’t matter which number, keep the job on lessening it.

Measuring code smells

Back in history, when we would go to the woods to collect food, and there was no expiration date impressed on it, we had to use our senses. If you didn’t want to get food poisoned, you would smell it first.

That’s the same analogy to the code. It doesn’t necessarily point to a bug or a rotten piece of code. It just raises the smell that something may not be good. It can be an anti-pattern, duplicated code, bad practices, anything that could be an alert for developers.

Static Analysis can find those smells in an automated way. There are open-source linters that do an excellent job looking for them. The metric here is the absolute number of them found in your code. Very easy to calculate.

Measuring security issues

Good code is secure. That’s why it is crucial running an automated tool that looks for SQL injection, data leaks, and other potential security issues that are common in the daily development routine.

Automated code review tools are not perfect, and some times, they trigger false-positive alerts. However, it is no excuse for not running them. If your codebase has too many false-positive alerts, you totally should start taking these alerts more seriously.

Static analysis software looks for known patterns (like using eval or not sanitizing your data before inserting in the database) and sums them up. That’s the metric. As simple as that.

Who’s accountable for measuring code quality?

In theory, companies rely on Tech Leads to ensure source code healthiness and quality. Thus, they need to find a way to get visibility on the development process in a quantitative way. Charts and numbers over the history of a project or product are the best way to oversee the development.

Using linters for this purpose is an excellent choice. By regularly looking at key metrics generated by them, Tech Leads can understand whether a source base is increasing or decreasing the cyclomatic complexity, the number of code smells, or the security issues.

Do you need code quality metrics for your team?

Start measuring code quality now for free!

Check all the features you get in SourceLevel’s 14-days trial.

However, the whole team should care about the metrics. Otherwise, they won’t be effective. It’s crucial to make it part of the team’s culture. Only by doing it, Software Engineers will care about enough to prevent new issues, and fix the existing ones.


The concept of quality may vary depending on the company, on the product stage, or even by each personal view. To keep or improve the quality of your code, you need to define what is quality for your team and measure it.

There are a lot of other metrics available. Keep your quality definition in mind and look for metrics that ensure your code matches it. There already are many tools designed to maximize and engage discussions about quality. Look for them!

In this blog post, I suggested three metrics, all of them (and much more) are present in our solution. SourceLevel runs automatically for every pull request open and keeps the history of the master branch so you can raise questions about your process looking to data, not opinions.

Sign up for free and enjoy our trial for 14 days!