Kontext: Ich bin ein Unternehmensentwickler in einem MS-Shop.
Kann jemand eine gute Methode empfehlen, um die Wartbarkeit eines Codeteils oder einer Anwendung objektiv zu messen ?
Warum Wartbarkeit : Ich habe es satt, dass in meiner Gruppe nur noch die Anzahl der Fehler und die Codeabdeckung im Vordergrund stehen. Beide Metriken sind einfach zu spielen, insbesondere wenn Sie die Wartbarkeit nicht messen. Kurzsichtigkeit und Fristen führen zu enormen technischen Schulden, die nie wirklich angegangen werden.
Warum die Fähigkeit, objektiv zu messen : Ich arbeite in einer großen Unternehmensgruppe. Wenn Sie es nicht objektiv messen können, können Sie die Leute nicht dafür zur Verantwortung ziehen oder sie dazu bringen, es besser zu machen. Subjektive Messungen passieren entweder nicht oder nicht konsequent.
Ich schaue mir die VS2010-Codemetriken an , frage mich aber, ob jemand andere Empfehlungen hat.
quelle
Antworten:
Die Realität ist, dass, es sei denn, Sie haben konkrete Beweise dafür, dass der Code nicht so wie er ist gewartet werden kann. Das Beheben eines Fehlers verursachte N Stunden nicht benötigte Zeit aufgrund von nicht wartbarem Code. dann ist es von Natur aus schwierig, ein Bein zum Stehen zu haben. In diesem Beispiel könnte dies darauf zurückzuführen sein, dass eine übermäßig komplexe Methodik verwendet wurde, wenn etwas viel Einfacheres ausgereicht hätte. Das Betreten eines Bereichs, in dem Sie versuchen, Methoden, Paradigmen und bewährte Methoden zu messen, wird zunehmend schwieriger, und dies mit geringem oder gar keinem langfristigen Gewinn.
Diesen Weg zu gehen ist leider eine Straße ins Nirgendwo. Konzentrieren Sie sich darauf, Stammprobleme aufzudecken, die einen erheblichen Nutzen haben und nicht mit persönlichen Gefühlen in Bezug auf ein Problem wie fehlende Namenskonventionen in der gesamten Codebasis verbunden sind, und finden Sie einen Weg, um den Erfolg und die Fehler in Bezug auf dieses Stammproblem zu messen. Auf diese Weise können Sie eine Reihe von Bausteinen zusammenstellen, aus denen Sie dann Lösungen formulieren können.
quelle
Nun, das Maß, das ich benutze oder das ich gerne benutze, ist folgendes:
Erstellen Sie für jede unabhängige, einzelne, einzeilige Take-it-or-Leave-it-Funktionsanforderung eine Momentaufnahme der Codebasis, bevor Sie sie implementieren. Implementieren Sie es dann, einschließlich des Findens und Behebens von Fehlern, die im Prozess aufgetreten sind. Führen Sie dann ein
diff
zwischen der Codebasis vor und nach. Dasdiff
zeigt Ihnen eine Liste aller Einfügungen, Löschungen und Änderungen, die die Änderung implementiert haben. (Wie das Einfügen von 10 aufeinander folgenden Codezeilen ist eine Änderung.) Wie viele Änderungen gab es? Je kleiner diese Zahl ist, desto besser kann der Code gewartet werden.Ich nenne das die Redundanz des Quellcodes, weil es wie die Redundanz eines fehlerkorrigierenden Codes ist. Die Informationen waren in einem Block enthalten, wurden jedoch als N Blöcke codiert, die alle zusammen ausgeführt werden müssen, um konsistent zu sein.
Ich denke, das ist die Idee hinter DRY, aber sie ist etwas allgemeiner. Der Grund, warum es gut ist, dass diese Anzahl niedrig ist, ist, dass Sie, wenn N Änderungen erforderlich sind, um eine typische Anforderung zu implementieren, und als fehlbarer Programmierer zunächst nur N-1 oder N-2 von ihnen korrekt ausführen 1 oder 2 Bugs. Zusätzlich zum Programmieraufwand für O (N) müssen diese Fehler entdeckt, lokalisiert und repariert werden. Deshalb ist kleines N gut.
Wartbar bedeutet für einen Programmierer, der nicht gelernt hat, wie der Code funktioniert, nicht unbedingt lesbar. Das Optimieren von N erfordert möglicherweise einige Dinge, die eine Lernkurve für Programmierer schaffen. Hier ist ein Beispiel. Eine Sache, die hilft, ist, wenn der Programmierer versucht, zukünftige Änderungen zu antizipieren und Anweisungen im Programmkommentar hinterlässt.
Ich denke, wenn N weit genug reduziert ist (das Optimum ist 1), liest sich der Quellcode eher wie eine domänenspezifische Sprache (DSL). Das Programm "löst" das Problem nicht so sehr, sondern "nennt" es "das Problem", da im Idealfall jede Anforderung nur als ein einziges Stück Code neu formuliert wird.
Leider sehe ich keine Leute, die sehr viel lernen, wie man das macht. Vielmehr scheinen sie zu glauben, dass mentale Substantive zu Klassen und Verben zu Methoden werden sollten, und alles, was sie tun müssen, ist die Kurbel zu drehen. Das führt nach meiner Erfahrung zu Code mit N von 30 oder mehr.
quelle
Die Wartbarkeit ist nicht wirklich messbar. Es ist eine subjektive Ansicht eines Individuums basierend auf seinen Erfahrungen und Vorlieben.
Lassen Sie sich für einen bestimmten Code eine Idee für ein perfektes Design einfallen .
Verringern Sie dann für jede Abweichung des realen Codes von diesem perfekten den Wert von 100 um eine Zahl. Worauf es genau ankommt, hängt von den Konsequenzen eines gewählten nicht perfekten Ansatzes ab.
Ein Beispiel:
Ein Teil des Codes liest und importiert ein Datenformat und zeigt möglicherweise eine Fehlermeldung an, wenn etwas nicht stimmt.
Eine perfekte Lösung (100) würde Fehlermeldungen an einem gemeinsamen Ort aufbewahren. Wenn Ihre Lösung sie als Zeichenfolgenkonstanten direkt im Code fest codiert hat, nehmen Sie beispielsweise 15 aus. Ihr Wartbarkeitsindex wird also 85.
quelle
Ein Ergebnis von Code, der schwer zu pflegen ist, ist, dass Sie (im Durchschnitt) länger brauchen, um Fehler zu beheben. Auf den ersten Blick scheint eine Metrik die Zeit zu sein, die benötigt wird, um einen Fehler zu beheben, und zwar von der Zuweisung (dh, der Fix wird gestartet) bis zur Testbereitschaft.
Nun, dies wird erst dann wirklich funktionieren, wenn Sie eine angemessene Anzahl von Fehlern behoben haben, um die "durchschnittliche" (was auch immer das bedeutet) Zeit zu ermitteln. Sie können die Zahl nicht für einen bestimmten Fehler verwenden, da die Schwierigkeit des Auffindens nicht nur von der "Wartbarkeit" des Codes abhängt.
Wenn Sie mehr Fehler beheben, wird der Code "einfacher" zu warten, da Sie ihn verbessern (oder zumindest sollten) und Sie sich mit dem Code besser auskennen. Diesem Umstand entgegenzuwirken, wird die Tendenz bestehen, dass die Bugs dunkler und daher noch schwerer aufzuspüren sind.
Dies leidet auch unter dem Problem, dass, wenn die Leute dazu neigen, Fehlerbehebungen zu beschleunigen, um eine niedrigere Punktzahl zu erhalten, dies entweder neue Fehler verursacht oder die vorhandene nicht richtig behebt, was zu noch mehr Arbeit und möglicherweise noch schlechterem Code führt.
quelle
Ich finde die Visual Studio-Codemetriken recht anständig, um eine schnelle Metrik für die Wartbarkeit bereitzustellen. Es werden 5 primäre Metriken erfasst:
Der Wartbarkeitsindex ist derjenige, den ich für nützlich halte. Es ist ein zusammengesetzter Index, basierend auf:
Gelegentlich schaue ich mir meine Methoden mit einem niedrigen Wartbarkeitsindex an (niedrig = schlecht für diesen). Fast immer sind die Methoden in meinem Projekt mit dem niedrigsten Wartbarkeitsindex diejenigen, die am dringendsten umgeschrieben werden müssen und die am schwierigsten zu lesen (oder zu warten) sind.
Siehe die Whitepaper für weitere Informationen über die Berechnungen.
quelle
Zwei, die sinnvoll sein werden, sind zyklomatische Komplexität und Klassenkopplung. Sie können die Komplexität nicht beseitigen. Sie können sie lediglich in überschaubare Teile unterteilen. Diese beiden Maßnahmen sollen Ihnen eine Vorstellung davon geben, wo sich schwer zu wartender Code befindet oder wo Sie am härtesten suchen müssen.
Die zyklomatische Komplexität ist ein Maß für die Anzahl der Pfade im Code. Jeder Pfad sollte getestet werden (ist es aber wahrscheinlich nicht). Etwas mit einer Komplexität von über 20 sollte in kleinere Module aufgeteilt werden. Ein Modul mit einer cycomatischen Komplexität von 20 (man könnte dies mit 20 aufeinanderfolgenden
if then else
Blöcken duplizieren ) hat eine Obergrenze von 2 ^ 20 zu testenden Pfaden.Die Klassenkopplung ist ein Maß dafür, wie eng die Klassen miteinander verbunden sind. Ein Beispiel für einen fehlerhaften Code, mit dem ich bei meinem vorherigen Arbeitgeber gearbeitet habe, ist eine "Datenschicht" -Komponente mit etwa 30 Elementen im Konstruktor. Die Person, die hauptsächlich für diese Komponente "verantwortlich" war, fügte den Konstruktor- / Open-Aufrufen weiterhin Geschäfts- und UI-Layer-Parameter hinzu, bis es ein wirklich großer Schlammball war. Wenn der Speicher richtig funktioniert, gab es ungefähr 15 verschiedene neue / offene Anrufe (einige werden nicht mehr verwendet), alle mit leicht unterschiedlichen Parametersätzen. Wir haben Codeüberprüfungen eingeführt, um ihn davon abzuhalten, mehr solche Dinge zu tun - und um zu vermeiden, dass es so aussieht, als würden wir ihn herausgreifen, haben wir den Code aller im Team überprüft, also haben wir ungefähr einen halben Tag für 4-6 verschwendet Menschen jeden Tag, weil wir nicht '
quelle
Unter dem Strich kann die Wartbarkeit wirklich nur nach Bedarf gemessen werden, nicht vorher . Das heißt, Sie können nur dann feststellen, ob ein Teil des Codes verwaltbar ist, wenn Sie ihn verwalten müssen.
Es ist relativ offensichtlich zu messen, wie einfach es war, einen Code an sich ändernde Anforderungen anzupassen. Es ist nahezu unmöglich, im Voraus zu messen, wie es auf veränderte Anforderungen reagieren wird. Dies würde bedeuten, dass Sie Änderungen der Anforderungen vorhersagen müssen. Und wenn du das schaffst, solltest du einen Nobelpreis bekommen;)
Das einzige, was Sie tun können, ist, sich mit Ihrem Team auf eine Reihe konkreter Regeln (wie SOLID-Prinzipien) zu einigen, von denen Sie alle glauben, dass sie die Wartbarkeit allgemein verbessern.
Wenn die Prinzipien gut gewählt sind (ich denke, mit SOLID zu beginnen, wäre eine gute Wahl), können Sie ganz klar nachweisen, dass sie verletzt werden, und die Autoren dafür zur Rechenschaft ziehen.
Sie werden es sehr schwer haben, zu versuchen, ein absolutes Maß für die Wartbarkeit zu fördern, und gleichzeitig Ihr Team schrittweise davon zu überzeugen, sich an einen festgelegten Satz realistischer Prinzipien zu halten.
quelle
Was ist mit technischen Schulden, die "von Ereignissen überholt" werden?
Ich schreibe beschissenen Code und stürze ihn in die Produktion.
Sie stellen - richtig - fest, dass es nicht wartbar ist.
Dieser Code ist jedoch die letzte Funktionsrunde für eine Produktlinie, die stillgelegt wird, weil sich der rechtliche Kontext geändert hat und die Produktlinie keine Zukunft hat.
Die "technische Verschuldung" wird durch eine Gesetzesänderung beseitigt, die alles überholt.
Die Metrik "Wartbarkeit" ist aufgrund äußerer Überlegungen von "schlecht" zu "irrelevant" übergegangen.
Wie kann das gemessen werden?
quelle
Das nächstbeste bei Peer-Code-Überprüfungen ist die Erstellung einer funktionsfähigen Architektur, bevor eine Einheit oder ein Produkt codiert wird. Rot-Grün-Refaktor ist ein ziemlich ordentlicher Weg, um es zu tun. Lassen Sie einen Senior eine funktionierende Schnittstelle zusammenstellen und die Arbeit aufteilen. Jeder kann sein Puzzlestück nehmen und seinen Weg zum Sieg rot-grün machen. Danach wäre ein Peer-Code-Review und -Refactor angebracht. Dies funktionierte verdammt gut bei einem früheren Hauptprodukt, an dem ich gearbeitet habe.
quelle
Fragebogen
Wie wäre es mit einem anonymen Fragebogen, den die Entwickler etwa einmal im Monat ausfüllen sollten? Die Fragen würden ungefähr so lauten:
(Fühlen Sie sich frei, zusätzliche Fragen hinzuzufügen, die Sie für nützlich halten, um die Wartbarkeit in den Kommentaren zu messen, und ich werde sie hinzufügen.)
quelle
Ich kann mir zwei Möglichkeiten vorstellen, um die Wartbarkeit zu beurteilen (ich bin mir sicher, dass es hoffentlich auch andere gibt, die gute Definitionen finden können).
Änderung ohne Verständnis.
Kann ein Bugfixer in den Code gelangen und ein Problem beheben, ohne dass er verstehen muss, wie das gesamte System funktioniert?
Dies kann durch umfassende Komponententests (Regressionstests) erreicht werden. Sie sollten in der Lage sein, zu überprüfen, ob Änderungen am System das Verhalten des Systems bei bestimmten guten Eingaben beeinflussen.
In dieser Situation sollte ein Bugfixer in der Lage sein, einen (einfachen) Bug mit nur minimalen Systemkenntnissen zu beheben. Wenn das Update funktioniert, sollte keiner der Regressionstests fehlschlagen. Wenn Regressionstests fehlschlagen, müssen Sie mit Stufe 2 fortfahren.
Änderung mit Verständnis.
Wenn eine Fehlerkorrektur nicht mehr einfach ist und Sie das System verstehen müssen. Wie sieht dann die Dokumentation des Systems aus? Wir sind nicht Dokumentation der externen API (sie sind relativ nutzlos). Wir müssen verstehen, wie das System funktioniert, wenn clevere (Lese-Hacks) Tricks in den Implementierungen usw. verwendet werden.
Die Dokumentation reicht jedoch nicht aus, der Code muss klar und verständlich sein. Um die Verständlichkeit eines Codes zu messen, können wir einen kleinen Trick anwenden. Geben Sie dem Entwickler einen Monat Zeit, um an etwas anderem zu arbeiten. Bitten Sie sie dann, zurückzukehren und das System so zu dokumentieren, dass ein Pier das System jetzt verstehen kann. Wenn der Code relativ einfach zu verstehen ist, sollte er schnell sein. Wenn es schlecht geschrieben ist, wird es eine längere Zeit dauern, bis die erstellten Informationen vorliegen und die Dokumentation erstellt wurde.
Vielleicht könnten wir uns ein Maß dafür einfallen lassen:
quelle
Ich stelle oft fest, dass die Lösung mit dem "kürzesten Äquivalent" am besten zu warten ist.
Das Kürzeste bedeutet hier die wenigsten Operationen (keine Linien). Und gleichwertig bedeutet, dass die kürzere Lösung keine schlechtere zeitliche oder räumliche Komplexität aufweisen sollte als die vorherige Lösung.
Dies bedeutet, dass alle logisch ähnlichen Wiederholungsmuster in die entsprechende Abstraktion extrahiert werden sollten: Ähnliche Codeblöcke? Extrahieren Sie es, um zu funktionieren. Variablen, die zusammen vorkommen? Extrahieren Sie sie in eine Struktur / Klasse. Klassen, deren Mitglieder sich nur nach Typ unterscheiden? Du brauchst ein Generikum. Sie scheinen an vielen Stellen dasselbe neu zu berechnen? Berechnen Sie am Anfang und speichern Sie den Wert in einer Variablen. Wenn Sie dies tun, wird der Code kürzer. Das ist im Grunde das DRY-Prinzip.
Wir können uns auch darauf einigen, dass nicht verwendete Abstraktionen gelöscht werden sollten: Klassen, Funktionen, die nicht mehr benötigt werden, sind toter Code und sollten daher entfernt werden. Die Versionskontrolle wird sich daran erinnern, ob wir sie jemals wiederherstellen müssen.
Was häufig diskutiert wird, sind Abstraktionen, auf die nur einmal verwiesen wird: Nicht-Rückruffunktionen, die nur einmal aufgerufen werden, ohne Grund, jemals mehr als einmal aufgerufen zu werden. Ein Generikum, das nur mit einem Typ instanziiert wird, und es gibt keinen Grund, warum es jemals mit einem anderen Typ instanziiert wird. Schnittstellen, die nur einmal implementiert werden, und es gibt keinen wirklichen Grund, warum sie jemals von einer anderen Klasse implementiert werden würden, und so weiter. Meiner Meinung nach sind diese Dinge unnötig und sollten entfernt werden, das ist im Grunde das YAGNI-Prinzip.
Es sollte also ein Tool geben, das Codewiederholungen erkennen kann, aber ich denke, dieses Problem ist vergleichbar mit dem Finden der optimalen Komprimierung. Dies ist das Problem der Kolmogorov-Komplexität, das nicht zu entscheiden ist. Auf der anderen Seite sind ungenutzte und unterbenutzte Abstraktionen anhand der Anzahl der Referenzen leicht zu erkennen: Eine Überprüfung kann automatisiert werden.
quelle
Es ist alles subjektiv und jede Messung, die auf dem Code selbst basiert, ist letztendlich irrelevant. Am Ende kommt es auf Ihre Fähigkeit an, Anforderungen zu erfüllen. Können Sie immer noch die Funktionen bereitstellen, die angefordert werden, und wenn Sie können, wie oft werden diese Änderungen auf Sie zurückkommen, weil noch etwas nicht stimmt, und wie ernst sind diese Probleme?
Ich habe gerade die Wartbarkeit (neu) definiert, aber sie ist immer noch subjektiv. Auf der anderen Seite ist das vielleicht nicht so wichtig. Wir müssen nur unseren Kunden zufrieden stellen und ihn genießen, das ist es, was wir anstreben.
Anscheinend müssen Sie Ihrem Chef oder Ihren Mitarbeitern beweisen, dass etwas getan werden muss, um den Zustand der Codebasis zu verbessern. Ich würde behaupten, es sollte ausreichen, dass Sie sagen, Sie seien frustriert darüber, dass Sie für jede Kleinigkeit, die Sie ändern oder hinzufügen müssen, 10 andere Probleme beheben oder umgehen müssen, die hätten vermieden werden können. Nennen Sie dann eine berüchtigte Gegend und stellen Sie sie auf den Kopf. Wenn das in Ihrem Team keine Unterstützung bringt, sind Sie vielleicht woanders besser dran. Wenn es die Leute in Ihrer Umgebung nicht interessieren, ändert der Beweis, dass Sie es tun, sowieso nichts an Ihrer Meinung.
quelle