Architektur als Belastung

Während meiner Karriere arbeitete ich mit verschiedenen Legacy-Projekten, von denen jedes unter verschiedenen Mängeln litt.


Das Hauptproblem war natürlich oft die schlechte Qualität der Software (fehlende Komponententests, Weigerung, die Prinzipien des sauberen Codes zu verwenden ...), aber es gab auch Schwierigkeiten, deren Ursache die zu Beginn des Projekts oder sogar zu Beginn des Unternehmenssystems getroffenen Architekturentscheidungen waren. Meiner Meinung nach ist diese Klasse von Problemen die Ursache für die größten Schmerzen bei vielen Projekten.


Im Wesentlichen ist die Verbesserung des Codes ziemlich einfach, insbesondere jetzt, da die Software-Handwerksbewegung bewährte Verfahren in Teams fördert. Das Ändern der Kernteile von Systemen, die zu Beginn ihres Lebenszyklus auferlegten Einschränkungen, ist jedoch eine äußerst schwierige Aufgabe.


Ich erzähle Ihnen von verschiedenen Arten von Architekturlösungen, die mir begegnet sind und die für Teams, die an der Unterstützung solcher Systeme beteiligt sind, zu einer echten Belastung werden können.



Ihr gesamtes Unternehmen teilt Ihre Datenbank


Dies ist vielleicht eines der häufigsten Probleme, die ich gesehen habe. Wenn mehrere Anwendungen gemeinsam genutzte Daten verwenden müssen, warum gewähren wir ihnen dann nicht einfach gemeinsamen Zugriff auf eine gemeinsam genutzte Datenbank? Duplizierung wird in der Softwareentwicklung doch als böse angesehen, oder? Nun, das ist nicht immer wahr, besonders wenn es um die Datenbank geht. Venkat Subramaniam drückte es so aus: "Die Datenbank ist wie eine Zahnbürste: Lassen Sie sie niemals von jemandem benutzen." Was ist so schlimm daran, eine Datenbank zu teilen? In der Tat ziemlich viel ...


Das erste, was mir in den Sinn kommt, ist die Kopplung des Datenmodells. Stellen Sie sich vor, zwei Anwendungen, A und B, verarbeiten Daten zu Autos. Anhang A wird von dem Team verwendet, das für die Reparaturarbeiten verantwortlich ist, und daher müssen viele technische Informationen gespeichert werden: über Mechanik, Pannen, Verlauf der Eingriffe in das Auto ... Anhang B wird verwendet, um Aufgaben für das technische Team festzulegen, sodass nur grundlegende Informationen über das Auto benötigt werden, die für ausreichen seine Identifizierung. In diesem Fall ist es nicht sinnvoll, für beide Programme dieselbe Datenstruktur zu verwenden: Sie verwenden unterschiedliche Daten, daher sollte jedes seine eigene Datenstruktur verwenden. Dies wird erleichtert, da das Auto leicht zu identifizieren ist und keine allgemeine Referenz erforderlich ist.


Das zweite Problem ist auch auf diese Vernetzung des Datenmodells zurückzuführen. Stellen Sie sich vor, dass Anwendung B die Fahrzeugkennung umbenennen möchte - geben Sie ihr einen logischeren Namen in Bezug auf ihren Themenbereich. In diesem Fall muss auch Anwendung A aktualisiert werden - der Spaltenname hat sich geändert ... Um das Team von Anwendung A nicht zu stören, beginnen Entwickler B, Informationen in einer anderen Spalte zu duplizieren, da sie eine vorhandene Spalte nicht ändern können ... Entwickler A wird dies natürlich sagen Sie planen, den Namen der Spalte in Zukunft zu ändern, um nicht dieselben Informationen in zwei Spalten zu speichern, aber wir alle wissen: Höchstwahrscheinlich wird dies niemals geschehen ...


Noch ekelhafter wird es, wenn Anwendungen Daten aus einer Quelle nicht nur lesen, sondern auch ändern! Wer ist in diesem Fall der Dateneigentümer? Wem kann man vertrauen? Wie kann die Datenintegrität gewährleistet werden? Dies ist selbst dann schwierig, wenn dieselben Daten von verschiedenen Teilen derselben Anwendung geändert werden. Wenn jedoch mehrere unterschiedliche Anwendungen dies tun, wird das Problem viel schwerwiegender ...


Der letzte Fall, den ich gesehen habe: Zwei Anwendungen, die dieselbe Datenstruktur zum Speichern von Informationen über zwei Geschäftsobjekte verwenden, sind relativ ähnlich, aber gleichzeitig unterschiedlich genug, um das Verständnis der Anwendung, auf die sich die Daten beziehen, ernsthaft zu erschweren. Beide Anwendungen verwendeten dieselbe Tabelle, um Ausführungen auf dem Finanzmarkt zu modellieren, jedoch mit unterschiedlichen Aggregationsebenen. Nichts deutete darauf hin, dass die Tabelle Daten von zwei Typen enthält, daher mussten wir uns eine andere Tabelle (die zur zweiten Anwendung gehört) ansehen, um die von jedem der Programme generierten Zeilen zu bestimmen ... Jeder neue Entwickler, der mit dieser Tabelle arbeiten musste, kam unweigerlich auf dem gleichen Rechen wie alle seine Vorgänger und verwendet falsche (anfällige) Daten, mit allen Risiken, die sich daraus für das Unternehmen ergeben.


Ihr System ist an die im Unternehmen verwendete Software gebunden


Nicht jedes Unternehmen kann Software entwickeln, die alle Anforderungen seines Geschäfts erfüllt. In vielen Fällen wäre dies sogar eine Erfindung des Fahrrads, da die Anforderungen vieler Unternehmen gleich sind und es einfach ist, Software auf dem Markt zu finden, die bereits über die erforderliche Funktionalität verfügt.


Im Allgemeinen ist es oft billiger, ein Produkt zu kaufen, als es zu erstellen. Aber das Produkt, das Sie gerade gekauft haben, funktioniert natürlich nicht sofort nahtlos mit der Software, die Sie bereits verwenden. Daher müssen Sie eine Brücke zwischen den beiden (in den meisten Fällen proprietären) Anwendungen schlagen. Sie werden sicherlich Ihre eigenen Tools für bestimmte Teile Ihres Unternehmens entwickeln. Solange diese teure Software, die Sie bereits gekauft haben, über ein geeignetes Modell verfügt, müssen Sie lediglich die Datenbank verwenden und Ihre Daten zu den Tabellen dieser Datenbank hinzufügen ...


Mehrere Jahre vergehen, ein Dutzend Entwickler oder Teams führen diese Aktionen immer wieder aus, und dann befinden Sie sich in einer Sackgasse: Sie können einfach keine andere Software verwenden, wenn der Entwickler der von Ihnen gekauften Software diese schließt oder die Unterstützung des Produkts einstellt oder sich herausstellt, dass es sich um eine neue Software handelt besser auf Ihre Bedürfnisse zugeschnitten. In einigen Fällen können sogar technische Abhängigkeiten von externer Software bestehen. Wenn der Autor der von Ihnen verwendeten Softwarelösung möchte, dass Sie die Version der Sprache / des Frameworks / etwas anderes verwenden, die er benötigt, bedeutet dies, dass Ihre Systemarchitektur nicht Ihnen gehört. Wenn Sie eine neue Version verkaufen möchten, um eine Funktion bereitzustellen, die Sie unbedingt benötigen, diese Version jedoch Änderungen der technischen Anforderungen unterliegt, müssen Sie Ihren Technologie-Stack aktualisieren, um die Empfehlungen anderer zu erfüllen. Ich weiß, wie es sich anfühlt, und Sie möchten nicht, dass eine solche erzwungene Migration häufig vorkommt ...


Ich habe an einem Projekt gearbeitet, bei dem die Entwickler des von uns verwendeten Produkts nicht für alle unsere Kunden neue Funktionen hinzufügen wollten, da es für sie zu schwierig war, Wettbewerbsänderungen und mehrere aktuelle Versionen beizubehalten (jeder Kunde hatte seine eigene Version mit Funktionen, die nur für ihn erforderlich waren). Deshalb haben sie beschlossen, uns das SDK zu verkaufen, damit wir unsere eigenen Funktionen implementieren können. Natürlich lieferten sie nicht genügend Dokumentation dazu, und außerdem mussten wir ihre Geschäftseinheiten verwenden, die wir dekompilieren mussten, um ihre Struktur zu verstehen - da wir weder Quellcode noch Dokumentation hatten ... Implementierung Die einfachste Funktion dauerte mehrere Tage, und es war fast unmöglich, sie zu testen, da alles zu kompliziert war und sogar Kenntnisse einer Skriptsprache erforderte, die niemand im Team mit einem bereits komplexen technologischen Stack kannte ...


Starkes Ineinandergreifen zwischen mehreren Anwendungen


Erinnern Sie sich an die frühen 2000er Jahre: Wie angenehm es war, Enterprise Java Beans (EJB) zu verwenden, um Remote-Anrufe zwischen Anwendungen in Ihrem Informationssystem zu verarbeiten. Zu dieser Zeit schien dies eine gute Idee zu sein. Das Teilen Ihres Codes mit anderen Teams, um Doppelarbeit zu vermeiden, sieht ebenfalls gut aus. Ja, alle Teams waren gezwungen, ihre Anwendungen gleichzeitig auszurollen, um sicherzustellen, dass die binären Abhängigkeiten nicht unterbrochen wurden, aber es machte Spaß, abends mit Kollegen Pizza zu essen, während sie darauf warteten, dass die Anwendung 2 Stunden lang geliefert wurde, oder?


Eigentlich hat es nicht so viel Spaß gemacht. Und die Unmöglichkeit, eine separate Klasse in Ihrem eigenen Code umzugestalten - einfach weil jemand anderes im Unternehmen Ihren Code mochte und sich entschied, ihn in seiner nicht getesteten Anwendung zu verwenden - ist immer noch ein Vergnügen.


Sobald Sie feststellen, wie verwirrt diese frühen Entscheidungen sind, ist der Aufwand, der erforderlich ist, um Ihre Anwendung vom Rest der Welt zu trennen, enorm. Sie sehen, im wahrsten Sinne des Wortes wird es Jahre dauern, bis Ihr Projekt in verschiedene Komponenten unterteilt ist, sodass andere Anwendungen den Kern Ihres Themenbereichs, Ihren Client oder den Caching-Mechanismus nicht mehr verwenden können. alle Aufrufe an externe Klassen zu entfernen, die zu einer starken Verknüpfung mit anderen Projekten führen; Um alle EJB-Aufrufe durch REST-APIs zu ersetzen ... Für all diese Bemühungen wird jedoch jeder mit dem Projekt verbundene Mitarbeiter mehr als belohnt: Entwicklung und Test werden vereinfacht, der Bereitstellungsprozess wird beschleunigt, da Ihre Arbeit jetzt nicht mehr mit jemand anderem synchronisiert werden muss ;; Konzepte in Ihrem eigenen Code werden besser getrennt; Das Abhängigkeitsmanagement wird vereinfacht, Probleme mit transitiven Abhängigkeiten verschwinden, wenn Sie eine Reihe von Abhängigkeiten anderer Anwendungen in Ihren Klassenpfad importieren ... All diese kostspieligen Änderungen retten nur das Leben des Teams und sie könnten viel einfacher zu implementieren sein, wenn Sie sie zu Beginn des Projekts vorgenommen haben!


Sie erstellen Ihr Projekt auf der Grundlage des Projekts eines anderen


Es ist sehr wahrscheinlich, dass Sie auf dieses Problem nicht stoßen, aber es kann trotzdem auftreten. In diesem Fall ist dies das Worst-Case-Szenario, da mehrere der zuvor beschriebenen Probleme kombiniert werden. In Wahrheit bin ich in einem der ersten Projekte meiner beruflichen Laufbahn auf ein ähnliches gestoßen.


Als ich mich dem Projekt anschloss, wurde mir gesagt, dass das Unternehmenssystem komplett neu geschrieben wurde und dass die Arbeit an dem Projekt erst vor zwei Monaten begann. Stellen Sie sich meine Überraschung vor, als ich eine komplexe Webanwendung mit einem vollwertigen Verwaltungsmodul sah, das bereits komplexe Geschäftsfunktionen implementiert und ein entwickeltes Framework zum Schreiben anderer Module entwickelt hat. Bald stellte ich fest, dass das meiste davon nicht von meinem Team geschrieben wurde: Um nicht bei Null anzufangen, wurde beschlossen, das von einem anderen Unternehmen in unserer Gruppe entwickelte Framework wiederzuverwenden. Das Problem war, dass dieses Framework nicht von dem Projekt isoliert war, für das es entwickelt wurde. Unser Team erhielt also einfach ein Archiv mit dem gesamten Quellcode für das Projekt eines anderen Unternehmens, einschließlich der Geschäftslogik, die nichts mit unserem eigenen Geschäft zu tun hatte. Um die Sache noch schlimmer zu machen, haben wir auch das Datenbankschema und die Daten selbst von ihnen geerbt ...


Für einen Neuling im Team war es nicht einfach zu verstehen, welcher Code sich auf das Framework bezieht, der sich auf unser Projekt bezieht und der sich auf das Geschäft eines anderen Unternehmens bezieht. Das Team wollte dieses Durcheinander beseitigen, aber mehrere Versuche, dies zu tun, führten zu schwerwiegenden Regressionsfehlern aufgrund von Abhängigkeiten zwischen den Teilen des Codes (die Sprache nennt es nicht Module, weil es nur ein Modul gab!), Und natürlich gibt es dort keine automatisierten Tests war. Darüber hinaus mussten wir die Idee der Verwendung eines anderen Anwendungsservers aufgeben, da dieser von einem anderen Unternehmen im gesamten System bestimmten Code verwendet hatte, was eine solche Migration für unser kleines Team zu kostspielig machte.


Irgendwann wollten wir dem Framework einige nette Funktionen hinzufügen, aber uns wurde gesagt, dass dies bereits in einem anderen Unternehmen durchgeführt wurde. Deshalb wurden wir gebeten, unsere aktuelle Version mit der aktuellen Version des Codes eines anderen Unternehmens zusammenzuführen ... Das Team konnte diesen Albtraum vermeiden, indem es einfach einige der mit der neuen Funktion verbundenen Commits umleitete (Cherry-Pick), aber es war im Vergleich dazu immer noch zu kompliziert und schwierig was wir brauchten ...


Wir haben es geschafft, dieses Projekt abzuschließen, aber seine Qualität war ein echtes Problem. Mindestens 40% des Codes und des Inhalts der Datenbank waren nicht verwendetes Ballast, und das Entfernen dieses toten Codes hatte keine Priorität. Ich hoffe, das Team hatte endlich die Möglichkeit, seinen eigenen Code zu trennen - ich weiß nicht, ich habe das Team verlassen, bevor dies geschah!


Ihre gesamte Geschäftslogik wird in einem Regelverwaltungssystem gespeichert


Es ist gängige Praxis, einen Teil Ihrer Geschäftslogik in ein Regelverwaltungssystem zu integrieren. Dies ist beispielsweise nützlich, wenn einige Ihrer Geschäftsregeln häufig aktualisiert werden müssen und der Bereitstellungsprozess Ihrer monolithischen Anwendung eine lange Testphase erfordert, bevor Sie den Release-Kandidaten überprüfen können. Dies macht es unmöglich, einige Ihrer „flüchtigen“ Regeln zu konfigurieren. "Regeln. Obwohl ich einen Ansatz bevorzuge, bei dem alle Regeln des Themenbereichs im Quellcode enthalten sind, kann ich verstehen, dass in einigen Situationen ein Regelverwaltungssystem nützlich sein kann.


Ich bin jedoch auf eine Anwendung gestoßen, in der sich fast ALLE Geschäftslogik im Regelverwaltungssystem befand, und manchmal wurden die Regeln basierend auf einer Excel-Datei generiert! Darüber hinaus sollten die Regeln nicht sehr oft geändert werden, da das Projekt im Großen und Ganzen ein einfaches ETL-Paket war . Das Java-Projekt, auf dem all dies basierte, bestand nur aus technischen Details zum Stapelverarbeitungs-Framework und reinem Lese- / Schreibzugriff von den Quell- und Zielsystemen, ohne dass eine Verbindung zum Themenbereich bestand.


Infolgedessen wurden alle Regeln in einer speziellen Sprache geschrieben, die niemand im Team wirklich gut kannte, die schwer zu schreiben war (unsere IDEs unterstützten sie nicht) und die praktisch unmöglich zu debuggen und zu testen war. Wenn eine neue Regel oder eine Änderung an einer vorhandenen angefordert wurde, kopierten die meisten Entwickler in den Teams einfach die vorhandene Regel, was zu vollständig identischen Dateien führte, mit Ausnahme einer bestimmten Änderung (häufig war die einzige solche Änderung das Feld, auf das die Regel angewendet wurde).


Wenn dies bereits als Problem erscheint, dann ist hier noch etwas anderes: Es gab in keiner Regel einen Hinweis auf seinen Zweck. Die Regeln wurden wie Regel1, Regel2 usw. benannt, mit insgesamt über 100! Grundsätzlich bestand jede Regel aus Überprüfungen und der Zuweisung fest codierter Werte ohne Domänenbegriffe. Selbst der Name des Projekts hat den Zweck der gesamten ETL nicht klargestellt.


Fazit


Wie Onkel Bob in seinem Buch „Saubere Architektur“ erklärte, sollten einige Entscheidungen, wenn er über die Architektur seines Projekts nachdenkt, verschoben werden, bis wir wirklich eine Entscheidung treffen müssen, ohne die wir unserem Produkt keinen Mehrwert mehr hinzufügen können (wie die Auswahl einer Datenbank) zum Beispiel). Andere Entscheidungen müssen sehr früh getroffen werden - warten Sie nicht, bis es schlecht wird. Glücklicherweise ist diese Art von kritischen Entscheidungen leicht zu identifizieren, da sie als "Architektur mit Seele" bezeichnet werden können: Wenn Sie über solche Ideen nachdenken, sehen Sie nichts Gutes in ihnen - nur ein Problem, das früher oder später wiederkommt und wird Verfolge dich. Leider ist diese Art von Belastung bei der Arbeit mit Legacy-Projekten oft tief im Code vergraben, was die Beseitigung sehr kostspielig macht.


Aber wir sollten keine Angst haben. Ja, das Aufräumen des Chaos, das sich im Laufe der Jahre und sogar Jahrzehnte angesammelt hat, ist keine leichte Aufgabe, aber als professionelle Softwareentwickler können wir einfach nicht zulassen, dass solche Probleme weiterhin verrotten und die Motivation der Entwickler, das Vertrauen der Kunden und unsere Fähigkeit, ihnen zu helfen, in unser Produkt eingebettet.


Natürlich kann jede Art von architektonischer Belastung, die ich beschrieben habe, auf verschiedene Weise beseitigt werden - es gibt keine Silberkugel, um eines dieser Probleme zu lösen. Ich bin mir jedoch sicher, dass sich jedes Team etwas einfallen lassen kann, um diese Belastung endgültig zu beseitigen. Stellen wir uns also gemeinsam unseren Problemen und beginnen, die Dinge in Ordnung zu bringen!

Source: https://habr.com/ru/post/de427591/


All Articles