So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt, ohne das Team zu demotivieren

So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt, ohne das Team zu demotivieren
Es ist einfach, einen statischen Code-Analysator auszuprobieren. Aber die Umsetzung, insbesondere bei der Entwicklung eines großen alten Projekts, erfordert Geschick. Bei falscher Vorgehensweise kann der Analysator zusätzliche Arbeit leisten, die Entwicklung verlangsamen und das Team demotivieren. Lassen Sie uns kurz darüber sprechen, wie Sie die Integration der statischen Analyse in den Entwicklungsprozess richtig angehen und sie als Teil von CI/CD verwenden können.

Einführung

Kürzlich wurde ich auf die Veröffentlichung aufmerksam gemacht „Erste Schritte mit statischer Analyse, ohne das Team zu überfordern". Einerseits ist dies ein guter Artikel, der es wert ist, gelesen zu werden. Andererseits scheint es mir, dass er immer noch keine vollständige Antwort darauf gibt, wie man statische Analysen in einem Projekt mit viel Aufwand problemlos implementieren kann von Legacy-Code. In dem Artikel heißt es, dass man technische Schulden akzeptieren und nur an neuem Code arbeiten kann, aber es gibt keine Antwort darauf, was man später mit diesen technischen Schulden machen soll.

Unser PVS-Studio-Team äußert sich zu diesem Thema. Schauen wir uns an, wie das Problem der Implementierung eines statischen Code-Analysators überhaupt entsteht, wie man dieses Problem überwindet und wie man technische Schulden schrittweise und schmerzlos beseitigt.

Probleme

Es ist normalerweise nicht schwierig, einen statischen Analysator zu starten und zu sehen, wie er funktioniert [1]. Möglicherweise entdecken Sie interessante Fehler oder sogar beängstigende potenzielle Schwachstellen im Code. Man kann sogar etwas reparieren, aber dann geben viele Programmierer auf.

Alle statischen Analysegeräte erzeugen falsch positive Ergebnisse. Dies ist ein Merkmal der statischen Code-Analysemethodik und es kann nichts dagegen unternommen werden. Im allgemeinen Fall ist dies ein unlösbares Problem, wie durch den Satz von Rice bestätigt wird [2]. Auch maschinelle Lernalgorithmen werden nicht helfen [3]. Auch wenn man nicht immer erkennen kann, ob dieser oder jener Code falsch ist, sollte man das vom Programm nicht erwarten :).

Fehlalarme stellen kein Problem dar, wenn der statische Analysator bereits konfiguriert ist:

  • Deaktivierte irrelevante Regelsätze;
  • Einige irrelevante Diagnosefunktionen wurden deaktiviert.
  • Wenn wir über C oder C++ sprechen, dann werden Makros markiert, die bestimmte Konstrukte enthalten, die dazu führen, dass an jeder Stelle, an der solche Makros verwendet werden, nutzlose Warnungen erscheinen;
  • Es werden eigene Funktionen markiert, die ähnliche Aktionen wie Systemfunktionen ausführen (ihr eigenes Analogon). memcpy oder printf) [4];
  • Falsch-positive Ergebnisse werden mithilfe von Kommentaren gezielt verhindert.
  • Und so weiter.

In diesem Fall können wir mit einer niedrigen Falsch-Positiv-Rate von etwa 10–15 % rechnen [5]. Mit anderen Worten: 9 von 10 Analysatorwarnungen deuten auf ein echtes Problem im Code oder zumindest auf „stark riechenden Code“ hin. Stimmen Sie zu, dieses Szenario ist äußerst angenehm und der Analysator ist ein echter Freund des Programmierers.

So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt, ohne das Team zu demotivieren
In der Realität sieht das Ausgangsbild bei einem Großprojekt völlig anders aus. Der Analysator gibt Hunderte oder Tausende von Warnungen für Legacy-Code aus. Es ist unmöglich, schnell zu verstehen, welche dieser Warnungen relevant sind und welche nicht. Es ist irrational, sich hinzusetzen und sich mit all diesen Warnungen auseinanderzusetzen, da die Hauptarbeit in diesem Fall für Tage oder Wochen ruhen wird. Normalerweise kann sich ein Team ein solches Szenario nicht leisten. Es wird auch eine große Anzahl von Unterschieden geben, die den Änderungsverlauf verderben. Und die schnelle Massenbearbeitung so vieler Fragmente im Code führt unweigerlich zu neuen Tippfehlern und Fehlern.

Und vor allem macht eine solche Leistung im Kampf gegen Abmahnungen wenig Sinn. Stimmen Sie zu, dass die meisten kritischen Fehler bereits behoben wurden, da das Projekt bereits seit vielen Jahren erfolgreich läuft. Ja, diese Korrekturen waren sehr teuer, mussten debuggt werden, erhielten negatives Benutzerfeedback zu Fehlern und so weiter. Ein statischer Analysator würde dabei helfen, viele dieser Fehler bereits in der Codierungsphase schnell und kostengünstig zu beheben. Aber im Moment sind diese Fehler auf die eine oder andere Weise behoben und der Analysator erkennt hauptsächlich unkritische Fehler im alten Code. Dieser Code darf nicht verwendet werden, er kann sehr selten verwendet werden und ein Fehler darin darf keine spürbaren Folgen haben. Vielleicht hat der Schatten des Knopfes irgendwo die falsche Farbe, aber das beeinträchtigt nicht die Verwendung des Produkts durch irgendjemanden.

Natürlich sind auch kleine Fehler immer noch Fehler. Und manchmal kann ein Fehler eine echte Schwachstelle verbergen. Allerdings scheint es eine zweifelhafte Idee zu sein, alles aufzugeben und Tage/Wochen damit zu verbringen, sich mit Mängeln zu befassen, die sich kaum bemerkbar machen.

Programmierer schauen, schauen, schauen sich all diese Warnungen über den alten Arbeitscode an ... Und sie denken: Auf statische Analyse können wir verzichten. Lassen Sie uns einige neue nützliche Funktionen schreiben.

Auf ihre Art haben sie Recht. Sie gehen davon aus, dass sie zunächst einmal all diese Warnungen irgendwie loswerden müssen. Nur dann können sie von der regelmäßigen Nutzung des Code-Analysators profitieren. Andernfalls werden neue Warnungen einfach in alten untergehen und niemand wird sie beachten.

Dies ist die gleiche Analogie wie bei Compiler-Warnungen. Nicht umsonst empfehlen sie, die Anzahl der Compiler-Warnungen auf 0 zu belassen. Wenn es 1000 Warnungen gibt, dann achtet man bei 1001 niemanden darauf, und es ist nicht klar, wo man nach dieser neuesten Warnung suchen soll.

So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt, ohne das Team zu demotivieren
Das Schlimmste an dieser Geschichte ist, wenn jemand von oben Sie in diesem Moment dazu zwingt, eine statische Code-Analyse zu verwenden. Dies wird das Team nur demotivieren, da aus ihrer Sicht zusätzlicher bürokratischer Aufwand entsteht, der nur im Weg steht. Niemand wird sich die Berichte des Analysators ansehen und jede Verwendung erfolgt nur „auf dem Papier“. Diese. Formal ist die Analyse in den DevOps-Prozess integriert, aber in der Praxis nützt dies niemandem. An den Ständen hörten wir ausführliche Geschichten von Konferenzteilnehmern. Eine solche Erfahrung kann Programmierer für lange Zeit, wenn nicht für immer, davon abhalten, statische Analysetools zu verwenden.

Implementierung und Beseitigung technischer Schulden

Tatsächlich ist die Einführung einer statischen Analyse selbst in einem großen alten Projekt weder schwierig noch beängstigend.

CI / CD

Darüber hinaus kann der Analysator sofort in den kontinuierlichen Entwicklungsprozess eingebunden werden. Die PVS-Studio-Distribution enthält beispielsweise Dienstprogramme zum bequemen Anzeigen des Berichts im gewünschten Format sowie Benachrichtigungen an Entwickler, die problematische Codeabschnitte geschrieben haben. Für diejenigen, die mehr daran interessiert sind, PVS-Studio von CI/CD-Systemen aus zu starten, empfehle ich, sich mit den entsprechenden Informationen vertraut zu machen Abschnitt Dokumentation und eine Artikelserie:

Aber kehren wir zum Problem der großen Anzahl falsch positiver Ergebnisse in den ersten Phasen der Implementierung von Code-Analysetools zurück.

Behebung bestehender technischer Schulden und Umgang mit neuen Warnungen

Mit modernen kommerziellen statischen Analysegeräten können Sie nur neue Warnungen untersuchen, die in neuem oder geändertem Code erscheinen. Die Implementierung dieses Mechanismus variiert, aber das Wesentliche ist dasselbe. Im statischen Analysator PVS-Studio wird diese Funktionalität wie folgt implementiert.

Um schnell mit der statischen Analyse beginnen zu können, empfehlen wir PVS-Studio-Benutzern, den Mechanismus zur Massenunterdrückung von Warnungen zu verwenden [6]. Die allgemeine Idee ist die folgende. Der Benutzer startete den Analysator und erhielt zahlreiche Warnungen. Da ein Projekt, das sich seit vielen Jahren in der Entwicklung befindet, noch am Leben ist, sich entwickelt und Geld verdient, wird der Bericht höchstwahrscheinlich nicht viele Warnungen enthalten, die auf kritische Mängel hinweisen. Mit anderen Worten: Kritische Fehler wurden bereits auf die eine oder andere Weise mit teureren Methoden oder dank des Feedbacks von Kunden behoben. Dementsprechend kann alles, was der Analysator derzeit findet, als technischer Fehler betrachtet werden, der nicht sofort beseitigt werden kann.

Sie können PVS-Studio anweisen, diese Warnungen vorerst als irrelevant zu betrachten (technische Schulden für später aufheben) und sie dann nicht mehr anzuzeigen. Der Analysator erstellt eine spezielle Datei, in der er Informationen über Fehler speichert, die noch nicht von Interesse sind. Und jetzt gibt PVS-Studio Warnungen nur für neuen oder geänderten Code aus. Darüber hinaus ist das alles geschickt umgesetzt. Wenn beispielsweise am Anfang der Quellcodedatei eine leere Zeile hinzugefügt wird, erkennt der Analysator, dass sich tatsächlich nichts geändert hat, und schweigt weiterhin. Diese Markup-Datei kann in ein Versionskontrollsystem eingefügt werden. Die Datei ist groß, aber das ist kein Problem, da es keinen Sinn macht, sie oft zu speichern.

Jetzt sehen alle Programmierer Warnungen, die sich nur auf neuen oder geänderten Code beziehen. So können Sie den Analysator, wie es so schön heißt, schon am nächsten Tag nutzen. Und Sie können später zu den technischen Schulden zurückkehren und nach und nach Fehler korrigieren und den Analysator konfigurieren.

Damit wurde das erste Problem bei der Implementierung des Analysators in einem großen alten Projekt gelöst. Lassen Sie uns nun herausfinden, was mit technischen Schulden zu tun ist.

Fehlerbehebungen und Refactorings

Am einfachsten und natürlichsten ist es, sich etwas Zeit zu nehmen, um massiv unterdrückte Analysatorwarnungen zu analysieren und sich schrittweise mit ihnen auseinanderzusetzen. Irgendwo sollten Sie Fehler im Code beheben, irgendwo sollten Sie eine Umgestaltung vornehmen, um dem Analysator mitzuteilen, dass der Code unproblematisch ist. Einfaches Beispiel:

if (a = b)

Die meisten C++-Compiler und -Analysatoren beschweren sich über solchen Code, da die Wahrscheinlichkeit hoch ist, dass sie tatsächlich schreiben wollten (a == b). Es besteht jedoch eine unausgesprochene Vereinbarung, und dies wird normalerweise in der Dokumentation vermerkt: Wenn zusätzliche Klammern vorhanden sind, wird davon ausgegangen, dass der Programmierer diesen Code absichtlich geschrieben hat, und es besteht kein Grund zu schwören. Beispielsweise in der PVS-Studio-Dokumentation zur Diagnose V559 (CWE-481) Es steht klar geschrieben, dass die folgende Zeile als korrekt und sicher angesehen wird:

if ((a = b))

Ein anderes Beispiel. Ist es in diesem C++-Code vergessen? brechen oder nicht?

case A:
  foo();
case B:
  bar();
  break;

Der PVS-Studio-Analysator gibt hier eine Warnung aus V796 (CWE-484). Dabei handelt es sich möglicherweise nicht um einen Fehler. In diesem Fall sollten Sie dem Parser durch Hinzufügen des Attributs einen Hinweis geben [[durchfallen]] oder zum Beispiel __attribute__((fallthrough)):

case A:
  foo();
  [[fallthrough]];
case B:
  bar();
  break;

Man kann sagen, dass solche Codeänderungen den Fehler nicht beheben. Ja, das stimmt, aber es bewirkt zwei nützliche Dinge. Erstens beseitigt der Analysebericht Fehlalarme. Zweitens wird der Code für die an seiner Wartung beteiligten Personen verständlicher. Und das ist sehr wichtig! Allein dafür lohnt es sich, kleinere Refactorings durchzuführen, um den Code übersichtlicher und wartbarer zu machen. Da der Analysator nicht versteht, ob eine „Pause“ erforderlich ist oder nicht, ist dies auch für andere Programmierer unklar.

Neben Bugfixes und Refactorings können Sie gezielt offensichtlich falsche Analysator-Warnungen unterdrücken. Einige irrelevante Diagnosefunktionen können deaktiviert werden. Jemand hält beispielsweise Warnungen für sinnlos V550 über den Vergleich von Float-/Double-Werten. Und einige stufen sie als wichtig und studienwürdig ein [7]. Welche Warnungen als relevant gelten und welche nicht, liegt im Ermessen des Entwicklungsteams.

Es gibt andere Möglichkeiten, Fehlalarme zu unterdrücken. Makro-Markup wurde beispielsweise bereits erwähnt. All dies wird in der Dokumentation ausführlicher beschrieben. Das Wichtigste ist, zu verstehen, dass daran nichts auszusetzen ist, wenn man schrittweise und systematisch an die Arbeit mit Fehlalarmen herangeht. Die überwiegende Mehrheit der uninteressanten Warnungen verschwindet nach der Konfiguration und es bleiben nur Stellen übrig, die wirklich einer sorgfältigen Untersuchung und einigen Änderungen im Code bedürfen.

Außerdem helfen wir unseren Kunden immer bei der Einrichtung von PVS-Studio, wenn Schwierigkeiten auftreten. Darüber hinaus gab es Fälle, in denen wir selbst falsche Warnungen beseitigt und Fehler korrigiert haben [8]. Für alle Fälle möchte ich erwähnen, dass diese Option einer erweiterten Zusammenarbeit auch möglich ist :).

Ratschenmethode

Es gibt einen weiteren interessanten Ansatz zur schrittweisen Verbesserung der Codequalität durch Eliminierung der Warnung des statischen Analysators. Unterm Strich kann die Zahl der Warnungen nur sinken.

So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt, ohne das Team zu demotivieren

Die Anzahl der vom statischen Analysator ausgegebenen Warnungen wird aufgezeichnet. Quality Gate ist so konfiguriert, dass Sie jetzt nur einen Code eingeben können, der die Anzahl der Vorgänge nicht erhöht. Daher beginnt der Prozess der schrittweisen Reduzierung der Alarmanzahl mit der Anpassung des Analysators und der Korrektur von Fehlern.

Selbst wenn jemand ein wenig schummeln möchte und beschließt, das Qualitätstor nicht durch die Beseitigung von Warnungen in seinem neuen Code, sondern durch die Verbesserung des alten Codes von Drittanbietern zu überwinden, ist dies nicht beängstigend. Trotzdem dreht sich die Ratsche in eine Richtung und die Anzahl der Defekte nimmt allmählich ab. Auch wenn jemand seine neuen Fehler nicht selbst beheben möchte, muss er dennoch etwas im benachbarten Code verbessern. Irgendwann gibt es keine einfachen Möglichkeiten mehr, die Anzahl der Warnungen zu reduzieren, und irgendwann werden echte Fehler behoben.

Diese Methodik wird in einem sehr interessanten Artikel von Ivan Ponomarev ausführlicher beschrieben.Implementieren Sie statische Analysen in den Prozess, anstatt sie zum Auffinden von Fehlern zu verwenden", dessen Lektüre ich jedem empfehle, der an der Verbesserung der Codequalität interessiert ist.

Der Autor des Artikels hat auch einen Bericht zu diesem Thema: „Kontinuierliche statische Analyse".

Abschluss

Ich hoffe, dass die Leser nach diesem Artikel eine größere Akzeptanz für statische Analysetools entwickeln und diese in den Entwicklungsprozess integrieren möchten. Bei Fragen stehen wir Ihnen jederzeit zur Verfügung konsultieren Benutzer unseres statischen Analysators PVS-Studio und helfen bei der Implementierung.

Es gibt weitere typische Zweifel daran, ob statische Analysen wirklich praktisch und nützlich sein können. Ich habe versucht, die meisten dieser Zweifel in der Veröffentlichung „Gründe für die Einführung des statischen Code-Analysators PVS-Studio in den Entwicklungsprozess“ auszuräumen.9].

Vielen Dank für Ihre Aufmerksamkeit und kommen Sie скачать und probieren Sie den PVS-Studio-Analysator aus.

Zusätzliche Links

  1. Andrej Karpow. Wie kann ich schnell interessante Warnungen sehen, die der PVS-Studio-Analysator für C- und C++-Code erzeugt?
  2. Wikipedia. Satz von Rice.
  3. Andrey Karpov, Victoria Khanieva. Verwendung von maschinellem Lernen bei der statischen Analyse des Programmquellcodes.
  4. PVS-Studio. Dokumentation. Zusätzliche Diagnoseeinstellungen.
  5. Andrej Karpow. Eigenschaften des PVS-Studio-Analysators am Beispiel der EFL-Kernbibliotheken, 10-15 % falsch positive Ergebnisse.
  6. PVS-Studio. Dokumentation. Massenunterdrückung von Analysatormeldungen.
  7. Iwan Andrjaschin. Darüber, wie wir die statische Analyse in unserem Projekt eines pädagogischen Simulators für endovaskuläre Röntgenchirurgie getestet haben.
  8. Pavel Eremeev, Svyatoslav Razmyslov. Wie das PVS-Studio-Team den Unreal Engine-Code verbessert hat.
  9. Andrej Karpow. Gründe, den statischen Code-Analysator PVS-Studio in den Entwicklungsprozess einzuführen.

So implementieren Sie einen statischen Code-Analysator in einem Legacy-Projekt, ohne das Team zu demotivieren

Wenn Sie diesen Artikel mit einem englischsprachigen Publikum teilen möchten, verwenden Sie bitte den Übersetzungslink: Andrey Karpov. Wie man einen statischen Code-Analysator in ein Legacy-Projekt einführt und das Team nicht entmutigt.

Source: habr.com

Kommentar hinzufügen