Читать книгу Dojos für Entwickler - Stefan Lieser - Страница 27
Den Kern zerlegen
ОглавлениеNachdem ich diese Komponenten identifiziert hatte, habe ich die Aufgabenstellung Erzeugen der Daten zerlegt. Aufgabe des Testdatengenerators ist es, Datenzeilen zu erzeugen. Dabei soll jede Datenzeile aus mehreren Spalten bestehen. Diese Aufgabe kann in folgende Funktionseinheiten zerlegt werden:
Erzeugen eines einzelnen Wertes,
Erzeugen einer Zeile,
Erzeugen mehrerer Zeilen.
Dabei scheint die Trennung in das Erzeugen einer Zeile und das Erzeugen mehrerer Zeilen auf den ersten Blick möglicherweise etwas merkwürdig. Wenn eine Zeile erzeugt werden kann, genügt doch eine simple Schleife, und schon können mehrere Zeilen erzeugt werden. Dennoch halte ich es für wichtig, diese beiden Funktionseinheiten zu identifizieren. Denn für die testgetriebene Entwicklung ist es nützlich, im Vorfeld zu wissen, welche Funktionseinheiten auf einen zukommen. So fällt es nämlich viel leichter, ausreichende Testfälle zu finden, sprich: die Anforderungen zu klären. Und bei den Anforderungen liegt die Herausforderung eher darin, klar zu definieren, was die Anforderungen an das Erzeugen einer einzelnen Zeile sind. Dies dann zu übertragen auf die Erzeugung mehrerer Zeilen ist in der Tat trivial. Aber ohne die Trennung würde möglicherweise nur eine Funktionseinheit entstehen, die mehrere Datenzeilen erzeugt. Das würde die testgetriebene Entwicklung unnötig erschweren.
Nachdem ich für das Erzeugen der Daten die Funktionseinheiten identifiziert hatte, habe ich überlegt, welche davon Komponenten werden sollen. Erst Komponenten erlauben eine parallele Entwicklung von Funktionseinheiten durch mehrere Entwickler oderTeams gleichzeitig. Dies ist zwar hier nicht das Ziel, doch resultiert aus der Trennung von Kontrakt und Implementierung, dass die Komponenten austauschbar sind. Dies betrachte ich beim Testdatengenerator an einer Stelle für besonders wichtig: bei den Generatoren. Die werden später sicher immer wieder ergänzt werden. Da ist es hilfreich, wenn dann nicht jeweils die gesamte Anwendung neu übersetzt werden muss, sondern neue Generatoren mit geringem Aufwand ergänzt werden können. In einer weiteren Ausbaustufe wäre es sogar denkbar, die Generatoren zur Laufzeit zu laden. Dann könnten später beliebige zusätzliche Generatoren verwendet werden, ohne dass am Testdatengenerator selbst etwas geändert werden muss.
Damit sind die Generatoren zunächst einmal eine Komponente. Eine andere Aufteilung wäre ebenfalls denkbar, man könnte Generatoren zum Beispiel nachTyp in Komponenten zusammenfassen. Eine Komponente mit Stringgeneratoren, eine für int-Generatoren et cetera. Zurzeit sind es nur wenige Generatoren, daher habe ich mich dafür entschieden, sie alle in einer Komponente unterzubringen. Innerhalb der Komponente habe ich die Generatoren nach Typ in Unterverzeichnisse geordnet. Dies ist in Abbildung 5 zu sehen.
[Abb. 5] Generatoren, nach Typ geordnet, in Unterverzeichnissen.
Eine weitere Komponente bildet die Funktionseinheit, die dafür zuständig ist, Zeilen aus Einzelwerten zu bilden. Diese Komponente habe ich DataPump genannt.
Eine dritte Komponente bildet das Speichern der Daten. Implementiert habe ich einen CsvDataAdapter. Ein DbDataAdapter zum Speichern der Testdaten in einer Datenbank liegt auf der Hand, auf diesen habe ich aus Zeitgründen jedoch verzichtet. Übergangsweise kann man sich damit behelfen, die CSV-Dateien mit einem ETL-Prozess (Extract, Transform, Load) in die Datenbank zu schaufeln.
Die Komponenten Generators, Data-Pump, DbDataAdapter und CsvDataAdapter haben nur geringe Abhängigkeiten, wie Abbildung 6 zeigt. Der CsvDataAdapter ist nicht von den anderen Komponenten abhängig, weil er lediglich auf dem gemeinsamen Datenmodell aufsetzt.
[Abb. 6] Abhängigkeitsdiagramm der Komponenten.