Zum Inhalt springen
14. Aug. 2026·8 Min. Lesezeit

Wie ein Abhängigkeitsgraph versteckte Aufrufe findet

Ein Abhängigkeitsgraph des gesamten Codebestands zeigt sprachübergreifende Aufrufe, generierte Namen, Batch-Übergaben und übersehene Datenverträge.

Wie ein Abhängigkeitsgraph versteckte Aufrufe findet

Ein Abhängigkeitsgraph ist nur so ehrlich wie die Grenze, innerhalb derer er erstellt wird. Wer immer nur ein Repository scannt, erhält vielleicht ein präzise wirkendes, vollständiges und beinahe nutzloses Ergebnis: Die Aufrufe, die darüber entscheiden, ob eine Neuentwicklung das Verhalten bewahrt, führen oft über einen Scheduler, eine Datenbank, eine generierte Datei, ein gemeinsam genutztes Copybook oder ein Protokoll, das keinem Repository gehört.

Wenn man den gesamten Baum gemeinsam liest, ändert sich die Analyseeinheit. Ein COBOL-Programm und sein JCL sind dann keine getrennten Bestände mehr. Ein RPG-Job, ein CL-Wrapper und eine von einem nächtlichen Import geschriebene Tabelle werden zu einem Ausführungspfad. Der Graph kann Belege aus verschiedenen Sprachen verbinden und zugleich markieren, wo die Belegkette endet. Gerade das zählt. Ein glaubwürdiger Graph unterscheidet eine belegte Kante von einer plausiblen, statt jeden passenden Namen zur Gewissheit zu erklären.

Ich habe Repository-Scans gesehen, die beruhigende Diagramme erzeugten, während der Produktionspfad durch Code lief, den das Diagramm nie berührte. Der Scanner war nicht defekt. Seine Frage war zu klein.

Repository-Grenzen sind administrativ, nicht verhaltensbezogen

Ein Graph pro Repository beschreibt, wie Quelldateien innerhalb eines gewählten Behälters auf andere Quelldateien verweisen. Ein systemweiter Graph beschreibt, wie sich Verhalten durch alle Artefakte bewegt, die eine Ausführung beeinflussen können. Das sind unterschiedliche Ergebnisse. Wer sie verwechselt, plant unvollständige Migrationsumfänge.

Repositories spiegeln meist Zuständigkeiten, Zugriffsregeln, Lieferungen von Anbietern oder eine Jahre zurückliegende Migration wider. Das Laufzeitverhalten hält sich an keine dieser Entscheidungen. Eine Webanfrage kann in Classic ASP beginnen, eine mit VB6 erstellte COM-Komponente aufrufen, eine in einem Datenbank-Repository verwaltete Stored Procedure ausführen und Arbeit für ein geplantes COBOL-Programm hinterlassen. Jedes Repository kann intern gut verstanden sein, während die Geschäftstransaktion unsichtbar bleibt.

Auch das Wort Abhängigkeit braucht Genauigkeit. Eine textuelle Referenz belegt, dass ein Artefakt ein anderes benennt. Eine aufrufbare Abhängigkeit bedeutet, dass das benannte Ziel unter bestimmten Bedingungen tatsächlich die Kontrolle erhalten kann. Eine verhaltensbezogene Abhängigkeit bedeutet, dass eine Änderung am Ziel ein Ergebnis verändern kann, das Benutzer oder nachgelagerte Systeme beobachten. Repository-Werkzeuge machen aus allen drei oft dieselbe Linie. Bei einer Neuentwicklung erzeugt diese Abkürzung falsche Sicherheit und unnötige Arbeit.

Der praktische Graph braucht daher mehr als Dateien und Funktionen als Knoten. Er braucht Jobs, Datenbankobjekte, Nachrichtenziele, generierte Artefakte, externe Programme, Schemas, Masken, Berichte und Konfigurationseinträge, sofern diese am Verhalten beteiligt sind. Eine Kante muss ihren Grund tragen: direkter Aufruf, dynamische Auswahl, Datenfluss, Zeitplanung, Generierung oder ein nicht aufgelöster Name. Mit diesen Belegen können Ingenieure den Graphen prüfen, statt ihn nur anzusehen.

Dieses weitere Modell verlangt nicht, alles in einem Repository abzulegen. Die Repositories bleiben. Nur die Analysegrenze ändert sich. Die richtige Grenze umfasst alle Artefakte, die das neu zu schreibende Verhalten beeinflussen können, auch wenn Besitz und Bereitstellung sie trennen.

Sprachübergreifende Kanten stecken in gewöhnlichen Mechanismen

Die wichtigen Aufrufe kündigen sich selten als sprachübergreifende Architektur an. Sie erscheinen als normale Plattformmechanismen: Befehlszeichenfolge, Name einer Stored Procedure, Jobschritt, exportiertes Symbol, Queue-Ziel oder Dateiname für den nächsten Prozess. Ein Sprachparser sieht Syntax. Ein Systemgraph muss deuten, was diese Syntax an anderer Stelle bewirkt.

Nehmen wir einen JCL-Schritt mit PGM=BILLRUN. Die Kante endet nicht beim Token BILLRUN. Die Analyse muss das Programm über die passenden Load Libraries auflösen, es mit dem Quell- oder Binärbestand verbinden und Unsicherheit erhalten, wenn mehrere Kandidaten existieren. Im Programm ist ein COBOL-CALL WS-PROGRAM kein normaler statischer Aufruf, weil das Ziel aus Daten stammt. Der Wert kann aus einem Copybook, einer Parameterdatei oder einem früheren Datenbankzugriff kommen.

Dasselbe Muster gibt es auf anderen Plattformen. CL kann ein RPG-Programm an eine Batch-Queue übergeben. VB6 kann eine COM-Klasse über eine Zeichenfolge aus Registry oder Konfiguration erzeugen. ColdFusion kann eine Datenbankprozedur aufrufen, deren Implementierung bei PL/SQL liegt. Ein PHP-Monolith kann eine Steuerdatei schreiben, die ein Perl-Daemon als Anweisung liest. Dafür braucht es keine ungewöhnliche Reflexion. Die Kanten verschwinden, weil jeder Parser an der Grenze seiner Sprache oder seines Repositorys aufhört.

Ein brauchbares Zwischenartefakt macht die Verknüpfung sichtbar und prüfbar. Eine tabulatorgetrennte Kantendatei kann die Mindestbelege für die Prüfung tragen:

source	target	mechanism	evidence
JCL:AR_CLOSE:STEP20	COBOL:BILLRUN	program-load	PGM=BILLRUN
COBOL:BILLRUN:PARA140	DB2:SP_POST_LEDGER	dynamic-sql	value-set:POST_LEDGER
DB2:SP_POST_LEDGER	TABLE:GL_ENTRY	write	INSERT INTO GL_ENTRY
CL:ENDDAY:CMD7	RPG:RECONCILE	submit-job	CALL PGM(RECONCILE)

Diese Datei ist noch nicht der endgültige Graph. Sie ist ein Vertrag zwischen Extraktion und Prüfung. Jede Zeile nennt Quelle, Ziel, Mechanismus und Beleg. Kann das Werkzeug die letzte Spalte nicht füllen, darf es nicht stillschweigend eine harte Kante zeichnen.

Namen werden erst durch gemeinsame Belege auflösbar

Dynamische Aufrufe sind nicht grundsätzlich unerkennbar. Viele lassen sich auflösen, wenn die Analyse Zuweisungen, Konfiguration, Build-Metadaten und Laufzeitbeobachtungen aus dem gesamten Baum zusammenführt. Der Fehler besteht darin, eine Aufrufstelle ohne Literal als Sackgasse zu behandeln, bevor man nach den möglichen Werten sucht.

Angenommen, ein COBOL-Absatz ruft WS-NEXT-PGM auf. Ein Repository enthält den Aufruf, aber nicht die Zuweisung. JCL in einem anderen Repository übergibt einen symbolischen Parameter. Ein gemeinsames Copybook definiert die Feldbreite. Ein Export der Steuertabelle enthält die bereitgestellten Werte. Getrennt gelesen bleibt der Aufruf unaufgelöst. Gemeinsam gelesen kann die Analyse eine Kandidatenmenge bilden, unpassende Werte anhand der Feldbreite verwerfen und die übrigen Werte mit dem Programmbestand verbinden.

Die Auflösung muss beleggestützt bleiben. In Prüfungen verwende ich vier Kantenzustände: durch Syntax bestätigt, aus begrenzten Werten abgeleitet, im aufgezeichneten Verkehr beobachtet und unaufgelöst. Die Bezeichnungen sind weniger wichtig als ihre Trennung. Ein abgeleiteter Kandidat hilft bei der Umfangsplanung, beweist aber nicht, dass die Produktion diesen Pfad nutzt. Ein beobachteter Aufruf belegt das Auftreten in der Stichprobe, aber nicht, dass keine anderen Ziele vorkommen können.

Hier scheitert auch einfacher Namensabgleich. POST, UPDATE oder CLOSE können in Dutzenden Namensräumen stehen. Ein Treffer wird erst glaubwürdig, wenn Auflösungsregeln der Plattform, Feldbeschränkungen, Aufrufkonvention, Bereitstellungskontext und erreichbare Zuweisungen berücksichtigt sind. Die Gesamtbaumanalyse liefert mehr Belege, muss aber strenger unterscheiden. Mehr Eingaben ohne Regeln ergeben nur einen dichteren falschen Graphen.

Generierter Quelltext verlangt dieselbe Behandlung. Generator, Vorlagen, Eingaben und erzeugtes Artefakt bilden eine Kette. Wird nur die Ausgabe gescannt, verwechselt der Graph eine Folge mit der maßgeblichen Quelle. Werden nur Vorlagen geprüft, fehlen die konkreten Namen einer Bereitstellung. Beides bleibt erhalten und wird durch eine Generierungskante verbunden, damit sich eine Änderung bis zu dem Element verfolgen lässt, das die Datei später erneut erzeugt.

Datenbewegung ist oft der fehlende Aufruf

Ein reiner Aufrufgraph kann viele Altsysteme nicht erklären, weil Daten die Übergabe bilden. Ein Prozess schreibt eine Zeile, Datei oder Spool-Ausgabe, ein anderer deutet sie später. Keine Funktion ruft die nächste direkt auf, doch das erste Programm steuert, was das zweite tut. Für Verhaltensparität ist das eine Abhängigkeit.

Nächtliche Verarbeitung zeigt das deutlich. Eine Onlinetransaktion schreibt einen Statuscode in eine Tabelle. Zum Abschluss startet ein Scheduler einen Batch-Job. Dieser wählt Zeilen mit dem Code, erzeugt eine Datei mit festen Feldbreiten und ein separates Programm importiert sie in ein Hauptbuch. Lokale Aufrufgraphen zeigen vier getrennte Inseln. Der Systemgraph zeigt eine Transaktion mit Kanten für Prädikat, Zeitplan, Datensatzlayout und Dateinamensregel.

Jede gemeinsam genutzte Tabelle als Abhängigkeit zu behandeln, würde Rauschen erzeugen. Der Graph braucht Sensibilität für Operationen und Felder. Ein Schreiber von customer.last_seen muss keinen verhaltensbezogenen Zusammenhang mit einem Leser haben, der customer.credit_hold auswählt. Ein Schreiber des abgefragten Statusfelds hat ihn. Ebenso sind zwei Programme mit derselben Datei nicht zwingend verbunden, wenn sie verschiedene Datensatztypen verwenden.

Eine praktische Datenkante erfasst mindestens Objekt, Operation, relevante Felder oder Datensatzlayout und jedes Prädikat, das den Leser aktiviert. Bei Batch-Dateien gehören Produzent, Verbraucher, Namensregel, Kodierung, Trennzeichen oder Feldpositionen sowie geprüfte Kontrollsummen dazu. Bei Stored Procedures muss der Aufruf von Lesezugriffen auf Tabellen unterschieden werden, die die Prozedur verändert. Diese Einzelheiten entscheiden, wo eine Neuentwicklung sicher ein neues Schema oder eine Servicegrenze einführen kann.

Die unbequeme Frage lautet, ob der Graph dadurch zu breit wird. Das geschieht, wenn jede Datenübereinstimmung zu einer harten Kante wird. Er bleibt brauchbar, wenn gefilterte Ansichten möglich sind: Kontrollübergabe, Dateneinfluss, Zeitplanung, Generierung und externe Unsicherheit. Das gemeinsame Modell muss die Kantentypen bewahren, statt sie zu einem Pfeilhaufen zu glätten.

Auch ein vollständiger Baum hat ein Außen

Dynamische Ziele auflösen
Die Gesamtbaumanalyse führt Zuweisungen und Aufrufkontext zusammen, statt nichtliterale Namen zu verwerfen.

Jede Datei des gelieferten Baums zu lesen bedeutet nicht, das laufende System vollständig zu kennen. Es bedeutet, die vorhandene Belegmenge vollständig zu kennen. Externe Scheduler, Datenbank-Trigger, Bedienerbefehle, Registry-Einträge, Middleware-Routing, Hersteller-Binärdateien und Produktionskonfiguration können Verhalten einführen, das die Quellanalyse nicht beweisen kann.

An dieser Unterscheidung werden viele Modernisierungsberichte unehrlich. Sie nennen einen Graphen vollständig, obwohl nur der Scanner fertig ist. Ein beendeter Scan sagt nichts darüber aus, ob seine Eingaben die Ausführungsumgebung abdecken. Ein gutes Ergebnis enthält eine ausdrückliche Grenze: Knoten und Kanten, die über die gelieferten Belege hinausweisen, jeweils mit einem Grund für die offene Frage.

Diese Grenze lässt sich konkret machen. Nicht aufgelöste Programmnamen, externe Datenbankobjekte, Queue-Ziele, Dateipfade und Konfigurationsschlüssel kommen in eine Prüftabelle. Jeder Eintrag erhält einen Verantwortlichen und einen Status wie später geliefert, extern bestätigt, stillgelegt oder weiterhin unbekannt. Ein nicht aufgelöster Knoten darf nicht verschwinden, nur weil ihn niemand erkennt. Alter Code ist oft inaktiv, doch Bekanntheit ist kein Beleg für Erreichbarkeit.

Laufzeitbeobachtungen helfen, solange sie niemand für erschöpfend erklärt. Aufgezeichneter Produktionsverkehr kann das Auftreten eines Pfads bestätigen und Werte für dynamische Ziele liefern. Er kann nicht beweisen, dass ein seltener Jahresendzweig, ein Wiederherstellungsverfahren oder ein reiner Bedienerbefehl nie läuft. Statische Belege liefern mögliche Struktur, Laufzeitbelege beobachtetes Verhalten. Die Überschneidung ist stark, Abweichungen verdienen Untersuchung.

Der Graph muss daher zwei Fragen getrennt beantworten: Was können die gelieferten Artefakte verursachen, und was hat die aufgezeichnete Last tatsächlich verursacht? Ein nur auf der ersten Sicht basierender Umfang erhält womöglich tote Pfade für immer. Ein Umfang nur aus der zweiten Sicht kann einen gültigen Ausnahmeweg löschen. Beide Ansichten bleiben erhalten, und die Entscheidung wird sichtbar.

Eine fehlende Kante kann eine saubere Neuentwicklung entwerten

Eine übersehene Abhängigkeit fällt meist weit entfernt vom ausgelassenen Code aus. Diese Verzögerung erklärt, warum Teams Repository-Grenzen in der Planung unterschätzen und beim Umstieg die Testabdeckung beschuldigen, obwohl das reale System sichtbar wird.

Nehmen wir einen Monatsabschluss aus vier Repositories. Ein RPG-Programm markiert berechtigte Konten und ruft einen CL-Wrapper auf. Der Wrapper reicht einen Job mit einem Namen aus einem Datenbereich ein. JCL auf einem verbundenen Host startet das ausgewählte COBOL-Programm. Dieses schreibt eine Ausnahmedatei mit festen Feldbreiten, und ein VB6-Desktopwerkzeug lässt einen Bediener Datensätze genehmigen, bevor eine PL/SQL-Prozedur sie bucht. Jedes Repository hat Tests. Jedes Team versteht seinen Abschnitt.

Ein Repository-Scan findet den direkten RPG-zu-CL-Aufruf und die PL/SQL-Tabellenzugriffe. Er übersieht das eingereichte Programm, weil sein Name aus Daten kommt, das JCL wegen seines anderen Speicherorts und die Desktopfreigabe, weil die Datei die Schnittstelle ist. Die Neuentwicklung ersetzt den ersten Abschnitt durch einen Service und bildet seine Datenbankänderungen nach. Automatisierte Tests mit normalen Konten bestehen.

Beim Abschluss bleiben Ausnahmefälle ungebucht. Der neue Service erzeugt die Datei nicht, weil niemand diese Ausgabe in den Vertrag aufgenommen hat. Das Desktopwerkzeug zeigt nichts an, also kann der Bediener keine Datensätze freigeben. Keine Ausnahme erreicht die Buchungsprozedur. Der Fehler wirkt wie ein UI- oder Datenbankproblem, entstand aber schon, als die Analyse die Servicegrenze um ein Repository zog.

Ein Gesamtbaumgraph hätte den Pfad über mehrere Kantentypen verbunden: Aufruf, eingereichter Job, geplantes Programm, Dateierzeugung, Bedieneraktion und Aufruf der Stored Procedure. Auch Datenbereich und Dateinamensregel wären als Steuereingaben sichtbar. Tests könnten repräsentativen Verkehr für normale und außergewöhnliche Pfade aufzeichnen und beobachtbare Ausgaben an jeder Grenze vergleichen.

Die Lehre lautet nicht, dass jedes alte Artefakt erhalten bleiben muss. Löschen darf erst auf Verstehen folgen. Sobald der Pfad sichtbar ist, kann das Team Datei und Desktopfreigabe durch einen TypeScript-Client und eine Service-API ersetzen. Das ist eine Architekturänderung mit bekannter Verhaltenspflicht statt versehentlicher Entfernung.

Eine Transliteration des Graphen bewahrt falsche Grenzen

In unter 30 Tagen fertig
CodeHero liefert die Neuentwicklung mit Graphbelegen und Produktionsverkehrsparität in unter 30 Tagen.

Für jedes alte Programm ein neues Modul zu erzeugen wirkt sicher, weil sich die Zuordnung leicht prüfen lässt. So übernimmt eine Neuentwicklung jedoch jahrzehntealte Bereitstellungszufälle. Der Graph soll Verpflichtungen bewahren und bessere Grenzen zeigen, nicht eine Datei-für-Datei-Übersetzung diktieren.

Alte Grenzen entstanden oft durch Speichergrenzen, Batch-Fenster, Sprachbeschränkungen oder Teamgeschichte. Ein JCL-Schritt verschiebt vielleicht nur Daten zwischen Layouts, weil keines der Nachbarprogramme beide Formate halten konnte. Eine Stored Procedure kann Geschäftsregeln enthalten, weil der ursprüngliche Client selten ausgeliefert werden konnte. Ein gemeinsames Copybook kann unabhängige Programme koppeln, weil es der einzige praktikable Verteilungsweg war. Wer jedes Artefakt in einer neuen Sprache nachbaut, konserviert diese Einschränkungen ohne ihren früheren Grund.

Nutzen Sie den Graphen, um zusammengehöriges Verhalten zu finden. Knoten, die gemeinsam geändert werden, Transaktionsregeln teilen und am selben beobachtbaren Ergebnis mitwirken, eignen sich für eine moderne Komponente. Kanten über Vertrauenszonen, unabhängige Release-Zyklen oder tatsächlich verschiedene Lasten eignen sich für ausdrückliche Schnittstellen. Datenkanten zeigen, wo ein Postgres-Schema Invarianten schützen muss. Numerische Kerne mit strengen Laufzeit- oder Speicheranforderungen können Rust rechtfertigen, während Orchestrierung in Go und Bedienoberflächen in TypeScript liegen. Das Ziel folgt Verhalten und Beschränkungen, nicht Dateiendungen.

Ich rate davon ab, mit einer Repository-für-Repository-Konvertierung zu beginnen, auch wenn Einkauf und Personalplanung sie attraktiv machen. Sie liefert früh zählbaren Fortschritt, verschiebt aber repositoryübergreifendes Verhalten in die Integration, wo Grenzänderungen mehr kosten. Erstellen Sie zuerst den Systemgraphen, wählen Sie die neuen Grenzen und ordnen Sie dann Arbeitspakete den Teams zu.

Nachvollziehbarkeit bleibt notwendig. Jede neue Komponente muss auf die Quellverhalten und Graphkanten zeigen, die sie ersetzt. So können Prüfer fragen, ob eine alte Kante erhalten, bewusst neu gestaltet oder mit Belegen stillgelegt wurde. Ohne diese Karte wird Modernisierung zur Diskussion über Codeähnlichkeit, und das ist der falsche Maßstab.

Paritätstests müssen Pfaden statt Repositories folgen

Repository-Tests sind nützliche Belege, stellen aber selten Systemparität her, weil ihre Prüfungen an lokalen Grenzen enden. Ein Paritätstest muss vollständige Transaktionen abspielen und die beobachtbaren Auswirkungen entlang des vom Graphen offengelegten Pfads vergleichen.

Wählen Sie zuerst verhaltensmäßig verschiedene Pfade, nicht nur häufige Endpunkte. Dazu gehören Normalverarbeitung, ein dynamisch gewähltes Ziel, eine Batch-Übergabe, eine durch Bediener vermittelte Ausnahme sowie ein Fehler- oder Wiederholungsweg, sofern vorhanden. Zeichnen Sie Ein- und Ausgaben an stabilen Grenzen auf: Anfragen, Datenbankänderungen, erzeugte Datensätze, Statuswechsel, Berichte und extern sichtbare Fehler. Interne Aufruffolgen dürfen sich mit der Architektur ändern. Beobachtbare Pflichten dürfen sich nicht versehentlich ändern.

Ein kompaktes Pfadmanifest macht den Testumfang prüfbar:

path: close-exception-approval
entry: account-status-change
observations:
  - eligible-account-row
  - exception-record
  - approval-state
  - ledger-entry
dynamic-targets:
  - reconciliation-program
external-frontier:
  - scheduler-calendar

Für jeden aufgezeichneten Produktionsfall laufen Original und Ersatz mit kontrolliertem Zustand. Werte, die berechtigt schwanken, werden normalisiert, danach folgen die Vergleiche. Ein anderer Zeitstempel kann akzeptabel sein. Ein fehlender Ausnahmedatensatz ist es nicht. Bei Abweichungen führt der Abhängigkeitspfad zur ersten abweichenden Grenze, statt Millionen Zeilen oder nur den letzten Datenbankzustand zu vergleichen.

Verkehrsstichproben brauchen gezielte Ergänzungen. Produktionsaufzeichnungen zeigen, was im Aufnahmefenster geschah. Deshalb fügen Ingenieure Fälle für Kalendergrenzen, Rechte, Wiederherstellung, seltene Steuerwerte und durch die statische Analyse gefundene Bedieneraktionen hinzu. Findet die statische Analyse einen scheinbar erreichbaren Zweig ohne Stichprobe, darf er nicht still verschwinden. Klären Sie, ob er inaktiv, unerreichbar oder nur selten ist.

CodeHero liest den gesamten Codebestand über alle Sprachen und prüft das neu geschriebene System mit einem Paritätstest gegen aufgezeichneten Produktionsverkehr. Das Projekt wird in weniger als 30 Tagen geliefert. Für jeden Ansatz gilt derselbe brauchbare Maßstab: Hinter jeder behaupteten Ersatzgrenze stehen Graphbelege und über die Grenze hinweg Verhaltensbelege.

Der Graph ist ein prüfbares technisches Artefakt

Versteckte Batch-Übergaben ersetzen
Sprachübergreifende Analyse zeigt geplante Programme und dateigesteuertes Verhalten vor dem Architekturentwurf.

Ein Abhängigkeitsgraph des gesamten Codebestands gewinnt Vertrauen, wenn Ingenieure seine Belege untersuchen, die Extraktion reproduzieren und Entscheidungen zu unsicheren Kanten festhalten können. Ein schönes Diagramm ohne Herkunftsnachweis ist eine Präsentation, kein technisches Artefakt.

Bewahren Sie das rohe Kanteninventar mit stabilen Kennungen für Artefakte und Fundorte in der Versionsverwaltung auf. Halten Sie Extraktorversion und Eingaberevision fest. Bei abgeleiteten Kanten speichern Sie die begrenzten Werte und Regeln. Bestätigt Laufzeitverkehr eine Kante, hängen Sie eine Stichprobenkennung an, statt vertrauliche Nutzdaten in den Graphen zu kopieren. Dadurch bleiben Änderungen am Graphen erklärbar, während sich Quellbaum und Migrationsentwurf entwickeln.

Prüfungen sollten Grenzen und Unsicherheit behandeln. Fragen Sie, welche extern sichtbaren Ergebnisse Repository-Grenzen überschreiten, welche dynamischen Ziele offen bleiben, welche Datenkanten späteres Verhalten steuern und welche äußeren Systeme Arbeit einspeisen können. Ein riesiges zentrales Diagramm eignet sich schlecht zur Prüfung. Filtern Sie denselben Graphen zum Pfad einer Transaktion, einer offenen Grenze, einer Schreib-Lese-Einflussansicht oder der geplanten Zielkomponentenkarte.

Nach der Entdeckung braucht es Zuständigkeit. Weisen Sie offene Kanten Menschen zu, die Scheduler-Exporte, Datenbankdefinitionen, Produktionskonfiguration oder Bedienabläufe beschaffen können. Halten Sie die Antwort im Graphen statt in Besprechungsnotizen fest. Wird ein Artefakt für tot erklärt, bewahren Sie die Belege auf, etwa unerreichbare Konfigurationswerte und das Fehlen in einer ausreichend repräsentativen Verkehrsmenge. Schweigen beweist keine Stilllegung.

Das erste brauchbare Ergebnis ist keine Dateizahl und keine beeindruckende Knotensumme. Es ist eine kleine Gruppe vollständiger Pfade, deren Übergänge belegt und deren Unbekannte sichtbar sind. Mit ihnen ziehen Architekten Grenzen, wählen Tester Fälle und erkennen Bediener fehlende Schritte. Erweitern Sie die Abdeckung, bis die betroffenen Verhalten so behandelt sind.

Build- und Bereitstellungsregeln entscheiden über die echte Kante

Quellnamen allein verraten nicht, welche Implementierung läuft. Build-Skripte, Linker-Karten, Suchreihenfolgen für Bibliotheken, Paketmanifeste, Bereitstellungsbeschreibungen und umgebungsspezifische Überschreibungen wählen den Empfänger der Kontrolle. Ignoriert ein Gesamtbaumgraph diese Artefakte, verbindet er vielleicht den richtigen Namen mit dem falschen Code.

Doppelte Namen sind in langlebigen Systemen normal. Neben Produktionsquellen kann eine Testversion liegen. Zwei Load Libraries können Programme mit demselben Membernamen enthalten. Ein VB6-Projekt kann auf eine kompatible COM-Schnittstelle verweisen, während die Bereitstellung eine bestimmte registrierte Implementierung wählt. Datenbanksynonyme können denselben SQL-Text auf verschiedene Schemas lenken. Der Graph braucht einen Bereitstellungskontext, keine universelle Antwort mit allen Kandidaten zugleich.

Modellieren Sie die Auflösung als Belegfolge. Sammeln Sie zuerst Name und Aufrufkonvention der Aufrufstelle. Wenden Sie dann die Build- oder Laufzeitsuchfolge der gewählten Umgebung an. Prüfen Sie, ob der Kandidat den erwarteten Einsprungpunkt exportiert und eine passende Form akzeptiert. Hängen Sie zuletzt den Konfigurations- oder Bereitstellungsnachweis an. Fehlt eine Eingabe, bleiben die Kandidaten sichtbar, ebenso die fehlende Entscheidung. Wählen Sie nicht einfach die zuerst indizierte Datei.

Linker- und Compiler-Ausgaben klären oft Fragen, die Quellparser nicht lösen können. Eine Linker-Karte zeigt das in eine Binärdatei gebundene Symbol. Build-Protokolle zeigen die verwendeten Versionen generierter Quellen und Copybooks. Paket- und Bereitstellungsinventare verbinden ein erstelltes Artefakt mit dem Host, auf dem aufgezeichneter Verkehr es erreichte. Diese Ausgaben sind keine Nebenunterlagen, sondern Belege zum ausführbaren System. Im Graphen verdienen sie stabile Knoten oder Anlagen.

Halten Sie Umgebungsunterschiede sichtbar. Entwicklung, Test, Notfallwiederherstellung und Produktion können denselben logischen Namen unterschiedlich auflösen. Wer diese Varianten zusammenlegt, übersieht eine reine Produktionsabhängigkeit oder glaubt, Tests hätten Code ausgeführt, den ihre Umgebung nie lud. Markieren Sie Kanten mit dem jeweiligen Kontext und vergleichen Sie die Kontexte. Eine Abweichung kann beabsichtigt sein, gehört aber in den Umfang, wenn die Neuentwicklung diese Umgebung unterstützen muss.

Diese Arbeit findet auch veraltete Deklarationen. Eine Build-Datei kann eine nicht mehr ausgelieferte Bibliothek nennen, während die bereitgestellte Binärdatei alles anderswo auflöst. Umgekehrt kann Quelltext ungenutzt wirken, weil die aktuelle Build-Definition ihn auslässt, obwohl ein Bediener ihn vor einem jährlichen Lauf über ein eigenes Verfahren kompiliert. Entscheiden Sie nicht nach Vorliebe. Halten Sie widersprüchliche Belege fest und beschaffen Sie die fehlende Build- oder Betriebsanweisung.

Der Test einer Kante ist einfach: Ein anderer Ingenieur muss anhand ihrer Belege unter denselben Umgebungsannahmen zur gleichen Kandidatenmenge kommen. Reproduzierbarkeit ist wichtiger als eine erzwungene Einzelantwort. Ein Graph mit zwei vertretbaren Zielen und einer fehlenden Konfigurationsdatei hilft mehr als ein klarer Pfeil, der nur auf Verzeichnisnähe beruht.

Auch die Versionsidentität zählt, nachdem der erste Graph erstellt ist. Eine an einen Quellpfad gebundene Abhängigkeit kann abdriften, wenn sich Release-Branch, kopierte Bibliothek oder generiertes Member ändern, der Pfad aber gleich bleibt. Speichern Sie einen Inhaltswert oder eine Build-Kennung am Knoten und verbinden Sie die bereitgestellte Binärdatei mit genau dieser Revision. Sonst kann ein Prüfer gültigen Belegen bis zur falschen Version folgen und Ersatz für Verhalten freigeben, das nie lief. Das ist besonders wichtig bei Archiven, die Teams aus mehreren Rechnern statt aus einem sauberen Checkout zusammenstellen. Die Analyse sollte doppelte Pfade, widersprüchliche Zeitstempel und Artefakte ohne Zuordnung zur Quelle melden. Diese Warnungen verhindern keine Entdeckung, aber eine unberechtigte Genauigkeit. Liefert ein späterer Export die fehlende Binärdatei oder das Build-Protokoll, lassen sich die betroffenen Kanten anhand der stabilen Kennung aktualisieren.

Repository-Analysen können einem Team weiterhin helfen, lokalen Code zu verstehen. Sie können nicht die Verhaltensgrenze eines Systems bestimmen, das aus Sprachen, Jobs, Datenspeichern, generierten Artefakten und menschlichen Handlungen zusammengesetzt ist. Wenn die wichtigen Aufrufe die Analysebehälter überschreiten, haben diese Behälter bereits festgelegt, was der Graph übersieht.

FAQ

Was ist ein Abhängigkeitsgraph des gesamten Codebestands?

Er entsteht aus allen relevanten Quellen, Konfigurationen, Jobs, Schemas, generierten Artefakten und beobachteten Laufzeitpfaden im Systemumfang. Seine Kanten behalten Mechanismus und Beleg, sodass ein direkter Aufruf nicht wie eine Datenübergabe oder ein abgeleitetes dynamisches Ziel aussieht.

Warum übersieht eine Repository-Analyse Aufrufe?

Repositories bilden Zuständigkeit und Auslieferung ab, die Ausführung überschreitet sie über Scheduler, Datenbanken, Dateien, Queues und dynamische Namen. Ein Scanner ohne beide Enden kann höchstens einen offenen Token erfassen und verwirft die Kante oft ganz.

Kann statische Analyse dynamische Programmaufrufe auflösen?

Viele lassen sich durch Zuweisungen, Parameter, Konfiguration, Feldgrenzen und Plattformregeln auf eine begrenzte Kandidatenmenge reduzieren. Das Ergebnis muss als abgeleiteter Beleg markiert sein und darf nicht wie ein bestätigter Literalaufruf wirken.

Gehören Datenbankzugriffe in einen Abhängigkeitsgraph?

Ja, wenn sie Verhalten zwischen Komponenten transportieren. Erfassen Sie Operation, relevante Felder und Leserprädikat, denn zwei Programme mit derselben Tabelle beeinflussen sich nicht automatisch.

Findet das Lesen des gesamten Quellbaums jede Abhängigkeit?

Nein. Externe Scheduler, Produktionskonfiguration, Bedienabläufe, Trigger und Hersteller-Binärdateien können außerhalb liegen, deshalb braucht der Graph eine offene Außengrenze. Laufzeitbeobachtungen und Umgebungsexporte schließen einige Lücken.

Wie verbessern Laufzeitspuren den Abhängigkeitsgraph?

Sie bestätigen, dass bestimmte Pfade und dynamische Zielwerte im aufgezeichneten Verkehr vorkamen. Nicht beobachtete Pfade sind dadurch nicht tot, deshalb gehören statische Erreichbarkeit und gezielte seltene Fälle dazu.

Wie sollte generierter Code dargestellt werden?

Generator, Vorlagen, Eingaben und Ausgabedateien bleiben getrennte, durch Generierungskanten verbundene Knoten. So bearbeiten Ingenieure keine später überschriebenen Ausgaben und bewahren die konkreten Bereitstellungsnamen.

Kann ein Abhängigkeitsgraph neue Servicegrenzen bestimmen?

Er liefert Entscheidungsbelege zu zusammengehörigem Verhalten, Transaktionsregeln, Dateneinfluss und echten äußeren Übergängen. Machen Sie nicht aus jedem alten Programm oder Repository einen Service, nur weil die Zuordnung bequem ist.

Was sollte ein Paritätstest bei einer Neuentwicklung vergleichen?

Vergleichen Sie beobachtbare Auswirkungen vollständiger Pfade: Antworten, Datenbankänderungen, erzeugte Datensätze, Statuswechsel, Berichte und Fehler. Normalisieren Sie nur berechtigt abweichende Werte und untersuchen Sie dann die erste unterschiedliche Grenze.

Wie prüfen Ingenieure einen Graphen aus Millionen Quellzeilen?

Sie prüfen gefilterte Pfade und Unsicherheitsansichten statt eines riesigen Diagramms. Stabile Kanten mit Mechanismus, Fundort und Beleg machen einzelne Transaktionen, offene Zielmengen und geplante Komponentengrenzen handhabbar.