Software development is currently one of the fastest-growing fields around. New software startups are entering the industry every day. Unsurprisingly, the competition is fierce. A whopping 70% of startups fail within two years of launch. To get ahead, businesses need to leverage their teams to deliver innovative, reliable, and scalable products quickly. However, it can be hard to support productive and efficient development without the right insights. Tracking the right software intelligence KPIs can help. That’s why we’re taking a deep dive into the extremely popular, but often misunderstood, code quality metric: Code Complexity.
Code complexity can be one of the more challenging software intelligence metrics to understand because there are so many ways to define and measure it. Complexity covers several different properties of software applications that affect internal operations making it difficult to pin down a single definition of complexity. Complexity can range from the number of logical paths in a block of code to complex interactions between files in an application.
When tracking complexity, it’s also important to distinguish between code that is complicated (i.e., difficult to understand, and thus, maintain or refactor) and code that is complex (files, modules, and objects are interconnected or dependent on several other files, modules, or objects). Complicated and complex code can both have a severe impact on development efficiency and productivity.
With all that said, it’s important to understand that not all complexity is bad. When it comes to software code, complexity can be either Essential or Accidental.
Essential complexity refers to unavoidable complexity that crops up because of conscious decisions made in the development process. The intended use of the software as well as customer requirements can often have a strong impact on the complexity of an application. For example, the software behind a self-driving car’s navigation and acceleration system will almost certainly be more complex than the software used to build a mobile racing game app.
Accidental complexity, on the other hand, is unintentional complexity that comes from sloppy coding or poor decision-making in the development process. Sub-standard code leads to ad-hoc fixes, quick workarounds, or other behaviors that go against software best practices. This kind of complexity can often be compounded by tight deadlines, inexperienced developers, changing requirements, and poor communication in teams.
As applications grow and the number of code contributors increases, it’s natural for the codebase to become more complex. In fact, complexity can be thought of as a necessary part of software development. It’s only when complexity starts to grow out of control that it becomes a threat.
So, how can you tell if your software is becoming overly complex?
Several metrics are currently used to measure complexity in software applications. 3 of the most popular metrics are:
One of the advantages of cyclomatic complexity is its ease of calculation. It uses a simple algorithm to obtain a reliable measure of complexity.
Where:
V(G) = Maximum number of linearly independent paths i.e. the Cyclomatic Complexity
E = Total number of edges
N = Total number of nodes
P = Total number of predicate nodes (conditional nodes)
When cyclomatic complexity is high, the difficulty and cost of testing also increase. The more branches there are, the more time must be spent on testing to achieve complete coverage. While cyclomatic complexity is great for estimating testability and is a useful indicator for error-prone code, it’s not as good at providing insights into maintainability.
Like cyclomatic complexity, cognitive complexity takes the linearly independent paths in an area of code into consideration. However, this method calculates complexity by using different values for the paths that the code can branch into. While cyclomatic complexity is focused on the number of branches, cognitive complexity is concerned with how the number of branches, breaks in the flow or “readability”, and the depth of nesting in conditional statements can make understanding code more difficult.
The Halstead complexity is another metric that aims to provide a more comprehensive understanding of computational complexity in applications. It’s based on Maurice Howard Halstead’s measurable qualities of software code.
Halstead complexity is often an aggregate of Halstead metrics like:
This metric is relatively easy to implement and can be done statically, meaning it can be done without running the program. It’s also useful for predicting defect rates and maintenance efforts. Another advantage is that it can be applied to any programming language easily.
While these are the 3 most popular methods for measuring complexity in development, others can also be used. At Foreworth, for example, we use a variety of additional low-level metrics in conjunction with cyclomatic complexity, cognitive complexity, and Halstead complexity. By taking all complexity metrics into account, we can provide a clear view of the factors influencing complicated and complex code.
To build a more comprehensive and inclusive view of complexity in source code, we recommend looking at metrics like:
Other important considerations to track include architectural issues like:
If you’re aiming to improve visibility in your software applications, tracking complexity is a great place to start. Even without a well-rounded software intelligence platform, it’s still possible to track code complexity on your own.
To do this effectively, you’ll probably want to start by identifying the areas in your code that are likely sources of complexity. You can do this by checking in with your QA and Developer teams to identify code quality “hotspots” where defects or bugs tend to occur. Areas where bugs are commonly caused by excessive complexity or developer error tend to be the usual suspects.
Once you’ve identified these “hotspots”, you’ll need to spend some time (and developer capacity) on:
The downsides to this, however, are the higher relative cost in time and developer capacity, the added risk of human error, and the challenges that setting up data capture, cleaning, and storage pipelines can introduce.
Like most other KPIs used in software development code, complexity should be used to gain a deeper understanding of the application under development. Tracking complexity in your codebase offers several unique benefits including:
It has a direct relationship to development productivity in terms of how team effort is allocated. Over complexity can often negatively impact efficiency and software performance, requiring code to be refactored. However, the more complex code is, the more difficult and consequently more expensive it can be to resolve or refactor.
Tracking code complexity helps with gauging the growth of complexity in your applications. Working to balance your team’s code output with complexity in the system can help to manage maintenance costs.
When code becomes too complex to work with safely, it can cause serious problems for your applications. By measuring complexity in your application’s modules, you can gain a better idea of the approximate cost of maintenance versus the cost of completely rewriting overly complex code.
Understanding the relative costs of maintenance versus rework can help guide decision-making when it comes to allocating mission-critical resources.
Without the right insights, it‘s more difficult to strategically plan out your development efforts. Developing new features or adding new functionalities to existing applications need to be considered within the context of existing complexity. This becomes even more difficult without the right insights.
By measuring complexity in your applications in a consistent and ongoing way, you can stay up to date with complexity in your application. The added visibility from tracking code complexity can help improve future planning in development.
Consistently measuring code complexity also helps with improving code quality. The fact is that overly complex code is a ticking timebomb waiting to go off. Excessive complexity in the code base has a strong correlation with defects or bugs. These defects can, in turn, lead to critical failures or security vulnerabilities.
Understanding where complexity is most concentrated in your application can help with strategically allocating testing efforts early in development. With early detection, it’s much easier to address defects or vulnerabilities before they become critical issues.
So, what can you do with complexity KPIs once you have them?
The first thing we’d recommend is identifying areas of high complexity in your code base. You should then check them against your current code quality metrics (e.g., defect detection rates, defect distribution, etc.) to determine where to focus your investigations. From there, we recommend:
While individual code complexity measures can be easy enough to calculate and report, they’re best when used together. Each of the complexity metrics we’ve described can offer valuable insights, but they only offer single perspectives of complexity in your code base. Combining different complexity measures and using them in tandem with code quality KPIs is a much more holistic approach to tracking productivity and efficiency in development.
Although this can be a time-consuming and occasionally costly endeavor, it doesn’t have to be. There are a variety of software intelligence tools on the market that can help. Foreworth, for example, provides a 360º view of your software development efforts, including the complete list of code complexity metrics from top to bottom. Learn more about how we can help maximize the ROI on your development efforts here.