So teilen Sie ein großes Java-Projekt in kleinere Komponenten

7

Wir haben versucht, eine große Codebasis in logische Module zu unterteilen. Ich würde gerne einige Empfehlungen für Tools sowie alle Erfahrungen, die Sie mit dieser Art von Dingen haben könnten, haben.

Die Anwendung besteht aus einer Server WAR und mehreren Rich-Clients, die in JARs verteilt sind. Das Problem ist, dass es alles in einer großen, haarigen Codebasis, einem Quellbaum von & gt; 2k Dateien Krieg. Jede JAR verfügt über eine dedizierte Klasse mit einer main -Methode, aber das Gewirr von Abhängigkeiten ist schnell verzwickt. Es ist gar nicht so schlecht, gute Praktiken wurden konsequent befolgt und es gibt Komponenten mit spezifischen Aufgaben. Es braucht nur einige Verbesserungen, um unserem Team zu helfen, zu wachsen.

Die Module befinden sich jeweils in einem Maven-Projekt, das von einem Eltern-POM erstellt wurde. Der Prozess hat bereits damit begonnen, jedes JAR / WAR in sein eigenes Projekt zu verschieben, aber es ist offensichtlich, dass dies nur die Oberfläche kratzen wird: ein paar Klassen in jeder App JAR und ein Mammut- "Legacy" -Projekt mit allem anderen. Außerdem gibt es bereits einige Einheiten- und Integrationstests.

Jedenfalls bin ich an Tools, Techniken und allgemeinen Ratschlägen interessiert, um eine zu große und verwickelte Code-Basis in etwas überschaubarer zu zerlegen. Free / Open Source ist bevorzugt.

    
sblundy 15.11.2008, 20:17
quelle

6 Antworten

8

Schauen Sie sich eine Struktur 101 an. Es ist großartig, Abhängigkeiten zu visualisieren und die Abhängigkeiten aufzuzeigen, die auf Ihrem Weg zu einer saubereren Struktur zu brechen sind.

    
Jens Schauder 15.11.2008 20:52
quelle
6

Wir haben kürzlich eine ähnliche Aufgabe erfüllt, d. h. ein Projekt, das aus & gt; 1k Quelldateien mit zwei Hauptklassen, die aufgeteilt werden mussten. Wir hatten vier verschiedene Projekte, eines für die Basis-Utility-Klassen, eines für das Client-Datenbank-Zeug, eines für den Server (das Projekt ist eine RMI-Server-Client-Anwendung) und eines für das Client-GUI-Zeug. Unser Projekt musste getrennt werden, da andere Anwendungen den Client nur als Befehlszeile verwendeten und wenn Sie versehentlich eine der gui-Klassen verwendet haben, gab es kopflose Ausnahmen, die nur beim Start auf dem headless Deployment Server auftraten.

Einige Dinge, die wir aus unserer Erfahrung wissen sollten:

  • Verwenden Sie einen ganzen Sprint zum Trennen der Projekte (lassen Sie andere Aufgaben nicht die Aufteilung stören, denn Sie benötigen die ganze Zeit eines Sprints)
  • Verwenden Sie Versionskontrolle
  • Unit-Tests schreiben bevor Sie die Funktionalität woanders hin verschieben
  • Verwenden Sie ein kontinuierliches Integrationssystem (spielt keine Rolle, ob zuhause oder aus der Box)
  • Minimieren Sie die Anzahl der Dateien im aktuellen Changeset (Sie sparen sich viel Arbeit, wenn Sie einige Änderungen rückgängig machen müssen)
  • Verwenden Sie vor dem Verschieben von Klassen ein Abhängigkeitsanalyse-Tool (wir haben mit DependencyFinder gute Erfahrungen gemacht) )
  • Nehmen Sie sich die Zeit, die Pakete in sinnvolle Paketpakete pro Projekt zu strukturieren
  • Haben Sie keine Angst, Interfaces zu ändern, sondern haben alle abhängigen Projekte im Arbeitsbereich, so dass Sie alle Kompilierungsfehler bekommen
Daniel Hiller 17.11.2008 06:39
quelle
2

Zwei Ratschläge: Das erste, was Sie brauchen, ist Test-Suiten. Der zweite Ratschlag besteht darin, in kleinen Schritten zu arbeiten.

Wenn Sie bereits eine starke Testsuite haben, sind Sie in einer guten Position. Ansonsten würde ich einige gute High-Level-Tests (aka: Systemtests).

Der Hauptvorteil von High-Level-Tests ist, dass eine relativ geringe Anzahl von Tests eine gute Abdeckung erzielen kann. Sie werden Ihnen nicht helfen, einen Fehler zu lokalisieren, aber Sie werden das nicht wirklich brauchen: Wenn Sie in kleinen Schritten arbeiten und sicherstellen, dass die Tests nach jeder Änderung ausgeführt werden, können Sie schnell erkennen (versehentlich eingeführt) Bugs: Die Wurzel des Bugs ist in dem kleinen Teil des Codes seit der letzten Ausführung der Tests geändert worden.

    
Itay Maman 15.11.2008 20:35
quelle
1

Ich würde mit den verschiedenen Aufgaben beginnen, die Sie ausführen müssen.

Ich hatte vor kurzem eine ähnliche Aufgabe, da ich eine 15 Jahre alte Codebasis hatte, die von einer Reihe von Entwicklern erstellt wurde, die untereinander keine Kommunikation hatten (eine arbeitete am Projekt, links, dann eine andere) eingestellt, usw., ohne Übersprechen). Das Ergebnis ist ein totaler Mischmasch von sehr unterschiedlichen Stilen und Qualitäten.

Damit es funktioniert, mussten wir die notwendige Funktionalität isolieren, die sich vom dekorativen Flaum unterscheidet, damit alles funktioniert. Zum Beispiel gibt es eine Menge verschiedener String-Klassen und eine Person hat viel Zeit damit verbracht, eine 2k-Zeilen-Conversion zwischen COleDateTime zu const char* und wieder zurück zu machen; Das war Fluff, Code, um eine Aufgabe zu lösen, die neben dem Hauptziel stand (Dinge in und aus einer Datenbank zu bekommen).

Was wir letztendlich tun mussten, war ein großes Ziel zu identifizieren, das dieser Code erreichte, und dann die Basislogik dafür zu schreiben. Wenn es eine Aufgabe gab, die wir erledigen mussten, die wir schon vorher gemacht hatten, fanden wir sie und verpackten sie in Bibliotheksaufrufe, so dass sie alleine existieren konnte. Ein Code-Chunk aktiviert beispielsweise einen USB-Gerätetreiber, um ein Bild zu erstellen. Dieser Code bleibt von diesem aktuellen Projekt unberührt, wird aber bei Bedarf über Bibliotheksaufrufe aufgerufen. Ein anderer Code-Chunk funktioniert mit dem Sicherheits-Dongle, und ein anderer fragt Remote-Server nach Daten ab. Das ist alles notwendige Code, der gekapselt werden kann. Der Zeichnungscode war jedoch über 15 Jahre lang gebaut worden, und solch ein Gebäude zum Wahnsinn, dass ein OpenGL-Umschreiben im Laufe eines Monats die Zeit besser nutzte, als zu versuchen herauszufinden, was jemand anderes getan hatte und dann hinzuzufügen dazu.

Ich bin ein bisschen handwavy hier, weil unser Projekt MFC C ++ zu .NET C # war, aber die Grundprinzipien gelten:

  1. finde das Hauptziel
  2. Identifizieren Sie alle kleinen Ziele, die das Hauptziel ermöglichen
  3. Isolieren Sie die bereits gekapselten Codeteile, falls vorhanden, als Bibliotheksaufrufe
  4. finde die Logik heraus, um alles zusammenzufügen.

Ich hoffe, das hilft ...

    
mmr 15.11.2008 20:46
quelle
1

Um Itays Antwort fortzusetzen, empfehle ich, Michael Feathers "Effektiv mit Legacy-Code arbeiten" (pdf) . Er empfiehlt außerdem, jeden Schritt mit Tests zu untermauern. Es gibt auch eine Buchversion .

    
Yuval F 17.11.2008 07:42
quelle
1

Maven ermöglicht es Ihnen, kleine Projekte als Kinder eines größeren zu erstellen. Wenn Sie einen Teil Ihres Projekts als separate Bibliothek für andere Projekte extrahieren möchten, können Sie dies auch mit maven tun.

Nachdem Sie das gesagt haben, müssen Sie definitiv Ihre Aufgaben dokumentieren, was jedes kleinere Projekt erreichen wird, und dann (wie hier schon mehrfach angegeben) testen, testen, testen. Sie benötigen Tests, die das gesamte Projekt durchlaufen, und dann Tests, die mit den einzelnen Teilen des Projekts arbeiten, die als Kinderprojekte enden.

Wenn Sie anfangen, Funktionen zu entfernen, benötigen Sie zusätzliche Tests, um sicherzustellen, dass Ihre Funktionalität konsistent ist und dass Sie die Eingabe in Ihre verschiedenen untergeordneten Projekte simulieren können.

    
Spencer Kormos 17.11.2008 16:41
quelle

Tags und Links