We use static code analysis tools more often these days that create great reports and funky graphs. But do we understand what it all mean?
Software metrics tends to be magic numbers for a lot of people, but they don't really have to be. Let me introduce you to a few basic and
most popular software metric and tools and explain you what they mean and how you can use them to produce better software.
11. “It is the mapping of a particular characteristic of a measured entity to a numerical value” Source: Object-Oriented Metrics in Practice What is a metric?
12. “Good design quality metrics are not necessarily indicative of good designs. Likewise, bad design quality metrics are not necessarily indicative of bad designs” Source: JdependDocs Software design
76. NPATH – acyclic execution path complexity NPATH is an objective measure of software complexity related to the ease with which software can be comprehensively tested Edgar H. Sibley
77. NPATH – acyclic execution path complexity expressions Number of && and || operators in expression if NP(<if-range>)+NP(<expr>)+1 if-else NP(<if-range>)+NP(<else-range>)+NP(<expr>) while NP(<while-range>)+NP(<expr>)+1 for NP(<for-range>)+NP(<expr1>)+NP(<expr2>)+ NP(<expr3>)+1 break 1 continue 1 return 1 sequential 1 function call 1
112. Summary “We believe that software metrics, in general, are just tools. No single metric can tell the whole story; it’s just one more data point. “ “Metrics are meant to be used by developers, not the other way around – the metric should work for you, you should not have to work for the metric. “ “Metrics should never be an end unto themselves. Metrics are meant to help you think, not to do the thinking for you.” Alberto Savoia
My main focus recently been code quality and finding ways of improving it in my day to day job, hence my involvement with Sonar project (which I am gonna talk about later on) and special interest in software metrics. And when I say software metrics I mean code and design metrics, not project metrics. If you’re here to find out how to measure your project progress or any sort of management stuff, then it’s not a talk for you. I will be talking about ways of measuring quality of your code and tools that can help you asses your design, identify structural problems in your code and find bad smells in it.But before I start, I’d like to know a few things. First of all how many of you use any software metrics? How many of you use tools like phploc, phpdepend or php mess detector? How many of you know what these tools are for or at least heard about them before?For many years the only the only thing that I could measure was number of WTFs a minute.
And not that we had any tools for that. When things were getting really bad you could judge that by the tone of voice or how load it was in the room. As funny as it might be this is a quite popular method a measuring code quality! Problem with it is that you can’t really tell what is wrong until you actually speak to the developer. Some of them won’t even speak after that! That makes reporting impossible. Another variant of this metric is swear count. Measuring that is a bit easier as you could write a simpler parser to get some data, but again it’s sill gonna be pretty hard to find out what’s broken and more importantly how to fix it. So it’s pretty obvious this is not the way you should be using to assess quality of your code.
Therefor I looked for more scientific methods of assessing code quality. But the first time I looked at code metrics I didn’t really know where to start. All these acronyms were really confusing! Not mentioning the fact there is so many of them!Thing is that if you don’t put metrics into some kind of context they don’t mean much and are not useful at all. LOC, NOM, ROOTS… WTF! That’s usually the first reaction you get. I am not gonna go through all of the metrics today that you can see here, we don’t have enough time. I have picked the ones that I think are the most interesting and which I believe will help you the most in your day to day job.
When talking about metrics it’s really important to understand what the metric is. In short we can say metric should allow us to describe a particular characteristic of an entity in a quantifiable way. The entity can be anything – you, this room, the screen. Also characteristic can be anything you want to – it could be height, weight, width. It’s you who define the metric. As long as you can assign a numerical value to it it will meet the definition of the metric. But that’s not all. A very important thing about measuring is to use the same unit when it comes to measuring. It obviously makes a difference when you say that one thing is 30 meters tall, and the other is 30 cm tall. Also should we measure everything? If not what should we measure? The important thing about measurement is to define clear goals. To understand what do you want to achieve by measuring something.
When we talk about software, metrics could help you assess software size, its quality and complexity at a specific point of development cycle. You have to understand that there is no universal magic metric that will tell you what exactly is wrong with the software. It is only a tool that can help you understand, overview and identify potential design problems. It can be very misleading if you don’t read your metrics right. Good metrics don’t mean quality of your software design is good and at the same time bad metrics not necessarily mean your design is bad and needs improvement. Bad smells and design flaws detected through code metrics are only guidelines! They are there as a starting point for a deeper analysis.
Metrics also can help you with legacy systems. They’re specifically useful when it comes to dealing with old and decaying software. We all know how hard it is to maintain it and refactor - whether it’s because of large size and lack of understanding of the code or severe duplication and patches all over the place.
Let’s start with some basic metrics.These metrics are independent of each other, and independent of the size of the project. They are useful if you want to assess size of the project.
It’ll be a tough task to count all of it manually, therefor you’d better use a tool for that. phploc is a small program that you can install using pear and use for basic source code analysis. It’s perfect for quick assessment of code size.But how do you interpret these values? How do you know if the project you are analyzing is big? Is 5000 lines of code big or small? When a class is too large? When it’s got 10, 20 or maybe 30 methods?Any metric to be useful needs to have associated thresholds that will define when a value is low, average, high and very high. This way you will know how to read the numbers and what they mean. There are two ways of identifying thresholds. First one is by using statistical data. It is perfect for assessing size, for example number of hairs, height, weight.The other one is based on widely accepted knowledge, for example number of meals a person consumes per day. Fortunately some of them have been already analysed and the thresholds already set.
For example, after analyzing 45 Java project, we can say that when cyclomatic complexity number per line of code is very high when it’s above 0.36, method is small when it’s got less then 7 lines of code and an average class has got between 7 and 10 methods.
Interestingly enough, when a similar analysis has been perform for 37 C++ project, the thresholds were different. A class with 7 methods would be rather considered small. You may ask why they are different? It’s all to specific for a given programming language ways of coding and using particular structures.
Knowing the basic metrics we can calculate some that will reveal some information about code complexity. The first one is WMC – weighted method count or weighted method per class and gives you a sum of complexity number for all the methods in a class. Abstract classes usually have a lower WMC number, while concrete classes performing specific jobs will have a high WMC number and will be potential candidates for refactoring.The second one is AMW – average method weight, which is an average complexity of a method.Knowing that, it’s easier to identify the most complex classes and methods in your projects.
Again, looking at the same analysis we also have thresholds set for these metrics. They are different per language, but general consensus seems to be that WMC number greater then 50 indicates a very complex class, that definitely needs looking into.
Now, obviously we are more interested in thresholds for PHP then for Java or C++. Unfortunately there is no official data available for that. Analysis performed by Manual Pichler, creator of tools like phpUnderControl, PHP Depend and PHP Mess Detector confirmed that thresholds I have shown you for Java apply for PHP as well. More or less.
Code coverage report shown here is a metric in itself. Or actually two. How many of you had a chance to generate it? And how many of you are using it in your day to day job? For the people that never heard of it or never seen it before, it is a report showing how much of your code has been executed when unit tests run. Apart from projects total coverage you get a information about how many lines of code have been actually executed and how well methods and classes are covered with unit tests. To generate the report you just have to run phpunit with one of the coverage options that will generate either a report in html format or xml format.A lot of people, even these who uses the report on a daily basis, is not aware of the second metric included in the report.
It’s the crap index displayed between function/methods section and lines section. A lot of people think, judging by the name, that this metrics tells you how crap your code is. As much as I would like to say the same, it’s not actually true. Well, maybe to some extends, but the purpose of the metric is slightly different. So first of all let’s solve the mystery of what CRAP actually is.
And it’s not CRAP, but C R A P.
Which stands for Change Risk Analysis and Predictions. As the name implies, the C.R.A.P. index is designed to analyze and predict the risk and effort associated in changing (maintaining and enhancing) an existing code – particularly (but not necessarily) by developers other than the original developers.
Index takes into account method’s cyclomatic complexity number and method test code coverage provided by automated tests – in this case by PHPUnit. Low C.R.A.P. numbers indicate code with relatively low change and maintenance risk – because it’s not too complex and/or it’s well-protected by automated and repeatable tests. High C.R.A.P. numbers indicate code that’s risky to change because of a hazardous combination of high complexity and low, or no, automated test coverage to make sure you have not introduced any unintentional changes. As the code coverage approaches 100%, the formula reduces to: CRAP index of a method being equal it’s cyclomatic complexity number. In other words, the change risk is linearly coupled with the complexity. If you have 100% test coverage and your C.R.A.P. index is still too high, you should consider some refactoring (e.g., method extraction).As the code coverage approaches 0%, the formula reduces to sum of method’s complexity and method’s complexity squared. Which means, if you have no tests, your change risk increases, roughly, as the square of the method complexity. This indicates that it’s time to write some tests.Generally speaking, you can lower your C.R.A.P. index either by adding automated tests or by refactoring to reduce complexity. Preferably both (and it’s a good idea to write the tests firsts so you can refactor more safely).
As I have mentioned cyclomatic complexity number several times already it’s time to reveal what it is. The Cyclomatic Complexity Number or in short CCN is the oldest complexity metrics. The first time this software metric was mentioned was in 1976 by Thomas J. McCabe. This metric counts the available decision paths in a software fragment to determine its complexity.
Each decision path starts with one of the conditional statements from the following list, so that it is fairly easy to detect them in existing source code.
This approach does not capture all decision paths that exist though. Logical expressions like and and or are not covered. A variation of the Cyclomatic Complexity Number that also takes into account them is called CCN2. The CCN2 is the most widely used variation of this software metrics. And tools like PHPUnit, PMD and Checkstyle report use it.
Due to the fact that Cyclomatic Complexity Number was originally invented for procedural programming languages, this definition of Cyclomatic Complexity Number still misses one element to measure the complexity of an object oriented software system. With the concept of exceptions a software gets additional decision paths for each catch statement used in the source code. While try contains the code for the regular execution code without special cases, similar to else and default statements.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
It’s called NPATH. This metric main objective is to count the number of execution paths and therefor the number of tests that will have to be written to fully cover a function or method.
Here is a few examples for NPATH is calculated for different control structures. In general NPATH is a Cartesian product of all the statements within a function or method. Structures like break, continue or return count as 1, while specific control structures are calculated separately. It’ll be the best to explain this on a specific example.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Let’s have a look at a small example and try to calculate the cyclomatic complexity number for this function. So every function or method counts as 1 in itself. Then we’ve got first if statement, and a second one and another elseif. Note that else is not taken into account as it counts for a default execution path and would exist anyway, no matter the if statement would exist or not. Then we have another elseif and finally for loop. That’s 6 in total. Now what does it mean – is it low or high complexity? What do you think? Over time thresholds have been defined to help categorize the metric. Today a method is considered to have low complexity if it has cyclomatic complexity number between 1 and 4. Functions with cyclomatic complexity number between 5 and 7 have average complexity. You can start expecting serious problems with functions with cyclomatic complexity number between 8 and 10, and everything above 11 should be refactored as soon as possible!Unfortunately McCabe’s metric is not perfect and doesn’t distinguish between different kinds of control structures. And some of them are harder to understand then the other. Also it doesn’t take into account the level of nesting. That’s why a new metric has been developed.
Now, nobody expects you to calculate all these metrics manually. It’d be madness. After all we have computers to do the math for us. There is a tool, written by Manuel Pichler, that performs static analysis of PHP code, and it’s called PHP Depend. It produces all sort of reports that will help you understand size and complexity of your code. It allows you to identify parts of your codebase that might require closer look and potentially refactoring. You get that for free, without even looking at the source code. And that’s not it.
Based on PHP Depend another tool has been written, by the same awesome guy, called PHP Mess Detector. The name of the tool reflect the purpose of the tool very well. It will basically reveal the most messy parts of you codebase telling you exactly what is wrong it. So if you don’t want to go through all the metrics that PHP Depends generates, or you simply want to save time, just use this. On the report you will even see hints how you can fix the issues that have been identified! All these metrics are great, but in general they are very simple. Some of them depend for example on a definition of a line of code or specific language structures. It’s also not really possible to compare 2 different projects based on these metrics. One of the most important aspects of metrics is its visualization. We have to remember that metrics are not only for developers and geeks. They need to be easily understandable for non-developers so appropriate actions and decisions could be taken.
Overview pyramid is a perfect example of a report that provides simple and size-independent visualization of a system. It covers 3 major structural aspects of a system.Size and complexity that allows to assess how big and complex given codebase is, Coupling which describes interaction between objects and allows to understand how closely classes are coupledAnd Inheritance – how reusable the code it and how well it implements object oriented principles.
In the size and complexity section we will put measures from the higher level unit – NOP, to complexity measure – CYCLO. So in this order we have total NOP, NOC, NOM, LOC and CYCLO.NOP - packages, namespacesNOC – number of classesNOM – number of operations – methods or global functionsLOC – lines of codeCYCLO – total number of possible program paths
Then we will compute ratios between these metrics in a cascading manner. This way we will get metrics that are comparable. These metrics can be used to compare different projects.So what do we get here then?First - packaging level – how big the packages are.Secondly - quality of class design – how many operations there is per class, high value means we have overloaded classesNext, operation size - how well code is distributed between operations, high numbers indicate heavy methodsAnd finally, operation complexity. How much conditional complexity we can expect in operations, for example 0.2 means a new branch is added every few lines
Coupling section will tell us how intensive or how how dispersed is coupling of the system.We have 2 metrics here:CALLS – which is total distinct number of operation invocations in the project – these are operations defined by user, so they don’t include any operations from external librariesMethod Foo() called 3 times within method boo() is counted once, but called once in method boo(), once in bar() and once in bah() will be counted 3 times.Second metric is FANOUT. It is defined as the number of other classes referenced by a class.
Direct metrics describe the total coupling amount of a system, but are not enough to characterize the system. But using NOM we can characterize it better.Using the same calculation method we can compute 2 additional metrics:1. Coupling intensity - level of coupling between operations, on average how many other operations are called from each operation, high values indicate excessive coupling 2. Coupling dispersion - how much coupling involves many classes – 0.5 means every 2 operations calls involve another class
At last we have 2 overall direct metrics that describe inheritance usage. In short they tell you how much of object orientedness you can expect in the system – usage of class hierarchies and polymorphismANDC – average number of derived classes. In other words it is an average number of direct subclasses of a class. AHH – average hierarchy height. This is an average of maximum length from a root class it its deepest subclass.
Having all these metrics in place we can add final touches to the pyramid. We can visualize thresholds for the computed metrics. Remembering all the thresholds would be madness, so3 different colours are used to describe them . It makes it much easier to interpret the values. Operations have rather low complexity, while size of methods and classes in Symfony is average. Also with 5.82 classes per package we can say Symfony has small packages.On the coupling side, framework is intensively coupled in terms of operations call, but the calls are not dispersed – they’re rather localized – methods call many operations from few classes. In terms of inheritance – classes hierarchies are widely used within the system (high ANDC value) and rather deep (high AHH value).
For reference these are the thresholds used by PHP Depend to decide how to classify these metrics when generating overview pyramid.
The last tool I want to mention today is Sonar. Application that visualize all the metrics that we have talked about today and many more in one place. It reuses all the reports generated by PHPUnit, PHP_Codesniffer, PHP Depend and PHP Mess Detector and serve them in a way that is easy to read.
So we have all the metrics on screen related to the size of the project and its complexity. It also includes unit test metrics – code coverage and percent of successful and failed tests. You can easily drill down into the reports and see all the details you need to.
It also reports detected violations – starting with coding violations and ending up with violations detected by Mess Detector. So you can easily find here overgrown methods and classes and parts of the codebase with the highest complexity – taking into account both cyclometric complexity number and npath.
There are also 2 plugin that are also worth mentioning, which use some of the metrics I have mentioned. The first one is SIG Maintainability Model which is an implementation of the Software Improvement Group Maintainability Model. The model is a 2 steps approach: calculate base indicators and then combine them to get higher level ones. Every indicator results to a 5-levels ranking from very bad to very good and represents the 4 axes of maintainability of a software – analyzability, changeability, stability and testability. The color of the spider represents the actual combined value, from RED being very bad to GREEN being very good.
The second plugin is called Technical debt and as the name suggest it evaluates how much technical debt a project is in. It consists of 4 advanced measures:The debt ratio – which is a percentage of the current technical debt of the project versus the total possible debt for the project. Calculating it this way it’s easier to compare technical debt between projects. If you think about it having 5 grand of debt on a small project is different to having the same amount of debt on a big project.The cost to reimburse – is an attempt to asses a cost to clean all defects on every axis – no more duplications, no more violations, reduce complexity, and so on.The work to reimburse – is the same cost but expressed in man days.The breakdown - a view of the debt distribution across the quality axis in a form of pie chart.All this is configurable in plugin settings.