Die Frage nach dem Umgang mit Legacy-Code adressiert Tammo noch explizit. Michael Feathers sagt: "Legacy-Code ist Code, für den es keine automatisierten Tests gibt." (aus "Working Effectivly with Legacy Code"). Daraus folgt für die Wartbarkeit: "Lieber schlechten Code mit guten Tests als guten Code ohne Tests." Für die nchträgliche Ausstattung von Code mit Tests bieten sich verschiedene Ansatzpunkte:
- beim Hinzufügen neuer Features
- beim Entfernen von Bugs
- bei Designverbesserungen / Refactorings
- beim Optimieren
Dann muss man immer mind. ein Teil der Programmierung machen, ohne Unittests als Sicherheitsnetz zu haben. Dann eignen sich Akzeptanz- und Integrationstests (z.B. mit FIT). Diese grobgranularen Tests lassen sich relativ einfach für existierenden Code erstellen.
Ein weiterer Ansatzpunkt für das nachträgliche Tests ist aspektorientierte Programmierung (AOP). Dann kann man z.B. nach Ende einer Methode automatisch Werte zu testen. Das hört sich interessant an. Allerdings habe ich bisher noch keinen Fall gesehen, wo das viel genützt hätte. AOP wäre immer nur eine Notlösung, weil der Entwurf unverändert schlecht testbar bleibt.
Dann programmieren Tammo und ich am Beamer etwas vor: Ungetester Code soll erweitert werden. Das ist auch deshalb interessant, weil Tammo den Beispielcode auch nicht kennt. Wir brauchen ca. 30 Minuten, um an einer Stelle eine Entkopplung von der Datenbank herzustellen. Da kommt die Frage auf, ob sich der Aufwand überhaupt lohnt. Tammo antwortet: "Ich warte immer noch auf das Projekt, das von sich sagt, dass zuviel in Qualität und Tests investiert wird. Ein Testproblem ist auch immer ein Entwurfsproblem." Also wird der Aufwand nicht nur für den Test investiert, sondern auch in den Entwurf. Daher wird sich der Aufwand i.d.R. lohnen. Er gibt dann auch die Empfehlung, das Testen und Refaktorisieren in die Entwicklung zu integrieren. Dann "versteckt" man die Aufwände und muss sich nicht dafür rechtfertigen, dass man testet.
Für den Entwurf und das Testen von Anwendungen mit Benutzungsoberflächen stellt Tammo das Model-View-Presenter-Muster (MVP) vor. Beispiel: Es gibt einen BookSearchDialog, der Books sucht.
interface BookSearchView {
void displayBooks(List books);
}
interfaces BookSearchPresenter {
void searchBooks(String name);
}
class BookSearchDialog implements BookSearchView {
// kennt BookSearchPresenter
}
BookSearchFacade implements BookSearchPresenter {
// kennt BookSearchView
}
Der Benutzer tippt den Buchnamen im BookSearchDialog ein und drückt dort auf "Search". Daraufhin ruft der BookSearchDialog am BookSearchPresenter die searchBooks-Methode auf. Diese sucht die passenden Bücher. Das Suchergebnis liefert die searchBooks-Methode nicht direkt zurück, sondern injiziert das Ergebnis in die displayBooks-Methode des BookSearchViews. Der Effekt ist jetzt, dass man den BookSearchDialog testen kann, indem man BookSearchPresenter wegmockt. Und man kann BookSearchFacade testen, indem man den BookSearchView wegmockt.
Das MVP-Muster wirkt auf mich erstmal gewöhnungsbedürftig. Dass man das Zeug gut testen kann, ist allerdings auch ein gewichtiges Argument. Außerdem adressiert das MVP-Muster möglicherweise ein Problem, dass häufig anzutreffen ist: Es gibt vielfältige ungetestete Methoden in den UI-Klassen, die Daten konvertieren. Das MVP-Muster kann dem entgegen wirken, weil die Transformationen in der BookSearchFacade durchgeführt werden. Und nicht zuletzt könnte es Entwürfe nach Quasar sauberer machen. Häufig sind in Quasar-Anwendungen alle UI-Komponenten R-Komponenten und damit "schmutzig". Die Dialog- und View-Klassen nach dem MVP-Muster könnten reine T-Komponenten sein.
Jetzt kommt Groovy dran. Tammo gibt eine Kurzeinführung in Groovy und es gibt eine Diskussion über den Nutzen von Closures. ("Ist Groovy eine Art Java für schreibfaule Entwickler.") Dann werden die Vorteile klarer und ein Teilnehmer stellt die Frage, ob Groovy das kommende Java sei. Wer weiß :-)
Tammo zeigt, wie man sich durch Tests mit Groovy auf Mock-Frameworks vezichten kann. Closures reichen häufig vollkommen aus.
Und dann habe ich ein neues Schlagwort von Tammo gelernt: "Hippie-Completion" bezeichnet die semantikfreie Auto-Completion im IDE. Typischweise guckt der Editor dann nur, ob es gleich beginnende Wörte in der Datei gibt. Diese Art der Completion ist insbesondere bei dynamischen Sprachen wie Groovy sinnvoll.
0 Kommentare:
Kommentar veröffentlichen