Archiv

Autor-Archiv

Buch-Rezension zu “Working Effectively with Legacy Code”

Legacy Code Viele Bücher zeigen wie man mittels TDD sauberen Code schreiben kann. Michael Feathers geht in “Working Effectively with Legacy Code” einen anderen Weg. Er zeigt wie man aus Legacy Code Schritt für Schritt und mit viel Arbeit eine saubere Codebasis schaffen kann.

Dieser Weg ist alles andere als leicht, startet dafür aber dort wo wohl die meisten Software-Projekte sind: Bei einer grossen Menge Code mit nur wenigen (oder gar keinen) Tests und der dennoch geschäftskritische Funktionen erfüllt. Wie erhält man dessen Funktionalität und schafft es gleichzeitig flexibel auf neue Anforderungen zu reagieren?

 

Schritt für Schritt

Wichtig ist das man nicht gleich zu Beginn alles hinwirft. Nur weil der Code noch über keinen einzigen Test verfügt bedeutet dies nicht dass dies so bleiben muss. Im Buch findet man für sehr viele Situationen Tipps und Tricks um mit dem Testen zu beginnen.

Allerdings kann man nicht von einem Extrem in andere springen. Wo noch keine Tests vorhanden sind gleich mit TDD alles machen zu wollen wird sehr schnell scheitern. Besser ist es mit wohlüberlegten und gezielten Tests zu beginnen. Vor der geplanten Änderung erst einmal den Code anschauen und mit Tests auf einer höheren Ebene (wie Integrations- oder Akzeptanztests) beginnen. Oft braucht es auch Mut erst einmal ein Loch aufzureissen um überhaupt einen Test scheiben zu können. Denn wenn man vor dem ändern von Code erst einen Test haben will und für diesen Test erst eine Anpassung am Code braucht steht man vor einem Henne-Ei Problem.

Soll sich die Situation verbessern muss man bereit seit für eine gewisse Zeit mit Code zu leben der nicht allen OO-Regeln folgt. Zusätzliche Konstruktoren nur um Abhängigkeiten zu übergeben sind oft nötig bis dies „korrekt“ gelöst werden kann. Bleibt man dran und geht konsequent den eingeschlagenen Weg kann man auch das grösste Gestrüpp entwirren – dies geschieht aber nicht über Nacht.

 

Einstellung ändern

Aber was ist eigentlich Legacy Code genau und warum ist dies etwas Schlechtes? Feathers hat in seinem Buch zwei Definitionen, von denen man in der Regel nur die weniger freundlich formulierte in Erinnerung behält:

Legacy Code is Code Without Tests

In dem Sinne liegt es bei jedem einzelnen Entwickler aufzuhören vorneweg Legacy Code zu schreiben und sich über die Qualität und Testbarkeit seines Codes Gedanken zu machen. Andernfalls sind all die im Buch aufgezeigten Ansätze für nichts und man ist in kurzer Zeit wieder da wo man begonnen hat.

Was Michael Feathers in seinem Buch leider nicht anspricht ist wie man sein Team von der Notwendigkeit von wartbarem Code überzeugen kann. Genau dies aber dürfte in vielen Projekten wohl das grösste Hindernis sein.

 

Characterization Tests

Von all den verschiedenen Ansätzen die in diesem Buch vorgestellt werden fand ich die Characterization Tests am hilfreichsten. Bei diesen Tests fängt man nicht wie bei TDD mit dem gewünschten Verhalten an und folgt dem Red-Green-Refactor Mantra. Stattdessen beginnt man den Test in dem man beim Assert-Aufruf das Resultat der Methode mit dem Default-Wert des entsprechenden Datentyps vergleicht. Der Test wird in den meisten Fällen fehlschlagen und die Fehlermeldung liefert einem den korrekten Wert. Dieser setzt man dann im Assert-Aufruf ein und hat so einen erfolgreich bestandenen Test.

Ohne den Code anzupassen kann man so recht schnell die einzelnen Eigenschaften einer Methode oder einer ganzen Klasse durch Tests fixieren. Dieses Korsett an Tests dient einem nach dem Refactoring zu verifizieren das die Verbesserungen das Verhalten des Codes nicht verändert haben.

Um Legacy Code mit Tests zu versehen macht man also genau das was bei TDD verpönt ist: Den Test so zu schreiben das der aktuelle Code diesen besteht ohne sich Gedanken über die wirklichen Anforderungen zu machen. Aber genau dies macht diese Art von Tests für mich so praxisrelevant. Hat man Legacy Code muss man auf diesen eingehen und eine Lösung finden die den aktuellen Code beschreibt. Hat man einmal so viele Tests dass man wirklich weiss was der Code macht gilt es wieder den Schalter umzulegen und zu prüfen ob dies auch wirklich korrekt ist. Bis es so weit ist muss man die liebgewordenen Regeln aber auch einmal zurückstellen können.

 

Weiterführende Bücher

Nach dem der Code mit Tests versehen ist geht es ans Aufräumen. Dazu verweist Feathers oft auf Martin Fowlers “Refactoring“. Das Standardwerk zu diesem Thema sollte man kennen, da man ansonsten den Ausführungen kaum folgen kann.

Wer mittels Refactoring grössere Ziele verfolgt sollte auch einen Blick auf “Refactoring to Patterns” von Joshua Kerievsky werfen. Dies baut ebenfalls auf Fowlers Buch auf und erklärt wie man mit einer Kombination von Refactorings grössere Strukturverbesserungen erreichen kann.

 

Fazit

Michael Feathers zeigt einem in diesem Buch wie man von einer durchschnittlichen Codebasis zu einer kommt die dank Tests auf geänderte Anforderungen reagieren kann. Der Weg dorthin ist aber nicht zu unterschätzen und man muss auch einmal bereit sein eine gewisse Unordnung zu akzeptieren. Will man sich darauf einlassen liefert einem dieses Buch viele wertvolle Tipps.

 

Zum Buch

Working Effectively with Legacy Code” von Michael Feathers, 2004 Prentice Hall, ISBN: 978-0-1311-7705-5, 434 Seiten, Englisch

Unterlagen zu “Ruby und Rails für .Net Entwickler” (Luzern)

26. April 2013 1 Kommentar

Die .Net User Group Zentralschweiz gab mir Anfangs Woche die Gelegenheit meinen Ruby und Rails Vortrag für .Net Entwickler zu präsentieren. Gut 6 Monate nach der ersten Präsentation bei der .Net User Group Bern konnte ich so nochmals rund 30 .Net Entwicklern zeigen das es neben C# noch andere interessante Programmiersprachen gibt.

In den letzten Monaten gab es bei Ruby und Rails einige entscheidende Neuerungen. Ruby ist zum 20. Geburtstag in der Version 2 erschienen und Rails 4 liegt nun als Beta vor. Für mich Grund genug neben dem Vortrag auch die Beispiele anzupassen.

 

Unterlagen

Die Präsentation findet sich auf Speakerdeck und kann dort auch als PDF heruntergeladen werden.

Präsentation auf Speakerdeck

 

Beispiele

Die grössere Beispielanwendung zu den Alltagsszenarien habe ich in Rails 4 Beta 1 neu erstellt. Die Aufgabenstellung ist noch dieselbe, die Entwicklungswerkzeuge sind aber um die hilfreichen Tools rund um die Fehlerbehandlung erweitert worden.
Vergleicht man die neue Beispielanwendung mit der für Rails 3.2 kann man so auch die Unterschiede (wie Strong Parameters) zwischen den Rails-Versionen sehen.

 

Weiterführende Informationen

Damit man sich die Links nicht aus den Folien zusammensuchen muss:

Webseiten & Tools

Tools für Windows

Podcasts & Videos

Bücher

In meinem Blog sind alle Beiträge zu Ruby & Rails mit dem Tag Ruby versehen.

 

Danke

Als Abschluss möchte ich mich nochmals bei der .Net User Group Zentralschweiz und den Teilnehmern bedanken. Neben der grossen Teilnehmerzahl freuten mich besonders die guten Gespräche in der Pause und nach dem Vortrag. Ich finde es toll dass es auch in Luzern eine so vielfältige .Net User Group gibt.

Kategorien:Ruby, webDotNet, webRuby Schlagworte: ,

Buch-Rezension zu “Practical Object-Oriented Design in Ruby”

POODR Ein gutes Buch über objektorientiertes Design (OOD) zu finden ist nicht einfach. Obwohl sich viele Bücher diesem Thema widmen fehlt doch immer wieder etwas: Entweder ist das Buch so theoretisch das es keinen Bezug zur Praxis hat oder die notwendige Theorie fehlt.

Practical Object-Oriented Design in Ruby” (kurz POODR) von Sandy Metz findet den Mittelweg zwischen Theorie und Praxis. In einer direkten Sprache wird man Schritt für Schritt an die Thematik OOD herangeführt.
Auch wenn die Beispiele in Ruby sind so ist dieses Buch auch für andere Sprachen sehr zu empfehlen – das benötigte Wissen über Ruby ist minimal und schnell erklärt.

 

Wozu OOD?

Sandy Metz definiert OOD als die Art und Weise wie man Code in einem Programm anordnet. OOD ist somit nicht nur etwas für Experten sondern betrifft jeden Programmierer. Denn jeder der Code schreibt beeinflusst dessen Design.

Design is more the art of preserving changeability than it is the act of achieving perfection.

Ob eine Erweiterung später einfach einzubauen ist hängt von den heute getroffenen Entscheidungen ab. Oft fehlt aber die Erfahrung und das Wissen wie sich Entscheidungen auswirken. Dieses Buch zeigt einem wie kleine Veränderungen die Erweiterbarkeit beeinflussen und was für Vor- und Nachteile die einzelnen Ansätze von OOD mitbringen. Dies ersetzt zwar nicht das Sammeln von eigenen Erfahrungen, bietet einem aber eine gute Ausgangslage um nicht alle Fehler selber machen zu müssen.

 

Einfache Beispiele

Nach all den Banken und Blogs kommen hier Fahrräder für die Beispiele zum Einsatz. Durch die Optimierung für E-Reader sind die Beispiele recht kurz. So lässt sich der Code übersichtlich darstellen und ist als Nebeneffekt einfach zu verstehen. Im Gegensatz zu anderen Büchern kann man sich so auf die Beispiele konzentrieren und muss nicht ständig hin und her blättern.

Das entscheidende bei den Beispielen ist der Weg zum Ziel. Daher gibt es entsprechend viele kleine Schritte die ausführlich erläutert werden. Allerdings führen nicht alle Schritte in die richtige Richtung. Umwege und falsche Ansätze werden in diesem Buch ebenfalls thematisiert und erklärt.
So kann man auf wenigen Seiten Erfahrungen sammeln die bei einem richtigen Projekt Monate an Arbeit verursachen.

 

Tests

Dem Thema Tests widmet sich das letzte Kapitel. Die in den vorherigen Kapiteln erarbeiteten Beispiele werden hier nun getestet. Man sieht so rasch wie die verschiedenen Ansätze von OOD sich auf die Testbarkeit von Code auswirken.

Sehr gelungen finde ich wie die Stolperfallen präsentiert werden. Der Mock für die Tests mag noch so gut sein. Wenn sich die Klasse ändert und der Mock dies nicht mitbekommt ist zwar der Test grün aber die Software läuft nicht. Die gezeigten Lösungen sind zwar auf dynamisch typisierte Programmiersprachen ausgerichtet, können aber auch bei C# beim Erkennen von Veränderungen helfen.

 

Was fehlt

Die gewählten Beispiele sind alle recht Kurz und meist weniger als 100 Zeilen lang. Auch wenn kurze Klassen und Methoden anzustreben sind so ist die Realität doch oft anderes. Ein längeres Beispiel bei dem man mittels OOD Ordnung hinein bringt hätte ich sehr begrüsst.

 

Weitere Informationen

Wer sich für OOD interessiert aber nicht gleich ein Buch dazu lesen will wird auf Confreaks fündig. Dort gibt es als Video abrufbare Präsentationen von Sani Metz die einzelne Konzepte aus dem Buch aufgegriffen.

Wer lieber Podcasts hört findet in Episode 87 von Ruby Rogues eine ausführliche Buchbesprechung mit zahlreichen Tipps rund um OOD die im Buch keinen Platz gefunden haben.

 

Fazit

POODR ist ein angenehm zu lesendes Buch das sehr viel Wissen vermittelt. Obwohl ich mich schon länger mit OOD beschäftige konnte ich hier ganz neue Aspekte kennen lernen. Die Beispiele sind so einfach das man davon nicht abgelenkt wird und doch komplex genug um all die verschiedenen Möglichkeiten zu erklären.

Für mich ist dieses Buch definitiv ein „Must Read“ für alle die sich mit Software-Entwicklung beschäftigen.

 

Zum Buch

Practical Object-Oriented Design in Ruby” von Sandy Metz, 2012 Addison-Wesley Professional, ISBN: 978-0-3217-2133-4, 272 Seiten, Englisch

Kategorien:Bücher, dnugBern, webRead, webRuby Schlagworte: , ,

EF 5: Modelle übersichtlicher gestalten

17. März 2013 1 Kommentar

Ob man nun “Model-First” oder “DB-First” folgt, bei Entity Framework steht man schnell einmal vor einem Problem: Das Datenmodell verliert an Übersichtlichkeit.

Die oft verwendeten Beispiele mit wenigen Tabellen und Verbindungen sehen im Designer von Visual Studio prima aus. Hat man aber ein komplexeres Modell steht man bald einmal vor so einer Ansicht:

Unübersichtliches Modell

Auch wenn man sehr viel Zeit aufwendet um die Entitäten hin und her zu ziehen, so bleibt das Modell doch unübersichtlich. Verwendet man Entity Framework 5 und Visual Studio 2012 gibt es aber 2 Hilfsmittel die einem bei der Organisation helfen können.

 

Farben

Mit Hilfe von Farben kann man thematisch zusammenhängende Bereiche hervorheben. Dazu klickt man im Designer die gewünschte Tabelle (oder mittels der Hilfe von CTRL mehrere) an und wählt in den Properties die entsprechende Füllfarbe (Fill Color):

Farbe auswählen

Die Farben haben einzig im Designer eine Bedeutung und beeinflussen das Modell nicht. Mit wenig Aufwand sieht das Diagramm dann so aus:

Farbiges Modell

 

Diagramme

Für grosse Modelle sind die Farben zwar ein Anfang, doch ist man damit noch nicht am Ziel. Neu kann man das Modell aber in verschiedene Diagramme aufteilen. Die entsprechende Funktion findet sich im Model Browser unter Diagramme:

Diagramm hinzufügen

Die gewünschten Entitäten können nun auf dieses neue Diagramm gezogen werden. Man muss dies aber nicht für jede Entität einzeln machen. Über das Kontextmenü auf einer Entität kann man mit “Include Related” alle verbundenen Entitäten auf einmal einfügen lassen.

Die so erzeugten Diagramme behandeln nur noch den Ausschnitt aus dem Modell den man genauer betrachten möchte:

Zusätzliches Diagramm

Beim Löschen von Entitäten aus dem Diagramm muss man aufpassen. Mittels “Delete from Model” wird die Entität aus dem Modell gelöscht und ist danach über den DB-Kontext nicht mehr abrufbar. In der Regel will man stattdessen die Funktion “Remove from Diagram” nutzen. So wird nur das Diagramm angepasst und das Modell bleibt unverändert.

 

Fazit

Mit Hilfe von Farben und zusätzlichen Diagrammen kann man Ordnung in sein DB-Modell bekommen. So kann man auch grössere Datenbanken in Entity Framework benutzen ohne die Übersicht zu verlieren.

Kategorien:.Net, dnugBern, webDotNet Schlagworte: ,

Die Testpyramide

10. März 2013 1 Kommentar

Seit einigen Monaten stosse ich immer wieder auf das Konzept der Testpyramide. Ich finde dieses Bild sehr passen, da es die wesentlichen Aspekte auf den Punkt bringt. Um ein System wirklich zu testen gilt es mehrere Ebenen anzuschauen. Die Testpyramide zeigt diese auf und vermittelt auf eine leicht verständliche Weise wie sich die Anzahl der Testfälle staffeln soll:

Die Testpyramide

 

Unit-Tests als Grundlage

Unit-Tests bilden die Basis der Testpyramide. Die kleinstmöglichen Tests sollten sicherstellen dass das System im Kern funktioniert. Eine wichtige Eigenschaft von Unit-Tests: Sie sind Schnell. In wenigen Sekunden sollte man wissen ob es überhaupt Sinn macht die länger laufenden Tests zu starten. Diese Sekunden sind wohlgemerkt nicht für einen einzigen Tests gedacht, sondern für alle Unit-Tests zusammen – womit ein Unit-Test der länger als 1/100 Sekunde dauert schon als langsam gelten muss.

Damit Tests so schnell sind dürfen sie nur wenig testen. Weder eine Verbindung zur Datenbank noch ein Zugriff aufs Dateisystem oder Aufruf eines Webservices ist erlaubt. All diese Abhängigkeiten müssen entfernt werden. Ob dies mittels Konfiguration oder mit Mocks gemacht wird spielt dabei keine Rolle.

Die Geschwindigkeit alleine kann aber nicht das einzige Kriterium für einen Unit-Test sein. Sonst besteht die Testsuite am Ende nur aus leeren Methoden. Das was man testet soll auch noch Sinn machen. Und einem in die richtige Richtung weisen wenn einmal ein Test fehlschlägt. So ist man schnell einmal bei mehreren Kriterien die von Ben Rady und Rod Coffin in “Continuous Testing” mit dieser Abkürzung zusammengefasst werden:

FIRE: Fast, Informative, Reliable and Exhaustive

 

Integrationstests

Zu wissen dass der eigene Code für sich alleine funktioniert ist ein Anfang. Damit weiss man aber noch nicht ob der Code auch mit anderen Teilen funktioniert. Hier kommen die Integrationstests ins Spiel.

Auf dieser Ebene werden all die Abhängigkeiten angeschaut die man bei den Unit-Tests entfernt hat. Was zuerst nach vermeidbarem Zusatzaufwand aussieht hat sehr wohl seine Berechtigung. Es genügt wenn man das Erzeugen, Speichern, Aktualisieren und Löschen eines Objekts in der Datenbank ein Mal pro Klasse testet. Dies hat die gleiche Aussagekraft (ist aber deutlich schneller) wie wenn man in allen Unit-Tests immer mit den Objekten aus der Datenbank arbeiten würde.

Da weniger Tests mit den Umsystemen nötig sind wirkt sich deren Ausführungsdauer nicht so stark auf die Länge des gesamten Testlaufs aus.

 

Akzeptanztests

Die Akzeptanztests bilden die Spitze der Testpyramide. Hier gilt es die Anwendung aus Sicht des Benutzers zu testen. Vom GUI durch die Geschäftslogik hin zur Datenbank und den externen Webservices soll hier alles geprüft werden.

Da man bereits weis das sowohl der Kern der Anwendung funktioniert und der auch mit den Umsystemen korrekt zusammenarbeitet benötigt man nur noch wenige Akzeptanztests. Diese dürfen noch einmal langsamer sein als die Integrationstests und sollen als letzte Stufe die Korrektheit der gesamten Anwendung belegen.

Und da es so wenige Tests sind kann man diese auch mit dem Kunden/Endbenutzer besprechen. Müssen wirklich nur die wichtigsten Tests angeschaut werden hat man gute Chancen dass dies auch wirklich gemacht wird.

 

Reihenfolge & Einschränkungen

Die Testpyramide gibt keine Reihenfolge für die Erstellung der Testfälle vor. Wenn es bei der Ausführung auch am meisten Sinn macht mit den Unit Tests zu beginnen so ist man beim Erstellen frei.

Hat man Glück und der Kunde will an Akzeptanztests mitarbeiten kann man einen Top-Down Ansatz wählen. Man beginnt mit einem fehlgeschlagenen Akzeptanztest und schreibt so lange Integrations- und Unit-Tests bis dieser erfüllt wird. Alternativ kann man aber auch mit den Unit-Tests beginnen und sich nach oben arbeiten.

Die Testpyramide ist aber nicht perfekt. Es gibt etliche Testarten die darin keinen Platz finden. Wo platziert man beispielsweise die Explorationstests? Oder die Performancetests? Trotz dieser Einschränkungen finde ich das Bild der Testpyramide sehr gelungen.

Follow

Bekomme jeden neuen Artikel in deinen Posteingang.

Schließe dich 175 Followern an