Lesen / Verbessern des von PHP berechneten CRAP-Index

73

Ich habe gerade angefangen, mit PHPUnit und seinen farbenfrohen Berichten zur Codeabdeckung zu arbeiten. Ich verstehe alle Zahlen und Prozentsätze außer einem: Der CRAP-Index. Kann mir jemand eine solide Erklärung geben, was es bedeutet, wie man es analysiert und wie man es senkt?

Levi Hackwith
quelle

Antworten:

109

@ Toader Mihai bot eine solide Erklärung. (+1 von mir)

So senken Sie es ab:

Schreiben Sie weniger komplexen Code ODER schreiben Sie besser getesteten Code. (Siehe die Grafik unten)

Besser getesteter Code?

In diesem Zusammenhang bedeutet dies nur: Eine höhere Codeabdeckung und führt normalerweise dazu, dass mehr Tests geschrieben werden.

Weniger komplexer Code?

Zum Beispiel: Refaktorieren Sie Ihre Methoden in kleinere:

// Complex
function doSomething() {
    if($a) {
        if($b) {
        }
        if($c) {
        }
    } else {
        if($b) {
        }
        if($c) {
        }
    }
}

// 3 less complex functions
function doSomething() {
    if($a) {
        doA();
    } else {
        doNotA();
    }
}

function doA() {
    if($b) {
    }
    if($c) {
    }
}

function doNotA() {
    if($b) {
    }
    if($c) {
    }
}

(Nur ein triviales Beispiel, ich bin sicher, Sie werden mehr Ressourcen dafür finden.)

Zusätzliche Ressourcen:

Lassen Sie mich zunächst einige zusätzliche Ressourcen bereitstellen:

Blogbeitrag des Erstellers über den Mistindex

Nur für den Fall: Zyklomatische Komplexität erklärt . Tools wie PHP_CodeSniffer und PHPMD teilen Ihnen diese Nummer mit, falls Sie dies wissen möchten.

Und während Sie selbst entscheiden müssen, welche Zahl "in Ordnung" ist, ist eine häufig vorgeschlagene Zahl (das ist ein wenig hoch imho) ein Mistindex von 30, was zu einem Diagramm wie diesem führt:

Alt-Text (Die .ods-Datei erhalten Sie hier: https://www.dropbox.com/s/3bihb9thlp2fyg8/crap.ods?dl=1 )

edorian
quelle
2
Hier ist ein Bild mit bis zu 5 als grün, 6-10 gelb und über 10 als rot: i.imgur.com/wwX1TbZ.png
dave1010
@edorian .ods Link ist defekt. Haben Sie einen neuen Link zur Verfügung zu stellen?
Niko9911
1
@ Niko9911 Aktualisiert den Link
edorian
64

Grundsätzlich möchte es ein Prädiktor für das Änderungsrisiko einer Methode sein.

Es hat zwei Faktoren:

  • Codekomplexität der Methode ( cyclomatic complexity), auch bekannt als wie viele Entscheidungspfade in dieser Methode vorhanden sind : comp(m).
  • Wie testbar ist diese Methode (über automatisierte Tests, die von einem Tool zur Codeabdeckung bereitgestellt werden)? Grundsätzlich misst dies, wie viele Entscheidungen in diesem Code automatisch testbar sind.

Wenn die Methode zu 100% abgedeckt ist, wird das Änderungsrisiko nur mit der Komplexität der Methode als gleichwertig angesehen : C.R.A.P.(m) = comp(m).

Wenn die Methode eine Abdeckung von 0% aufweist, wird das Änderungsrisiko als Polinom zweiten Grades im Komplexitätsmaß betrachtet (wenn Sie eine Änderung des Codepfads nicht testen können, erhöht dies das Bruchrisiko): C.R.A.P.(m) = comp(m)^2 + comp(m)

Hoffentlich hilft dir das.

Mir ist gerade aufgefallen, dass ich nur die halbe Antwort (den gelesenen Teil) gebe. Wie Sie es verbessern können, sollte ziemlich klar sein, wenn Sie die Argumentation des Index verstehen. Eine viel klarere Erklärung findet sich in der Antwort von @ edorian .

Die Kurzgeschichte lautet: Schreiben Sie Tests, bis Sie eine nahezu 100% ige Abdeckung haben, und überarbeiten Sie anschließend die Methoden, um die zyklomatische Komplexität zu verringern. Sie können versuchen, vor dem Ausführen von Tests eine Umgestaltung vorzunehmen. Abhängig von der tatsächlichen Komplexität der Methode besteht jedoch die Gefahr, dass ein Bruch auftritt, wenn Sie (aufgrund der Komplexität) nicht alle Konsequenzen der von Ihnen vorgenommenen Änderung begründen können.

Mihai Toader
quelle
1
Eine Sache, die nicht berücksichtigt wird, sind Abhängigkeiten. Ein einfaches function example() { $dep = new Dependency(); return $dep->someFunction(); }ist schwieriger zu testen (die function crappy($param) { switch ($param) { // 30 different cases with if-elses } }
Scheinlogik