Eine Hilfsfunktion liefert plötzlich Sekunden statt Millisekunden. Argumente und Rückgabetyp sehen gleich aus. Ein Aufrufer fordert keine Aktualisierung mehr an, ein anderer sortiert weiterhin richtig, und eine CSV-Spalte wird unbemerkt tausendmal zu klein. Eine Referenzliste allein verrät nicht, welches dieser Ergebnisse eingetreten ist.
Angenommen, eine kleine Anwendung listet Sitzungen auf, entscheidet über Aktualisierungen und exportiert deren Alter. Dies ist ein konstruiertes Lehrbeispiel. Die Ergebnisse unten stammen aus der Ausführung seines JavaScript mit festen Eingaben und unveränderten Assertions. Laden Sie das vollständige Beispiel herunter, um sie zu reproduzieren.
Die Änderung präzisieren, bevor Sie Aufrufer auflisten
Der Download enthält beide Versionen einer Hilfsfunktion in elapsed.mjs, damit dieselben Verbraucher mit beiden laufen können:
export function elapsedBefore(nowMs, startedMs) {
return nowMs - startedMs;
}
export function elapsedAfter(nowMs, startedMs) {
return (nowMs - startedMs) / 1000;
}
Beide Eingaben bleiben Zeitstempel in Millisekunden. Der vorgeschlagene Rückgabewert sind Sekunden einschließlich Nachkommastellen: Aus 2_500 Millisekunden werden 2.5, nicht 2. Für nowMs = 60_000 und startedMs = 15_000 ändert sich das Ergebnis von 45_000 auf 45.
Damit steht die genaue Frage fest: Welche Verbraucher benötigen die alte Einheit und welche nur eine Eigenschaft, die bei der Umrechnung erhalten bleibt? Eine Typprüfung, die in beiden Versionen eine Zahl sieht, beantwortet das nicht.
Sind die Eingabewerte unbekannt, verfolgen Sie zuerst einen Wert von seiner Quelle durch den Code. Die Einheit der Ausgabe und die der Eingabe zu ändern sind verschiedene Eingriffe; hier ändert sich nur die Ausgabe.
Mit Referenzen eine Kandidatenliste erstellen
Suchen Sie im Editor nach elapsed oder führen Sie aus:
rg -n 'elapsed' --glob '*.mjs' .
Öffnen Sie consumers.mjs. Zwei Aufrufer verdienen Aufmerksamkeit:
export function needsRefresh(elapsed, nowMs, lastSyncMs) {
return elapsed(nowMs, lastSyncMs) >= 30_000;
}
export function oldestFirst(elapsed, nowMs, sessions) {
return [...sessions]
.sort((a, b) => elapsed(nowMs, b.startedMs) - elapsed(nowMs, a.startedMs))
.map((session) => session.id);
}
needsRefresh vergleicht den Wert mit einem festen Schwellenwert. oldestFirst vergleicht zwei Werte derselben Hilfsfunktion. Markieren Sie beide als Kandidaten und notieren Sie ihre Zusagen an Aufrufer: ab dreißig Sekunden aktualisieren; Sitzungs-IDs von alt nach neu liefern, ohne das Eingabearray zu verändern.
Referenzen eines installierten und eingerichteten Sprachservers helfen bei der Navigation im verfügbaren Projekt. Betrachten Sie Ergebnisse als Hinweise. Aliase, injizierte Funktionen, Registrierung und Laufzeitkonfiguration erfordern weitere Prüfung; die Referenzansicht ist kein vollständiges Verzeichnis aller Verbraucher, die eine Bereitstellung wählen könnte.
Die Funktion durch die Registry verfolgen
app.mjs übergibt die Hilfsfunktion nicht nur an die beiden direkten Verbraucher. Es wählt per Konfiguration eine Factory und übergibt ihr die Funktion unter anderem Namen:
const factory = registry.get(config.exporter);
if (!factory) throw new Error(`Unknown exporter: ${config.exporter}`);
const exporter = factory({ measureAge: elapsed });
Folgen Sie register(registry) weiter oben in derselben Datei. In den Modi before und after ruft es registerAgeColumn auf, dessen Implementierung in age-column.mjs steht:
export function registerAgeColumn(registry) {
registry.set('age-column', ({ measureAge }) => ({
kind: 'age-column',
rows(nowMs, sessions) {
return [
'id,age_seconds',
...sessions.map(
(session) =>
`${session.id},${measureAge(nowMs, session.startedMs) / 1000}`,
),
].join('\n');
},
}));
}
Der CSV-Header verspricht Sekunden. Mit der alten Hilfsfunktion liefert die Division durch 1000 diese Einheit. Mit der neuen erfolgt die Division zweimal.
Eine Suche nur nach elapsed zeigt den Aufruf measureAge(...) in dieser Datei nicht. Erweitern Sie die Suche nach deren Entdeckung um Alias und Registrierungsschlüssel:
rg -n 'measureAge|age-column|exporter' --glob '*.mjs' .
Die Testanwendung wählt ausdrücklich { exporter: 'age-column' } und prüft selectedExporter. Das verbindet den Registry-Eintrag mit dem tatsächlich ausgeführten Pfad. Eine registrierte Factory ohne Prüfung der Auswahl zu finden ließe ihre Nutzung offen. In einer Serveranwendung beginnt dies möglicherweise bei Route und Konfiguration, die den Anfragepfad wählen.
Dieselben Erwartungen gegen beide Versionen ausführen
Entpacken Sie den Download und wechseln Sie in code-change-impact-analysis. Es gibt keine Drittanbieter-Abhängigkeiten. Der dokumentierte Lauf nutzte Node.js 22.22.1. Verwenden Sie Node.js 22 oder neuer und führen Sie die Befehle einzeln im Terminal aus:
node run.mjs before
node run.mjs after
node run.mjs migrated
after soll mit Code 1 enden. Verknüpfen Sie die Befehle nicht mit &&, sonst stoppt die Ausführung vor der migrierten Version. Alle drei Modi laden dieselben Assertions aus tests.mjs.
| Version | Bestanden | Fehlgeschlagen | Exit-Code |
|---|---|---|---|
before: Millisekunden-Helfer, ursprüngliche Verbraucher |
7 | 0 | 0 |
after: Sekunden-Helfer, ursprüngliche Verbraucher |
4 | 3 | 1, erwarteter Fehler |
migrated: Sekunden-Helfer, angepasste einheitsabhängige Verbraucher |
7 | 0 | 0 |
Die drei fehlgeschlagenen Prüfungen in after betreffen Aktualisierungsentscheidungen bei 30_000 und 31_000 Millisekunden sowie die CSV-Ausgabe. Knapp unter dem Schwellenwert besteht die Prüfung weiterhin. Beide Sortiertests und die Ablehnung eines unbekannten Exporternamens bestehen ebenfalls.
Um Werte zusammen mit den Assertions zu prüfen, führen Sie aus:
node demo.mjs
Bei nowMs = 60_000 beginnt Sitzung alpha bei 15_000, beta bei 57_500. Die ausgegebenen Beobachtungen umfassen:
| Beobachtung | before |
after |
migrated |
|---|---|---|---|
| Aktualisieren bei 30 Sekunden Alter | true |
false |
true |
| IDs von alt nach neu | alpha, beta |
alpha, beta |
alpha, beta |
CSV-Alter von alpha |
45 |
0.045 |
45 |
CSV-Alter von beta |
2.5 |
0.0025 |
2.5 |
demo.mjs gibt Beobachtungen aus; tests.mjs entscheidet, ob sie dem erwarteten Verhalten entsprechen. Der Standardbefehl node --test run.mjs führt nur before aus. Ein grüner Standardlauf validiert daher die vorgeschlagene Änderung nicht.
Betroffene Verbraucher von geprüften unbetroffenen unterscheiden
Das Ergebnis ist nützlicher als eine Referenzanzahl:
| Verbraucher oder Bereich | Befund | Beleg |
|---|---|---|
needsRefresh |
Bestätigt betroffen | Unveränderte Tests des Dreißig-Sekunden-Schwellenwerts schlagen mit dem Sekunden-Helfer fehl. |
oldestFirst |
Regression für geprüfte Eingaben ausgeschlossen | Gemischtes Alter, Sekundenbruchteile, gleiches Alter, Millisekundenunterschiede sowie leere und einelementige Listen behalten die erwartete Reihenfolge; Eingabe bleibt unverändert. |
Gewählter Exporter age-column |
Für diese Konfiguration bestätigt betroffen | Der Test wählt diese Factory und vergleicht die vollständige CSV-Zeichenfolge. Beide Alterswerte sind danach tausendmal zu klein. |
| Andere Bereitstellungskonfigurationen oder Verbraucher außerhalb des Downloads | Unbekannt | Sie wurden weder bereitgestellt noch ausgeführt. |
Auch für das Sortierergebnis gibt es eine Erklärung: Der Vergleich nutzt die Differenz zweier Alterswerte. Division beider Werte durch denselben positiven Faktor erhält für diese Eingaben das Vorzeichen. Die Sortierung braucht relative Reihenfolge, Schwellenwert und Exporter dagegen eine bestimmte Einheit.
Diese Überlegung hilft bei der Testauswahl. Sie erlaubt nicht die Behauptung, alle möglichen Zahlenwerte seien geprüft. Die Fixtures nutzen kleine, endliche ganzzahlige Millisekunden-Zeitstempel. Extreme Gleitkommawerte, ungültige Eingaben, asynchrone Aktualisierungsplanung und ein echter nachgelagerter CSV-Leser liegen außerhalb des Laufs. Der Download enthält einen Exporter und behauptet nichts über produktive Plugin-Bestände.
Einheitsabhängige Verbraucher anpassen
Behalten Sie elapsedAfter. Die migrierte Aktualisierungsfunktion in consumers.mjs vergleicht Sekunden mit Sekunden:
export function needsRefreshSeconds(elapsed, nowMs, lastSyncMs) {
return elapsed(nowMs, lastSyncMs) >= 30;
}
In age-column.mjs gibt registerAgeColumnSeconds direkt measureAge(...) aus und entfernt die zweite Division. app.mjs wählt im Modus migrated diese beiden angepassten Implementierungen. oldestFirst bleibt unverändert.
Die Tests verlangen weiterhin dieselben sichtbaren Ergebnisse: Aktualisierung bei dreißig Sekunden, dieselben sortierten IDs und Sekunden im CSV. Die sieben bestandenen Prüfungen zeigen deren Wiederherstellung für diese Fixture. Ändert Ihr Patch auch Erwartungswerte, prüfen Sie Assertions und Implementierung zusammen, bevor Sie einen grünen Lauf als gleichwertig betrachten.
KI nach der nächsten zu prüfenden Datei fragen
Beim Lesen kann eine optionale KI-Frage die Suche eingrenzen:
Verfolge den als
elapsedübergebenen Helfer, einschließlich Aliasen und registrierten Factories. Zeige für jeden Kandidaten den Code, der eine Einheit voraussetzt oder nur die Reihenfolge nutzt. Nenne Laufzeitauswahl und Testeingabe, mit denen ich die Folge prüfen kann. Trenne ungeprüfte Aufrufer von ausgeführten Ergebnissen.
Prüfen Sie vorgeschlagene Pfade im Quellcode und führen Sie Befehle selbst aus.