Software Code Quality Metrics Simplified!


What are the metrics for software code quality? How do you actually measure code quality? What are some best practices your team can use to improve their code quality? Simplicity. The best advice for developers is to keep it simple, add complexity only when needed. That goes for just about everything in software development. Code complexity is antithetical to code quality, so code complexity is what we need to measure and minimize. If only it was as simple as that.

High Quality Code is highly modular, easy to read, understand, change, and extend. That’s a good start. To be comprehensive, we should add that high quality code is also secure, well documented, works as intended, and performs well.

  • Code that is easy to read and understand is important because a) code is read more than written, b) every position on your software team may be filled by 3-4 different developers over the course of the software’s lifetime. (Cognitive Complexity)
  • Modular code is largely self-contained, requiring minimal interactions with other components. This is desirable so that as changes are made they will only require one or a few changes in other software components. Changes involving heavily interconnected components with many variables can go exponential. (McCabe Cyclomatic Code Complexity)
  • Modular code that’s easy to understand makes it easy to change and extend. Software will change over time due to new devices, new third-party software, new security requirements. New features may need to be added to keep the software commercially competitive. (McCabe Cyclomatic Complexity + Halstead Code Complexity)

Shortly, we’ll look at McCabe Cyclomatic Complexity, Cognitive Complexity and Halstead’s Code Complexity metrics. There are plenty of other systems that attempt to get an accurate or objective feel for complexity. Leastwise, that so many software engineering thought leaders have spent so much time trying to measure code complexity stands as a good indicator that it plays an important part in code quality.

Best Practices for Improving Code Quality

Coding Standards

We’ve covered the importance of having coding standards at length. Coding standards are essential for every team, but especially for startups, rapidly growing teams, and teams where there’s a shortage of senior developers. These conditions will inherently create additional code complexity and coding standards are your first line of defense and training to mitigate that. This warrants:

  1. Keeping style guides for the programming languages you use.
  2. Use a linter to catch and enforce your rules.
  3. Maintain a formal SOP of work processes (git branching strategy)
  4. Define “Good Enough Code”

The spirit of the effort is to keep everyone on the same page, read the same language, in the “dialect of your team” — as opposed to the potentially infinite styles every team member may bring from their own experience and training. A single character in the wrong place can throw things off – so we want to make it easier for everyone to catch it.

Flowcharts - Simplicity Begins with Design

Can you map what you’re writing?

It’s imminently useful to write the comment before writing the code, it helps keep it focused on what that portion of code needs to do. Keeping a pencil and paper at hand is helpful so you can outline the logic to the code and draw a flowchart or schematic for it. You’ve got a large portion of the logic and sequence to guide your coding. Additionally, you have a visual for the redundancy and can look to simplify the logic further.

Comments, schematics or flowcharts count serve as best practices for improving code quality – or at least minimizing code complexity.

Example from Programiz

Teamwork, Story Splitting, and Resource Libraries

Teamwork is everything and is an integral part of software development from code reviews and retrospectives. Senior and mid-level developers can also assist junior developers by referencing open source examples of the logic they’ll need for different components. Story splitting is another way to reduce the complexity of large story point tasks. For more on all of these points, check out Developer Skill and Team Organization.

Automated Software Development Metrics… Like Gitential

Software development metrics serve to enhance teamwork by helping to identify each developer’s skill levels in different programming languages. This helps you on how to best pair them with developers for code reviews and optimizing your team around project requirements.

In software development, Everything is Interconnected. Improving any metric while maintaining the same standard of quality will likely improve several metrics. Reducing code complexity will improve code quality, defect rates, velocity, and cycle time. Story splitting can help to improve utilization for junior developers while reducing the load on your senior developers. Optimizing utilization typically leads to improvements in efficiency and velocity, and decreased defects.

Is Test Coverage an Indicator of Code Quality?

Yes, sort of. At the least, a high level of (meaningful) test coverage is indicative of code that is easy to write tests for. If you’ve been working with the same team, you should have a good feel for the quality of their tests. You should know their defect rate, types of defects, and be able to assess whether the defects should’ve been picked up during testing.

Generally speaking, the relationship between defect rate and test coverage looks like:

 Low Test CoverageHigh Test Coverage
Low Defect RateAn anomaly, but possible owing to low cognitive complexityExpected result of all-around low code complexity
High Defect RateExpected result of high all-around code complexityIneffective Tests
“Lip Service to Quality”

Cognitive Complexity

There are cases where a high Cyclomatic Complexity may be very easy for humans to read and understand (variables involving months, ingredients, families of “things”). In some cases, the logic may be so simple that a test doesn’t need to be written for January, February, March, etc. Cognitive complexity for software code is a metric formulated by G. Ann Campbell from Switzerland’s SonarSource SA. You can download her paper, Code Complexity: A new way of measuring understandability for a complete technical overview of how it works. Cognitive complexity measures how difficult code is for a human to read and understand. Devised in 2018, it’s a comparatively new, but very insightful measurement for software developers. It uses three main rules:
  1. Ignore structures that allow multiple statements to be readably shorthanded into one
  2. Increment (add one) for each break in the linear flow of the code
  3. Increment when flow-breaking structures are nested
You might try the cognitive complexity tool written by Matthias Koch for Resharper (add-on for Visual Studio .NET developers).

McCabe Cyclomatic Complexity

Another tool for assessing code complexity was devised in 1976 by Thomas J. McCabe, Sr. This measures the number of linearly independent paths through a program and defines how many test cases it will need. You might check out Joshua Clayton’s Complexity tool on GitHub.
McCabe Cyclomatic Complexity works with a control-flow graph.

Complexity (M) = E – N + 2P

  • E = the number of edges of the graph
  • N = the number of nodes of the graph
  • P = the number of connected components

Boolean operators can (but don’t always) add one to complexity.
Binary decisions, like IF and WHILE statements add one to complexity.

Example from Programiz

A control-flow graph of a simple program.

The program begins executing at the red node, then enters a loop (group of three nodes immediately below the red node).

On exiting the loop, there is a conditional statement (group below the loop), and finally the program exits at the blue node.

This graph has 9 edges, 8 nodes, and 1 connected component.

Complexity (M) = E – N + 2P

Cyclomatic complexity = 9 – 8 + 2*1 = 3.

Example Courtesy of Wikipedia.

Halstead Code Complexity

Devised by Maurice Halstead, his method of calculating code complexity has been around since 1977. Ahmed Metwally created a tool that you can download from GitHub to calculate Halstead’s metrics. With it, software consists of tokens that are either operators (function calls) or operands (constants and variables), such that:
  • n1 = Number of distinct operators.
  • n2 = Number of distinct operands.
  • N1 = Total number of occurrences of operators.
  • N2 = Total number of occurrences of operands.

Halstead Code Complexity Metrics

Metric Calculation Use
Program Volume (V)
Size in bits needed to store the program.
Potential Minimum Volume (V*)
V* = (2 + n2*) * log2 (2 + n2*)
Potential smallest size in bits.

Program Length (N)

Total of all operators & operands.

Size of Vocabulary (n)

Total of unique operators & operands.

Program Level (L)

1 = minimum possible size; some languages can do more with less.

Language Level (L')

L' = V / D / D
Some languages are easier than others.

Program Difficulty (D)

D= (n1/2) * (N2/n2)
Tendency or susceptibility for errors.

Programming Effort (E)

E= V*D
Shorter, Simpler Code takes less effort!

Time to Implement (T)

T = E/18
Amount of time needed to translate code in seconds, based upon Stoud’s Number (or how fast we can think… on a good day.)

Delivered Bugs (B)

B = V / 3000
Estimate of the errors in implementation, though actual number is usually higher.

All of these metrics have their use especially in understanding how much code redundancy (N2 vs n2) is in a program. Where “bugs” are relative to volume, reducing redundancy should improve quality while reducing code complexity, bugs, and program difficulty.

Programming language can influence difficulty directly, but we don’t always have control over which language we use for specific components. Languages used should factor into defining project requirements. It’s also beneficial to task developers based upon their skills in specific programming languages.

Simplifying Code Complexity Metrics

There are probably more exceptions to the rules than cases that fit them – as there are all kinds of software development teams (skill levels, size, experience or time working together, environment, project types, etc.). There are different complexity metrics to measure different things, but that’s a buttload of math to do.

  1. Code Reviews and Cognitive Complexity. The check that should be built into the process. Can I say it? George Guimarães, co-founder and CEO of SourceLevel said it. I’m going to say it. “What the F*#@!” Well, maybe more like, WTF? WTF moments during code reviews should be fixed before committed. So, aside from any other metrics, there’s a teamwork issue to address. Developers doing code reviews should have the discretion, guidelines, and authority to mandate fixes and be made to feel comfortable doing so. That’s not always so easy, so this may be an issue we discuss in the future in more depth.
  2. Defect Rate vs Test Coverage. The quick objective check. If the team or a developer has a high defect rate, the next thing to look at is test coverage. If their test coverage is high, you need to look at their tests. Low defect rate + high test coverage is the best scenario. Low defect rate + low test coverage + low Cognitive Complexity is fine. All other scenarios are negative and force a focus on all aspects of code complexity.
  3. Halstead’s Volume vs. Potential Minimum Volume shows us how much redundancy can be reduced and the relative impact of doing so (proportional impact on bug rates). If the difference is large, then a deeper examination with McCabe’s Cyclomatic Complexity (flowcharts) can help identify how to simplify.

Seriously, there are a ton of metrics in software development, our saving grace is the Pareto Principle. Most problems (80%) are tied to a minority of causes (20%). Manage by exception, the other 80% of causes are causing 20% of the problems – which can still be a huge number. All of the code complexity metrics come into play at some point when focusing on coding quality. Teamwork itself has a variety of metrics and plays a huge role in team development.

Did you like our content?

Spread the word

Subscribe to Our Newsletter

Don't miss our latest updates.
All About Software Engineering Best Practices, Productivity Measurement, Performance Analytics, Software Team Management and more.

Did you like our content?

Spread the word

Subscribe to Our Newsletter

Don't miss our latest updates. All About Software Engineering Best Practices, Productivity Measurement, Performance Analytics, Software Team Management and more.