Content deleted Content added
m Task 70: Update syntaxhighlight tags - remove use of deprecated <source> tags |
Synapse554 (talk | contribs) m Moved to section on algebraic topology to its own heading, given its different context compared to the rest of the article |
||
(36 intermediate revisions by 27 users not shown) | |||
Line 1:
{{Short description|Measure of the structural complexity of a software program}}
'''Cyclomatic complexity''' is a [[software metric]] used to indicate the [[Programming complexity|complexity of a program]]. It is a quantitative measure of the number of linearly independent Cyclomatic complexity is computed using the [[control
One [[software testing|testing]] strategy, called [[basis path testing]] by McCabe who first proposed it, is to test each linearly independent path through the program
url=http://users.csc.calpoly.edu/~jdalbey/206/Lectures/BasisPathTutorial/index.html|
title=Basis Path Testing|
Line 9 ⟶ 10:
==Description==
[[Image:control flow graph of function with loop and an if statement without loop back.svg|thumb|
▲=== Definition ===
▲[[Image:control flow graph of function with loop and an if statement without loop back.svg|thumb|250px|right|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 (graph theory)|connected component]], so the cyclomatic complexity of the program is 9 - 8 + 2*1 = 3.]]
▲The cyclomatic complexity of a section of [[source code]] is the number of linearly independent [[path (graph theory)|paths]] within it—where "linearly independent" means that each path has at least one edge that is not in one of the other paths. For instance, if the source code contained no [[Control flow|control flow statements]] (conditionals or decision points), the complexity would be 1, since there would be only a single path through the code. If the code had one single-condition IF statement, there would be two paths through the code: one where the IF statement evaluates to TRUE and another one where it evaluates to FALSE, so the complexity would be 2. Two nested single-condition IFs, or one IF with two conditions, would produce a complexity of 3.
<math display="block">M = E - N + 2P,</math>
▲Mathematically, the cyclomatic complexity of a [[Structured programming|structured program]]{{efn|1=Here "structured" means in particular "with a single exit ([[return statement]]) per function".}} is defined with reference to the [[control flow graph]] of the program, a [[directed graph]] containing the [[basic block]]s of the program, with an edge between two basic blocks if control may pass from the first to the second. The complexity '''M''' is then defined as<ref name="mccabe76">{{cite journal| last=McCabe|date=December 1976| journal=IEEE Transactions on Software Engineering|issue=4| pages=308–320|
where
[[Image:control flow graph of function with loop and an if statement.svg|thumb|
An alternative formulation of this, as originally proposed, is to use a graph in which each exit point is connected back to the entry point. In this case, the graph is [[strongly connected]]
This may be seen as calculating the number of [[linearly independent cycle]]s that exist in the graph
For a single program (or subroutine or method),
<math display="block">M = E - N + 2.</math>
Cyclomatic complexity may
McCabe showed that the cyclomatic complexity of
url=https://www.froglogic.com/blog/tip-of-the-week/what-is-cyclomatic-complexity/| title=What exactly is cyclomatic complexity?|quote=To compute a graph representation of code, we can simply disassemble its assembly code and create a graph following the rules: ... |first=Sébastien|last=Fricker|date=April 2018|website=froglogic GmbH|access-date=October 27, 2018}}</ref> Decisions involving compound predicates like those found in [[high-level
▲title=What exactly is cyclomatic complexity?|quote=To compute a graph representation of code, we can simply disassemble its assembly code and create a graph following the rules: ... |first=Sébastien|last=Fricker|date=April 2018|website=froglogic GmbH|access-date=October 27, 2018}}</ref> Decisions involving compound predicates like those found in high-level languages like <code>IF cond1 AND cond2 THEN ...</code> should be counted in terms of predicate variables involved, i.e. in this example one should count two decision points, because at machine level it is equivalent to <code>IF cond1 THEN IF cond2 THEN ...</code>.<ref name="mccabe76"/><ref name="ecst">{{cite book|
title=Encyclopedia of Computer Science and Technology|
publisher=CRC Press|year=1992|
pages=367–368}}</ref>
Cyclomatic complexity may be extended to a program with multiple exit points
<math display="block">\pi - s + 2,</math>
where
=== Interpretation ===
=== Explanation in terms of algebraic topology ===▼
In his presentation "Software Quality Metrics to Identify Risk"<ref>{{cite web |url=http://www.mccabe.com/ppt/SoftwareQualityMetricsToIdentifyRisk.ppt |title=Software Quality Metrics to Identify Risk |author=Thomas McCabe Jr. |year=2008 |archive-url=https://web.archive.org/web/20220329072759/http://www.mccabe.com/ppt/SoftwareQualityMetricsToIdentifyRisk.ppt |archive-date=2022-03-29 |url-status=live}}</ref> for the Department of Homeland Security, Tom McCabe introduced the following categorization of cyclomatic complexity:
An ''even subgraph'' of a graph (also known as an [[Eulerian path|Eulerian subgraph]]) is one where every [[Vertex (graph theory)|vertex]] is incident with an even number of edges; such subgraphs are unions of cycles and isolated vertices. In the following, even subgraphs will be identified with their edge sets, which is equivalent to only considering those even subgraphs which contain all vertices of the full graph.▼
* 1 - 10: Simple procedure, little risk
The set of all even subgraphs of a graph is closed under [[symmetric difference]], and may thus be viewed as a vector space over [[GF(2)]]; this vector space is called the ''cycle space'' of the graph. The [[cyclomatic number]] of the graph is defined as the dimension of this space. Since GF(2) has two elements and the cycle space is necessarily finite, the cyclomatic number is also equal to the 2-logarithm of the number of elements in the cycle space.▼
* 11 - 20: More complex, moderate risk
* 21 - 50: Complex, high risk
* > 50: Untestable code, very high risk
A basis for the cycle space is easily constructed by first fixing a [[Glossary of graph theory#Trees| spanning forest]] of the graph, and then considering the cycles formed by one edge not in the forest and the path in the forest connecting the endpoints of that edge; these cycles constitute a basis for the cycle space. Hence, the cyclomatic number also equals the number of edges not in a maximal spanning forest of a graph. Since the number of edges in a maximal spanning forest of a graph is equal to the number of vertices minus the number of components, the formula <math>E-N+P</math> above for the cyclomatic number follows.<ref>{{cite book▼
▲An
▲The set of all even subgraphs of a graph is closed under [[symmetric difference]], and may thus be viewed as a [[vector space]] over [[GF(2)]]
For the more topologically inclined, cyclomatic complexity can alternatively be defined as a relative [[Betti number]], the size of a [[relative homology]] group:▼
:<math>M := b_1(G,t) := \operatorname{rank}H_1(G,t),</math>▼
which is read as "the rank of the first homology group of the graph ''G'', relative to the terminal nodes ''t''". This is a technical way of saying "the number of linearly independent paths through the flow graph from an entry to an exit", where:▼
* "linearly independent" corresponds to homology, and means one does not double-count backtracking;▼
* "paths" corresponds to ''first'' homology: a path is a 1-dimensional object;▼
* "relative" means the path must begin and end at an entry or exit point.▼
▲A [[basis (linear algebra)|basis]] for the cycle space is easily constructed by first fixing a [[Glossary of graph theory#Trees|
▲
▲which is read as "the rank of the first [[Homology (mathematics)|homology]] group of the graph ''G''
It can also be computed via [[homotopy]]. If one considers the control flow graph as a 1-dimensional [[CW complex]] called <math>X</math>, then the [[fundamental group]] of <math>X</math> will be <math>\pi_1(X) = \Z^n</math>. The value of <math>n+1</math> is the cyclomatic complexity. The fundamental group counts how many loops there are through the graph, up to homotopy, and hence aligns with what we would intuitively expect.▼
▲* "linearly independent" corresponds to homology, and
▲* "relative" means the path must begin and end at an entry (or exit) point.
This cyclomatic complexity can be calculated. It may also be computed via absolute [[Betti number]] by identifying the terminal nodes on a given component, or drawing paths connecting the exits to the entrance. The new, augmented graph <math>\tilde G</math> obtains
▲It can also be computed via [[homotopy]].
==Applications==
===
One of McCabe's original applications was to limit the complexity of routines during program development
▲One of McCabe's original applications was to limit the complexity of routines during program development; he recommended that programmers should count the complexity of the modules they are developing, and split them into smaller modules whenever the cyclomatic complexity of the module exceeded 10.<ref name="mccabe76" /> This practice was adopted by the [[NIST]] Structured Testing methodology, with an observation that since McCabe's original publication, the figure of 10 had received substantial corroborating evidence, but that in some circumstances it may be appropriate to relax the restriction and permit modules with a complexity as high as 15. As the methodology acknowledged that there were occasional reasons for going beyond the agreed-upon limit, it phrased its recommendation as "For each module, either limit cyclomatic complexity to [the agreed-upon limit] or provide a written explanation of why the limit was exceeded."<ref name="nist">{{cite web|
url=http://www.mccabe.com/pdf/mccabe-nist235r.pdf| title=Structured Testing: A Testing Methodology Using the Cyclomatic Complexity Metric|author1=Arthur H. Watson |author2=Thomas J. McCabe | year=1996|publisher=NIST Special Publication 500-235}}</ref>
===
{{
Section VI of McCabe's 1976 paper is concerned with determining what the control
In order to calculate this measure, the original CFG is iteratively reduced by identifying subgraphs that have a single-entry and a single-exit point, which are then replaced by a single node. This reduction corresponds to what a human would do if they extracted a subroutine from the larger piece of code. (Nowadays such a process would fall under the umbrella term of [[refactoring]].) McCabe's reduction method was later called ''condensation'' in some textbooks, because it was seen as a generalization of the [[condensation (graph theory)|condensation to components used in graph theory]].<ref>{{cite book|author=Paul C. Jorgensen|title=Software Testing: A Craftsman's Approach, Second Edition|url=https://books.google.com/books?id=Yph_AwAAQBAJ&pg=PA150|year=2002|publisher=CRC Press|isbn=978-0-8493-0809-3|pages=150–153|edition=2nd}}</ref> If a program is structured, then McCabe's reduction/condensation process reduces it to a single CFG node. In contrast, if the program is not structured, the iterative process will identify the irreducible part. The essential complexity measure defined by McCabe is simply the cyclomatic complexity of this irreducible graph, so it will be precisely 1 for all structured programs, but greater than one for non-structured programs.<ref name="nist"/>{{rp|80}}<!--note that the original paper has an error here in that it subtracts the number of nodes from that [and thus can give negative essential complexity measures for some non-structured programs], but the later technical report fixed that]-->▼
▲
=== Implications for software testing ===▼
Another application of cyclomatic complexity is in determining the number of test cases that are necessary to achieve thorough test coverage of a particular module.
It is useful because of two properties of the cyclomatic complexity,
*
*
All three of the above numbers may be equal: branch coverage <math>\leq</math> cyclomatic complexity <math>\leq</math> number of paths.
Line 125 ⟶ 107:
</syntaxhighlight>
[[File:Control flow graph of function with two if else statements.svg|thumb|250px|right|The control
In this example, two test cases are sufficient to achieve a complete branch coverage, while four are necessary for complete path coverage. The cyclomatic complexity of the program is 3 (as the strongly connected graph for the program contains
In general, in order to fully test a module, all execution paths through the module should be exercised. This implies a module with a high complexity number requires more testing effort than a module with a lower value since the higher complexity number indicates more pathways through the code. This also implies that a module with higher complexity is more difficult
Unfortunately, it is not always practical to test all possible paths through a program. Considering the example above, each time an additional if-then-else statement is added, the number of possible paths grows by a factor of 2. As the program grows in this fashion, it quickly reaches the point where testing all of the paths becomes impractical.
One common testing strategy, espoused for example by the NIST Structured Testing methodology, is to use the cyclomatic complexity of a module to determine the number of [[white-box testing|white-box tests]] that are required to obtain sufficient coverage of the module. In almost all cases, according to such a methodology, a module should have at least as many tests as its cyclomatic complexity
As an example of a function that requires more than
* <code>c1()</code> returns true and <code>c2()</code> returns true
Line 147 ⟶ 129:
===Correlation to number of defects===
|journal=IEEE Transactions on Software Engineering|author1=Norman E Fenton |author2=Martin Neil |
url=http://www.eecs.qmul.ac.uk/~norman/papers/defects_prediction_preprint105579.pdf|
title=A Critique of Software Defect Prediction Models|
year=1999|volume=25|issue=3|pages=675–689
{{cite web |url=http://www.leshatton.org/TAIC2008-29-08-2008.html |title=The role of empiricism in improving the reliability of future software |author=Les Hatton |year=2008 |at=version 1.1}}</ref> that complexity has the same predictive ability as lines of code.
Studies that controlled for program size (i.e., comparing modules that have different complexities but similar size) are generally less conclusive, with many finding no significant correlation, while others do find correlation. Some researchers
{{cite book |title=Metrics and Models in Software Quality Engineering |author=Kan |pages=316–317 |publisher=Addison-Wesley |year=2003 |isbn=978-0-201-72915-3}}</ref> Although this relation
journal=Journal of Software Quality|
author=G.S. Cherf|
title=An Investigation of the Maintenance and Support Characteristics of Commercial Software|
year=1992|volume=1|issue=3|pages=147–158|
issn=1573-1367|doi=10.1007/bf01720922|
==See also==
Line 180 ⟶ 157:
* [[Software testing]]
* [[Static program analysis]]
* [[Maintainability]]
Line 192 ⟶ 168:
* [http://www.mathworks.com/discovery/cyclomatic-complexity.html Generating cyclomatic complexity metrics with Polyspace]
* [http://www.leshatton.org/Documents/TAIC2008-29-08-2008.pdf The role of empiricism in improving the reliability of future software]
* [https://web.archive.org/web/20230203195937/https://www.cqse.eu/en/news/blog/mccabe-cyclomatic-complexity// McCabe's Cyclomatic Complexity and Why We Don't Use It]▼
▲* [https://www.cqse.eu/en/blog/mccabe-cyclomatic-complexity/ McCabe's Cyclomatic Complexity and Why We Don't Use It]
[[Category:Software metrics]]
|