Blog
Testen Sie Ihre Legacy-Anwendungen in der Produktion, um sie sicher auslaufen zu lassen.

Viele von uns haben mit Altlasten zu tun. Denken Sie an eine Anwendung, die veraltete Technologien verwendet oder die nicht ausreichend dokumentiert und getestet wurde. Irgendwann werden diese Anwendungen zu einer Belastung. Folglich muss man sich bemühen, sie entweder drastisch zu verbessern oder sie ganz abzuschaffen.
Die Ausgestaltung dieser Bemühungen ist nicht trivial. Wir wollen modernisieren, aber natürlich ohne Rückschritte. Diese Legacy-Anwendungen bieten notwendige Funktionen, auch wenn wir vielleicht nicht einmal wissen, was diese Funktionen eigentlich beinhalten. Ein guter Ansatz ist es, schrittweise vorzugehen - kleine Teile zu ersetzen oder zu refaktorisieren.
Vor kurzem war ich Teil eines Teams in einer E-Commerce-Umgebung, und wir standen vor der Herausforderung, eine Altanwendung auslaufen zu lassen. Diese Anwendung war die Plattform, die für fast alle E-Commerce-Funktionen verantwortlich war, vom Einkaufskorb bis zur Abwicklung. Wir verfolgten den Ansatz, die Funktionalität zu extrahieren, indem wir an den Rändern begannen, mit der Zahlung und der Abwicklung, und uns langsam nach innen zum Warenkorb und zum Bestellprozess vorarbeiteten. Stück für Stück konnten wir so das gesamte System ersetzen.
Nun stellt sich die Frage, wie man mit einem solchen Stück effektiv umgehen kann.
Bevor wir beginnen: Isolieren Sie den Bereich
Bevor wir mit der Produktion beginnen können, müssen wir herausfinden, was genau wir entwickeln sollen. Was ist der Funktionsumfang des Teils, das wir ersetzen wollen? Bestehende Tests, sofern vorhanden, können eine gewisse Hilfe sein. Der Code selbst könnte eine Quelle sein, die man sich ansehen sollte, wenn der Code gut lesbar ist. Meine bevorzugte Strategie besteht darin, die öffentlichen Schnittstellen zu identifizieren, die die Funktionalität innerhalb unseres Geltungsbereichs bieten, und dann damit zu beginnen, neue Tests hinzuzufügen. Michael Feathers beschreibt eine Charakterisierungstest Prozess zur Ermittlung der Funktionalität einer Software.
Die Isolierung des Bereichs mit einer Reihe von Tests funktionierte gut für uns, als wir die Zahlungsfunktionalität extrahierten. Als es an der Zeit war, die Funktion zur Berechnung des Warenkorbwerts in einen separaten Dienst zu migrieren, standen wir vor einer weiteren Herausforderung. Die eingehende Anfrage für diese Berechnung enthielt viele Daten, die das Ergebnis beeinflussen, z.B. die Produkte des Warenkorbs, hinzugefügte Rabatte, einige Benutzerdaten und Informationen zur Lieferkette. Die Geschäftsregeln waren nicht immer klar. Es war jedoch zwingend erforderlich, dass sie sich nicht änderten.
Wir können endlos viel Zeit damit verbringen, Tests hinzuzufügen und den Code zu untersuchen. Die Chancen stehen gut, dass wir niemals alle in der Software verborgenen Geschäftsregeln vollständig herausfinden werden. Wir können nie sicher sein, dass wir die vorhandene Funktionalität richtig umgesetzt haben, wenn wir nicht das Feedback aus der Produktion nutzen.
Testen in der Produktion
Unsere Benutzer können eine wertvolle Quelle für Testdaten sein. Wenn wir die Produktionsdaten duplizieren und sie an unsere neue Implementierung weiterleiten, können wir damit die Leistung der Anwendung überprüfen. Bei dieser Validierung liefert die Legacy-Anwendung die erwartete Antwort. Dieser Validierungsprozess ähnelt demjenigen, den das Tool Diffy verwendet, um eine neue Version desselben Dienstes zu validieren.
Dieser Prozess besteht aus zwei Teilen, die kompliziert werden können:
Zunächst möchten wir den Datenstrom so nah wie möglich an der Grenze unseres isolierten Bereichs duplizieren. Wenn diese Grenze ein einfacher REST-Dienst ist, können wir die Anfrage vielleicht in einem API-Gateway duplizieren. In anderen Fällen müssen wir selbst einen Duplizierungsmechanismus bereitstellen. Wir sollten den Benutzer in keiner Weise behindern. Die duplizierte Anfrage sollte asynchron verarbeitet werden und nicht viele Ressourcen beanspruchen, um Leistungseinbußen zu vermeiden.
Zweitens handelt es sich bei der Validierung oft nicht um einen einfachen Vergleich von Antworten. Wenn wir die Antworten vergleichen, können sie unterschiedlich modelliert sein. In anderen Fällen kann der eingehende Datenstrom Seiteneffekte in einer Datenbank verursachen oder eine Nachricht in eine Warteschlange stellen, die wir für unseren Vergleich benötigen.
Bevor wir dieses Verfahren zur zusätzlichen Validierung unserer Software einsetzen, müssen wir uns ein klares Bild davon machen, was wir validieren wollen und ob sich der Aufwand lohnt. Diese Analyse kann sehr zeitaufwändig sein. Mein Rat ist, klein anzufangen und zu experimentieren. Hören Sie auf, wenn der zusätzliche Nutzen gering oder zu kostspielig ist.
In der Praxis: die Berechnung des Warenkorbs
Im Falle unserer Warenkorbberechnungsfunktion wollten wir herausfinden, ob es irgendwelche Kombinationen eingehender Daten gibt, die das Berechnungsergebnis ohne unser Wissen beeinflussen. Unser Berechnungsergebnis sollte dasselbe sein wie das Ergebnis der alten Anwendung.
Um unsere neue Implementierung zu validieren, haben wir den REST-Endpunkt für die Berechnung erweitert. Als die ursprüngliche Antwort an das konsumierende System zurückgeschickt werden sollte, riefen wir asynchron einen speziellen Schattenendpunkt unseres neuen Dienstes auf. Wir haben die ursprüngliche Anfrage und die ursprüngliche Antwort zu diesem Aufruf hinzugefügt. Mit der Anfrage riefen wir den neuen Dienst auf und validierten die Antwort des neuen Dienstes mit der ursprünglichen Antwort. Die Validierung bestand aus dem Vergleich aller Geldbeträge.
Wir fügten ein Dashboard hinzu, das eine Erfolgsmetrik und die Daten der fehlgeschlagenen Anfragen in unserem Observability-Tooling anzeigt. Unsere erste Version hatte eine Erfolgsquote von ~50%, einfach weil wir noch keine Rabatte implementiert hatten. Die vollständige Version war zu etwa 85% genau. Wir hatten u.a. eine Geschäftsregel in Bezug auf die Lieferkosten falsch interpretiert. Am Ende erreichten wir eine konstante Genauigkeit von etwa 99%.
Warum es in Ordnung ist, keine 100%ige Genauigkeit zu haben
Warum also nicht 100%? Nun, aus einer Reihe von Gründen:
Aufdeckung von Fehlern - genau wie beim Charakterisierungstest ist der Mechanismus zur Verwendung von Produktionsdaten für die Validierung eine Methode der Entdeckung. Wir fanden heraus, dass der ursprüngliche Berechnungsdienst in einigen rabattbezogenen Randfällen einen Rundungsfehler von 1 Cent aufwies.
Verschlechterung verhindern - Wir haben diesen Prozess auch angewandt, als wir einen Algorithmus für das Routing von Paketsendungen ersetzen sollten. Das Ziel des neuen Algorithmus war es, eine Verbesserung zu bieten, so dass die Antworten nicht in allen Fällen gleich sein würden. Wir wollten sicherstellen, dass es keine Leistungseinbußen geben würde. Außerdem wollten wir einen Einblick in die Fälle erhalten, in denen sich die Ergebnisse der Algorithmen unterscheiden würden, um zu sehen, ob der neue Algorithmus tatsächlich die erwartete Verbesserung bietet.
Entdecken Sie unvorhergesehene Nebenwirkungen - Ein weiterer Grund, warum 100 % nicht erreicht werden können, könnte eine unvorhergesehene Nebenwirkung sein. Ein Warenkorb wird immer erst kurz vor dem Absenden der Bestellung berechnet. Da der Vergleich asynchron erfolgt, konnte es vorkommen, dass ein durch einen Gutschein ausgelöster Rabatt nicht mehr anwendbar war; der Gutschein war durch die Bestellung bereits gesperrt.
Verfasst von
Jochum Börger
Unsere Ideen
Weitere Blogs
Contact



