Mittwoch, Juli 30, 2008

Taskboard: Gute geklaut...

...ist besser als schlecht selbst gemacht :-)
Ich finde die Kanban-Ansätze von David J. Anderson interessant, beschrieben z.B. in seinem Blog-Eintrag Kanban in Action. Ich bin nicht in allen Punkten einer Meinung mit ihm. Er stellt es z.B. als Vorteil dar, dass er keine Iterationsplanung braucht. Ich bin mir aber nicht so sicher, ob es sich nicht vielleicht doch um einen Bug handelt, weil er keine Iterationsplanung machen kann. Aber das ist letztlich Spekulation. Ich keine sein Setting nicht im Detail.

Zwei Dinge habe ich aber bei ihm geklaut und in verschiedene Taskboards übernommen:
  1. Blockaden/Hindernisse
  2. Kapazitätsbeschränkungen
Blockaden/Hindernisse
Dass man Hindernisse bei den täglichen Standup-Meetings benennt und festhält, hat sich inzwischen allgemein durchgesetzt. Häufig werden diese einfach als Liste festgehalten. Man kann jedoch zwei Typen von Hindernissen unterscheiden: Hindernisse, die mich bei der Arbeit behindern und Blockaden, die die Weiterarbeit an einer Aufgabe blockieren (z.B. fehlende Zulieferungen von Dritten). Aufgabenbezogene Blockaden schreiben wir daher nicht mehr in die Hindernisliste, sondern kleben eine rote Haftnotiz auf die blockierte Aufgabe. Das gibt eine schöne Visualisierung einer häufig gruseligen Situation: Das Team arbeitet gar nicht an den Aufgaben mit der höchsten Priorität, sondern an den wenigen Aufgaben, die gerade nicht blockiert sind.

Kapazitätsbeschränkungen
In einem unserer Festpreisprojekte arbeitet das Team an einem großen Auftrag. Der Kunde ist sehr zufrieden mit unserer Arbeit und versorgt uns daher immer fleißig mit weiteren kleinen Aufträgen. Diese müssen wir schätzen - wir sind immer noch in der Festpreiskonstellation. Die Aufwandsschätzung liefert natürlich das Team selbst. Die Schätzungen durchzuführen, sind Aufgaben, die bei der Iterationsplanung eingeplant werden. Mitunter hat der Kunde aber soviele tolle neue Ideen, dass wir vor lauter Schätzarbeit (Vorleistung) gar nicht mehr zum Hauptauftrag kommen. Da hat es sehr geholfen, dass wir eine neue Kartenfarbe (blau) spendiert haben für solche Aufgaben ohne bezahlten Auftrag und das Taskboard in der Kapazität für blaue Karten auf "2 pro Iteration" beschränkt haben. Das sorgt dafür, dass wir unsere Zeit im Wesentlichen auf den Hauptauftrag konzentrieren können. Und bisher ist dem Kunden dadurch auch kein Nachteil entstanden.

Post bewerten

Sonntag, Juli 27, 2008

Google-Testing-Blog: Testing Against Interfaces

Auf dem Google-Testing-Blog ist gerade ein Artikel "Testing Against Interfaces" erschienen. Es geht darum, wie man verschiedene Implementation desselben Interfaces testet. Der Artikel schlägt vor, eine abstrakte Testklasse zu dem Interface zu bauen. Im setUp dieser abstrakten Testklasse wird eine abstrakte Methode createXYZ aufgerufen, die das zu testende Objekt liefert. Jetzt leitet man von der abstrakten Testklasse konkrete Testklasse je getesteter Klasse ab. In diesem konkreten Testklassen überschreibt man die createXYZ-Methode und kann dann verkünden: "ich habe fertig" :-)

Das klingt plausibel, ist nach meiner Erfahrung in vielen Fällen aber nicht praktikabel. Dafür sind zwei Gründe verantwortlich:
  1. Man benötigt in Tests das getestete Objekt mitunter in unterschiedlichen Ausprägungen, und muss mitunter unterschiedliche Konstruktoren aufrufen. Dann muss man die createXYZ-Methode parametrisieren. Das funktioniert aber nur solange gut, wie alle Implementationen des getesteten Interfaces dieselben Parameter bekommen. Ist das nicht der Fall, muss man die Signatur der createXYZ-Methode aufblähen mit Parametern, die nur für einzelne Implementationen einen Sinn ergeben. Hinweis: Das Kochbuch zu JUnit benutzt z.B. unterschiedlich erzeugte Objekte im selben Test (natürlich ohne die Interface-Problematik).
  2. Häufig reicht ein einzelnes Objekt als Fixture nicht aus. Es werden mehrere Objekte benötigt. Jetzt müsste die createXYZ-Methode mehrere Objekte zurück liefern (als Liste?) oder man ruft mehrere createXYZ-Methoden auf, oder... Alles nicht besonders elegant.
Diese Probleme waren bei uns in früheren Jahren in der Praxis so massiv, dass wir diese Konstruktion fallen gelassen haben. Stattdessen haben wir eine andere Lösung konzipiert: Wir bauen ein Test-Center auf. Das ist eine konkrete Klasse, die mir einzelne parametrisierte Testmethoden anbietet. Diese ruft man aus den konkreten Testklassen auf. Damit eliminiert man die Redundanzen in den Tests. Natürlich sind meine Tests etwas länger, weil man die Testmethoden zur Delegation trotzdem alle hinschreiben muss, a la


public void testXYZ() { meinTestCenter.testXYZ(meinObjekt); }


Als weiteren Vorteil bringt die Test-Center-Lösung die Abwesenheit von Vererbung. Die Kopplung zwischen den Testklassen wird also reduziert.

Interessanterweise hatten wir für solche Konstruktionen umso weniger Anwendungsfälle, desto mehr wir uns von technischen Frameworks hin zu konkreten Anwendungssystemen orientiert haben.

Anmerkung: Das Fixtures aus mehreren Objekten bestehen, bedeutet noch nicht automatisch, dass es sich um Integrationstests handelt. Es ist meiner Meinung nach erlaubt und auch notwendig, in Unit-Tests wenige eng zusammenarbeitende Objekte als eine Fixture zu begreifen. Ansonsten neigen die Tests zur Trivialität und in statisch getypten Sprachen wie Java müsste ich überall Interfaces einziehen und in jedem Test Mocks benutzen.

Post bewerten

Mittwoch, Juli 16, 2008

Bug oder Featurewunsch?

Eine der häufigsten Konfliktlinien in der Softwareentwicklung ist die immer wiederkehrende Frage: "Ist das ein Bug oder ist das ein neuer Featurewunsch?"

Diese Frage tritt regelmäßig auf, wenn der Kunde neue Systemfunktionen präsentiert bekommt und feststellt, dass er es eigentlich anders bräuchte. Im Zweifel steht der Kunde auf der Position, dass es sich um einen Bug handelt während die Entwickler im Zweifel die Auffassung vertreten, es handele sich um einen neuen Featurewunsch.

Bug oder Featurewunsch? "Da regt mich ja die Frage schon auf!" (Loriot) Schließlich will diese Frage zu allererst den Schuldigen finden. Ist es ein Bug, haben die Entwickler Schuld - sie haben falsch programmiert. Ist es ein Featurewunsch, hat der Kunde Schuld - er hat falsch spezifiziert. Wir haben also ein Gegeneinander von Entwicklern und Kunde.

Dass mit dieser Einstellung nur schwer gute Projekte durchgeführt werden können, dürfte einleuchten. Statt an einer gemeinsamen Lösung zu arbeiten, wird über die Schuldfrage gestritten. Also sollten wir uns nicht die Frage stellen, ob etwas ein Bug oder ein Featurewunsch ist. Stattdessen reicht es vollkommen aus, festzustellen, dass es zu einer Systemfunktion noch Nacharbeiten gibt. Diese müssen erledigt werden. Wenn der Eindruck entsteht, dass Nacharbeiten hätten vermieden werden können, dann sollte man darüber in der Retrospektive sprechen und gemeinsam nach Verbesserungsmöglichkeiten suchen. Die Schuldfrage sollte uns dabei nicht im Weg stehen.

Und was ist bei Festpreisverträgen? Da muss entschieden werden, wer die Kosten für die Nacharbeiten trägt. Das bedeutet schlicht: Festpreisverträge richten Interessen von Kunden und Entwicklern entgegengesetzt aus und führen zu suboptimalen Ergebnissen. Wer wirklich gute Software schreiben (lassen) will, sollte die Finger von Festpreisverträgen lassen.

Post bewerten

Sonntag, Juli 13, 2008

Deadline der XP-Days Germany verlängert bis 27.07.2008

Wir haben bereits ein gute Sammlung hochwertiger Session-Vorschläge für die XP-Days Germany 2008. Da der offene Review-Prozess gut funktioniert, werden wir weniger Zeit für die finale Begutachtung der Beiträge im Programm-Komitee brauchen. Daher haben wir die Deadline für Einreichungen verlängert bis zum 27.7.2008.

Das bedeutet auch, dass bis dahin existierende Beiträge noch überarbeitet und Reviews geschrieben werden können / sollen.

http://www.xpdays.de

Post bewerten

Freitag, Juli 11, 2008

Lisp auf der Java-VM

als alter Lisp-Fan lese ich sowas natürlich gerne: Exploring LISP on the JVM

Post bewerten

Testen mit C++, EXPECT und ASSERT

Im Google-Testing-Blog ist ein Artikel über das Unit-Testen mit C++ erschienen: EXPECT vs. ASSERT. Der Artikel ist auch deshalb großartig, weil hier die längst vergessen geglaubte Kunst des ASCII-Comics wieder auflebt. Aber auch der Einhalt ist interessant. Für C++-Entwickler scheint ein relevantes Problem adressiert zu werden. Für mich bleibt die Erkenntnis: "Ein Glück, dass ich nicht C++ programmieren muss. Diese Art von Problemen wäre nicht für mich."

Post bewerten

Separation of Concerns: Application Logic vs. Creation Logic

Im Google-Testing-Blog ist mal wieder ein schöner Artikel erschienen: How to Think About the "new" Operator with Respect to Unit Testing. Inhaltlich ist es nicht wirklich neu: Objekterzeugung mit new in Klassen mit Logik ist gefährlich, weil das isolierte Testen kleiner Einheiten erschwert wird. Stattdessen sollte man die Objekterzeugung separieren und Dependency-Injection verwenden.
Auch wenn diese Erkenntnis nicht neu ist, kann sie wahrscheinlich gar nicht oft genug wiederholt werden - viel zu vielen Entwicklern scheint sie fremd zu sein.

Und dann schimmert durch den Artikel noch eine generelle Forderung durch: "Trenne Anwendungslogik immer von Erzeugungslogik". Die meisten Entwickler, die sich der new-Problematik bewusst sind, lagern nicht alle Objekterzeugungen aus. Sie machen das nur an den Stellen, wo es zum Testen auch notwendig ist und das sind längst nicht alle Stellen. Die Erzeugung generell auszulagern, bedeutet etwas erhöhten Programmieraufwand (weil man z.B. Factories schreibt, obwohl man von der Flexibilität zur Zeit keinen Gebrauch macht). Möglicherweise lohnt sich dieser Zusatzaufwand: man muss weniger überlegen, bekommt einheitlicheren Code im Team und muss die Erzeugung später nicht refaktorisieren, wenn man doch isolieren will.


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

InfoQ: Komplexität rund um Einfachheit

Gerade ist ein InfoQ-Artikel The Complexity Around Simplicity erschienen. In dem Artikel wird eine "Erkenntnis" genannt, der ich zustimme: 'What is "simple" for one request may not be "simple" for the whole!'
Aber der genannten Konsequenz stimme ich so nicht zu: 'trying to simplify one part of the system may bring undue complexities in other parts of the system. There is a need to view the system as a whole.'
Das würde ja bedeuten, dass ich bei Projektstart doch alles wissen muss und letztlich agile Vorgehensweisen zu komplexen/schlechten Entwürfen führen müssen.
Ich würde aus der erstgenannten Erkenntnis eine andere Konsequenz ableiten: Die einfache Lösung muss für den Kern des Systems passen. Wenn das dazu führt, dass der Rand des Systems etwas komplexer zu realisieren ist, ist das vollkommen OK.
Konkretes Beispiel: Verteilte Transaktionen lassen sich mit EJBs verhältnismäßig einfach realisieren. Wenn ich keine verteilten Transaktionen brauche, bedeuten EJBs aber zusätzliche Komplexität. Aber woher weiß ich, dass ich keine verteilten Transaktionen brauchen werde? Ich kenne ja noch nicht alle Anforderungen. Ich kann es nicht wissen.
Viele Teams neigen dann dazu, EJBs auf Vorrat in das System einzubauen. Leider belasten sie dann das ganze System mit der damit einhergehenden Komplexität.
Ich gucke mir den Kern des Systems an, ob ich verteilte Transaktionen brauche. Wenn ich dort keine verteilten Transaktionen brauche, setze ich auch kein EJB ein. Wenn später dann am Systemrand verteilte Transaktionen benötigt werden, akzeptiere ich für diese paar Zeilen Code auch eine deutlich höhere Komplexität. Ich bin überzeugt davon, dass ich dadurch in der Gesamtsumme die einfachere Lösung bekomme.

Post bewerten