Eine ausführliche Erklärung der Codekomplexität

Es ist kein Geheimnis Code ist eine komplizierte Sache zu schreiben, zu debuggen und zu warten, die für eine hohe Softwarequalität notwendig ist. Darüber hinaus bringt eine hohe Codekomplexität ein höheres Maß an Codefehlern mit sich, wodurch die Wartung des Codes kostspieliger wird.

Durch die Reduzierung der Codekomplexität können wir also die Anzahl der Fehler und Defekte sowie die Lebenszeitkosten reduzieren. Was genau ist komplexer Code? Wie können wir objektiv beurteilen, wie komplex ein Stück Code ist, ob es sich um eine ganze Codebasis oder eine kleine Funktion handelt?

In diesem Artikel werde ich drei Komplexitätsmetriken zur Bewertung der Codekomplexität durchgehen. Dies sind:

  • Zyklomatische Komplexität
  • Switch-Anweisung und logische Bedingungskomplexität
  • Entwicklerfähigkeiten

Ich werde auch einige der Vorteile der Bewertung und des Verständnisses der Codekomplexität durchgehen.

Zyklomatische Komplexität

1976 schlug Thomas McCabe Snr eine Metrik zur Berechnung der Codekomplexität vor, die als Zyklomatische Komplexität bezeichnet wird. Es ist definiert als:

Ein quantitatives Maß für die Anzahl der linear unabhängigen Pfade durch den Quellcode eines Programms … berechnet unter Verwendung des Kontrollflussdiagramms des Programms.

Wenn Sie mit einem Kontrollflussdiagramm nicht vertraut sind:

Es ist eine Darstellung aller Pfade, die ein Programm während seiner Ausführung durchlaufen kann.

Einfacher gesagt, je weniger Pfade durch einen Codeabschnitt und je weniger komplex diese Pfade sind, desto geringer ist die zyklomatische Komplexität. Infolgedessen ist der Code weniger kompliziert. Um die Metrik zu demonstrieren, verwenden wir drei etwas willkürliche Go-Codebeispiele.

Beispiel eins

func main() { fmt.Println("1 + 1 =", 1+1)}

Da es nur einen Pfad durch die Funktion gibt, hat sie einen zyklomatischen Komplexitätswert von 1, den wir finden können, indem wir gocyclo darauf ausführen.

Beispiel Zwei

func main() { year, month, day := time.Now().Date() if month == time.November && day == 10 && year == 2018 { fmt.Println("Happy Go day!") } else { fmt.Println("The current month is", month) }}

In diesem Beispiel rufen wir das aktuelle Jahr, den Monat und den Tag ab. Mit diesen Informationen prüfen wir dann, ob das aktuelle Datum der 10.November 2018 mit einer if / Else-Bedingung ist.

Wenn dies der Fall ist, wird im Code „Happy Go day!“ zur Konsole. Wenn dies nicht der Fall ist, werden „Der aktuelle Monat ist“ und der Name des aktuellen Monats gedruckt. Das Codebeispiel wird komplizierter, wenn die Bedingung aus drei Unterbedingungen besteht. Angesichts dessen hat es einen höheren Komplexitätswert von 4.

Beispiel drei

func main() { _, month, _ := time.Now().Date() switch month { case time.January: fmt.Println("The current month is January.") case time.February: fmt.Println("The current month is February.") case time.March: fmt.Println("The current month is March.") case time.April: fmt.Println("The current month is April.") case time.May: fmt.Println("The current month is May.") default: fmt.Println("The current month is unknown.") }}

In diesem Beispiel drucken wir den aktuellen Monat basierend auf dem Wert von month aus, der vom Aufruf von time.Now().Date() abgerufen wurde. Es gibt sieben Pfade durch die Funktion, einen für jede der case-Anweisungen und einen für den Standard.

Infolgedessen ist seine zyklomatische Komplexität 7. Wenn wir jedoch alle Monate des Jahres zusammen mit einem Ausfall berücksichtigt hätten, wäre seine Punktzahl vierzehn. Dies geschieht, weil Gocyclo die folgenden Berechnungsregeln verwendet:

1 ist die Basiskomplexität einer Funktion
+1 für jeden Fall ‚if‘, ‚for‘, ‚case‘, ‚&&‘ oder ‚||‘

Anhand dieser drei Beispiele können wir sehen, dass wir mit einer Standardmetrik zur Berechnung der Codekomplexität schnell beurteilen können, wie komplex ein Code ist.

Wir können auch sehen, wie unterschiedlich komplexe Codeabschnitte im Vergleich zueinander sind. Die zyklomatische Komplexität allein reicht jedoch nicht aus.

Komplexität der Switch-Anweisung und der logischen Bedingung

Der nächste Assessor der Codekomplexität ist die Komplexität der switch-Anweisung und der logischen Bedingung. Im folgenden Codebeispiel habe ich das zweite Go-Beispiel verwendet und die zusammengesetzte if-Bedingung in drei verschachtelte Bedingungen aufgeteilt. eine für jede der ursprünglichen Bedingungen.

func main() { year, month, day := time.Now().Date() output := fmt.Sprintf("The current month is %s", month) if month == time.November { if day == 13 { if year == 2018 { output = fmt.Sprintf("Happy Go day!") } } } fmt.Println(output)}

Was ist leichter zu verstehen (oder weniger kompliziert), das Original oder dieses? Lassen Sie uns nun darauf aufbauen, indem wir die folgenden drei Fragen betrachten.

  • Was wäre, wenn wir, wie oben beschrieben, mehrere if-Bedingungen hätten und jede ziemlich komplex wäre?
  • Was wäre, wenn wir mehrere if-Bedingungen hätten und der Code im Körper jedes einzelnen ziemlich komplex wäre?
  • Wäre der Code einfacher oder schwerer zu verstehen?

Es ist fair zu sagen, dass die Komplexität des Codes umso höher ist, je größer die Anzahl der verschachtelten Bedingungen und je höher der Komplexitätsgrad innerhalb dieser Bedingungen ist.

Softwareentwickler-Qualifikationsniveau

Was ist mit dem Qualifikationsniveau des Entwicklers? Schauen Sie sich die C-Version des zweiten Go-Beispiels unten an.

#include <stdio.h>#include <time.h>#include <string.h>int main(){ time_t t = time(NULL); struct tm tm = *localtime(&t); const char * months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; if (tm.tm_year == 2018 && strncmp(months, "November", strlen(months)) == 0 && tm.tm_mday == 10) { printf("Happy C Day!.\n"); } else { printf("The current month is %s.\n", months); }}

Technisch macht es das, was die anderen Beispiele tun. Es erfordert jedoch mehr Code, um das gleiche Ergebnis zu erzielen. Um fair zu sein, wenn ich mit C besser vertraut wäre, wäre der Code möglicherweise nicht länger als das Go-Beispiel.

Nehmen wir jedoch an, dies ist das Minimum, das erforderlich ist, um dasselbe Ergebnis zu erzielen. Wenn Sie die beiden vergleichen, ist es angesichts der ausführlicheren Syntax von C im Vergleich zu Go schwieriger zu verstehen.

Was mehr ist, wenn Sie keine vorherige Erfahrung mit C hatten, trotz einer vergleichsweise ähnlichen zyklomatischen Komplexitätsbewertung, was wäre Ihre Wahrnehmung?

Würden Sie den Code für weniger oder komplizierter halten? Dies ist also ein weiterer wesentlicher Faktor für das Verständnis der Codekomplexität.

Die Vorteile der Messung der Softwarekomplexität

Es gibt vier Hauptvorteile der Messung der Codekomplexität plus einen zusätzlichen.

Bessere Tests

Wenn wir wissen, wie viele unabhängige Pfade es durch einen Code gibt, wissen wir, wie viele Pfade es zu testen gibt.

Ich plädiere übrigens nicht für eine 100% ige Codeabdeckung – das ist oft eine bedeutungslose Software-Metrik. Ich plädiere jedoch immer für eine möglichst hohe Codeabdeckung, die sowohl praktisch als auch möglich ist.

Wenn wir also wissen, wie viele Codepfade es gibt, können wir wissen, wie viele Pfade wir testen müssen. Als Ergebnis haben Sie ein Maß dafür, wie viele Tests mindestens erforderlich sind, um sicherzustellen, dass der Code abgedeckt ist.

Reduziertes Risiko

Wie das alte Sprichwort sagt:

Es ist schwieriger, Code zu lesen, als ihn zu schreiben.

Was ist mehr:

  1. Code wird viel mehr gelesen als geschrieben
  2. Ein guter Softwareentwickler sollte niemals nach den Codezeilen beurteilt werden, die er geschrieben (oder geändert) hat, sondern nach der Qualität des Codes, den er gepflegt hat.

Da Sie durch die Reduzierung der Codekomplexität das Risiko der Einführung von Fehlern verringern; ob sie klein oder groß, leicht peinlich oder konkursauslösend sind.

Geringere Kosten

Wenn das Risiko potenzieller Defekte reduziert wird, gibt es weniger Defekte zu finden — und zu entfernen. Dadurch reduzieren sich auch die Wartungskosten.

Wir alle kennen die Kosten, die mit dem Auffinden von Fehlern in den verschiedenen Lebensphasen einer Software verbunden sind, wie in der folgenden Tabelle veranschaulicht.

Rising cost of defects

Wenn wir also die Komplexität unseres Codes verstehen und welche Abschnitte komplizierter sind als andere, sind wir in einer weitaus besseren Position, um diese Komplexität zu reduzieren.

Indem wir diese Komplexität reduzieren, verringern wir die Wahrscheinlichkeit, dass Fehler auftreten. Das fließt in alle Lebensphasen einer Software ein.

Bessere Vorhersagbarkeit

Durch die Reduzierung der Softwarekomplexität können wir mit größerer Vorhersagbarkeit entwickeln. Damit meine ich, dass wir besser mit Zuversicht sagen können, wie lange ein Codeabschnitt dauert. Wenn wir dies wissen, können wir besser vorhersagen, wie lange eine Veröffentlichung dauert.

Basierend auf diesem Wissen ist das Unternehmen oder die Organisation besser in der Lage, seine Ziele und Erwartungen festzulegen, insbesondere solche, die direkt von dieser Software abhängen. In diesem Fall ist es einfacher, realistische Budgets, Prognosen usw. festzulegen.

Hilft Entwicklern beim Lernen

Entwicklern beim Lernen und Wachsen zu helfen, ist der letzte Vorteil, wenn Sie verstehen, warum ihr Code als komplex angesehen wird. Die Tools, mit denen ich die Komplexität bis zu diesem Zeitpunkt bewertet habe, tun dies nicht.

Sie liefern einen Gesamt- oder granularen Komplexitätswert. Ein umfassendes Codekomplexitätstool wie Codacy tut dies jedoch.

Dateikomplexitätsliste

Im obigen Screenshot können wir sehen, dass eine der sechs aufgelisteten Dateien eine Komplexität von 30 hat, eine Punktzahl, die normalerweise als ziemlich hoch angesehen wird.

Die zyklomatische Komplexität ist ein guter Indikator, um zu verstehen, ob sich die Codequalität bei einer bestimmten Änderung verschlechtert. Zyklomatische Komplexität kann schwieriger zu verstehen sein, wenn man sie betrachtet oder ganze Module vergleicht, da sie unendlich groß ist und nicht mit der Modulgröße zusammenhängt. Etwas, das Sie jedoch nützlich finden könnten, ist die nach Priorität sortierte Dateiliste von Codacy, die Ihnen hilft zu verstehen, welche Dateien Kandidaten für eine schlechte Codequalität sind, und dann ihre Module.

Das ist ein Wrap

Außerdem wurde ausführlich darüber diskutiert, was Codekomplexität ist, wie sie bewertet wird und welche erheblichen Vorteile eine Reduzierung bietet. Obwohl es mehr zum Verständnis der Codekomplexität gibt, als ich hier behandelt habe, haben wir einen langen Weg zum Verständnis zurückgelegt.

Wenn Sie zum ersten Mal von dem Begriff hören oder etwas über eines der Tools lernen, empfehle ich Ihnen, die verknüpften Artikel und Tools zu erkunden, damit Sie mehr erfahren. Wenn Sie nicht in Go oder C codieren, dann google „Code Complexity Tool“ plus Ihre Software-Sprache (n). Sie sind sicher, viele Werkzeuge zur Verfügung zu finden.

Weitere Tipps zur Verbesserung der Codequalität finden Sie in einigen anderen Blogbeiträgen von Codacy.

Wenn Sie ein umfassendes Tool zur Bewertung der Codequalität wünschen, das Ihren Entwicklern hilft, zu lernen und zu wachsen, dann probieren Sie Codacy aus.

Codacy wird von Tausenden von Entwicklern verwendet, um täglich Milliarden von Codezeilen zu analysieren!

Der Einstieg ist einfach – und kostenlos! Verwenden Sie einfach Ihr GitHub-, Bitbucket- oder Google-Konto, um sich anzumelden.

ERSTE SCHRITTE

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.