Gibt es ein Software-Engineering-Prinzip, das die Kosten für Wiederverwendung und Regressionstests auf einem Produktionssystem in Beziehung setzt?


12

Ich habe an einem großen Finanztransaktionssystem für eine Bank gearbeitet, die sich um Renten und Investitionen kümmerte. Nach 15 Jahren Funktionsänderungen waren die Kosten für den manuellen Regressionstest auf 200.000 USD pro Release gestiegen. (10 Millionen LOC, 10 Millionen US-Dollar pro Tag). Dieses System ist auch mit 19 anderen Systemen im Unternehmen verbunden, die viele Daten übertragen. Dieses System wurde in Java implementiert.

Was wir jedoch beobachten, ist, dass die Kosten für Regressionstests umso höher sind, je mehr wir wiederverwenden. (Der Grund dafür ist, dass Sie "den Code testen müssen, den Sie berühren" - und wiederverwendeten / freigegebenen Code beeinflusst eine Vielzahl von Stellen, wenn er berührt wird. Trotz "DRY - Wiederholen Sie sich nicht" - dh kopieren Sie den Code nicht und fügen Sie ihn nicht ein - Wir sehen einen finanziellen Anreiz, Code zu kopieren und einzufügen, um die Kosten für Regressionstests zu senken, da wir den Code, der gemeinsam genutzt werden kann, nicht ändern möchten, da dies einen großen Einfluss auf die Regressionstests hat.)

Meine Frage ist, ob es ein Software-Engineering-Prinzip gibt, das den Zusammenhang zwischen Wiederverwendungs- und Regressionstestkosten beschreibt.

Der Grund, warum ich diese Frage stelle, ist, dass die Zerlegung des Systems in kleinere zu testende Teile möglicherweise einen Kostenvorteil mit sich bringt.

Annahmen:

  1. "Regressionstest" bedeutet "Abnahmetest" - dh eine andere Gruppe verbringt Zeit damit, neue Tests zu schreiben und alte Tests für das Unternehmen, einschließlich Umgebungs- und Datenkonfigurationen, erneut für das System zu verwenden.

  2. Ich weiß, dass die Reaktion auf die hohen Kosten eines Regressionstests eher automatisierte Tests sind. Das ist ein gutes Prinzip. In diesem Umfeld gibt es einige Herausforderungen.

    (a) Automatisierte Tests sind über Systemgrenzen hinweg weniger nützlich, es sei denn, das System verfügt auch über eine hohe Abdeckung durch automatisierte Tests. (Einflussbereich Herausforderung).

    (b) Wenn Ihr System bereits groß und komplex ist, ist es kulturell schwierig, die Programmiererzeit oder die Kapitalinvestition für eine hohe automatisierte Testabdeckung in Schwung zu bringen.

    (c) Die Kosten für die Aufrechterhaltung automatisierter Tests sind in einem Projekt verborgen, sodass sie auf Projektebene leicht verworfen werden können.

    (d) Dies ist nur die kulturelle Realität der Arbeit in einer Bank.

    (e) Ich arbeite daran, dieses Problem auf andere Weise zu lösen (Zersetzung).


2
Sie machen die handgewellte Aussage, dass " wir beobachten, dass je mehr" Wiederverwendung "wir tun, desto mehr [Akzeptanz-] Testkosten steigen " - könnten Sie das erweitern? Sollte ein Akzeptanztest nicht unabhängig von Implementierungsdetails wie Vererbungshierarchien sein und stattdessen beispielsweise Nutzungsszenarien durchspielen?
amon

2
Ihre Frage ist interessant, enthält aber einige sehr voreingenommene Annahmen wie "Wiederverwendung ist eine Folge von OO" oder den erwähnten Teil @amon. Ich schlage vor, Sie löschen den Teil "OO" vollständig daraus, da Ihre Kernfrage unabhängig von der Programmiersprache oder einer OO-Programmierung ist. Und es ist ziemlich unklar, welche Art von "Wiederverwendung" Sie beabsichtigen - "Wiederverwendung" ist ein weit gefasster Begriff, die Wiederverwendung durch Kopieren und Einfügen unterscheidet sich von der Wiederverwendung von Komponenten oder Bibliotheken.
Doc Brown

Danke, das ist hilfreich. Ich habe Verweise auf OO entfernt und die Idee, gemeinsam genutzten Code (oder Code, der zu gemeinsam genutztem Code wird) zu berühren, erweitert.
Hawkeye

1
In der jetzigen Form würde ich wahrscheinlich nur "Nein, ich glaube nicht" auf Ihre Frage antworten - was für Sie vermutlich nicht sehr befriedigend wäre. Oder interessieren Sie sich für Prinzipien und Vorgehensweisen, um die Testkosten zu senken, wenn Sie ein großes System wie das Ihre mit selbst hergestellten wiederverwendbaren Komponenten bauen?
Doc Brown

Antworten:


11

Wir möchten keinen Code ändern, der freigegeben werden könnte, da dies einen großen Einfluss auf den Regressionstest hat

Oben klingt ungefähr richtig für mich. Je wichtiger der Code ist, je mehr er geteilt wird, desto höher sind die Qualitätsanforderungen, desto mehr sollte die Qualitätssicherung bei Änderungen einbezogen werden.

Da Ihr System in Java implementiert ist, können Sie ein Beispiel in Java-Standardbibliotheken (JDK) sehen. Die Hauptversionen sind selten und werden von aufwändigen Tests begleitet. Selbst kleinere Releases durchlaufen eine sehr umfassende JCK -Testsuite, um zu überprüfen, ob Regressionen vorliegen.

Sie denken vielleicht, dass dies die Entwicklung von gemeinsam genutztem Code irgendwie hemmt, und ... ja, das ist ungefähr richtig. Je mehr Auswirkungen und Risiken mit Codeänderungen verbunden sind, desto sorgfältiger sollten Sie vorgehen, umso mehr Aufwand ist mit dem Testen der Versionen verbunden.

Im Idealfall sollte die Qualität von Veröffentlichungen von weit verbreitetem Code so sein, dass keine großen Änderungen erforderlich sind (abgesehen von seltenen Verbesserungen). Diese Gedankenrichtung spiegelt sich in einem berühmten Zitat von Joshua Bloch wider :

Öffentliche APIs sind wie Diamanten für immer. Sie haben eine Chance, es richtig zu machen, also geben Sie Ihr Bestes.


Wie bereits erwähnt, scheinen einige der von Ihnen beschriebenen Probleme auf eine ineffiziente Strategie zur Entwicklung von gemeinsam genutztem Code zurückzuführen zu sein. Insbesondere sieht es besonders problematisch aus, dass für wiederverwendeten Code nur zwei Optionen in Betracht gezogen werden: entweder diesen Code duplizieren oder ihn sofort in "Kern" -Freigabebibliotheken aufnehmen.

Es ist nicht erforderlich, sich nur auf diese beiden Optionen zu beschränken, und auch hier finden Sie Beispiele dafür, wie dies in dem von Ihnen verwendeten JDK besser gemacht werden kann. Werfen Sie einen Blick auf java.util.concurrentPakete ( JSR 166 ) - bis zum Release von Java 5 waren diese eine separate Bibliothek und nicht Teil der Kern-JDK-Releases.

Denken Sie daran, das ist eine dritte Option, die Sie übersehen haben, und eine ziemlich pragmatische, die Sie bei der Einführung von neuem gemeinsam genutzten Code berücksichtigen müssen. Wenn Sie sich nur einen Code ausdenken, der von zwei bis drei Komponenten gemeinsam genutzt werden kann, müssen Sie ihn nicht sofort in die Kern-API des Systems aufnehmen.

Sie können diesen "unausgereiften" gemeinsam genutzten Code als separate Bibliothek packen und freigeben, genau wie dies bei gleichzeitig ausgeführten Java-Dienstprogrammen der Fall war. Auf diese Weise müssen Sie keine vollständigen Regressionstests durchführen, da Sie nur eine relativ kleine Menge der beteiligten Komponenten verwenden können. Infolgedessen haben Sie mehr Spielraum, um diesen gemeinsam genutzten Code zu ändern und zu verbessern und zu testen, wie er in der Produktion funktioniert.

Nachdem Ihre Bibliothek ausgereift und stabil genug ist, um Ihnen die Gewissheit zu geben, dass weitere Änderungen unwahrscheinlich sind, können Sie ihre Aufnahme in die Kernbibliotheken des Systems in Betracht ziehen, genau wie die gleichzeitigen Dienstprogramme, die schließlich in JDK aufgenommen wurden.


Ein konkretes Beispiel dafür, wie viel Aufwand (einschließlich Testen) mit dem Ändern von häufig wiederverwendetem Code verbunden sein kann, findet sich wiederum in JDK. In Release 7u6 wurde die interne StringDarstellung geändert , was zu einer substringLeistungsänderung führte. Kommentare eines Feature-Entwicklers bei Reddit beschreiben, wie viel Aufwand mit dieser Änderung verbunden war:

Die erste Analyse stammt aus der GC-Gruppe im Jahr 2007 ...

Intern unterhält das Oracle-Leistungsteam eine Reihe repräsentativer und wichtiger Apps und Benchmarks, anhand derer sie Leistungsänderungen bewerten. Diese Apps waren für die Bewertung der Änderung der Teilzeichenfolge von entscheidender Bedeutung. Wir haben uns sowohl die Leistungsänderungen als auch die Änderungen des Footprints genau angesehen. Wie bei jeder wesentlichen Änderung kam es auch bei einigen Apps zwangsläufig zu Rückgängen und bei anderen zu Zuwächsen. Wir haben die Regressionen untersucht, um festzustellen, ob die Leistung noch akzeptabel war und die Richtigkeit beibehalten wurde ...

Meine Antwort erhebt keinen Anspruch auf Vollständigkeit, ist aber eine sehr kurze Zusammenfassung der fast sechsmonatigen Arbeit ...


Anscheinend haben wir beide parallel an einer Antwort gearbeitet, mit vielen ähnlichen Gedanken ...
Doc Brown

@DocBrown ja, es ist interessant , dass wir auch fast gleichzeitig beantwortet, etwa eine Stunde nach Frage in Form bearbeitet wurde
gnat

9

Ich glaube nicht, dass es Metriken zur Berechnung der "Kosten für Regressionstests / LOC von wiederverwendetem Code" gibt. Und ich glaube nicht, dass jemals jemand so viel Zeit und Geld investiert hat, um dasselbe "große" System zweimal zu bauen, eine Version mit vielen wiederaufladbaren Komponenten und eine ohne, um ernsthafte Nachforschungen anzustellen.

Aber ich habe schon früher Probleme durch Wiederverwendung gesehen, und vielleicht sind Sie an einigen Überlegungen interessiert, wie Sie damit besser umgehen können.

Erstens ist es nicht die Wiederverwendung, die Ihr Problem ist, sondern der Versuch, Ihre eigenen wiederverwendbaren Komponenten zu erstellen und systemweit zu verwenden. Ich bin mir sicher, dass Sie große Softwarepakete häufig wiederverwenden, wenn Ihre Probleme nicht auftreten: Denken Sie an den gesamten Java-Stack, den Sie verwenden, oder an Komponenten von Drittanbietern (vorausgesetzt, Sie waren mit diesen Komponenten zufrieden). Aber was ist anders an dieser Software, zum Beispiel den Java-Bibliotheken, während Ihre eigenen wiederverwendbaren Komponenten Ihnen so viele zusätzliche Kosten für Regressionstests verursachen? Ich denke, hier sind einige Punkte, die anders sein könnten:

  • Diese Komponenten sind sehr ausgereift und stabil

  • Sie werden isoliert von einer völlig anderen Organisation entwickelt und vollständig getestet

  • um sie (wieder) zu verwenden, müssen Sie sie nicht ändern (in der Tat könnten Sie nicht einmal, wenn Sie das möchten, da Sie den Quellcode nicht pflegen)

  • Sie erhalten nicht täglich eine neue Version, nur kleinere Updates (maximal pro Monat) oder größere Updates in Intervallen pro Jahr

  • Die meisten Updates sind zu 100% abwärtskompatibel, insbesondere kleinere Updates

Um Ihre eigenen wiederverwendbaren Komponenten erfolgreicher zu machen, sollten Sie einige dieser Dinge von oben für Ihre eigene Entwicklung anpassen:

  • Haben Sie für jede wiederverwendbare Komponente eine klare Verantwortung, die die Wartung durchführt, und stellen Sie sicher, dass alle Personen, die eine Komponente wiederverwenden, umgehend einen Bugfix erhalten, wenn Probleme auftreten.

  • Richten Sie strikte Versions- und Freigaberichtlinien ein. Wenn Sie eine wiederverwendbare Komponente entwickeln, geben Sie sie nicht jeden Tag "für jedermann" frei (zumindest nicht, wenn dies bedeuten würde, einen vollständigen 200.000-Dollar-Regressionstest für das System durchzuführen). Lassen Sie stattdessen neue Versionen nur von Zeit zu Zeit veröffentlicht werden, und stellen Sie Mechanismen bereit, mit denen Benutzer dieser Komponente die Änderung der neuen Version aufschieben können.

  • Je öfter eine Komponente wiederverwendet wird, desto wichtiger ist die Bereitstellung einer stabilen Schnittstelle und eines abwärtskompatiblen Verhaltens.

  • wiederverwendbare Komponenten benötigen sehr vollständige Testsuiten, um sie isoliert zu testen.

Viele dieser Faktoren bedeuten, dass die Kosten für den Bau der Komponente selbst steigen, aber auch die Kosten für Änderungen, die durch fehlgeschlagene Regressionen verursacht werden, sinken.


0

Während es aufgrund der Notwendigkeit weiterer Tests zu einem "beobachtbaren" Kostenanstieg kommen kann, macht diese Art der Umgestaltung den Code in der Regel in Zukunft besser wartbar, wenn Sie die technische Verschuldung im System verringern.

Dies sollte hoffentlich zukünftige Fehler reduzieren und die Implementierung neuer Funktionen oder Änderungen an vorhandenen Funktionen vereinfachen.

Mit "einfacher" meine ich, sie sollten weniger Zeit in Anspruch nehmen und daher weniger kosten.

Reduzieren, einfacher und weniger sind hier alles ziemlich nebulöse Begriffe, und jede zukünftige Einsparung (oder vielmehr erhoffte Einsparung) kann nicht berechnet werden, da dies noch nicht geschehen ist.

Eine einfachere Codebasis sollte es neuen Mitarbeitern oder vorhandenen Mitarbeitern ermöglichen, schneller mit dem Projekt zu beginnen, insbesondere bei großen Systemen.

Dies kann auch die Fluktuation des Personals verringern, da die Moral der vorhandenen Projektmitglieder verbessert werden könnte.

Es ist natürlich nicht garantiert, dass Sie diese Vorteile erhalten, aber dies sind Dinge, die neben den messbaren Kosten (wie erhöhten Tests) berücksichtigt werden sollten.

Tatsächlich sollte ein besserer Code die Testkosten im Laufe der Zeit senken, auch wenn aufgrund Ihrer Beschreibung eine anfängliche Zunahme zu verzeichnen ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.