View
6.764
Download
0
Category
Preview:
Citation preview
Sebastian Marek, Software Architect
Magic behind the numbers
Software metrics in
practice
@proofek
• a Pole living in Sheffield• over 10 years PHP
experience• co-author of 2 PHP books • big fan of process
automation• TDD and CI• occasionally contributes
to open source projects• wants to be a knight
Agenda
What I will be talking about• Code metrics• Design metrics
What I will not be talking about• Project metrics
Most effective code quality measure
“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?
“Good design quality metrics are not necessarily indicative of good designs. Likewise, bad design quality metrics are not necessarily indicative of bad
designs”
Source: Jdepend Docs
Software design
System maintenance
• Obsolete documentation• Convoluted design• Intensive patch mechanism (hacking)• Large size• Severe duplication• Obsolete parts (dead code)• Long build times• Loss of original developers
Simple metrics
• CLOC – comment lines of code• ELOC – executable lines of code• LOC – lines of code• NCLOC – non comment lines of code• NOP – number of packages• NOC – number of classes• NOM – number of methods• CYCLO – cyclomatic complexity number
phploc
phploc 1.6.1 by Sebastian Bergmann.
Directories: 6Files: 20
Lines of Code (LOC): 5478 Cyclomatic Complexity / Lines of Code: 0.13Comment Lines of Code (CLOC): 2143Non-Comment Lines of Code (NCLOC): 3335
Namespaces: 0Interfaces: 1Classes: 18 Abstract: 2 (11.11%) Concrete: 16 (88.89%) Average Class Length (NCLOC): 191Methods: 151 Scope: Non-Static: 143 (94.70%) Static: 8 (5.30%) Visibility: Public: 116 (76.82%) Non-Public: 35 (23.18%) Average Method Length (NCLOC): 22 Cyclomatic Complexity / Number of Methods: 3.72
Anonymous Functions: 0Functions: 2
Constants: 4 Global constants: 3 Class constants: 1
JAVA
Metric Low Avg High V.High
CYCLO/Line of code 0.16 0.20 0.24 0.36
LOC/Method 7 10 13 19.5
NOM/Class 4 7 10 15
Source: Object-Oriented Metrics in Practice (based on 45 Java projects)
C++
Metric Low Avg High V.High
CYCLO/Line of code 0.20 0.25 0.30 0.45
LOC/Method 5 10 16 24
NOM/Class 4 9 15 22.5
Source: Object-Oriented Metrics in Practice (based on 37 C++ projects)
WMC and AMW
Weighted Method Count – total complexity of a class
Average Method Weight – average complexity of a method
JAVA
Metric Low Avg High V.High
WMC 5 14 31 47
AMW 1.1 2.0 3.1 4.7
LOC/Class 28 70 130 195
Source: Object-Oriented Metrics in Practice (based on 45 Java projects)
C++
Metric Low Avg High V.High
WMC 4 23 72 108
AMW 1.0 2.5 4.8 7.0
LOC/Class 20 90 240 360
Source: Object-Oriented Metrics in Practice (based on 37 C++ projects)
Coverage report
C.R.A.P
C.R.A.P
Change Risk Analysis and Predictions
ChangeRiskAnalysis and Predictions
C.R.A.P formula
Code coverage = 100%
Code coverage = 0%
Cyclomatic Complexity
Cyclomatic complexity measures the amount of decision logic in a single software
module.
Cyclomatic Complexity Number (CCN)
Conditional statements:• ?• case• elseif• for• foreach• if• while
CCN2
Conditional statements:• ?• case• elseif• for• foreach• if• while
• &&• ||• or• and• xor
Cyclomatic complexity
Conditional statements:• ?• case• elseif• for• foreach• if• while
• &&• ||• or• and• xor• catch
Cyclomatic complexity - example
class Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) {
fiddle();
} elseif ($a2 == $b2) {
fiddle();
} else {
fiddle();
}
} elseif ($e == $f) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() { 1 if ($a == $b) {
if ($a1 == $b1) {
fiddle();
} elseif ($a2 == $b2) {
fiddle();
} else {
fiddle();
}
} elseif ($e == $f) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() { 1 if ($a == $b) { 2 if ($a1 == $b1) {
fiddle();
} elseif ($a2 == $b2) {
fiddle();
} else {
fiddle();
}
} elseif ($e == $f) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() { 1 if ($a == $b) { 2 if ($a1 == $b1) { 3 fiddle();
} elseif ($a2 == $b2) {
fiddle();
} else {
fiddle();
}
} elseif ($e == $f) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() { 1 if ($a == $b) { 2 if ($a1 == $b1) { 3 fiddle();
} elseif ($a2 == $b2) { 4 fiddle();
} else {
fiddle();
}
} elseif ($e == $f) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() { 1 if ($a == $b) { 2 if ($a1 == $b1) { 3 fiddle();
} elseif ($a2 == $b2) { 4 fiddle();
} else {
fiddle();
}
} elseif ($e == $f) { 5 for ($n = 0; $n < $h; $n++) {
fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() { 1 if ($a == $b) { 2 if ($a1 == $b1) { 3 fiddle();
} elseif ($a2 == $b2) { 4 fiddle();
} else {
fiddle();
}
} elseif ($e == $f) { 5 for ($n = 0; $n < $h; $n++) { 6 fiddle();
}
} else {
fiddle();
}
}
}
Cyclomatic complexity - example
class Foo {
public function example() {
6
if ($a == $b) { if ($a1 == $b1) { fiddle(); } elseif ($a2 == $b2) { fiddle(); } else { fiddle(); } } elseif ($e == $f) { for ($n = 0; $n < $h; $n++) { fiddle(); } } else { fiddle(); } }}
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
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
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) {
fiddle();
} else {
fiddle();
}
}
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) {
fiddle(); 1 } else {
fiddle();
}
}
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) {
fiddle(); 1 } else {
fiddle(); 2 }
}
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) { 2 fiddle(); 1 } else {
fiddle(); 2 }
}
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) {
2 fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
if ($a1 == $b1) {
2 fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) { 2 if ($a1 == $b1) {
2 fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) { 2 if ($a1 == $b1) {
2 fiddle(); } else { fiddle(); } } 3
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle();
}
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {
fiddle(); 1 }
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) { 1 fiddle(); 1 }
}
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) { 1 fiddle(); 1 } 2 }
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {2 fiddle();
} }
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
for ($n = 0; $n < $h; $n++) {2 fiddle();
} }
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) { 3 for ($n = 0; $n < $h; $n++) {
2 fiddle(); } }
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) { 3 for ($n = 0; $n < $h; $n++) {
2 fiddle(); } } 4
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
4 for ($n = 0; $n < $h; $n++) { fiddle(); } }
return true;
}
}
NPATH – exampleclass Foo {
public function example() {
if ($a == $b) {
3
if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) {
4 for ($n = 0; $n < $h; $n++) { fiddle(); } }
return true; 1 }
}
NPATH – exampleclass Foo {
public function example() {
12
if ($a == $b) { if ($a1 == $b1) { fiddle(); } else { fiddle(); } }
if ($e == $f && $g == $z) { for ($n = 0; $n < $h; $n++) { fiddle(); } } return true; }}
PHP Depend
PHP_Depend 0.10.6 by Manuel Pichler
Parsing source files:.................... 20
Executing CyclomaticComplexity-Analyzer:............. 261
Executing ClassLevel-Analyzer:............ 247
Executing CodeRank-Analyzer:. 28
Executing Coupling-Analyzer:............. 267
Executing Hierarchy-Analyzer:............ 246
Executing Inheritance-Analyzer:. 30
Executing NPathComplexity-Analyzer:.............. 283
Executing NodeCount-Analyzer:........ 174
Executing NodeLoc-Analyzer:.......... 205
Generating pdepend log files, this may take a moment.
Time: 00:05; Memory: 25.50Mb
PHP Mess Detector
Overview pyramid
Size and complexity – direct metrics
Size and complexity – computed proportions
System coupling – direct metrics
System coupling – computed proportions
System inheritance
Complete Overview Pyramid
PHP
Metric Low Avg High
CYCLO/LOC 0.16 0.20 0.24
LOC/NOM 7 10 13
NOM/NOC 4 7 10
NOC/NOP 6 17 26
CALLS/NOM 2.01 2.62 3.2
FANOUT/CALLS 0.56 0.62 0.68
ANDC 0.25 0.41 0.57
AHH 0.09 0.21 0.32
http://pdepend.org/
Metrics visualisation with Sonar
Metrics visualisation with Sonar
Violations reporting
SIG Maintainability Model
---0+++
Very bad
BadAverageGoodVery good
Technical Debt
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
Resources
• PHP Depend - http://pdepend.org/• PHP Mess Detector - http://phpmd.org/• Manuel’s home page - http://manuel-pichler.de/• PHPUnit - http://www.phpunit.de/• phploc - http://sebastianbergmann.github.com/phploc/• Sonar - http://www.sonarsource.org/• “Object-Oriented Metrics in Practice” by Michele Lanza
and Radu Marinescu (ISBN 978-3540244295)
Questions
http://joind.in/3588
Questions?
Recommended