Textsuche vs. Codeverständnis

Warum Textsuche nicht dasselbe ist wie Codeverständnis

Ein Entwickler öffnet zum ersten Mal eine große, ältere Codebasis. Er muss verstehen, was mit einem Kundendatensatz passiert, wenn ein Konto geschlossen wird: welche Programme ihn aktualisieren, welche Batch-Jobs ihn anschließend lesen, welche Felder dabei geändert werden und ob nachgelagerte Systeme vom Endzustand abhängen. Der erste Schritt ist natürlich die Suche. Er sucht mit grep nach dem Feldnamen, überfliegt die Ergebnisse, öffnet einige Dateien und beginnt zu lesen. Innerhalb einer Stunde findet er Verweise in zwölf Programmen, drei SQL-Skripten und einem JCL-Jobstream. Außerdem findet er denselben Feldnamen in siebzehn Kommentarblöcken, vier Log-Formatierungszeichenfolgen, zwei Testdateien und einer Variable in einem völlig unabhängigen Subsystem, die zufällig denselben Namen trägt. Allein anhand der Suchergebnisse kann er nicht erkennen, welche dieser Einträge tatsächliche Lese-, Schreib- oder Transformationsvorgänge sind und welche lediglich zufällige Namenskonflikte darstellen. Er kennt den Namen des Feldes. Er versteht aber noch nicht, was der Code damit macht.

Das Verständnis von Code beginnt hier

SMART TS XL Erstellt ein Strukturmodell Ihrer gesamten Codebasis und bildet Abhängigkeiten über alle Sprachen und Plattformen hinweg ab.

Mehr Info

Diese Kluft zwischen dem Auffinden einer Zeichenkette und dem Verstehen von Code lässt sich nicht durch eine verbesserte Suche schließen. Es handelt sich vielmehr um eine Kluft zwischen zwei grundlegend verschiedenen Arten von Anfragen: der Frage „Wo erscheint dieser Text?“ und der Frage „Was bewirkt dieser Code?“. Die Textsuche liefert eine hervorragende Antwort auf die erste Frage. Auf die zweite Frage ist sie jedoch völlig ungeeignet, und die Vermischung beider Fragetypen ist eine der häufigsten Ursachen für verschwendete Mühe, übersehene Abhängigkeiten und fehlerhafte Folgenabschätzungen in der Softwareentwicklung. Diese Unterscheidung ist in großen, heterogenen Unternehmenssystemen von größerer Bedeutung als in kleinen, modernen Codebasen, da diese Systeme über Jahrzehnte gewachsene Strukturen, sprachübergreifende Abhängigkeiten und implizite Beziehungen enthalten, die ausschließlich im Verhalten des Codes existieren, nicht aber in einzelnen Zeichenketten seiner Quelldateien. Wie die Analyse von … zeigt, … Codequalitätsmetriken und ihre AuswirkungenDie Komplexität einer Codebasis hat einen erheblichen Einfluss auf die Wartbarkeit, und keine Metrik, die allein auf Textmustern basiert, erfasst die strukturellen Beziehungen, die das tatsächliche Verhalten des Codes bestimmen.

Was die Textsuche tatsächlich leistet

Die Textsuche ist eine Teilzeichenfolgen-Suche, die auf Dateien angewendet wird, welche als reine Zeichenketten behandelt werden. Die Suchanfrage ist eine Zeichenkette oder ein Muster. Das Ergebnis ist eine Liste der Stellen, an denen dieses Muster vorkommt. Das Tool kennt weder die Programmiersprache der Dateien noch die Grammatik, die dem Text seine Struktur verleiht, und hat kein Modell der Beziehungen zwischen den Codeelementen, die der Text repräsentiert. Ein grep-Befehl, der eine Million Zeilen COBOL-Quellcode durchsucht, arbeitet nach demselben Modell wie ein grep-Befehl, der eine Million Zeilen HTML durchsucht: Zeichenketten in Dateien, gruppiert nach Dateipfad, werden zurückgegeben, wenn die Zeichenkette übereinstimmt.

Dies ist für eine bestimmte Aufgabenkategorie äußerst nützlich: das Auffinden einer bekannten Zeichenkette, die Bestätigung, ob ein bestimmter Begriff verwendet wird oder nicht, die schnelle Überprüfung von Namenskonventionen und das Auffinden der Datei mit einer bestimmten Fehlermeldung. Für diese Aufgaben ist die Textsuche das richtige Werkzeug, da es hier tatsächlich um das Auffinden von Zeichenketten geht. Die Geschwindigkeit, die Portabilität und die einfache Konfiguration von grep und seinen Äquivalenten sind ideale Eigenschaften, wenn die Frage lautet: „Existiert diese Zeichenkette in diesen Dateien, und wenn ja, wo?“

Das Problem tritt auf, wenn die Textsuche für Fragen verwendet wird, die sich nicht auf Zeichenketten beziehen. „Was ruft diese Funktion auf?“ ist keine Frage nach dem Vorkommen des Funktionsnamens. Es ist eine Frage nach dem Aufrufgraphen, einer strukturellen Eigenschaft des Codes, deren Erstellung Parsing und semantische Analyse erfordert. „Wo ist dieses Feld definiert?“ ist keine Frage nach dem Vorkommen des Feldnamens. Es ist eine Frage nach dem Datenfluss, deren Beantwortung das Verständnis der Zuweisungssemantik der jeweiligen Programmiersprache voraussetzt. „Was wird kaputtgehen, wenn ich diese Schnittstelle ändere?“ ist keine Frage nach dem Vorkommen des Schnittstellennamens. Es ist eine Frage nach Abhängigkeitsbeziehungen, deren korrekte Beantwortung die Auflösung von Importen, Vererbung und Modulkopplung erfordert.

Jede dieser Fragen verwendet einen Namen als Ausgangspunkt, was die Versuchung birgt, sie als Suchaufgaben zu behandeln. Doch der Name ist lediglich der Einstiegspunkt. Die Antwort findet sich im Strukturmodell des Codes, nicht im Text der Quelldateien.

Das Rauschproblem: Zu viele Ergebnisse, die nichts bedeuten

Der erste Fehler, der bei der Textsuche im Zusammenhang mit Code-Verständnisaufgaben auftritt, ist die Überproduktion: Es werden weit mehr Ergebnisse zurückgegeben als relevant sind, ohne dass ein Mechanismus vorhanden ist, um zu erkennen, welche Ergebnisse strukturell signifikant und welche zufällig sind.

Eine kurze Kennung wie status, id, typeden date können in einer großen Codebasis tausendfach vorkommen. Noch längere Bezeichner kollidieren über verschiedene Sprachen und Namensräume hinweg: calculate_tax Als Funktionsname in einem Python-Modul, als COBOL-Absatzname, als gespeicherte Datenbankprozedur, als JavaScript-Hilfsfunktion und als Zeichenkette in einer Protokollierungskonfiguration liefern alle übereinstimmende Textsuchergebnisse. Der Entwickler, der diese Ergebnisse erhält, muss sie manuell filtern und sein eigenes Codeverständnis anwenden, um die relevanten Vorkommen zu ermitteln. Diese manuelle Filterung erfordert selbst Codeverständnis, was bedeutet, dass der Entwickler die Arbeit erledigt, die eigentlich das Tool leisten sollte – und zwar ohne dessen Unterstützung.

In der Praxis filtern Entwickler intuitiv und aufgrund ihrer Erfahrung. Sie erkennen, dass ein Ergebnis in einer Testdatei wahrscheinlich nicht von einem Aufruf in der Produktionsumgebung stammt. Sie wissen, dass ein Ergebnis innerhalb eines Kommentarblocks zur Dokumentation gehört und kein Aufruf ist. Ergebnisse in Dateien, die sie für irrelevant halten, ignorieren sie. Diese Filter sind jedoch fehlerhaft und nicht überprüfbar. Ein Entwickler, der sich auf sein Filtervermögen verlässt, kann falsch liegen. Ein Entwickler, der vorsichtig filtert, kann Stunden damit verbringen. Und in beiden Fällen ist das Ergebnis eine Reihe von Erkenntnissen, die das Urteilsvermögen des Entwicklers widerspiegeln, nicht aber eine verifizierte Strukturanalyse des Codes.

Betrachten wir ein konkretes Beispiel. Ein COBOL-Entwickler sucht nach einem Absatznamen, bevor er ihn entfernt:

Cobol

SEARCH-RESULTS FOR "CALC-INTEREST":

1. CALC-INTEREST.PGM        line   5  : IDENTIFICATION DIVISION.
2. CALC-INTEREST.PGM        line  42  : CALC-INTEREST.
3. FINPROCESS.CBL            line 178  : PERFORM CALC-INTEREST
4. RPTMONTH.CBL              line  91  : * Old routine: CALC-INTEREST replaced by CALC-INT-V2
5. CUSTBATCH.CBL             line 234  : PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT
6. DATADICT.txt              line  12  : CALC-INTEREST - computes monthly interest for savings accts
7. TESTHARNESS.CBL           line  67  : PERFORM CALC-INTEREST
8. ARCHIVEJOB.CBL            line 156  : * PERFORM CALC-INTEREST (disabled 2019-03-14)

Von diesen acht Ergebnissen sind genau zwei aktive Aufrufer, die bei Entfernung des Absatzes nicht mehr funktionieren würden: Zeile 3 und 5. Zeile 2 enthält die Definition. Zeile 4 und 8 sind Kommentare. Zeile 6 ist ein Eintrag im Datenwörterbuch. Zeile 7 ist ein Testframework. Um herauszufinden, welche zwei dieser acht Ergebnisse aktive Aufrufstellen darstellen, muss man jede Datei im Kontext lesen, die COBOL-Syntax verstehen und beurteilen, was „deaktiviert“ in einem Kommentar in Zeile 8 für die Ausführung bedeutet. Die Textsuche lieferte das Rohmaterial. Das Verständnis des Codes lieferte die Antwort.

Das Problem der Stille: Relevante Ergebnisse, die nie zurückgegeben werden

Der zweite Fehlermodus ist die Unterproduktion: Es fehlen Ergebnisse, die strukturell bedeutsam sind, weil sie nicht in einer Form ausgedrückt werden, die die Textsuche erfassen kann.

Indirekte Aufrufe sind die häufigste Ursache für fehlende Ergebnisse. Wenn Funktion A Funktion B aufruft und Funktion B wiederum die veraltete Funktion C aufruft, findet eine Textsuche nach dem Namen von C zwar Funktion B als direkten Aufrufer, aber nicht Funktion A als indirekten Aufrufer. Ob A ein relevantes Ergebnis ist, hängt vom Zweck der Suche ab: Soll alles verstanden werden, was C auslöst, ist A entscheidend. Geht es hingegen nur darum, die direkten Aufrufer zu finden, ist A irrelevant. Die Textsuche kann diese Unterscheidung nicht treffen, da sie kein Konzept eines Aufrufgraphen kennt. Sie gibt einfach den gesamten übereinstimmenden Text zurück, ohne zu wissen, wozu dieser Text gehört.

Sprachübergreifende Referenzen stellen eine systematisch fehlende Kategorie dar. Ein Java-Dienst, der ein COBOL-Programm über eine Middleware-Schicht namentlich aufruft, enthält den Programmnamen als String-Literal, das von der Textsuche gefunden werden kann. Derselbe Java-Dienst hingegen, der den Programmnamen dynamisch generiert, aus einer Konfigurationsdatei liest oder über eine Abstraktionsschicht aufruft, enthält den Namen überhaupt nicht. Diese Aufrufer können von der Textsuche unabhängig von deren Gründlichkeit nicht gefunden werden. Wie im Kontext von … untersucht wurde … Statische Analyse von verschleiertem und dynamisch generiertem CodeWenn Ausführungspfade indirekt über Konfigurationen, Vorlagen oder Laufzeit-Dispatch-Mechanismen ausgedrückt werden, können die von ihnen repräsentierten strukturellen Beziehungen nicht allein aus dem Text der Quelldateien wiederhergestellt werden.

Feldaliase und Transformationen erzeugen eine weitere Kategorie stiller Fehler. Ein COBOL-Feld namens WS-ACCT-BAL Das wird in eine Datenbankspalte mit dem Namen geschrieben. ACCT_BALANCE, das anschließend von einem Java-Dienst gelesen wird als accountBalanceund wurde schließlich in Fortsetzungen veröffentlicht als account_balance In einer JSON-Antwort repräsentiert jeder einzelne Textstring dasselbe Datenelement. Die Suche nach einem dieser Strings erfasst nicht die anderen drei. Um zu verstehen, dass alle vier Strings dasselbe zugrunde liegende Geschäftskonzept bezeichnen, ist es notwendig, die Transformationskette zu kennen und nicht alle Vorkommen eines einzelnen Namens zu finden.

Was Codeverständnis tatsächlich erfordert

Codeverständnis als technische Fähigkeit bezeichnet die Beherrschung von Code, indem man dessen Struktur und Semantik anstatt des reinen Textes analysiert. Es erfordert den Aufbau und die Abfrage eines Codemodells, das die Bedeutung des Codes repräsentiert, nicht nur dessen Inhalt.

Die Mindestanforderungen an das technische Codeverständnis, die für die Unterstützung von Entwicklungsaufgaben in großen Unternehmenssystemen erforderlich sind, sind beträchtlich. Jede dieser Anforderungen stellt eine Fähigkeit dar, die die Textsuche nicht bietet und die sich durch keine Kombination aus Textsuche und manuellem Aufwand in großem Umfang zuverlässig nachbilden lässt.

Parsing: Vom Text zur Struktur

Der erste Schritt nach der Textsuche ist das Parsen: das Lesen des Quellcodes gemäß der Grammatik seiner Sprache und das Erzeugen einer strukturierten Repräsentation, typischerweise eines abstrakten Syntaxbaums, der die syntaktischen Beziehungen zwischen den Codeelementen kodiert. Eine geparste Repräsentation von PERFORM CALC-INTEREST THRU CALC-INTEREST-EXIT ist keine Zeichenkette; es ist ein strukturiertes Objekt, das dies als PERFORM-Anweisung mit einem Bereichsziel identifiziert, wobei beide Endpunkte Absatznamen im aktuellen Programm sind, die gegen die PROCEDURE DIVISION-Struktur des Programms aufgelöst werden können.

Das Parsen ist sprachspezifisch. Ein COBOL-Parser versteht die COBOL-Grammatik. Ein Java-Parser versteht die Java-Grammatik. Ein JCL-Parser versteht die JCL-Syntax. In einem mehrsprachigen Unternehmenssystem benötigt das Codeverständnis für jede vorhandene Sprache einen Parser, der strukturelle Repräsentationen erzeugt, die sprachübergreifend konsistent analysiert werden können. Wie in der detaillierten Untersuchung von Statische TypeScript-Analyse im UnternehmensmaßstabDie strukturelle und semantische Analyse, die versteht, wie Code organisiert ist, wie Module interagieren und wie Kontrolle und Daten durch eine Anwendung fließen, ist die Grundlage dafür, über die Syntaxprüfung hinauszugehen und echte Codeintelligenz zu erlangen.

Symbolauflösung: Von Namen zu Entitäten

Nach dem Parsen müssen Namen im Quellcode in die Entitäten aufgelöst werden, auf die sie sich beziehen. Der Bezeichner CALC-INTEREST in einer PERFORM-Anweisung muss die Definition im jeweiligen Absatz eines bestimmten Programms oder Copybooks aufgelöst werden. Der Methodenname calculateLegacyFee Bei einem Java-Aufruf muss die spezifische Methodendefinition in der jeweiligen Klasse unter Berücksichtigung von Vererbung und Überladung aufgelöst werden. Der Spaltenname ACCT_BALANCE in einer SQL-Abfrage muss die Variable auf die spezifische Spalte in der spezifischen Tabelle im Datenbankschema aufgelöst werden.

Die Symbolauflösung wandelt einen Namen von einer Zeichenkette in eine Referenz auf eine spezifische, identifizierbare Codeeinheit mit Speicherort, Typ und Beziehungen zu anderen Einheiten um. Ohne Symbolauflösung sind alle Codeabfragen Textabfragen. Mit Symbolauflösung ist eine Abfrage nach „allen Aufrufern dieser Funktion“ eine Strukturabfrage gegen einen aufgelösten Graphen von Aufrufbeziehungen. Sie liefert nur die Ergebnisse, die tatsächlich Aufrufe der spezifischen Funktion darstellen, und nicht alle Dateien, in denen der Funktionsname zufällig vorkommt.

Die Symbolauflösung wird in mehrsprachigen Umgebungen deutlich komplexer, da dasselbe Konzept in verschiedenen Sprachen unterschiedlich benannt wird. Die sprachübergreifende Auflösung von Feldäquivalenzen wird im breiteren Kontext von … untersucht. Reduzierung der mittleren Wiederherstellungszeit durch sprachübergreifende IndexierungSie ist eine Voraussetzung für jede Strukturanalyse, die Daten- oder Kontrollflüsse über eine Sprachgrenze hinweg verfolgt. Ohne sie endet die Analyse an der Grenze, und das gewonnene Verständnis ist unvollständig.

Kontrollflussanalyse: Ausführungspfade verstehen

Die Kontrollflussanalyse bildet die möglichen Ausführungspfade eines Programms ab: welche Verzweigungen unter welchen Bedingungen ausgeführt werden, welche Anweisungen erreichbar sind, welche Codepfade nicht ausgeführt werden und in welcher Reihenfolge Anweisungen zueinander ausgeführt werden. Diese Informationen werden als Kontrollflussgraph dargestellt, wobei die Knoten grundlegende Blöcke sequenziellen Codes und die Kanten bedingte oder unbedingte Kontrollübergaben repräsentieren.

Die Kontrollflussanalyse ermöglicht es, Fragen wie „Unter welchen Bedingungen wird dieser Codepfad ausgeführt?“ und „Ist dieser Code von jedem Einstiegspunkt aus erreichbar?“ zu beantworten. Die Textsuche kann diese Fragen nicht beantworten, da sie sich auf Ausführungspfade beziehen und nicht auf das Vorkommen von Zeichenketten. Eine Anweisung im Quellcode kann ausgeführt werden oder nicht, abhängig von den Bedingungen des Zweigs, in dem sie sich befindet. Eine in einem Modul definierte Funktion kann aufgerufen werden oder nicht, je nachdem, ob ein Ausführungspfad eine Aufrufstelle erreicht. Nur die Kontrollflussanalyse kann diese Eigenschaften bestimmen. Wie die Untersuchung von … zeigt, … Priorisierung von Problemen mit statischem Code während der ModernisierungDas Verständnis dafür, welche Codepfade tatsächlich ausgeführt werden, wie häufig sie ausgeführt werden und unter welchen Bedingungen sie aktiviert werden, unterscheidet eine umsetzbare Analyse von Erkenntnissen, die zwar signifikant erscheinen, aber nicht die operative Realität widerspiegeln.

Datenflussanalyse: Werte durch den Code verfolgen

Die Datenflussanalyse verfolgt, wie Werte durch ein Programm fließen: wo einer Variablen ein Wert zugewiesen wird, wo ihr Wert gelesen wird, welche Transformationen zwischen Zuweisung und Verwendung angewendet werden und ob der Wert einer Variablen vom Wert einer anderen abhängt. Diese Informationen beantworten Fragen wie „Woher kommt der Wert dieses Feldes?“ und „Welcher Code ist betroffen, wenn sich der Wert dieses Feldes ändert?“

Die Datenflussanalyse bildet die technische Grundlage für Feldverfolgung, Datenfehleranalyse und Abhängigkeitsnachverfolgung auf Wertebene. Sie arbeitet mit dem Kontrollflussdiagramm des Programms, indem sie Wertinformationen entlang der Ausführungspfade weiterleitet und erfasst, wo Werte entstehen, wohin sie fließen und wo sie verbraucht werden. Das Ergebnis ist ein Datenflussdiagramm, das Definitionen mit Verwendungen im gesamten Ausführungsbereich des Programms verbindet, nicht nur innerhalb des sequenziellen Textes der Quelldatei.

In Unternehmenssystemen muss die Datenflussanalyse Sprachgrenzen überschreiten, um sinnvoll zu sein. Ein Wert, der in einem COBOL-Programm entsteht, einen Datenbankeintrag durchläuft und anschließend von einem Java-Dienst gelesen wird, weist einen Datenfluss auf, der zwei Sprachgrenzen überschreitet. Die Nachverfolgung dieses Flusses erfordert eine Datenflussanalyse, die die COBOL-Zuweisungssemantik, die SQL-Datenbewegung und die Java-Variablenzuweisung als Teil derselben einheitlichen Analyse versteht und nicht als drei separate Analysen, deren Ergebnisse manuell verknüpft werden müssen. Wie in der Analyse von Wissenstransfer von COBOL-Experten zu modernen EntwicklungsteamsDie Fähigkeit, komplexe COBOL-Systeme für moderne Entwickler verständlich zu machen, ohne dass diese die Sprache beherrschen müssen, hängt von einer Strukturanalyse ab, die das Verhalten des Systems in einer Form darstellen kann, die über den Quelltext hinausgeht.

Die Aufgaben, bei denen der Unterschied am wichtigsten ist

Die Unterscheidung zwischen Textsuche und Codeverständnis ist nicht akademischer Natur. Sie zeigt sich in konkreten, kritischen Entwicklungsaufgaben, bei denen das falsche Werkzeug zwar vollständig erscheinen lässt, es aber nicht ist, und bei denen das Handeln auf der Grundlage unvollständiger Ergebnisse messbare Konsequenzen hat.

Folgenabschätzung vor der Änderung

Bevor ein Entwickler die Signatur einer Funktion ändert, ein Feld umbenennt oder das Verhalten einer gemeinsam genutzten Hilfsfunktion anpasst, muss er wissen, welche Auswirkungen dies hat. Dies nennt man Folgenabschätzung: Dabei werden alle Komponenten aufgelistet, die von dem zu ändernden Element abhängen, sodass die Änderung sicher durchgeführt und alle betroffenen Komponenten aktualisiert werden können. Die Folgenabschätzung ist eine Aufgabe des Codeverständnisses. Sie erfordert das Auflösen der Abhängigkeitsbeziehungen zwischen den Komponenten, das Durchlaufen dieser Beziehungen vom geänderten Element aus und das Zurückgeben aller Komponenten, die auf irgendeiner Ebene des Abhängigkeitsbaums betroffen sind.

Die Textsuche nähert sich der Auswirkungsanalyse an, indem sie findet, wo der Name des geänderten Elements vorkommt. Sie kann jedoch nicht zwischen Abhängigkeiten und Kommentaren, direkten und transitiven Abhängigkeiten oder aktiven Abhängigkeiten und Verweisen in totem Code unterscheiden. Entwickler, die sich vor einer bedeutenden Änderung auf die Textsuche zur Auswirkungsanalyse verlassen, treffen eine sicherheitskritische Entscheidung auf Basis einer Annäherung. In einer kleinen, einsprachigen Codebasis mag diese Annäherung ausreichend sein. In einem Unternehmenssystem mit sprachübergreifenden Abhängigkeiten, gemeinsam genutzten Bibliotheken, die von vielen Diensten verwendet werden, und über Jahrzehnte gewachsenen Aufrufbeziehungen kann die Diskrepanz zwischen den Ergebnissen der Textsuche und den tatsächlichen Auswirkungen der Änderung erheblich sein.

Betrachten Sie den Unterschied in den Ergebnissen dieser beiden Ansätze bei einer Schemaänderung einer häufig verwendeten Datenbankspalte:

Was der Entwickler wissen mussTextsuchergebnisErgebnis des Codeverständnisses
Programme, die diese Kolumne lesenAlle Dateien, die den Spaltennamen enthalten, einschließlich der KommentareNur Programme mit SQL-SELECT-Anweisungen, die auf diese Spalte verweisen.
Programme, die diese Kolumne schreibenDieselbe ungefilterte ListeNur Programme, die SQL-INSERT- oder UPDATE-Anweisungen ausführen, die in diese Spalte schreiben.
Von dieser Spalte abhängige DiensteKeine sprachübergreifende SichtbarkeitJava-, Python- und .NET-Dienste, die die Spalte einem Objektfeld zuordnen
Verweise auf toten CodeIn den Ergebnissen enthalten, nicht gekennzeichnetAusgeschlossen oder separat gekennzeichnet
Transitive AbhängigeNicht sichtbarAufgezählt bis zu jeder beliebigen Tiefe
Vertrauen in die VollständigkeitUnbekanntVerifizierbar anhand des indizierten Bereichs

Onboarding und Code-Navigation

Ein Entwickler, der neu in einer großen Codebasis ist, muss sich ein mentales Modell der Funktionsweise des Codes erstellen: wie Komponenten miteinander verbunden sind, welche Daten durch das System fließen, welche Programme Einstiegspunkte und welche Hilfsprogramme sind und wie der Ausführungspfad für einen bestimmten Geschäftsprozess aussieht. Diese Modellbildung ist in erster Linie eine Aufgabe des Codeverständnisses. Die Textsuche hilft zwar beim Auffinden bestimmter Zeichenketten, liefert aber keinen strukturellen Kontext: Sie findet zwar, wo ein Wort vorkommt, aber nicht, welche Rolle der enthaltende Code im System spielt.

Werkzeuge zur Codeanalyse beschleunigen das Onboarding, indem sie die Systemstruktur übersichtlich darstellen. Ein interaktiver Aufrufgraph zeigt, welche Programme welche anderen aufrufen. Eine Datenflussanalyse zeigt Ursprung und Ziel eines Feldes. Eine Kontrollflussvisualisierung veranschaulicht die Ausführungsbedingungen einzelner Verzweigungen. Eine Abhängigkeitskarte zeigt, welche Komponenten unabhängig voneinander gefahrlos geändert werden können und welche die Abstimmung mit anderen Teams erfordern. All dies sind keine Ergebnisse der Textsuche, sondern Ergebnisse der Strukturanalyse, die Werkzeuge zur Codeanalyse durchführen. Wie im Kontext von … untersucht Was ist statische Codeanalyse?Die Fähigkeit, Komplexität durch strukturierte Analyse statt durch manuelles Lesen zu bewältigen, ermöglicht es Teams, effektiv in Systemen zu arbeiten, die zu groß sind, als dass ein Einzelner sie im Kopf erfassen könnte.

Identifizierung von totem Code und ungenutzten Elementen

Toter Code ist Code, der zwar definiert, aber nie ausgeführt wird: Funktionen, die nie aufgerufen werden, Verzweigungen, die nie erreicht werden, Variablen, denen zwar ein Wert zugewiesen, aber nie gelesen wird. Die Identifizierung von totem Code ist eine Aufgabe des Codeverständnisses, die die Erstellung eines vollständigen Aufrufdiagramms und die Bestimmung der definierten Elemente erfordert, die von keinem erreichbaren Einstiegspunkt aus eingehende Aufrufkanten haben. Die Textsuche kann toten Code nicht identifizieren, da toter Code per Definition von nirgends referenziert wird. Das Fehlen einer Referenz ist keine Zeichenkette, die die Textsuche finden kann.

Für die Entfernung veralteter Funktionen ist die Identifizierung von totem Code von direkter Relevanz. Einige Elemente, die scheinbar Aufrufer einer veralteten Funktion sind, können selbst toter Code sein: Funktionen, die zwar geschrieben wurden, um die veraltete Funktion aufzurufen, aber selbst nie aufgerufen werden und daher keine aktive Abhängigkeit darstellen. Die Unterscheidung zwischen aktiven und toten Aufrufern erfordert dieselbe Aufrufgraphenanalyse, die allgemein zur Identifizierung von totem Code dient. Wie im Kontext von … untersucht essentielle Refactoring-TechnikenDie statische Nutzungsanalyse liefert ausreichende Erkenntnisse, um festzustellen, ob Funktionen, Labels, Absätze oder Module jemals aufgerufen werden, und diese Analyse ist nur durch die Konstruktion eines strukturellen Aufrufgraphen möglich, nicht durch das Zählen von Textvorkommen.

Sicherheits- und Compliance-Audits

Sicherheits- und Compliance-Audits erfordern die Nachverfolgung sensibler Daten im System: die Identifizierung der Speicherorte personenbezogener Daten, der Zugriffspfade auf diese Daten, die korrekte Implementierung von Zugriffskontrollen in allen Ausführungspfaden, die zu sensiblen Daten führen, und die Frage, ob sensible Daten über Protokollierung, Fehlermeldungen oder API-Antworten das System verlassen können. Diese Aufgaben der Daten- und Kontrollflussanalyse lassen sich durch Textsuche nur unzureichend abbilden.

Eine Textsuche nach einem sensiblen Feldnamen findet Dateien, die diesen Namen enthalten. Sie kann jedoch nicht feststellen, ob diese Dateien autorisierten, unautorisierten oder gar keinen Zugriff ermöglichen. Ebenso wenig lässt sich ermitteln, ob im Ausführungspfad, der zum Feldzugriff führt, eine Zugriffskontrolle existiert. Auch kann nicht nachverfolgt werden, ob der Feldwert anschließend in ein Protokoll geschrieben oder in einer API-Antwort zurückgegeben wird, die ihn nicht enthalten sollte. Die sogenannte Taint-Analyse, die den Fluss sensibler Werte durch das System verfolgt und identifiziert, wo diese nicht vertrauenswürdige Ausgaben erreichen können, ist eine Funktion der Datenflussanalyse. Genau diese Funktion bieten sicherheitsbewusste Tools zur Codeanalyse, die eine Textsuche nicht annähernd erreichen kann.

Wie SMART TS XL Gewährleistet unternehmensweites Codeverständnis

SMART TS XL Die Plattform basiert auf der Prämisse, dass Unternehmenssysteme ein strukturelles Verständnis und nicht bloßes Textrecherche erfordern. Ihre Software-Intelligence-Plattform analysiert Quellcode aus allen Sprachen und Plattformen der Umgebung, erstellt sprachspezifische abstrakte Syntaxbäume und löst diese in einen einheitlichen, sprachübergreifenden Graphen auf, der die strukturellen Beziehungen des gesamten Systems abbildet. COBOL-Programme, JCL-Jobstreams, Java-Dienste, .NET-Anwendungen, Python-Skripte, SQL-Schemas, TypeScript-Module und Konfigurationsartefakte werden in diesem Graphen als Knoten und Kanten dargestellt, wobei die Beziehungen als typisierte Verbindungen ausgedrückt werden: Aufrufe, Datenflüsse, Copybook-Einbindungen, Schema-Referenzen und sprachübergreifende Äquivalenzen.

Die unternehmensweite Suchfunktion der Plattform bildet den Ausgangspunkt für das Verständnis von Code, funktioniert aber grundlegend anders als die Textsuche. Die Ergebnisse werden nach Beziehungstyp und Artefaktstruktur organisiert, nicht nach dem Vorkommen von Zeichenketten. Eine Abfrage nach einem Feldnamen liefert Definitionen, Lese- und Schreibvorgänge, SQL-Referenzen und Copybook-Einträge als separat kategorisierte Ergebnistypen. So erhält ein Entwickler, der fragt „Was schreibt in dieses Feld?“, genau die Schreibbeziehungen und nicht eine ungeordnete Liste aller Dateien, in denen der Name vorkommt. Diese Struktur der Suchergebnisse spiegelt das zugrunde liegende Querverweismodell wider und liefert Entwicklern die spezifischen, umsetzbaren Informationen, die sie benötigen, ohne dass sie Zeichenketten manuell filtern müssen.

Die Funktionen der Plattform zur Wirkungsanalyse, Aufrufgraph-Analyse, Kontrollflussvisualisierung und Datenflussverfolgung basieren alle auf demselben einheitlichen Strukturmodell. Wenn ein Entwickler eine veraltete Funktion identifiziert, zeigt der Aufrufgraph alle Aufrufer auf jeder Hierarchieebene an. Bei geplanten Schemaänderungen listet die Wirkungsanalyse alle Nutzer in allen Programmiersprachen auf. Wenn ein neuer Entwickler einen Batch-Prozess verstehen muss, ermöglicht die Kontrollflussvisualisierung die Navigation durch den Ausführungspfad, ohne dass er Hunderte von Quellcodezeilen sequenziell lesen muss. Wie im breiteren Kontext betrachtet… Entwicklererfahrung und DX-Metriken für Legacy-CodebasenDie Komplexität des Codes und die strukturelle Verschachtelung sind die Faktoren, die die Wartbarkeit bestimmen, und die Werkzeuge, die diese strukturellen Eigenschaften und nicht nur den Oberflächentext offenlegen, sind es, die komplexe Systeme in großem Umfang handhabbar machen.

Der Unterschied zwischen dem, was SMART TS XL Was die Textsuche bietet, ist der Unterschied zwischen einer beantworteten und einer aufgeworfenen Frage. Die Textsuche ist der Beginn einer Untersuchung. Das Verständnis von Code schließt sie ab.

Die fortlaufenden Kosten der Ersetzung von Suche durch Verständnis

Die praktischen Folgen der Verwendung von Textsuche anstelle von Codeverständnis summieren sich unbemerkt in jeder Entwicklungsaufgabe, die strukturelles Wissen über die Codebasis erfordert. Jede Folgenabschätzung, die auf Textsuche basiert, birgt eine unbekannte Anzahl übersehener Abhängigkeiten. Jede Feldverfolgung, die an einer Sprachgrenze endet, lässt Teile des Systems unsichtbar. Jede Identifizierung von totem Code, die Zeichenketten zählt, anstatt die Erreichbarkeit des Aufrufgraphen zu analysieren, liefert Fehlalarme und übersieht tatsächlich toten Code. Jedes Sicherheitsaudit, das nach sensiblen Feldnamen sucht, anstatt den Datenfluss durch die Ausführungspfade zu verfolgen, bietet eine unvollständige und nicht überprüfbare Sicherheit.

In einer kleinen, einsprachigen und häufig modifizierten Codebasis sind diese Kosten möglicherweise überschaubar. Die Entwickler verfügen über ausreichend Kontext, um Suchergebnisse präzise zu filtern, die Systemgrenzen sind allen Teammitgliedern bekannt, und die manuelle Überprüfung schließt die durch die Textsuche entstandenen Lücken schnell genug, um schwerwiegende Fehler zu vermeiden. In einem großen Unternehmenssystem mit mehreren Sprachen, jahrzehntelang angesammeltem Code und Teamstrukturen, die verhindern, dass ein Einzelner das Gesamtbild versteht, summieren sich die Kosten. Übersehene Abhängigkeiten treten im Produktivbetrieb zutage. Folgenabschätzungen, die im Meetingraum Vertrauen erweckten, führen bei der Veröffentlichung zu unerwarteten Fehlern. Sicherheitsaudits, die jedes Vorkommen von Zeichenketten abdeckten, übersehen die Datenflusspfade, die sensible Daten offenlegen. Das Wissen ehemaliger Entwickler lässt sich durch die Textsuche nicht rekonstruieren, da die von ihnen verstandenen strukturellen Zusammenhänge nie in den Quelldateien kodiert wurden.

Der Übergang von der Textsuche zum Codeverständnis bedeutet nicht, dass das eine Werkzeug durch das andere ersetzt wird. Die Textsuche behält ihre Berechtigung für Aufgaben, für die sie geeignet ist: das Auffinden von Zeichenketten, die schnelle Orientierung, Konfigurationsprüfungen und die Dateinavigation. Das Codeverständnis hingegen bietet die Strukturanalyse, die die Textsuche nicht leisten kann: Aufrufdiagramme, Datenflussanalysen, Wirkungsanalysen, die Identifizierung von totem Code und die Auflösung sprachübergreifender Abhängigkeiten. Beide arbeiten auf unterschiedlichen Abstraktionsebenen, beantworten unterschiedliche Fragetypen und dienen unterschiedlichen Zwecken. Die Folgen einer Vermischung dieser beiden Ansätze sind übersehene Abhängigkeiten, falsche Einschätzungen und die stetige Anhäufung von Risiken, die entstehen, wenn man weitreichende Änderungen an komplexen Systemen mit einem unvollständigen Verständnis ihrer tatsächlichen Funktionsweise vornimmt.