Posts mit dem Label Architektur werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Architektur werden angezeigt. Alle Posts anzeigen

Sonntag, Dezember 07, 2008

Rezension zu: Refactorings in großen Softwareprojekten

Ralph Johnson hat die englische Übersetzung des Refactoring-Buches von Martin und mir gelesen und findet es gut. Da fühle ich mich jetzt ja schon ein wenig geadelt...




Post bewerten

Dienstag, November 11, 2008

Artikelserie Perspektivenwechsel in Java-Magazin und auf JAXenter

Es gibt eine Artikelserie namens "Perspektivenwechsel" im Java-Magazin, in der ich hin und wieder auch mitschreibe. In der Artikelserie werden unterschiedlichste Themen aufgegriffen, manchmal vielleicht auch etwas provokativ. Mit etwas Verzögerung erscheinen die Artikel auch online auf JAXenter.

Post bewerten

Samstag, November 08, 2008

XP and Frameworks

At the XP2000 conference I had a talk about eXtreme Programming and frameworks. Some people archive things for a really long time. One of them reread my article and asked me a few days ago if I did further research on it. I didn't really do research but I collected some experiences which lead me to some simple conclusions (which didn't changed too between 2000 and now):
  • Use before reuse. First you have to use some code successfully and than you can think about generalizing it for reuse. That means that you have to invest effort to refactor application code to framework code. A lot of teams try to avoid this "rework" but in most cases the effect is that the framework becomes bloated and hard to use.
  • Running application: You always have to have a running application on top of your framework that proves that the framework is useful. This application may be a demo application but that would restrict the "prove". A real application is much better.
  • Supporting framework team: This is the really hard one. When your framework grows larger and supports more than one application team you normally need an own framework team. That is easy part, here is the hard part: The framework team has to have a perspective that the application teams are their customers and that they have to listen to the application teams and support them. Most frameworks teams I met had another attitude. They thought that they understand much better how to implement applications than the application developers know and that the application developers are dumb and foolish to a certain degree. That results in the attempt to prescribe how to develop with the framework. And that doesn't work, especially not if you try to support agile teams that should be self organized and empowered.

Post bewerten

Freitag, November 07, 2008

Technical Debt

Martin Fowler hat einen Vorschlag gemacht, wie man Technical Debt "messen" kann. Das ist sicher ein guter Anfang.

Post bewerten

Color Modeling

Color Modeling ist die Modellierungstechnik, die Feature-Driven-Development (FDD) vorschlägt - aber nicht verpflichtend macht. Aber auch außerhalb von FDD kann Color Modeling sehr nützlich sein. Ich habe es (in adaptierter Form) in Scrum/XP-Projekten eingesetzt.
Insgesamt finde ich, dass die Technik zu wenig bekannt ist und unterschätzt wird. Daher freut es mich, dass jetzt eine gute Erläuterung zu Color Modeling mit ein paar Erfahrungswerten aufgetaucht ist.

Post bewerten

Mittwoch, November 05, 2008

W-JAX: Hochperformante Webanwendungen

Heute habe ich auf der W-JAX einen interessanten Vortrag von Peter Roßbach gehört. Es ging um Tipps und Tricks, wie man Webanwendungen schneller machen kann. Besondere interessant fand ich, dass man sehr viele Dinge ohne Programmierung, einfach durch Konfiguration (z.B. in Apache) regeln kann - Caching, Zippen etc.
Die meisten Dinge kann man sofort umsetzen und sie versuchen keinen oder nur wenig Zusatzaufwand. Ein paar Beispiele sind:
  • Bilder sollten nicht im Browser skaliert werden, sondern in der benötigten Größe vom Server geliefert werden.
  • GET-Requests (ohne Parameter) können häufig gecacht werden und damit kann man leicht mal 50% Bandbreite sparen.
  • Man sollte immer erst die CSS-Dateien in seine HTML-Seiten einbinden und dann die Java-Script-Dateien. Sonst wird mitunter doppelt gerendert.
  • Man sollte Links ohne Ziel vermeiden (z.B. Favicons, die es nicht gibt). Diese führen intern zu 404 und 404 kann nicht gecacht werden.
  • etc.

Post bewerten

Freitag, September 05, 2008

Software-Putzer?

Nico Josuttis schreibt in seinem Blog über Software-Putzmänner und die nächste IT-Revolution. Er schlägt darin vor, schlechte Softwarequalität einfach als Fakt hinzunehmen und nicht immer zu versuchen, die Qualität zu verbessern. Vielmehr ginge es darum, mit dieser schlechten Qualität umzugehen. Als eine mögliche Alternative schlägt er Software-Putzkolonnen vor, die hin und wieder kommen und dann im Code aufräumen.

Dazu fallen mir gleich ein paar Sachen ein.

Zuerst zum Akzeptieren schlechter Qualität: Wenn die Qualität wirklich schlecht ist, wirkt sich das mannigfaltig unangenehm aus. Selbst der Product Owner bemerkt es. Nicht nur durch die langsame Entwicklungsgeschwindigkeit sondern auch dadurch, dass er aus technischen Gründen seine Priorisierungen ändern und seine Stories anders aufschreiben muss.

Und ich habe auch gerade ein aktuelles Projektbeispiel zur Hand, dass sich das Aufräumen lohnt. Beim Kunden dümpelte ein Team bei 30 Story Points je Sprint rum. Irgendwann hat das Team festgestellt, dass umfangreichere Refactorings im Bereich CSS notwendig sind, um schneller zu werden. Sie haben die Refactorings in Angriff genommen und die haben viel länger gedauert als zunächst gedacht - das ist nach meiner Erfahrung fast immer so bei größeren Refactorings. Aber sie haben es durchgestanden, obwohl es sogar soweit ging, dass nicht mehr alle Entwickler während des Sprints beschäftigt werden konnten. Nach dem Refactoring hat die Geschwindigkeit des Teams deutlich zugelegt. Heute liegt die Geschwindigkeit bei 80 Story Points je Sprint.
Mindestens in diesem Fall hat sich das Aufräumen schnell gelohnt und es wäre finanzieller Irrsinn gewesen, das Refactoring nicht durchzuführen.

Und zu den Putz-Kolonnen kann ich gleich zwei Erfahrungen beisteuern.
Erstens: Wir hatten bei it-agile mal so ein Dienstleistungsprodukt im Angebot. Das war ein Ladenhüter. Daher gibt es das jetzt nicht mehr als explizites Produkt bei uns. Wenn jemand sich dafür interessiert, beleben wir es aber jederzeit gerne wieder :-)
Zweitens: Wir hatten in einem Projekt mal sowas wie eine Putz-Kolonne in ganz zarten Ansätzen. Das hat in meinen Augen nicht funktioniert. Zum einen liefern die Projekte dann noch schlechtere Qualität - die Putz-Kolonne wird es schon richten. Zum anderen musste die Putz-Kolonne ständig bei den Entwicklern nachfragen, was bestimmter Code bedeutet. Und damit wurde das Team dann doch wieder mit Putzarbeiten belastet.

Langer Rede kurzer Sinn: Ich vertrete genau den konträren Ansatz. Wir als Entwickler sind für die technische Qualität des Systems verantwortlich. Wer schlechte technische Qualität abliefert, verstößt aus meiner Sicht gegen den Code of Ethics unserer Zunft und sollte sich was schämen. Niemand wird uns die Zeit und das Geld zum Aufräumen geben und die Putz-Kolonne wird auch nicht kommen. Wir als Entwickler müssen die Sache selbst in die Hand nehmen und zu unserer Verantwortung stehen!

P.S.: Zum Code of Ethics: Punkt 3 lautet: "PRODUCT - Software engineers shall ensure that their products and related modifications meet the highest professional standards possible." Das bedeutet meiner Meinung nach auch, hohe Qualität abzuliefern.

P.P.S.: Wer mehr darüber erfahren möchte, wie guter Code für agile Entwicklung aussieht und wie man den schreibt: ich werde auf der OOP darüber einen Vortrag halten.

Post bewerten

Samstag, August 30, 2008

Wie misst man technical debt?

Das Konzept des Technical Debt (technische Schuld) ist schon alt: Wenn man Qualität opfert, um einen bestimmten Termin zu halten, geht man eine technische Schuld ein. Diese technische Schuld bezahlt man zunächst mit einer reduzierten Entwicklungsgeschwindigkeit. Wenn man die technische Schuld dann irgendwann zurückzahlen will, kostet es i.d.R. ein Vielfaches von dem, was man ursprünglich "eingespart" hat.

Soweit so gut. Leider hilft das Konzept in der Projektpraxis nicht so fürchterlich gut. Es gibt kein vernünftiges Verfahren, um Höhe und "Zinssatz" der technischen Schuld zu messen.

Hier gibt es jetzt mal einen Vorschlag, technische Schuld zu messen und zwar in WTFs pro Minute.

Lustig? Klar!
Ernsthaft verwendbar in der Projektpraxis: Da sollte man vielleicht mal drüber nachdenken...

Post bewerten

Dienstag, August 12, 2008

Technical Debt und das geistige Taskboard

Entwickler wollen ihren eigenen Ansprüchen genauso gerecht werden wie den Ansprüchen anderer. Daher tun sich viele Scrum-Teams am Anfang schwer, sich einzugestehen, dass sie sich für den Sprint zuviel vorgenommen haben (Over Commitment). Für Product Owner ist es anfänglich ebenso schwer. Schließlich hat man auch als Product Owner seine Ziele und möglicherweise sogar bestimmte Features zu einem festen Zeitpunkt versprochen.
Beides zusammen kann ausreichend Druck erzeugen, dass die Entwickler in den Zug einsteigen, der direkt in die Hölle fährt: Sie opfern Qualität, um den geplanten Sprintinhalt zum Sprintende zu schaffen. Sie gehen eine technische Schuld ein (Technical Debt), die ihnen später sehr schmerzhaft auf die eigenen Füße fällt - in Form einer steilen Aufwandskurve.
Dabei ist das erste Problem aus meiner Sicht gar nicht, dass man die technische Schuld eingegangen ist. Das erste Problem ist, dass das implizit passiert. Die Entwickler machen sich beim Programmieren geistige Tasks in der Art "Hier müsste man noch mal das Refactoring XYZ durchführen.", "Hier müssten noch die Tests nachgeschrieben werden." etc.
Diese Tasks gehören nicht in den "Hinterkopf". Diese Aufräum-Tasks gehören explizit und für alle sichtbar ins Sprint-Backlog (und damit auf das Taskboard). Damit hat man nicht nur die Merker, was man noch erledigen muss. Es wird auch sofort klar, dass man das Sprint-Commitment trotzdem NICHT erreicht hat. Man hat nur die übrig gebliebenen Tasks getauscht. Es sind keine fachlichen Features mehr offen, sondern technische Aufräumarbeiten.
Dieser Fakt ist erstmal zu akzeptieren und in der Sprint-Retrospektive zu beleuchten. Warum konnten wir unser Commitment nicht halten und wie machen wir es nächstes Mal besser? Und dann sollte man sich auch gleich noch die Frage stellen: Warum haben wir Qualität geopfert anstatt Funktionalität zu reduzieren und ist das Opfern der Qualität wirklich der bessere Weg?

Post bewerten

Freitag, August 01, 2008

Können Anwender/Fachexperten modellieren?

Auf diese Frage hätte ich früher mit einem klaren "Nein" geantwortet. Inzwischen mehren sich aber deutlich die Anzeichen, dass sie mit entsprechender Unterstützung vielleicht doch viel mehr können, als zumindest ich früher dachte.
  • In Feature-Driven-Development sind die Fachexperten beim Color Modeling mind. sehr stark in die Erstellung fachlicher Klassenmodelle involviert.
  • Bei InfoQ ist ein Artikel erschienen, der beschreibt, wie die Fachexperten selbst mit Domain Driven Design fachliche Klassenmodelle erstellt haben, die die Entwickler dann auch genau so umgesetzt haben.
Der InfoQ-Artikel hat mir auch nochmal eine Situation in Erinnerung gerufen, die wir vor 2 oder 3 Jahren in einem Projekt hatten. Wir hatten zeitliche Ereignisse an Wasserzählern modelliert (Einbau, Wechselung, Eichung etc.). Es wurde irgendwann im Projekt klar, dass wir das Modell ändern müssen. Der Code war schwer verständlich und sträubte sich gegen Änderungen.

In der Diskussion über das Zielmodell haben sich zwei Fronten im Team gebildet, die sich auch nicht von selbst auflösten. (Dass die Fronten entstanden sind, halte ich heute für ein Sympton eines tieferliegenden gruppendynamischen Problems, aber das ist hier nicht das Thema.)
Wir haben ziemlich viel Zeit in die Diskussion gesteckt, ohne zu einem Ergebnis zu kommen. Irgendwann habe ich einen Fachexperten einfach mal die beiden Modelle skizziert und gefragt, ob er etwas beitragen kann. Konnte er. Er hat gesagt, dass beide Modelle nicht so gut passen und ein drittes skizziert. Dieses Modell leuchtete dem ganzen Team schnell ein und wir haben die Änderungen durchgeführt. Tatsächlich beseitigte das Modell des Fachexperten unsere Probleme im System.

Post bewerten

Mittwoch, Juli 02, 2008

REST für Geschäftsanwendungen

Dem REST-Architekturstil wird häufig "vorgeworfen", er würde für komplexe Situationen / Geschäftsanwendungen nicht funktionieren. Tatsächlich gibt es bisher wenig Erfahrungen mit REST in Geschäftsanwendungen. Es gibt aber Beispiel-Geschäftsanwendung, die zeigt, dass REST durchaus auch für Geschäftsanwendungen funktionieren kann.

Post bewerten

Dienstag, März 18, 2008

Software-Architektur mit Dependency-Injection

Überblick

Dieser Artikel beschreibt meine Erfahrungen mit Dependency-Injection (DI) in mehrjährigen Großprojekten. Dabei geht es vor allem um die Best-Practices für Entwurf und Architektur.

Wir haben vor allem handprogrammierte DI, Pico-Container und Java-Server-Faces als DI-Container eingesetzt. Der Artikel bezieht sich primär auf Pico-Container. Die „Erkenntnisse“ lassen sich aber auf andere DI-Container übertragen.

In einem Großprojekt haben wir ein System mit vielen Singletons schrittweise auf Pico-Container umgestellt. Wir haben einige größere Refactorings in dem Projekt durchgeführt und bei vielen war der Nutzen letztlich zweifelhaft. Der Umbau auf Pico-Container gehört aber definitiv zu den Umbauten, die sich deutlich gelohnt haben.

Zielsetzungen

Mit DI kann man eine Reihe von Zielen erreichen:

  • Entwurf entkoppeln
  • Abhängigkeiten explizieren
  • Testbarkeit verbessern
  • Singletons und static-Attribute eliminieren

Entwurf entkoppeln

DI führt nicht automatisch zu einer Entkopplung der Systemkomponenten. Man kann sich auch mit DI eigenartige und unwartbare Abhängigkeitsgeflechte zusammenbauen. Ohne DI hingegen ist es in der Praxis fast unmöglich, entkoppelte Systeme zu bauen. In diesem Sinne ist DI eine notwendige, aber keine hinreichende Bedingung für Entkopplung. Wenn man zusätzlich zu DI noch Interfaces und testgetriebene Entwicklung einsetzt, bekommt man aber ohne größere Anstrengungen ein gut entkoppeltes System.

Abhängigkeiten explizieren

DI macht die Abhängigkeiten von Objekten an ihrer Schnittstelle deutlich. Dadurch ist erstmal natürlich nur ein wenig Dokumentation gewonnen. In unseren Projekten hat dieses kleine bisschen Mehr an Dokumentation aber erheblichen Einfluss darauf gehabt, wie gut man Entwürfe verstehen konnte.

Testbarkeit verbessern

Durch die Entkopplung ließen sich die einzelnen Komponenten besser testen. Hier fällt insbesondere die Harmonie von DI mit Mock-Testen[1] positiv auf. Zusammen mit testgetriebener Entwicklung entsteht ein schlagkräftiges Trio.

Nicht zuletzt laufen so entkoppelte Tests viel schneller ab als klassisch erstellte Unit-Tests (in einigen Fällen konnten wir Testlaufzeiten von mehreren Minuten auf unter 10 Sekunden reduzieren).

Singletons und static-Attribute eliminieren

Setzt man DI konsequent ein, braucht man weder Singletons noch irgendeine andere Form statischer Attribute. Dadurch werden Zustandsabhängigkeiten im System reduziert, so dass sich Systemteile besser unabhängig voneinander wieder verwenden und testen lassen.

In unseren Projekten sind durch die Umstellung von Singletons auf DI eine ganze Reihe eigenartiger Phänomene beim Ausführen und beim Testen verschwunden.

Pico-Container im Code

Pico-Container ist ein sehr leichtgewichtiger DI-Container, der programmatisch konfiguriert wird. Daher können programmatisch DI-Container erzeugt und an andere Objekte übergeben werden. Da ist eine Fußangel versteckt: Man sollte Pico-Container minimal-invasiv benutzen. Das bedeutet, dass möglichst wenig Code Kenntnis davon haben soll, dass Pico-Container (oder ein anderer DI-Container) eingesetzt wird. Folglich sollten die Pico-Container nur im Startup erzeugt werden. Weitere Klassen dürfen nicht vom Pico-Container abhängen. In der Schichtung des Systems liegt der Pico-Container also ganz oben.

Pico-Container in Tests

In Unittests hat Pico-Container nichts verloren. Sind die getesteten Klassen so kompliziert miteinander verflochten, dass man sie manuell nicht zusammenstecken kann, ist Refactoring angesagt – und zwar schleunigst.

Welche Klassen registriert man beim DI-Container?

In unseren Projekten haben sich drei Typen von Klassen etabliert, die wir typischerweise beim DI-Container registrieren.

  • Fabriken
  • Services
  • Objekte, die nur einmal existieren dürfen (ehemalige Singletons)

Wofür baut man Fabriken?

Wenn ein Objekt andere Objekte erzeugen will, kann man diese Objekte nicht über DI hineinreichen – man weiß ja noch nicht, wie viele Objekte erzeugt werden. In solchen Fällen reicht man stattdessen Fabriken per DI in das Objekt.

Fabriken werden häufig mit static-Methoden implementiert. Wenn man die Fabriken beim DI-Container registriert, wäre das jedoch einigermaßen witzlos. Also gilt: Fabriken sollten keine static-Methoden enthalten – static-Attribute sowieso nicht.

In vielen Projekten habe ich beobachtet, dass viel zu selten Fabriken benutzt werden! Fabriken (ohne static-Methoden) helfen bei DI und erleichtern das Testen mit Mocks ungemein[2]. Im Zweifel würde ich lieber eine Fabrik zuviel spendieren.

Abschluss

Unsere Erfahrungen mit Pico-Container haben wir in erster Linie in Rich-Clients gesammelt. Wir haben Pico-Container serverseitig nicht verwendet. Es sollte jedoch möglich sein, weil der Pico-Container sehr leichtgewichtig ist. Der Overhead für die Erzeugung bei jedem Request oder EJB-Aufruf sollte in den meisten Anwendungen zu verkraften sein. Wenn der Overhead zu groß wird, kann man den Pico-Container mind. bei Webanwendungen auch in der Session speichern.

Inzwischen kommen viele Server-Infrastrukturen aber bereits mit eigenen DI-Containern (Spring, JSF, EJB 3), so dass man serverseitig i.d.R. wahrscheinlich nicht in die Verlegenheit kommt, Pico-Container einzusetzen.

Referenzen



[1] z.B. mit Easy Mock

[2] Beim Testen gilt: Jedes Testproblem kann durch eine weitere Indirektion gelöst werden.

Post bewerten

Samstag, Dezember 15, 2007

Screencast zum Vortrag "Einfachheit in Softwareprojekten"

Auf den XP-Days habe ich einen Vortrag mit dem Titel "Einfachheit in Softwareprojekten" gehalten. Den habe ich als Screencast aufgezeichnet und dabei leider das Mikro so übersteuert, dass der Ton unbrauchbar ist.
Glücklicherweise hat Jens Himmelreich den Ton separat aufgezeichnet und mir zur Verfügung gestellt. Nach ziemlich viel Arbeit habe ich es dann auch geschafft, Bild und Ton so zu mischen, dass sie synchron laufen.
Das Gesamtkunstwerk kann man sich hier ansehen (oder einfach nur den Ton oder die Folien als PDF runterladen).

Nochmal vielen vielen Dank an Jens Himmelreich. Ohne seine Ton-Aufnahme wäre das alles nichts geworden.

Post bewerten

Samstag, Dezember 08, 2007

Lohnt sich Dependency-Injection

Auf InfoQ ist gerade eine Zusammenfassung einer Diskussion erschienen, in der es um die Frage geht, ob sich Dependency-Injection auszahlt. Die einen sagen, dass DI nur dazu gut ist, damit man entkoppelt mit Mocks testen kann. Stattdessen könne man aber auch bessere Mock-Frameworks benutzen, die DI nicht erzwingen. Die anderen sagen, dass Testen DI erzwingt und dass daher DI automatisch gut ist.

Ich finde, die Diskussion geht etwas am eigentlichen Kern vorbei. DI ist erstmal nur eine Technik, genauso wie Mock-Testen. Keines von beiden ist generell gut oder schlecht. Genauso wie Entkopplung nicht automatisch gut ist. Man muss auch die richtigen Teile entkoppeln.

Meiner Meinung nach ist das Dependency-Inversion-Principle (DIP) das übergeordnete Konzept. DIP sagt, dass ein High-Level-Konzept nicht von Low-Level-Implementationen abhängen sollen. Demnach darf z.B. die Fachlogikschicht nicht von der Datenbankschicht abhängen. Begründung: Low-Level-Implementationen ändern sich häufiger als High-Level-Konzepte und die Änderungen finden nicht nur hinter dem API der Low-Level-Implementation statt, sondern schlagen häufig bis in die Klienten durch. Hängen die High-Level-Konzepte von den Low-Level-Implementationen ab, müssen sie unnötig häufig geändert werden.

Das bedeutet: DIP ist generell gut.

DI und Mocks erlauben mir, DIP umzusetzen. Daher sind DIP und Mocks mind. dann gut, wenn sie für DIP eingesetzt werden.


Interessanterweise korreliert DIP mit vielen Aspekten aus Quasar.

Post bewerten

Warum einfach, wenn es auch kompliziert geht?

Ich habe auf den XP-Days in Karlsruhe einen Vortrag über Einfachheit in Softwareprojekten gehalten, den ich hoffentlich bald als Screencast online stellen kann.
In dem Vortrag ich von einem Experiment berichtet, dass von Bavelas an der Stanford-Universität durchgeführt wurde. Man hat Propanden mit Bildern von Gewebezellen konfrontiert. Sie sollten ohne medizinische Vorkenntnisse diagnostizieren, ob die Zellen gesund oder krank sind. Sie bekamen als Feedback dann jeweils, ob sie richtig oder falsch gelegen haben. Aus dem Feedback entwickelten sie ein Modell darüber, woran man krankhafte Gewebezellen erkennt.
Allerdings hat man nur der einen Gruppe korrektes Feedback gegeben. Die andere Gruppe hat zufälliges Feedback erhalten.
Schließlich hat man Paare mit jeweils einem Vertreter jeder Gruppe gebildet, die dann gemeinsam Gewebezellen diagnostizieren sollten. Und dabei setzte sich meistens die Person durch, der man das zufällige Feedback gegeben hatte.
Begründung: Diese Person hat sich auf Basis des zufälligen Feedbacks ein sehr kompliziertes (aber falsches) Modell darüber gemacht, woran man krankhafte Zellen erkennt. Die Person mit dem korrekten und einfachen Modell war begeistert von der Detailtiefe des komplizierten Modells ("da habe ich selbst wohl etwas übersehen") und ist daher der meist falschen Einschätzung seines Partners gefolgt.
Und dieses Phänomen findet sich auch ständig in der Softwareprojekten. Es ist so verführerisch den komplizierten Architekturen, Technologien und Vorgehensmodellen zu folgen. Ich glaube jedoch, dass das meistens der falsche Weg ist: Komplizierte Lösungen sind auch dann falsch, wenn sie richtig sind.

Eine genauere Beschreibung des Experimentes findet sich in "Wie wirklich ist die Wirklichkeit?" von Paul Watzlawick im Kapitel ("Warum einfach, wenn es auch kompliziert geht?"). Der Text findet sich unter der gleichen Überschrift auch Online auf Seite 20ff.

Post bewerten

Mittwoch, November 07, 2007

W-JAX: REST-Vortrag

Gestern habe ich auf der W-JAX einen sehr interessanten Vortrag zu REST gehört von Stefan Tilkov. Der Vortragende hat lange Zeit mit Web-Services gearbeitet und propagiert heute REST.
Inzwischen gibt es den JSR-311 namens JAX-RS für ein standardisiertes API für REST, an dem Stefan Tilkov auch mitarbeitet. Der ist noch im Early-Draft-Stadium. Es sieht aber schon ganz nett aus.
Beim Vortrag habe ich denn auch ein Tool kennengelernt, dass wir bei unserem REST-Projekt auch benötigt hätten: curl. Mit dem Ding kann man HTTP über die Kommandozeile machen. Im Gegensatz um Browser kann man manuell den Header, die Methode (GET, POST, PUT, DELETE etc.) festlegt und auch den Body.

Post bewerten

Samstag, Oktober 06, 2007

Klassen und Methoden im Wandel

Als ich studierte gab es genau eine Art, Klassen und Methoden zu benennen: Klassen wurden mit Substantiven benannt, die direkt dem ungesetzten Konzept bzw. ihrer Verantwortlichleit entsprechen sollten, z.B. Auftrag. Bei den Methoden wurde streng zwischen Funktionen und Prozeduren unterschieden. Funktionen liefern Werte und lassen den Objektzustand schön in Ruhe, während Prozeduren den Objektzustand ändern und keinen Rückgabewert haben. Ob etwas Funktion oder Prozedur ist, sollte nicht nur an der Signatur deutlich werden, sondern auch im Namen. Prozeduren werden immer in Befehlsform geschrieben (z.B. berechneSumme) während Funktionen eine Substantivform bekommen (ggf. mit einem 'get' als Präfix, z.B. 'getNummer'). Diese ganze Konzeption wurde z.B. von Bertrand Meyer vertreten und auch gut begründet:
Wenn man eine Klasse sucht, kann man sie leicht anhand ihres Namens finden. Und wenn man dann das API der Klasse liest, ist gleich klar, was die Methoden tun. Insbesondere ist klar, ob eine Methode nur einen Wert liefert oder ob sie gefährlich den Objektzustand manipuliert.

In den letzten Jahren hat sich an verschiedenen Stellen ein deutlich anderer Programmierstil entwickelt. Der primäre Fokus hat sich gewandelt. Es geht nicht mehr primär darum, dass man das API einer Klasse leicht lesen und verstehen kann. Stattdessen soll der Klientencode möglichst gut lesbar sein.

Bei der Benennung von Unit-Tests findet sich eine zarte Andeutung in diese Richtung. Statt AuftragTest.testSummenberechnung findet man heute immer häufiger AuftragTest.berechnetSummeDerPositionen. Die zweite Variante lässt sich als Spezifikation lesen "Auftrag berechnet Summe der Positionen".

Noch deutlicher wird es, wenn man sich Behaviour Driven Development (BDD) ansieht.

Schließlich nutzen die Fluent Interfaces dieses Konzept auch außerhalb des Testens bzw. Spezifizierens für Produktivcode.

Aus


TimeInterval meetingTime = new TimeInterval(fiveOClock, sixOClock);

wird

TimeInterval meetingTime = fiveOClock.until(sixOClock);


Für viele Entwickler, die schon länger im Java- oder C++-Geschäft sind, sind diese fließenden Interfaces sehr gewöhnungsbedürftig. Allerdings wird eine Klasse viel häufiger eingesetzt als gelesen. Also scheint es nicht gerade abwegig, mehr Gewicht auf die Benutzbarkeit als die API-lesbarkeit zu legen.

Trotzdem wird man absehbar wohl nicht alle Klassen mit einem Fluent Interfaces versehen. Dazu ist der Aufwand zu groß. Aber bei den Klassen, die sehr häufig benutzt werden, sind Fluent Interfaces sicher eine Überlegung Wert.

Nachtrag: Ein Beispiel für ein Fluent Interface findet sich z.B. in Hibernate, wenn man eine Criteria zusammenbaut.

Post bewerten

Freitag, Mai 04, 2007

Buchkritik zu "Refactoring in Large Software Projects"

Schon vor einiger Zeit ist die englische Übersetzung des Buches Refactorings in großen Softwareprojekten von Martin Lippert und mir erschienen: Refactoring in Large Software Projects.
Dazu gibt es jetzt auch Kritiken: hier und hier.

Post bewerten

Montag, März 19, 2007

Transaktionslose Anwendungsentwicklung

Ich selbst bin kein großer Freund verteilter Transaktionen. Sie bergen meiner Meinung nach eine Komplexität, die nur die wenigsten Entwickler beherrschen.
Daher halte ich es auch für sehr schade, dass sich in breiten Kreisen die Ansicht durchgesetzt hat, dass man auf jeden Fall verteilte Transaktionen braucht, wenn man mehrere Datenbanken oder zu integrierende Systeme hat.
Dass das keineswegs so ist, beschreibt Martin Fowler am Beispiel eBay.

Post bewerten

Montag, März 12, 2007

Die Mächtigkeit der Gleichförmigkeit

An verschiedenen Stellen (z.B. erst vor ein paar Tagen hier) habe ich immer mal wieder behauptet, das Cobol-System, an dem ich als Student mitgearbeitet habe, sei besser strukturiert gewesen als viele der C++- und Java-Systeme, denen ich danach begegnet bin. Diese Aussage hat bei einigen Lesern zu Unverständnis bis Entsetzen geführt. Grund genug, der Sache einmal auf den Grund zu gehen.

Gilt diese Aussage generell für Cobol-Systeme?
Nein, definitiv nicht. Ich habe auch einige Cobol-Systeme gesehen, die deutlich schlechter strukturiert waren als viele Java-Systeme.

Liegt es daran, dass an die Java-Systeme viel höhere Anforderungen gestellt wurden also an die Cobol-Systeme?
Nein. Viele der Java-Systeme unterschieden sich nur dadurch von den Cobol-Systemen, dass sie eine grafische Benutzungsoberfläche mit Swing hatten. Und die ist in Java eher leichter zu programmieren als in Cobol alles von Hand für zeichenbasierte Oberflächen zu codieren. Und selbst wenn Swing die Sache erschwert hätte, hätte das nur Auswirkungen auf die oberflächennahen Teile des Systems haben dürfen und nicht auf die Gesamtstruktur.

Liegt es daran, dass das Cobol-System besonders klein und übersichtlich war?
Nein. Es handelte sich um eine komplette Warenwirtschaft mit Lagerverwaltung und Produktion. Das System ist von ca. 10 Leuten über 10 Jahre lang weiterentwickelt worden.

Liegt es daran, dass am Cobol-System besonders gut ausgebildete Entwickler gearbeitet haben?
Nein. Es gab kaum ausgebildete Informatiker im Team. Einer der Entwickler war vorher Koch und ein anderer Steuerfachgehilfe.

Woran lag es denn dann?
Das System hatte eine einfache Musterarchitektur, die sich durch das ganze System zog. Stammdatenprogramme, Dialog-Programme, Auswahl-Dialoge, Batch-Programme, Druck-Jobs wurden nach dem immer gleichen Schema entwickelt, dass über die Jahre entstanden ist.

Damit war jedem Entwickler bei einer neuen Anforderung sofort klar, wo welche Änderungen notwendig waren und auch, wie teuer diese werden würden. Schätzungen, die stark von den tatsächlichen Aufwänden abwichen, habe ich im Projekt nie erlebt.

Dabei sind natürlich unglaublich viele Redundanzen entstanden. Wenn man ein neues Stammdatenprogramm schreiben wollte, hat man sich ein existierendes Stammdatenprogramm geschnappt und dieses angepasst. Das war Wiederverwendung durch Copy&Paste in Reinkultur.
Und trotzdem hat es funktioniert. Dabei sind sich alle einig, dass das eigentlich unmöglich ist.

Ich glaube, der Grund ist in der Gleichförmigkeit zu suchen, die das System hatte. Redundanzen sind gar nicht so schlimm, wenn sie jedem klar sind. Wenn ich für das Hinzufügen eines Feldes 100 Stellen anpassen muss, ist das halb so wild, wenn mir
  1. klar ist, wo ich die 100 Stellen im Code finde und
  2. jede Änderung mechanisch durchführbar ist, gerade wg. der Gleichförmigkeit des Codes.
Steht so eine Änderung an, ist diese zwar langweilig, aber nicht aufwändig. 100 gleichförmige Änderungen in bekanntem Code macht man in 2-4 Stunden.

Für diese Änderungen ist neben der Gleichförmigkeit eine andere Eigenschaft wichtig: Minimale Abhängigkeiten. Wenn niemand von den geänderten Code-Stellen abhängt, besteht nur geringe Gefahr, durch die Änderungen etwas kaputt zu machen. Außerdem gibt es das Risiko des Ripple-Effekts nichts: Die Änderung bringt weitere Änderungen in abhängigen Code nach sich, die wieder Änderungen in abhängigem Code nach sich ziehen...

Das führt mich zu der These, dass die bessere Cobol-Struktur sich an nur einer Eigenschaft festmacht: Es gab in dem Cobol-System weniger und klarer definierte Abhängigkeiten als in vielen Java-Systemen.

Diese Eigenschaft hat man sich erkauft durch Redundanzen (geht in Cobol auch nicht wirklich anders). Offensichtlich konnte man mit den Redundanzen aufgrund der Gleichförmigkeit besser umgehen als mit Java-Strukturen, die weniger Redundanzen aber dafür größere Abhängigkeiten aufweisen.

Sollten wir also zu Cobol zurück? Auf gar keinen Fall!

Wir sollten uns aber bewusster werden, wie gefährlich Abhängigkeiten zwischen Systemteilen werden können und wie leicht man sich in OO-Programmiersprachen unentwirrbare Abhängigkeitsgeflechte schafft. Vielleicht sollten wir eher einmal gleichförmige Redundanzen zulassen, um damit Abhängigkeiten zu reduzieren?

Post bewerten