Montag, 31. Mai 2010

Gezieltes Coding Dojo

Dass das Coding Dojo am 26.5.2010 kein Coding Dojo war, darüber sind Ilker und ich uns durchaus einig. Der Rahmen war zwar der des üblichen Münchner Dojos – der Inhalt wich dann jedoch stark davon ab. Ilker hat diese Abweichung jetzt nochmal begründet und ich habe auch schon innerhalb dieser bezweckten Abweichung reflektiert. Was bleibt da noch zu sagen?

Messlatte #1: Die offizielle Zieldefinition

image Mir geht der Kommentar von Steffen Forkmann nicht recht aus dem Kopf. Ist da wirklich etwas zu kurz gekommen beim Dojo? Wenn etwas zu kurz kommt, dann weicht etwas vom Ziel ab. Was aber ist das Ziel eines (oder des Münchner) Coding Dojos?

In einem früheren Posting von Ilker ist zu lesen, das Ziel eines Coding Dojos sei…

“[d]ie erfolgreiche Vermittlung von nutzbaren Lerneffekten – für jeden Teilnehmer. Er sagte dass ein Dojo keine feste, durchgeplante Veranstaltung mit fixem Programm oder Paradigma sei, sondern dass das Dojo primär die Teilnehmer und den Lerngedanken im Fokus hat.”

Wenn ich das in Anschlag bringe, dann bin ich ziemlich sicher, dass auch das letzte Coding Dojo sein Ziel erreicht hat. Niemand sollte zu kurz gekommen sein. Denn einen “nutzbaren Lerneffekt” hat es für jeden gegeben. (Wer keinen hatte, melde sich bitte bei mir. Dann bessere ich nach.)

Und da es keine “feste, durchgeplante Veranstaltung mit fixem Programm oder Paradigma” ist, sollte auch meine anders als übliche Nutzung der Dojo-Zeit dojokonform gewesen sein.

Allerdings: Wie steht es mit den “Teilnehmer[n] und de[m] Lerngedanken”? Mein Eindruck war, dass die Teilnehmer nicht nur Empfänger waren, sondern stets mitgestaltet haben. Anders als sonst, aber immer noch aktiv. Sehr aktiv sogar.

Fazit: Gem. der öffentlichen Definition des Münchner Coding Dojos ist alles im grünen Bereich gewesen. Anders, ungewohnt, aber zielführend. Ilker hat sich “nichts zu Schulden kommen lassen”. Als “Salonier” des Community Lernens hat er seine Aufgabe erfüllt. Merci, Ilker!

Messlatte #2: Selbstgebastelt

Soweit die offizielle Definition von Coding Dojo. Ich möchte jedoch die Gelegenheit nicht verstreichen lassen, mir auch selbst über die Ziele eines Coding Dojos Gedanken zu machen. Was gehört aus meiner Sicht dazu?

Zunächst einmal zum Begriff bzw. dem Bild des Dojo: Steffen Forkmann (und andere) scheinen enttäuscht gewesen zu sein, dass im letzten Dojo soviel “Lehrereinsatz” war. Das ist allerdings – zumindest im Hinblick auf das klassische Dojo – ein Missverständnis. Ein klassische Dojo ist ein Ort des Lernens des rechten Pfads, der auch von Religion geprägt ist. Im Dojo geht es also klassisch um einen Kanon vermittelt durch eine Lehrer/Meister-Schüler/Lehrling-Hierarchie. Der Gedanke einer gleichberechtigten Community in Bezug auf die Lerninhalte ist dem klassischen Dojo fremd.

Wenn nun die Softwaregemeinde den Begriff Dojo für sich entdeckt, dann halte ich es für vermessen (oder zumindest missverständlich) ihn ohne diese klassische Wurzel zu denken. Ein Dojo nur als Dojo zu akzeptieren, wenn es keinen Lehrer gibt, täte also besser, die Veranstaltung anders zu nennen.

Das soll nicht bedeuten, dass in einem Coding Dojo alles so laufen soll wie in einem Kendo Dojo im Japan des 17. Jahrhunderts. Modernisierung im Geiste westlicher Gleichberechtigung und Individualität ist natürlich völlig ok. Achtsamkeit im Umgang mit einem Traditionsbegriff scheint mir jedoch angebracht. Insofern bin ich der festen Überzeugung, dass in einem Dojo auch mal eine Hierarchie auftreten darf: einer weiß was, die anderen wollen es von ihm lernen.

Überwachung der Zielerreichung: Ob mit der ohne Lehrer – in Ilkers Definition ist das ja auch offen gelassen –, ein Ziel ist für ein Dojo wie für jede Veranstaltung nötig. Laut Ilker ist das “nutzbare Lerneffekte”; im Dojo soll also irgendetwas gelernt werden. Die Teilnehmer sollen nachher schlauer sein. Was das ist, sei einmal dahingestellt. Ich nehme irgendeinen fachlichen Aspekt an. Ilker lässt auch das frei in seiner Definition – konkretisiert jedoch in der normalen Praxis. Test-Driven Development scheint mir am ehesten die Praktik, die das Dojo als Lerninhalt zu vermitteln versucht.

Wichtiger als der Lerninhalt ist mir an dieser Stelle jedoch, wie der erreicht wird. Steffen und andere favorisieren ein “Peer-Learning”, d.h. ein Lernen irgendwie ohne Lehrer, sondern von Teilnehmern auf mehr oder weniger gleicher Kenntnisstufe. Dazu gleich mehr.

Das ist ein valider Ansatz – allerdings kann ich dahinter nur Ernsthaftigkeit erkennen, wenn im Rahmen des Dojo auch eine Überprüfung stattfindet, ob das Ziel erreicht wurde. Wie findet aber eine Lernerfolgskontrolle statt? Bei den Dojos, die ich erlebt habe – sorry to say –, habe ich davon wenig gesehen.

Am Ende Spaß gehabt zu haben, ist keine Lernerfolgskontrolle in Bezug auf ein fachliches Ziel. Auch Funktionalität hergestellt zu haben, ist keine Lernerfolgskontrolle. Wie also stellen sich Steffen und die anderen es sich vor, den Lernerfolg in Bezug auf TDD oder anderes festzustellen? Solange der Anspruch existiert, dass nur ein ganz bestimmter Stil ein rechtes Dojo ausmacht, solange sollte auch klar gemacht werden können, wie denn dieser Stil seinen Erfolg sicherstellt.

Lernen von einander: Das Lernen in der Gruppe ist eine gute Sache. Lernen ist eine durchaus soziale Angelegenheit. Und Lernen ohne Machthierarchie ist auch wunderbar. Da bin ich dabei und finde es toll, das Ilker sich für einen solchen Lernprozess als “Facilitator” immer wieder zur Verfügung stellt. (Und nicht nur das! Ilker ist auch nimmermüder Motivator der Dojo-Sache. Das ist nicht zu unterschätzen.)

Ein Facilitator überwacht jedoch nur einen Prozess. Läuft alles gem. Prozessregelwerk? Tanzt keiner aus der Reihe? Gibt es keine Hindernisse, die dem Prozess im Wege stehen? Das im Blick zu behalten, ist Ilkers Sache.

Das bedeutet im Umkehrschluss und zur Entlastung von Ilker: Die Wissensvermittlung bzw. –generierung ist Sache der Teilnehmer.

Wie funktioniert das aber nur? Die Prämisse ist, dass es ein zu erlangendes Wissen gibt. Irgendwo hängt im Raum eine Latte (immer höher), die das Dojo überspringen soll. Aber wo hängt die? Wer weiß es, wenn kein “Lehrer” anwesend ist/sein darf?

image Leider, leider muss ich sagen, dass der Anspruch eines “Community Lernens”, bei dem alle gleich sind in der Diskussion, zwar schön ist – mir jedoch wenig effektiv und effizient erscheint. Es drängt sich mir das Bild eines Debattierclubs auf, in dem alle eine Meinung haben, es aber keiner so genau weiß.

Allemal solange keine systematische Ergebniserarbeitung und –sicherung stattfindet, wird da schnell viel geredet, die Energie fließt – nur wohin?

Wie gesagt: dass am Ende irgendwie Code läuft, ist mir nicht genug.

Wenn alle gleich “ahnungslos” sind, wer stellt am Ende fest, ob eine Lösung wirklich gut ist (oder zumindest besser als eine andere)? Gefühle haben dazu natürlich alle; und ein Durchschnittsgefühl lässt sich auch ermitteln. Solange wir jedoch den Anspruch haben, in einer Branche zu arbeiten, in der es auch mal gesichertes, also überindividuelles und geschmacksunabhängiges Wissen gibt, ist mir auch das zuwenig.

Übungsgruppen in der Universität arbeiten auch zusammen. Doch sie arbeiten in den Grenzen eines Korrektivs. Am Ende müssen sie ihre Ergebnisse präsentieren. Und die werden mit dem kanonischen Wissen verglichen. (Ausdrückliche Forschung, d.h. die Generierung neuer Erkenntnisse nehme ich hier aus.)

Beim Coding Dojo ist das zumindest nach dem Ideal einiger per Definitionem nicht der Fall; das nimmt kein kanonisches Wissen an – so scheint es mir zumindest. Wie also – das möge man mir erklären – kann ein Teilnehmer dann sicher sein, etwas zu lernen, wenn letztlich die anderen nicht schlauer sind als er – oder zumindest keine Rolle einnehmen dürfen, in der sie ihre Erkenntnisse gezielt den anderen vermitteln?

Man möge mich nicht falsch verstehen! Ich rede keiner Lehrerattitüde das Wort. Und der Wissenskörper befindet sich für mich immer im Fluss. Auch kann aus meiner Sicht Lernen immer nur jeder selbst; ein Lehrer ist bestenfalls Facilitator. (Im Clean Code Developer Camps haben Stefan Lieser und ich deshalb spaßeshalber das Ideal, dass das Lernen am besten funktioniert, wenn wir nur noch Kaffee ausschenken müssen und der Rest von selbst läuft ;-)

image Doch auch wenn der Wissenskörper im Fluss ist, hat er eine vom Einzelnen unabhängige (vorübergehende) Form, die zu erkennen sich lohnt. Zu der mögen TDD, Lambda Ausdrücke oder Funktionale Programmierung gehören. All das kann man besser oder schlechter tun. Aber wer weiß, ob eine Coding Dojo Gruppe es eher besser oder eher schlechter tut? Der Spaß an der Sache ist kein wirklicher Gradmesser dafür.

Mir geht es nicht darum, eine bestimmte Person auszuloben, die “es” besser weiß. Auch ich weiß nicht alles besser – aber von manchem glaube ich schon, dass ich es besser als manche weiß. Und so geht es mit anderen Themen anderen Community-Mitgliedern. Jeder weiß etwas – und auch mal besser als andere. Ist halt so. Und ist gut so.

Warum soll dann nicht der, der ein Thema besser beherrscht als andere, diese anderen anleiten? Warum muss Coding Dojo bedeuten, dass ohne Lehrer gearbeitet wird? Das will mir nicht in den Kopf.

Woher der Lehrer kommt, ist ja egal. Und über die Didaktik und Methodik lässt sich auch noch trefflich diskutieren.

Wenn es aber einen Lehrer gibt, also einen mit Wissensvorsprung, warum soll der nicht die anderen anleiten? Das halte ich für die effizientes Form des Lernens. Wir müssen uns ja nicht dümmer stellen als wir sind. Wie die Kinder zu lernen, also alles selbst herausfinden, ist eine romantische Vorstellung. Kinder lernen allerdings so, weil sie oft nicht anders können. Besser lernen sie, wenn man sie geeignet anleitet. Dann kann man nämlich das Verhältnis von Erfolg und Misserfolg steuern. Die Lernerfahrung ist dann eher motivierend.

Meine Zieldefinition

Und was ist der langen Rede kurzer Sinn? Was ist meine Definition von Coding Dojo? Hier Stichpunkte:

  • Coding Dojo bedeutet lernen in Gemeinschaft
  • Coding Dojo bedeutet den Willen zu Clean Code (Development)
  • Coding Dojo bedeutet, zunächst den state-of-the-art zu erarbeiten
  • Coding Dojo bedeutet, Code zu produzieren
  • Coding Dojo bedeutet Ergebnissicherung
  • Coding Dojo bedeutet, über das Lernen zu reflektieren
  • Coding Dojo bedeutet, Spaß mit gleichgesinnten Entwicklern zu haben

Das sind eine Menge Eckpunkte für ein Coding Dojo. Damit die alle verlässlich angelaufen werden, ist eine Moderation nötig. Ilker, du hast also auch in meinem Bild einen Job ;-)

Diese Eckpunkte spannen einen Raum auf, das Dojo. Wie das dann konkret mit Leben gefüllt wird, ist eine andere Sache. Ob Katas gemacht werden (kleine Aufgaben) oder über mehrere Sitzungen mit Hausaufgaben Projekte realisiert, das ist egal. Ob einer den anderen etwas vermittelt oder nicht, auch das ist mir letztlich egal – allerdings habe ich da so meine Meinung, wie effektiv das Lernen ist, wenn alle aus ihrer eigenen Unsicherheit heraus versuchen, Sicherheit zu erlangen. Das kann funktionieren – ist dann aber Forschung. Wer als pragmatischer Entwickler will aber forschen mit all dem, was an dem Begriff hängt?

Und nun kommt die Community. Was macht ein Dojo aus? Was gibt es diesen Eckpunkten hinzuzufügen? Was muss weg? Oder braucht es gar keine Definition und jeder macht einfach so für sich etwas und nennt es nur, wie die anderen?

Für mehr Qualität im Netz durch Identität [OOP 2010]

Auch mal anonym sein dürfen, ist ne schöne Sache. Keine Frage. Deshalb lieben wir das Bargeld immer noch. Ihm haftet nichts von uns an; damit können wir genauso Geschenke wie “Schmuddelkram” kaufen, ohne dass eine Spur auf dem Bankkonto entstünde, die uns verraten könnte.

Und auch sonst finden wir es entspannend, nicht überall und immer erkannt zu werden. Die Berühmten beneiden wir ja eher nur, solange wir nicht unter einer “Beobachtung” wie sie stehen. Wir verstehen, dass ihre hohen Gagen auch “Schmerzensgeld” sind zur Kompensation des Verlustes von Privatsphäre und Anonymität.

Das Internet schließlich hat die Anonymität zur Lebensweise erhoben. Wer hat in ihm nicht gleich mehrere Identitäten? In Diskussionsforen herrscht die Anonymität; kaum ein Eintrag wird mit Realname gemacht:

image

Das ist die ersten 25 Jahre online Foren witzig gewesen, würde ich sagen. Aber inzwischen finde ich es kontraproduktiv in seiner Selbstverständlichkeit. Warum?

 Weil Identität für mich mit Vertrauen und Qualität zu tun hat.

imageWer kennt nicht Flame-Kommentare, wer kennt nicht Trolle in Foren, wer kennt nicht die anonymen Rezensenten von Büchern, Musik und Software? Rechts als Beispiel ein Ausschnitt aus einer Liste von Buchbeurteilungen bei Amazon. Was soll ich von der Meinung von “Ein Kunde” oder “Sonja H.”  oder “fionara” halten? Nichts. Es ist egal, ob sie gut oder schlecht bewerten. Ich kann ihnen nicht vertrauen – allemal, da ich weiß, dass Verlage Rezensionen in Auftrag geben. Gute wie schlechte (für Werke anderer Verlage, versteht sich ;-)

Wer anonym bleibt, investiert nichts. Nicht mal seinen “guten Namen”.

Ohne Investition ist aber keine Ernsthaftigkeit zu erwarten. Ohne Investition ist auch nicht zu erwarten, dass jemand den Empfänger respektiert. Denn Disrespekt hat ja keine Konsequenz.

Konsequenzlosigkeit führt denn auch zu den tollsten Blüten: vom Flame-Kommentar bis zu Vandalismus und Schlimmerem.

Das wissen wir alle – und doch haben wir ein merkwürdig ambivalentes Verhältnis zu Identität und Anonymität. Wir möchten selbst anonym bleiben, hätten es aber gern, dass andere ihre Identität enthüllen. Das kann jeder an sich selbst beobachten, wenn er “gezwungen” wird, sich mit seinem richtigen Namen irgendwo im Internet anzumelden – und sich andererseits aufregt über unflätige Bemerkungen in anonymen Foren.

Ich will nicht abstreiten, dass Anonymität Vorteile hat – zum Beispiel für die “guten Kräfte” in totalitären Regimen. Ich will auch nicht abtun, dass anonyme Beiträge hohe Qualität haben können. Und schließlich erkenne ich auch an, dass ein Avatar/Nick zu einer Identität mit eigenem Wert werden kann; die mag von einer realen Person entkoppelt sein und doch vertrauenswürdig sein. (Dazu braucht es allerdings einige Zeit und wiederkehrende positive Erfahrungen mit dem Avatar/Nick.)

Unterm Strich möchte ich Anonymität also nicht grundsätzlich missen. Weder in der realen, noch in der digitalen Welt.

Dennoch plädiere ich dafür, dass wir uns öfter “zu erkennen geben”. Ich glaube, einfach daran, dass unsere Kommunikation effektiver und effizienter wird, wenn wir identitätsvoll kommunizieren. Ich melde mich daher immer öfter bei Plattformen mit meiner realtweltlichen Identität an (wobei ich mir Abkürzungen erlaube, solange ich über weitere Informationen identifizierbar bin). Das ist für mich eine Form von Investition oder Geben. Denn wenn ich nicht bereit bin, mich als Person (bekanntzu)geben und damit auch verletzlich zu machen, wie kann ich dann erwarten, dass andere das tun? Ohne Identität und Verletzlichkeit ist jedoch kein (zügiger) Vertrauensaufbau möglich. Und ohne Vertrauen kann ich nicht erwarten, dass irgendjemand sich bemüht. Und ohne Bemühen kann ich nicht auf Qualität hoffen.

imageGerade in unserer Branche, wo alle nach Qualitätsinformationen hungern, finde ich es wichtig, dass wir uns – wo immer möglich – persönlich, d.h. mit unseren realen Identitäten “in die Augen schauen” (auch wenn wir uns nicht gegenübersitzen, sondern nur chatten oder Forennachrichten austauschen).

Wir erwarten von unseren Kommunikationspartner in Twitter, Facebook, Google Groups, Blogosphere das Beste? Wir erwarten, dass Sie uns ernsthaft informieren? Und umgekehrt erwarten wir, dass andere uns ernst nehmen, wenn wir bloggen, twittern, kommentieren? Dann sollten wir als Minimum unsere Identität investieren. Kommen wir aus unserem Anonymitätsschneckenhaus heraus! Profil zeigen, Rückgrat strecken. Ja, auch wenn es mal kontrovers werden sollte.

Das Gute am Internet ist, dass wir vielfach anonym bleiben können. Wir haben die Wahl. Solange wir uns aber reflexartig für die Anonymität entscheiden, nutzen wir sie nicht. Erwachsener Umgang mit dem Internet bedeutet deshalb für mich, dass wir uns immer wieder diese Wahlmöglichkeit bewusst machen – und sie dann auch nutzen, indem wir uns für die Identität entscheiden.

Denn was können wir von einer Kultur der Anonymität, die letztlich für Unsicherheit, Angst und Grenzziehung steht, erwarten? Unsicherheit, Angst und Grenzen gebähren Unsicherheit, Angst und Grenzen - und deren Gegenteile: Sicherheitsdenken, Gewalt, Narzismus. Negative Extreme führen zu negativen Extremen.

Aber was gebiehrt der Wille zur Idendität, der Mut, Vertrauen, Offenherzigkeit, Rückgrat, Wohlwollen, Verletzlichkeit erfodert? Ich bin optimistisch, dass daraus mehr Mut, mehr Vertrauen, größere Offenherzigkeit, mehr Rückgrat, mehr Wohlwollen und mehr Sensibilität entstehen. Und wer wollte das nicht?

Zum Glück können wir alle dafür etwas tun. Mit ein bisschen weniger Anonymität jeden Tag ist ein erster Schritt getan.

Sonntag, 30. Mai 2010

Coding Dojo Muc Retrospektive

Softwareentwicklung mit Energie – die war wieder mal zu sehen beim Coding Dojo in München. Knapp 30 Entwickler waren zusammengekommen, um sich in geselliger Runde in der .NET Programmierung anhand einer Aufgabe zu üben.

Das Coding Dojo Muc hat sein Format und seinen Rhythmus. Im Fokus steht gewöhnlich die testgetriebene Entwicklung (TDD) einer Funktionalität, die sich mit einer Funktion als API ausdrücken lässt  (Beispiele: FizzBuzz, LOC Counter). Das Motto: Alles denkt, einer tippt.

Doch dieses Mal war vieles anders…

Der Ablauf

image Dieses Mal hatte Ilker mich eingeladen, um in das Dojo ein wenig architektonisches Denken hineinzutragen. Das Motto: Alles denkt, keiner tippt ;-) Zumindest nicht die ersten zwei Stunden.

Die Frage nun: hat das geklappt?

Die Aufgabe

Um architektonisches Denken zu üben, musste die Aufgabe natürlich etwas größer ausfallen als Dojo-gewöhnlich. Auf der anderen Seite durfte sie nicht zu groß sein, denn ich wollte ja auch mit Ergebnis mit den Teilnehmern erzielen.

Angemessen erschien mir schließlich eine Spellchecker-Anwendung: Das Programm sollte Texte in verschiedenen Sprachen auf Rechtschreibfehler überprüfen. Wenn man so ein Programm aufsetzen will, sind mehr als eine architektonisch relevante Funktionseinheit nötig; Architektur lohnt sich also.

Der Umfang dieser Aufgabe führte dann gleich zu einer ersten Neuerung bei Dojo: der Anforderungsanalyse. Nicht, dass bisher die Teilnehmer nicht versucht hätten, die Aufgaben zu verstehen. Aber so ein Programm machte eine systematischere Herangehensweise nötig. Die bestand aus zwei Schritten:

1. Featureliste

image Im ersten Schritt haben wir die Anforderungen mündlich ventiliert. Da kamen einige Fragen an den “Kunden” zusammen. Und der Kunde blieb keine Antwort, keinen Wunsch schuldig – allerdings konnte nicht alles wirklich in das Backlog übernommen werden. Wir hatten ja nur einen Abend für die Realisierung zur Verfügung. Nichtsdestotrotz war die Diskussion wichtig, um die Gruppe auf das Thema einzuschwingen.

Was am Ende dann realisierbar erschien, haben wir in eine Featureliste übertragen. Wichtig dabei: Nur aus Kundensicht Relevantes ging darin ein.

2. Ubiquitous Language

image Die Featureliste hat den generellen Scope der Entwicklung abgesteckt. Sie hat eine Grenze gezogen. Wie sah aber das Terrain innerhalb dieser Grenze aus? Wie sollten Problem und Lösung zusammenfinden?

Um einen Übergang in die Lösungswelt zu finden, haben wir im zweiten Schritt für die Features eine Ubiquitous Language mittels einer Concept Map erarbeitet.

Darin wurden die zentralen Begriffe der Domäne nicht nur gelistet, sondern auch qualifiziert in Beziehung gesetzt. Interessante Erkenntnisse wurden dadurch herausgearbeitet:

1. Um sich unzweideutig über die Domäne unterhalten zu können, ist zwischen Prüfworten und Fehlerworten zu unterscheiden. Prüfworte sind die, die auf Korrektheit geprüft werden müssen; Fehlerworte sind die, die als Inkorrekt erkannt wurden.

Fehlt die Unterscheidung, wird die Rede über die Domäne im besten Fall mühsam, im schlimmsten Fall jedoch Missverständlich.

2. Nachdem das Flipchart schon fast voll war, stellte sich die Frage, wer denn überhaupt die Rechtschreibprüfung vornehmen würde. Ihre Elemente (z.B. Prüfworte, Wörterbuch) waren vorhanden, es fehlte aber eine Instanz, die damit umging.

Diese Instanz war in der Diskussion immer implizit vorhanden. Das Team hatte sich oder das ganze Programm dafür in der Verantwortung gesehen. Das ist aber natürlich ungenügend, weil trivial bzw. impraktikabel. Es gilt vielmehr: Zentrale Domänenaufgaben müssen als “Bubbles” in einer Concept Map der Ubiquitous Language auftauchen.

Und so wurde spät aber doch der Prüfer als Vokabel in die Ubiquitous Language aufgenommen. Er prüft, ob ein Wort im Wörterbuch und damit korrekt oder als Fehlerwort zu melden ist.

Die Architektur

Nach soviel Vorgeplänkel waren die Teilnehmer natürlich gespannt darauf, wie denn aus den Anforderungen eine Architektur entstehen würde.

Einige wollten mit Klassendiagrammen anfangen. Andere wollten Schichten übereinander malen. Doch ich hatte mich entschieden, eine Architektur “nach der neuesten Mode” zu versuchen. Event-Based Components (EBC) sollten es sein.

Da keine Zeit für lange Erklärungen des Konzepts sein würde, fand ich mich mit dem EBC-Ansatz recht mutig. Aber es half nichts: Ich wollte einfach nicht mehr überholte Ansätze wie IBC (Injection-Based Components) widerkäuen. Viel simpler wäre es auch nicht nicht geworden. Womöglich sogar schwieriger, weil sich Abstraktionsniveaus mit IBCs schlechter modellieren lassen.

Also bin ich mit einem System-Umwelt-Diagramm eingestiegen und habe dessen System dann als “Hauptplatine” einer EBC-Architektur verfeinert und bin dann nochmal eine Ebene tiefer in den SpellChecker (SC) hinunter gestiegen:

  

In drei Abstraktionsschritten von den Anforderungen zur Architektur. Das war sicherlich überraschend für einige Teilnehmer.

Interessanterweise gab es aber weder dazu noch zu den “komischen Pfeilen”, die ja nicht wie üblich Abhängigkeiten, sondern Nachrichtenflüsse darstellen, grundsätzlich kritische Kommentare. Puh. Das hat mich erleichtert.

Die Kontrakte

Nach soviel Gerede und soviel Malerei stand dann zum Glück aber etwas Code auf dem Programm. Es galt, die die Kontrakte der ermittelten Komponenten festzuzurren. Trotz EBC bleibt Contract-First Design zentral für eine Architektur, die in der Implementierung nicht erodiert.

Für die Kontrakte (und den weiteren Code) hatte ich schon ein Google Project aufgesetzt und mit einer Visual Studio Solution ausgestattet. In die haben wir die Servicekontrakte für die Funktionalität und die Nachrichtenkontrakte “hineingegossen”:

image

Je Komponente (Bauteile und Platinen) ein Interface. Interface-Abhängigkeiten gibt es nicht – das ist ja der Trick bei EBCs.

Hier ein Beispiel für einen Servicekontrakt:

image

Und hier ein Teil des Nachrichtenkontrakts:

image

Die Vokabeln der Ubiquitous Language tauchen konsequenterweise darin wieder auf.

Die Implementation

Nach mehr als 2,5 Stunden war es dann soweit. Die Teilnehmer konnten in die Tasten greifen. Vier kleine Teams gingen daran, die Bauteil-Komponenten zu implementieren. Auch Gastgeber Ilker ließ es sich nicht nehmen, mitzumachen.

Anders als üblich arbeiteten die Teams allerdings still. “Entertainment” hatte es genug gegeben. Jetzt sollte nicht mehr lange (öffentlich) diskutiert werden. Gummi musste auf die Straße.

Um aber nicht nur Gummi bei der Implementation, sondern auch bei der Integration auf die Straße zu bekommen, schlug ich vor, zunächst nur Minimalfunktionalität ohne Tests zu implementieren. Das versetzte mich in die Lage, die Platinen zu prüfen.

Also machte der USB-Stick ein erstes Mal die Runde, um den Teams die Kontrakte zuzuspielen. Und dann ein zweites Mal die Runde zurück zu mir, um ihre rudimentären Implementationen abzuliefern. Darauf aufbauend war meine Aufgabe, die Hauptplatine und die SpellChecker-Platine zu implementieren und alles mit einer kleiner Host-EXE zu starten.

Anschließend gaben die Teilnehmer alles, um ihre Implementationen auszufleischen.

Um 22:17h war es dann soweit: Die Anwendung lief. Texte konnten gegen ein englisches und ein deutsches Wörterbuch geprüft werden. Dabei holperte es noch etwas im UI und die Wörterbücher waren mager – aber “der Kunde” konnte sehen, dass seine Anwendung lief.

Reflexion

Unterm Strich war das Coding Dojo ein Erfolg. Ich bin grundsätzlich zufrieden mit dem Ergebnis. Auch wenn es gedauert hat und wir über Stolpersteine gelaufen sind, gab es am Ende eine lauffähige Anwendung, die von einem verteilten Team realisiert worden ist.

Was ist gut gelaufen?

Ich würde sagen, dass das grundsätzliche Vorgehen gepasst hat. Anforderungen verstehen, Features aufschreiben, Context Map, Kontrakte implementieren: der Fluss war gut. Es gab allerdings Kritik, dass ich dabei zuviel angeleitet hätte. Diese Kritik kann ich gut nachvollziehen, doch ich sehe nicht, wie es hätte anders laufen können.

Wenn bei sonstigen Dojos nach 3 Stunden eine Funktion realisiert ist, dann wäre bei einer ganzen Architektur am Ende kaum etwas Lauffähiges herausgekommen. So schön eine gemeinsame Entwicklung durch die Teilnehmer gewesen wäre – sie hätte nicht mehr als ein gutes Erlebnis produziert. Da bin ich mir sicher. Der Grund: Wenn schon bei der Implementation einer Funktion die Meinung weit auseinandergehen, dann ist das noch mehr der Fall beim Thema Entwurf. Die unterschiedlichen Ansätze, ein leeres Flipchart-Blatt zu füllen, sind dafür der Beweis.

Ziel war nicht, die Gruppe “irgendwie” zu einem Ergebnis kommen zu lassen, sondern einen Weg systematisch zu beschreiten. Das bedarf der Anleitung.

Ich behaupte nicht, dass der Weg, den ich durch den Architekturdschungel “vorgetrampelt” habe, der beste ist. Aber ich behaupte, dass er lohnenswert war, einmal erfahren zu werden. Ich bezweifle, dass viele von den Teilnehmern in ihren Projekten je erlebt haben, wie nach einer sauberen Planung echt parallel und ohne Codekollisionen entwickelt werden kann. Das zu demonstrieren, war mein Anliegen.

Für eine “Diskussionskuschelrunde” mit etwas Architektur hätte Ilker mich auch nicht einladen müssen.

Bei einem nächsten Übungsprojekt wäre es möglich, mehr Arbeit ins Team zu verlagern. Dann würde sich zeigen, ob es etwas vom Vorgehen mitgenommen hat. Bei diesem ersten Mal war jedoch Anleitung in Form eines “fragend entwickelnden Unterrichtsgesprächs” und einem Architekturparadigma nötig.

Gefreut hat mich auch, dass die Concept Map so gut aufgenommen wurde und die Ubiquitous Language sich selbst bei diesem kleinen Projekt als hilfreich herausgestellt hat. Ich hatte mich zunächst gefragt, ob der Aufwand lohnt – doch jetzt bin ich gewiss. Die Concept Map sollte nie fehlen.

Basierend auf der Concept Map habe ich dann auch die Nachrichtenkontrakte gestaltet. Darin kamen im Grunde keine einfachen Typen mehr vor. Statt eines string hat das Frontend ein PrüfTextPaket geschickt. Das hat niemand als Overkill bemängelt. Sehr schön. Ich fühle mich in dem Ansatz bestätigt, zumindest auf Komponentenebene im Grunde keine primitiven Typen mehr einzusetzen. Man vergibt sich mit primitiven Typen nämlich ein Mittel, den Code verständlich zu machen. Aber dazu mehr in einem anderen Blogartikel.

Cool war es zu sehen, wie motiviert alle mitgedacht haben. Soviel Offenheit und Durchhaltevermögen bei Architekturdiskussion! Toll! Und dann auch zu später Stunde noch viel Ehrgeiz bei der Implementation. Wahnsinn!

Was ist weniger gut gelaufen?

Bis zur Implementation ist alles nach Plan gelaufen. Doch dann… Zwar hatte ich den richtigen Gedanken, Integrationsproblemen mit einer “Tracer Bullet” “Kurzimplementation” vorzubeugen. Aber die Ausführung habe ich schlecht vorbereitet.

Das Problem war nicht so sehr, dass Code nur per USB-Stick die Runde machen konnte. Schöner wäre zwar gemeinsamer Zugang mit Mercurial Repository gewesen… doch es ging auch so. Nur langsamer. Viel schlimmer war, dass ich zuwenig über Konventionen gesprochen habe. Denn wo Tools fehlen, müssen Konventionen her.

Die binären Kontrakte haben natürlich die grundsätzliche “Zusammensteckbarkeit” der getrennt entwickelten Komponenten garantiert. Das hat funktioniert. Wir hatten kein wirkliches Integrationsproblem der Assemblies.

Wie der Code aber an mich ausgeliefert wurde, das war ein Problem. Visual Studio kann ja in so unterschiedlicher Weise benutzt werden. Da habe zuwenig erklärt bzw. vorgegeben. Besser wäre es gewesen, ich hätte für jedes Komponenten kurz eine Rumpf-Projektmappe aufgesetzt. Das hätte zwar etwas Zeit gekostet – am Ende wäre dadurch aber so mancher Reibungsverlust vermieden worden.

Lehre #1: Solange Konventionen für die Codeorganisation unbekannt sind oder noch nicht verlässlich eingehalten werden, sollten Komponentenimplementationen als Rahmen vorgegeben werden. Dann gibt es keine Frage, wohin der Output-Path zeigen soll, woher NUnit kommt, wo die Tests zu hinterlegen sind, wie die Bennungen sind, so dass der autom. Buildprozess schlank bleibt.

Kreativität ist ja eine gute Sache – aber sie sollte einen Rahmen haben. Dass z.B. Entwickler die Freiheit haben, Komponenten nicht gem. der Ubiquitous Language zu benennen, ist falsch verstandene Kreativität.

Lehre #2: Die Ubiquitous Language ist heilig. Spaß mit Benennungen mögen Entwickler vielleicht hier und da in ihren Komponenten haben. An den Schnittstellen jedoch und auf Architekturebene ist dafür kein Raum. Verständlichkeit entsteht nur, wenn die gemeinsame Sprache auch wirklich gesprochen wird.

Die Zeit war am Ende knapp. So haben wir alle auf eine erfolgreiche Integration gestarrt. Darunter hat die Codequalität gelitten. TDD im Speziellen war dieses Mal nicht wirklich ein Thema. Und Clean Code Developer Bausteine im Allgemeinen (jenseits der Architektur) auch nicht. So haben sich – wie ein Blick in den Code zeigt – Unschönheiten eingeschlichen. Manche davon waren sogar auf der Projektion zu sehen, weil sie mit dem GUI zu tun hatten.

Lehre #3: Keine Integration ohne Code-Review. Soviel Zeit muss sein. Für den Event war es ok, mal ohne Review zu leben. Es ging ja vordringlich um den Architekturentwurf. Die Implementierung am Ende war Kür und Spaß. Wenn es jedoch etwas ernster wird, dann gibt es kein “Done!” ohne Review.

TDD erleben, ist eine gute Sache. Architekturen mit “parallel rauchenden Köpfen” umsetzen, ist aber auch eine gute Sache. Beides sollten Entwickler öfter tun. Für TDD mag dabei eine Projektion reichen. Beim parallelen Entwickeln ist jedoch erstens ein Coderepository und zweitens ein Zugriff für alle darauf unverzichtbar.

Lehre #4: Das Google Projects Repo war eine gute Sache  - allerdings nur für mich. Das sollte beim nächsten Mal anders sein. Wie könnte das gehen? Mehr Teilnehmer mit einem UMTS-Stick. Oder ein WLAN mit einem Rechner, der ein Repo hostet. Oder ich muss einfach auf dem Zettel haben, dass ich ja einen WLAN UMTS Stick habe, über den ich auch anderen Internetzugang geben kann. Die 4 Rechner hätte der wohl stemmen können.

Schwieriger wird es bei der Versionskontrollsoftware. Viele sind mit SVN oder TFS vertraut. Mit denen würde ich soetwas aber nicht machen wollen. Ein verteiltes Versionskontrollsystem wie Mercurial (oder auch Git) ist viel besser geeignet für verteilte Teams. Da kann jedes Team z.B. in mehreren Commits bis zur Tracer Bullet Implementation kommen, die mit einem Push auf den Server schieben und dann lokal weiterarbeiten, während die Integration sich den Tracer Bullet Stand von allen mit Pull herunterlädt.

Beim nächsten Mal versuche ich es mit TortoiseHg für alle. Das ist einfach zu bedienen. Damit bekommt jeder ein Clone, ein Commit und ein Push hin. Insbesondere ich Mercurial auch sehr tolerant gegenüber Löschungen und Umbenennungen.

Fazit

Trotz einiger Stolpersteine ist das Coding Dojo aus meiner Sicht schön gelaufen. Mein Eindruck war, die Teilnehmer haben etwas mitgenommen. Und sie haben auch Spaß gehabt. Sonst wären sie nicht bis zum bitteren Ende nach knapp 4 Stunden geblieben. Super! Danke an alle fürs Kommen und Mitdenken und Mitmachen.

Und Danke an Ilker für die Einladung. Und Danke an Microsoft für Raum und Annehmlichkeiten. Von mir aus können wir das gern wieder mal machen ;-)

Wem es Spaß gemacht hat und wer tiefer eintauchen möchte in systematischen Softwareentwurf und komponentenorientierte Entwicklung, der kann ja mal überlegen, ob er/sie beim Clean Code Developer Praktikum im Juli mitmachen will. Das bietet 5 Tage Praxis pur – und ist auch noch kostenlos.

Montag, 24. Mai 2010

Überraschende Relevanzwellen [OOP 2010]

image Schon interessant, was zu Wellen im Twitter-Teich führt. Da stolpere ich während der Lektüre von “Projektmanagement” von Thorsten Reichert beim “Zusammenfassungsservice” getAbstract über den Satz

„Viele Unternehmen haben nie Zeit, Dinge richtig zu tun, aber stets Zeit, Dinge mehrmals zu tun.”

Den twittere ich – und erzeuge unerwartet weitreichende Reaktionen. Wow!

Nicht, dass mich die Funktionsweise von Twitter wundert. Nein, mich wundert, was die Gemüter hier in Resonanz versetzt. Ist nicht mein erster Tweet, aber der erste, bei dem ich aus so unterschiedlichen Ecken Retweets sehe. Das Thema schlägt offensichtlich einige Saiten in der Entwicklergemeinde an.

Was sind denn typische Beispiele, wo das DRY-Prinzip vom Management nicht eingehalten wird? Doppeltarbeit statt “einmal richtig tun”? Wer mag Situationen und Fälle benennen? Je mehr Konkretes zusammengetragen wird, desto eher ists möglich, daraus Ursachenmuster abzuleiten und vielleicht doch mal etwas dagegen zu tun. In kleinen Schritten.

Freitag, 21. Mai 2010

Biosphere 2 - Sind Wissensinseln “böse”? [OOP 2010]

image Grad kommt alles zusammen. Ich lese einen Thriller über die Evolution, die auf einer abgeschiedenen Insel zu sehr bösen Kreaturen geführt hat (“Biosphere” von Warren Kaye). Dann höre ich Jens Coldewey auf der SET in Zürich, der darüber spricht, wie böse es für Projekte ausgehen kann, wenn sie sich nicht gegen Inseln wehren, gegen Wissensinseln.

Und dann spreche ich am selben Tag mit Ivan Engler, dem Regisseur des Sci-Fi Spielfilms “Cargo”, der kein Problem mit Wissensinseln zu haben scheint. Im Gegenteil! Sie machen für ihn einen Teil der Effizienz einer Spielfilmproduktion aus.

Ja, was denn nun? Sind (Wissens)inseln “gut” oder “böse”?

Natürlich gibt es da keine pauschale Antwort. Es kommt immer darauf an, auf den Kontext. Deshalb könnte ich das Thema auch zu den Akten legen und einfach sagen: Beim Film sind Wissensinseln ok, bei der Softwareentwicklung hingegen sind sie unakzeptabel. So ist das halt.

Doch ich mag mich noch nicht von den Wissensinseln in der Softwareentwicklung verabschieden. Der Begriff suggeriert Kontraproduktivität – aber den kann ich ja austauschen. Wenn ich stattdessen Spezialisierung sage, dann ist die Konotation schon ganz anders.

Wenn Wissensinseln pauschal “böse” sein sollten, dann ist Spezialisierung pauschal “gut”. Spezialisierung ist schließlich das Ergebnis einer komplizierten Welt, in der nicht mehr jeder alles können kann (oder will). Damit meine ich nun nicht die seelenlose Spezialisierung eines seiner Produkte entfremdeten Fließbandarbeiters. Nein, ich meine eine Spezialisierung wie die einer Maskenbildnerin oder eines Kameramannes oder eines Motoringenieurs oder eines Kommunikationselektronikers.

imageIvan Engler hat keine Angst, dass eine Maskenbildnerin krank wird. Sie ist auch in einer laufenden Filmproduktion in ihrer Funktion ersetzbar. Das mag nervig sein, weil dann Aufwand zu treiben ist für eine Ersatzkraft, doch das ist kein Beinbruch. Und auch VW hat keine Angst, dass ein Motoringenieur ausfällt. Ist der eine krank, übernimmt ein anderer diese hochspezialisierte Aufgabe.

In der Softwareentwicklung allerdings geht die Angst um. Der truck factor scheint quasi immer bei 1 zu sein, sobald sich eine Spezialisierung entwickelt. Das scheint mir der Befindlichkeit in vielen anderen Branchen zu widersprechen. Ich ahne eine Überempfindlichkeit der Softwareentwicklung.

Natürlich kann ich Jens Coldeweys grundsätzlichen Gedanken zustimmen. Es gibt Wissensinseln, die “böse” sind. Und man sollte sie sich auch nicht unbewusst entwickeln lassen. Praktiken wir Reviews und Pair Programming sind probat, um dem entgegen zu wirken. Kein Problem. Ich bin für diese Praktiken und Wissensaustausch im Team.

Und dennoch… Ich bin auch weiterhin der Überzeugung, dass es illusorisch ist anzunehmen, alle Entwickler könnten gleichermaßen Experten in all den Technologien sein, die in einer größeren Anwendung zum Einsatz kommen. Alle sind Silverlight-, WCF-, NHibernate-, WF-, Azure-, InRule-, Oracle-Profis usw.? Das ist Quatsch.

Im Umkehrschluss bedeutet das: Solange der Wille besteht, alle auf dem gleichen Level zu halten, kann dieses Level nur mittelmäßig at best sein.

Soweit die beiden Positionen: Wissensinseln sind “böse”, Spezialisierung ist für Höchstleistung unvermeidbar.

Lässt sich da noch eine Brücke schlagen?

Ja, mir scheint, das geht. Dazu müssen wir aber die Architektur in den Blick nehmen. Auch Jens Coldewey hat Conway´s Law erwähnt: Organisationsstrukturen spiegeln sich in Produktstrukturen wider. Da hake ich mal ein und frage: Wenn denn nun die Organisation dazu führt, dass eben keine Grenzen mehr zu sehen sind – alle sind in ihrem Wissen gleich –, wie soll denn dann die Software aussehen, die so eine Organisation produziert?

Vor dem Hintergrund von Conway´s Law bezweifle ich, dass eine Organisation, in der alle gleich sein sollen, Software herstellen kann, die wahrhaft modular ist, d.h. in der es ganz klare Verantwortlichkeiten gibt. Collective Code Ownership widerspricht insofern sauberer Architektur. Oder anders: Collective Code Ownership tut nichts dafür, dass es zu einer evolvierbaren Architektur durch Grenzziehung in Form von Entkopplung kommt. Wenn die hergestellt werden soll, dann muss ganz bewusst an anderer Stelle Kraft aufgewandt werden. Es gibt aus der Haltung zur Vermeidung von Wissensinseln heraus kein Bedürfnis, in Komponenten (oder gar “Services”) zu denken.

Und jetzt die Umkehrung: Ich setze voraus, dass Architektur modular (komponentenorientiert, serviceorientiert, entkoppelt usw.) sein soll. Punkt. Daran geht für mich nichts vorbei. Soviel ist der Langlebigkeit von Software geschuldet. Es geht ums pure Überleben des Produktes. Das bedeutet – im Sinne von Conway´s Law –, dass die Organisation ebenfalls “irgendwie” modular sein muss. Andernfalls reibt sie sich immer wieder auf, um Strukturen herzustellen, die ihr nicht entsprechen.

Unverbrüchliche Architekturprinzipien sollen also die Organisation treiben!

Daraus folgt für mich, dass z.B. eine grundlegende Trennung von Infrastruktur und Domäne in der Organisation zu sehen sein sollte. Domänenlogik ist etwas ganz anderes als ein Frontend, die Persistenz, die Sicherheit, die Kommunikation usw.

Nun die Masterfrage: In welchem dieser Bereiche sind Wissensinseln ein Problem? Aus meiner Sicht nur bei der Domäne. Software wird sehr sensibel überall dort, wo Domänenlogik im Spiel ist. Und das waren auch die Beispiele, die Jens Coldewey gebracht hat. Domänenlogik ist so sensibel, weil die Experten, die sich mit Softwareentwicklung und (!) Domäne auskennen, so dünn gesät sind.

Das ist übrigens auch der Fall im Filmbusiness. Kameramann und Regisseur und Schauspieler sind nicht so leicht auszutauschen wie eine Maskenbildnerin oder ein Mikrofongalgenhalter. Jene sind mit dem Thema des Films, der Vision eng verwoben; das ist die Domäne einer Produktion. Alles andere ist “Beiwerk” – wichtig, aber ohne Domänenbindung. Maskenbildner etc. haben generische Kompetenz.

Übertragen auf die Softwareentwicklung meine ich daher, dass wir dahin kommen müssen, architektonische Prinzipien ernst zu nehmen. Alles, was mit Infrastruktur zu tun hat, ist domänenunabhängig von der Architektur so zu kapseln, dass es von Experten mit generischer Kompetenz realisiert werden kann. Das mögen – je nach Anwendung – 5%, 10% oder 30% der Code sein. Immer bleibt der Löwenanteil jedoch in der Domäne.

Dennoch ist das ein Gewinn. Es ist nun ganz klar, welche Funktionalität grundsätzlich ohne truck factor realisierbar ist. Denn fällt der Silverlight-Experte aus, wird der nächste angeheuert. Der braucht nur wenig Einarbeitung, weil er keine Ahnung von der Domäne haben muss. Das hochspezialisierte Wissen für optimalen Technologieeinsatz macht kein Wissensinselproblem, weil es breit verfügbar ist (oder zumindest sein könnte). Hier kommt es vor allem auf Erfahrung mit nicht-funktionalen Anforderungen an. Die sind aber quasi in jedem Projekt zu gewinnen.

Es bleibt übrig der Bereich der Domäne. Hier werden die Experten in jedem Team individuell herangezüchtet. Und tatsächlich darf es in Bezug auf die Domäne im Team keine Wissensinseln geben. Domänenwissen ist so breit wie möglich verfügbar zu machen im Team. Denn dort sitzen die quasi einzigen Experten weltweit.

Von Domänenexperten dann aber auch noch Hochleistungen in technologischer Hinsicht zu erwarten, halte ich für eine Überforderung. Natürlich darf, kann, soll jeder Domänenexperte über eine Domänenkenntnis und gute “Programmierkenntnisse” der Plattform hinaus auch noch technologische Spezialgebiete haben. Nur sollte sich ein Projekt darauf nicht verlassen. Und es sollte nicht versuchen, solche technologischen Kompetenzen breit zu streuen. Das funktioniert nicht.

Stattdessen ist es Aufgabe der Architektur, Spezialgebiete (oder Belange) deutlich zu trennen. Die Domäne ist ein solches Spezialgebiet, Persistenz, Frontend etc. sind andere. Und für jedes Spezialgebiet ist Redundanz in Bezug auf die Kompetenzen herzustellen.

Redundanz in der Domäne ist Aufgabe des Projekteams, Redundanz bei Infrastrukturtechnologiekompetenzen ist Aufgabe des Marktes.

Die Filmindustrie hat das hinbekommen. Maskenbildern, Tischler, Bühnenbildner gibt es zuhauf. Bei der Domäne ist es dort aber naturgemäß schwierig. Dafür sind die Projekte auch zu kurz und personengebunden. Deshalb gibt es Versicherungen. Fällt der Hauptdarsteller wegen Unfall aus, kompensiert eine Versicherung den Verlust.

Das könnte auch in der Softwareindustrie funktionieren – wenn denn ein Team nachweisen kann, dass es Wissensinseln vermieden hat, soweit das möglich ist. Aber das ist ein anderes Thema…

An dieser Stelle ich mir wichtig, die Vereinigung aus Spezialisierung und Vermeidung von Wissensinseln herzustellen. Die liegt darin, die architektonisch saubere Separation of Concerns auf das Team zu übertragen. Daraus folgt, dass das Team bzw. Kernteam vor allem die Verantwortung für die Domäne bekommt. Darin sollen dann alle im Team Experten werden; Wissensinseln sind zu vermeiden, weil es außerhalb des Teams kaum Ersatz gibt.

Alle anderen Belange sollte das Kernteam aber nicht auch noch exzellent abdecken. Stattdessen sollte es sie strukturell isolieren und von externen Experten aufsetzen lassen. Im Team muss dann nur noch  Pflegekompetenz existieren. Teammitglieder müssen damit arbeiten und nur noch verstehen, was da gemacht wurde und hier und da korrigierend eingreifen können. Falls tiefere Kenntnis nötig werden sollte, wird wieder ein Experte “eingekauft”.

Damit vermeiden Teams den unmöglichen Spagat zwischen hoher Domänenkompetenz auf der einen Seite und technologischer Exzellenz auf der anderen Seite. Und so entsteht auch ein Markt für technologische “Söldnerexzellenz", die öfter als bisher in unterschiedlichen Projekten eingesetzt wird.


Anders, so glaube ich, kommen wir nicht heraus aus dem ewig mittelmäßig bis schlechten Einsatz von Technologien. Wissensinseln sind also tatsächlich zu vermeiden; das bedeutet jedoch nicht, wir müssen auf eine Spezialisierung verzichten. Spezialisten sind nötig, dürfen nur nicht unersetzbar sein. Deshalb darf der Anspruch nicht sein, alle Spezialisten “selbst herzustellen”. Das ist die Herausforderung.

Natürlich ist es einfacher, “alle sollen möglichst gleich sein” zu denken. Das macht weniger Planungsaufwand. Und das ist auch ok. Nur darf ein Team dann nicht erwarten, wenn es in vielen Disziplinen “gleichgeschaltet ist”, in allen auch Höchstleistungen zu erbringen. Das Prinzip “Wissensinseln vermeiden” sollte daher nicht pauschal allein Anwendung finden.

image

image PS: Ivan Engler wird übrigens auf der prio.conference die Keynote halten. Zumindest wenn er dann nicht gerade in Hollywood weilen muss. Doch ich bin da mal zuversichtlich…

Montag, 10. Mai 2010

Kaffeehauskonsultation in München

Umfrage: Kaffee ist Teil einer ausgewogenen Ernährung Am Donnerstag 27.5.2010 ist es wieder so weit: kostenlose Beratung in Sachen .NET Softwareentwicklung in München. Von 10h bis 17h können Sie mich in meiner “Praxis” konsultieren. Die öffne ich im Café Mozart und bin gespannt, worüber wir uns unterhalten. Sie finden mich dort “im Hinterzimmer” für die Kaffeehauskonsultation.

Bringen Sie Ihren Laptop mit, dann können wir uns auch Ihren Code ansehen, falls nötig. Einen Block für Diagramme habe ich dabei. Und dann reden wir über Softwarearchitektur, Clean Code Developer und andere spannende Themen.

Sie können natürlich einfach so vorbeischauen. Besser ist´s jedoch, wenn Sie mir schnell eine Email schicken, damit wir einen Termin abmachen. Jedes Gespräch sollte nicht länger als 75 Minuten dauern, damit auch andere eine Chance auf Konsultation bei Kaffee haben.

image

Donnerstag, 6. Mai 2010

Asynchrone Kommunikation mit EBCs statt “Async-Pattern”

Freut mich, dass Thomas Christian im build broken Blog eine Lanze für die asynchrone Kommunikation mit Events gebrochen hat. Schade allerdings, dass der Code dafür so umständlich aussieht.

Kommunikation à la Async-Pattern

Ein kleines Formular fordert von einem Calculator die Quadratur einer Zahl an: m_calculator.CalcAsync(number). Was würden Sie dann im Calculator für Code erwarten? Irgendwo sollte number * number stehen. Klar. Und ansonsten? Schauen Sie einmal, wie der Calculator bei Thomas aussieht:

image
image

Puh… Da ist es gar nicht so leicht, das zu finden, worauf es eigentlich ankommt, finde ich. Sehen Sie die kalkulierende Businesslogik? Und was macht der Rest des Codes? Der ist dazu da, ein Pattern zu implementieren.

Wenig Code für das Wesentliche, viel für Infrastruktur – das hört sich für mich nicht so gut an, auch wenn ich das Kommunikationsmodell voll unterstütze.

Ich schlage daher einen anderen Weg vor. Hier meine Version der Szenarios:

Kommunikation à la Event-Based Components

Zunächst die Businesslogik:

image

Hier finden Sie keine Rauschen durch Infrastrukturcode. Der Fokus ist ganz klar auf der Problemdomäne. Aber Achtung: Ich habe keine Funktion für Calc() geschrieben, sondern eine Prozedur, d.h. eine Methode ohne Rückgabewert. Das Resultat liefert die Methode dann über einen Event: DeliverCalcResult(). So ist das bei Event-Based Components.

Jetzt der Client-Code im Formular:

image

Auch hier kein Rauschen durch Infrastruktur. Nicht mal der Calculator wird als Komponenteninstanz injiziert. Das Formular kennt keinen Calculator. Es ist völlig unabhängig von einer solchen Funktionseinheit. Es äußert Berechnungswünsche lediglich über einen Event – CalcRequest – und empfängt Berechnungsresultate mit OnCalcResult().

Das ist im Prinzip sehr ähnlich wie bei Thomas. Im Detail ist es jedoch anders, da das Formular eben auf die Kenntnis einer Service-Funktionseinheit verzichtet. Die wird bei Thomas noch im Formular instanziert.

Und wie kommt es nun zu Berechnungen, wenn das Formular den Calculator nicht kennt? Beide Funktionseinheiten werden von außen verdrahtet. Damit sind Logik und Abhängigkeiten als Concerns sauber getrennt.

image

Voilà! Jetzt kann das Programm starten und berechnet Quadratzahlen. Zuerst werden die Funktionseinheiten instanziert. Dann werden die Eventhandler in die Events gesteckt. Mehr ist nicht nötig. Keine Funktionseinheit weiß von der anderen. Nur der Verdrahtungscode kennt sie.

Asynchrone Kommunikation

Die kleine Anwendung funktioniert nun zwar, aber synchron. Thomas Beispiel will ja aber gerade zeigen, wie einfach asynchrone Kommunikation mit Events ist. Was muss ich also tun, um meinen Nachbau ebenfalls asynchron zu machen?

Asynchronizität erfodert keine (!) Veränderung an der Geschäftslogik oder im Frontend. Das halte ich für den wesentlichen Vorteil meines Vorgehens. Ich muss lediglich die Verdrahtung anpassen:

image

Ich instanziere zwei kleine Standard-Funktionseinheiten, eine, die Events asynchron weiterleitet und eine, die Events zurück in den GUI-Thread bringt. Diese Funktionseinheiten schalte ich zwischen den Dialog und den Calculator. War die Verbindung z.B. bisher direkt

dlg.CalcRequest = calc.Calc;

so ist sie nun indirekt:

dlg.CalcRequest = asyncProcessAsynchronously;
async.OnAsynProcessing = calc.Calc;

Die Standard-Komponenten sind natürlich auch Event-Based Components, d.h. Input erhalten sie über Eventhandler und Output generieren sie mittels Events.

Das war´s. Mehr ist nicht zu tun. Die Geschäftslogik läuft jetzt im Hintergrund. Und die Ergebnisse kommen problemfrei im Vordergrund an. Wie das funktioniert? Egal :-) Das ist die Magie der Standard-Komponenten.

Fazit

Asynchrone Kommunikation mit Events ist eine gute Sache, da stimme ich Thomas zu. Aber man sollte diese Sache dann auch so einfach wie möglich halten. Das bedeutet für mich, dass ich in der Geschäftslogik (oder auch im Frontend) von technischen Klimmzügen, die die Asynchronizität herstellen, nichts sehen will. Geschäftslogik muss frei von diesem Concern sein. Der steckt am besten in wiederverwendbaren Standard-Komponenten. Event-Based Components bieten dafür eine gute Grundlage.

P.S.

Na, schön. Hier nun doch noch der Code für die Standard-Komponenten. Damit keiner sage, der sei bestimmt total kompliziert ;-)

image

image

Dieser Code ist wiederverwendbar. Er folgt nur dem Event-Based Component Muster für die Kommunikation. Deshalb kann er mit beliebigen Pins von anderen Komponenten zusammengesteckt werden, ohne dass die etwas davon merken. Das ist Composability.

Montag, 3. Mai 2010

Nullonade – Monade statt Null

In der Diskussion um Null als Rückgabewert gab es ein Codeschnippsel, mit dem Thomas Bandt zeigen wollte, dass der TryGetUserById(…)-Vorschlag nicht zwangsläufig zu intuitivem Code führt. Ich formuliere das Beispiel hier mal etwas knapper:

User tmpUser;
bool isAuth = repo.TryGetUserById("987", out tmpUser) &&
              sec.CheckUser("somepassword", tmpUser);

Als Problem sieht Thomas – durchaus zurecht – die Abhängigkeit von CheckUser() von einem Seiteneffekt. Die globale Variable tmpUser muss vor Aufruf gesetzt sein, was innerhalb des logischen Ausdrucks nicht ganz so offensichtlich ist.

Etwas deutlicher wäre die Abhängigkeit der Reihenfolge beider Methodenaufrufe, wenn der Ausdruck traditioneller als Schachtelung formuliert wäre:

bool isAuth;
User tmpUser;
if (repo.TryGetUserById("987", out tmpUser))
    isAuth = sec.CheckUser("somepassword", tmpUser);
else
    isAuth = false;

Doch eigentlich sind Schachtelungen ja “böse” ;-) Sie erhöhen die (zyklomatische) Komplexität des Codes. Also vielleicht lieber so:

User tmpUser;
bool isAuth = repo.TryGetUserById("987", out tmpUser);
isAuth = isAuth && sec.CheckUser("somepassword", tmpUser);

Das mag besser lesbar sein – doch das Grundproblem ist eigentlich nicht gelöst. Das besteht in der Abhängigkeit selbst, also letztlich in der zu beiden Methoden globalen Variablen tmpUser. Die ist nötig, weil Thomas keine Exception werfen möchte, falls es den angeforderten User nicht gibt. Wäre das anders, könnte er nämlich auch ohne diese Variable formulieren:

bool isAuth = sec.CheckUser(“somepassword”,
                            repo.GetUserById(“987”));

Das ist zwar wieder geschachtelter Code, doch irgendwie sind wir sowas ja gewohnt ;-)

Get into the flow

So richtig cool finde ich das aber alles noch nicht. Deshalb schlage ich mal eine weitere Alternative vor. Wäre es nicht am allerschönsten, wenn wir es so schreiben könnten:

var isAuth = repo.GetUserById(“987”) |> sec.CheckUser(“somepassword”);

Das ist natürlich Pseudocode. Aber schön wärs, oder? GetUserById() würde immer noch keine Exception werfen und trotzdem (!) würde das Ganze immer funktionieren.

In F# geht das. Da gibt es so einen Pipe-Operator |> und noch etwas anderes, das nötig ist, einen Option-Typ. Aber in C# sitzen wir erstmal auf dem Trockenen :-(

Zum Glück können wir daran etwas tun. Wir können mit etwas Vorarbeit auch in C# so einen “Flow” von Anweisungen schreiben. Hier meine C#-Version:

bool isAuth = repo.GetUserById("987")
                  .Continue(user => sec.CheckUser("somepassword", user))
                  .WithDefault(false);

Liest sich doch gar nicht schlecht, oder? Es soll ein User geladen werden und danach soll geprüft werden, ob der User ein bestimmtes Passwort hat. Ist das so, dann ist das Ergebnis true, ansonsten false.

Die Sequenz der Verarbeitungsschritte in unserem Kopf findet sich im Code wieder – ohne dass wir eine temporäre Variable bräuchten. Naja, nicht ganz: denn der user-Parameter der Lambda-Funktion ist eine solche temporäre Variable. Doch die ist nicht global, sondern lokal. Es gibt also keine schwer zu überblickenden Abhängigkeiten.

Optionen als Zwischenwerte

Möglich ist so eine Formulierung, wenn als Resultat von GetUserById() kein User (oder gar Null), sondern ein sog. Option-Wert zurückgeliefert wird. Den gibt es in F# gratis; für C# können wir ihn so bauen:

public class Option<T>
{
    public Option()
    {
        this.IsSome = false;
    }

    public Option(T some)
    {
        this.Some = some;
        this.IsSome = true;
    }

    public T Some { get; private set; }

    public bool IsSome { get; private set; }
    public bool IsNone { get { return !IsSome; } }

    …
}

Der Trick an Optionswerten ist, dass es immer eine Instanz gibt. Es geht also nicht um Objekt oder Null, sondern um Options-Objekt gefüllt oder nicht gefüllt. Wenn es gefüllt ist, dann liefert IsSome true, wenn nicht, dann liefert IsSome false bzw. IsNone true. Zugriff auf den Wert gibt die Some-Property.

var optInt = new Option<int>(42);
Console.WriteLine(“{0}, {1}”, optInt.IsSome, optInt.Some);

gibt aus:

true, 42

Mit so einem Typen kann GetUserById() nun umformuliert werden zu:

Option<User> GetUserById(string id) {…}

Die Methode liefert immer ein Option-Objekt zurück und die Umgebung muss prüfen, ob etwas drin steckt oder nicht:

var optUser = repo.GetUserById(“987”);
if (optUser.IsSome)
    …

Das ist fast so wie eine Prüfung auf Null – aber besser. Denn mit einem Option-Objekt kann man immer weiterarbeiten.

Logik verstecken in einer Monade

Das Ziel ist immer noch der “Flow”, d.h. globale Variablen und Prüflogik auf unerwünschte Ergebnisse zu verstecken. Weil nun immer ein Option-Objekt vorliegt, können wir darauf immer eine Methode aufrufen

public class Option<T>
{
    …

    public IEnumerable<Option<TOutput>> Continue<TOutput>(Func<T, TOutput> processor)
    {
        return new[] {this}.Continue(processor);
    }
}

und auch noch Erweiterungsmethoden in Anschlag bringen

public static class OptionExtensions
{
    public static IEnumerable<Option<TOutput>> Continue<TInput, TOutput>(
                                     this IEnumerable<Option<TInput>> values,
                                     Func<TInput, TOutput> processor)
    {
        return values.Where(v => v.IsSome)
                     .Select(v => new Option<TOutput>(processor(v.Some)));
    }

    public static TInput WithDefault<TInput>(
                                     this IEnumerable<Option<TInput>> values,
                                     TInput defaultInCaseOfNone)
    {
        return (values.FirstOrDefault() ??
                     new Option<TInput>(defaultInCaseOfNone)).Some;
    }
}

Ich denke, damit habe ich eine Monade definiert, d.h. ein “Dings”, mit dem sich quasi unsichtbar ein Kontext um mehrere Anweisungen wickeln lassen kann.

Dass ich dafür auf IEnumerable<> zurückgegriffen habe, ist lediglich meiner Faulheit geschuldet ;-) (Mit IEnumerable<> kriegen ist nämlich die Verkettung geschenkt, weil der Typ selbst schon eine Monade ist.) Ebenso die Methode Continue() der Option-Klasse. Hätte ich mir mehr Mühe gegeben, hätte ich statt IEnumerable<> eine spezielle Monadenklasse gebastelt. Das wäre sauberer gewesen.

Für den Punkt, den ich hier rüberbringen wollte, geht es aber auch so, würd ich sagen. Ich möchte einfach einen weiteren Weg aufzeigen, ohne Null leben zu können – und dadurch lesbaren Code zu bekommen. Die Verkettung könnte noch weiter gehen, falls mehr “Transformationsschritte” nötig wären, die immer wieder Output erzeugen, der Input für den nächsten sind. Die Leistung der Monade besteht darin, die Schritte abzubrechen, falls kein Ergebnis geliefert wird (der frühere Null-Fall). Die verbirgt die Logik der Prüfung, ob ein Zwischenergebnis vorliegt und es noch weitergehen soll.

Die C#-Mittel bleiben dabei immer etwas hinter denen von F# zurück. Doch mir scheint “das Denken in Option-Werten” durchaus den einen oder anderen Versuch wert. Wie gesagt, mit etwas mehr einmalig aufgewandter Zeit, ist das auch noch eleganter ;-)

Sonntag, 2. Mai 2010

Es hilft nichts, dass es darauf ankommt – nicht nur beim Null-Problemo [OOP 2010]

Erst ein Feiertag, jetzt ein Sonntag und die Diskussion um “Null oder nicht Null” geht weiter. Als hätten diese Softwareentwickler nichts anderes zu tun… ;-) Ilker hat versucht, einen ausbalancierenden Schlussstrich unter die Diskussion zu ziehen, um uns wenigstens ein Rest schönes Wetter genießen lassen zu können. Doch mich wurm da noch etwas. Und weil der Stein, an dem ich mich da anstoße, bei ihm so ausdrücklich in seinem Blogartikel zu lesen ist, greife ich auch am Sonntag Morgen nochmal in die Tasten:

Woran ich mich in dieser Diskussion – die allerdings nur stellvertretend für viele andere ist – störe, das sind Aussagen wie

“Es kommt auf den Anwendungsfall an. Die beliebte ‘It-Depends’-Weisheit streckt das Thema mit geballter Kraft nieder.”

und

“So oder so – beides ist machbar und beides hat seine Berechtigung.”

Ich kann das einfach nicht mehr hören. (Sorry, Ilker, ist nix Persönliches. Diese Formulierungen sind vielmehr ein Anti-Pattern unserer Branche.) Kommt irgendeiner mit ‘ner Frage, was er tun soll – diese oder jene Technologie oder dieses oder jenes Sprachfeature oder diesen oder jenen Lösungs weg? –, dann antwortet die Branche unisono: “It depends!”, “ Kommt darauf an… “, “Im Prinzip ist alles möglich.”

Was soll denn das? Ja, ja, ich mache so einen Spruch auch mal. Am Ende sind diese Aussagen aber doch ein Armutszeugnis. Vor allem aber: Sie helfen nicht. Niemandem. Vor allem nicht dem, der gefragt hat.

“Es kommt darauf an…” ist eine triviale Antwort. Sie ist trivial und nutzlos, weil sie quasi immer wahr ist. Es kommt immer im Leben darauf an. Auf irgendwas. Wo Wahlmöglichkeiten bestehen, da kommt es immer auf den einen oder anderen Faktor an, ob die eine oder andere Möglichkeit gewählt werden sollte. Diese Faktoren mögen subjektiv sein, also rein persönlich, oder objektiv, d.h. irgendwie aus der Problenstellung bzw. der angestrebten Lösung abgeleitet.

Also: Leute, ihr habt/wir haben immer Recht, wenn wir sagen “Es kommt darauf an…”. Super. Lasst uns darauf einen trinken. Und dann lasst uns endlich damit aufhören. Wer “Es kommt darauf an…” sagt (oder etwas Sinngleiches), der zahlt in Zukunft 5 EUR in das Phrasenschwein. Wie wäre das? Wir kommen einfach nicht voran mit solchen Sprüchen. Sie dienen nie-man-dem. Wir bringen weder den einzelnen Frager noch “unsere Kunst” damit voran.

Ok, so ein Spruch geht also nicht mehr. Was aber dann? Wir sollten, wann immer wie reflexartig “Es kommt darauf an…” sagen wollen, innehalten. Mund zu, Denkmaschine anwerfen… Das halte ich für den ersten Schritt. Nachdenken, ob denn aus einer Problembeschreibung sich nicht doch irgendwie ein Hinweis auf eine vorzuziehende Lösungsmöglichkeit ergibt.

Ja, Nachdenken verbraucht auch Kalorien, aber wir sollten uns diesen Sport gönnen. Der bringt uns selbst und “unsere Kunst” nämlich voran. Die Ergebnisse sind nämlich immer positiv: Schärfung der Wahrnehmung, Reflexion des eigenen Tuns, Ausarbeitung von Regeln.

Eine Regel hat sich ja auch in dieser Diskussion um das Null-Problemo herauskristallisiert:

Null-Regel #1: Man darf Null benutzen und auch als Wert zurückgeben – aber Vorsicht! Erst prüfen, ob es nicht auch anders geht.

Das ist doch schon mal ne schöne Sache, oder? Darin sind wir uns einig. Prost!

Nur verstehe ich nicht, warum Ilker dann schreibt

“Für mich gibt es beim Umgang und bei der Anwendung von Null keine Faustregel.”

Denn diese Regel ist doch eine Faustregel. Sie lautet: Setze Null eher nicht ein. Punkt. Warum sollten wir das runter spielen.

image Mein Gefühl ist, dass “die Branche” da an einem kollektiven mangelnden Selbstvertrauen leidet. “Man” traut sich nicht, einen Pflock in den Boden zu hauen. Denn wer Pflöcke in den Boden haut und die dann auch  noch mit Latten zu einem Areal verbindet, der läuft Gefahr, dass andere einen Streit von diesem Zaun brechen. Und das will “man” doch nicht. Ne, Streit ist doof.

“Wer Regeln formuliert oder verbreitet, wird mit Stirnrunzeln oder gar flame comments bestraft.” – so lautet das unausgesprochene Gesetz.

Regeln stören den Seelenfrieden dessen, dem sie “aufgedrückt” werden. Oder sie stören womöglich sogar den Seelenfrieden dessen, der sie aufstellt. Denn wer Regeln formuliert, der muss sich ja auch daran halten. Will “man” das aber? Wer weiß, vielleicht findet “man” es morgen bequemer, es anders zu tun – und dann wäre die Regel hinfällig. Aaargh… Also besser mal keine Regel aufstellen. Und schon gar nicht anderen die Befolgung einer Regel nahelegen. Denn was auch, wenn die damit nicht zum Erfolg kommen? Dann sind sie sauer auf “einen”.

Das sind natürlich sehr verständliche Regungen. Aber: Leute, Leute, so kommen wir nicht voran. Niemand behauptet, dass “alles” reglementiert werden sollte oder gar könnte. Angst, in der “künstlerischen Programmiererfreiheit” eingeschränkt zu werden, ist völlig (!) unbegründet. Maler, Bildhauer, Schauspieler, Musiker… alle sind vielmehr erst Künstler durch die Regeln ihres Metiers. Ohne Regeln keine Kunst. Denn Kunst ist sozusagen “mit und in den Regeln schaffen und spielen”. Ohne Regeln ist alles keine Kunst. Wir schätzen einen Meister seines Metiers dafür, dass er “gar künstlich” (d.h. soviel wir “nach den Regeln der Kunst” oder “virtuos”) etwas (er)schafft.

image Wer am leeren Tisch sitzt und hört, “Schaffe mal ein Kunstwerk”, der hat es schwer, nicht leicht. Sitzt er aber vor einer Staffelei mit Ölfarbenpallette und Pinsel in der Hand und bekommt den Auftrag “Schaffe ein impressionistisches Landschaftsbild”, der kann loslegen. Öl, Pinsel, Leinwand, Stilrichtung, Motiv: das sind Begrenzungen mit impliziten Regeln, die erst die Möglichkeit bieten, Künstler zu sein.

(Ja, ja, es gibt immer mal wieder auch Künstler, die dadurch groß werden, dass sie (scheinbar) regellos oder gegen die Regeln arbeiten. Aber Achtung: Erstens können sie sich nur profilieren im Kontrast zu etablierten Regeln der Kunst, zweitens schaffen diese Künstler durch ihr Tun (bewusst oder unbewusst) wieder neue Regeln, und drittens sind solche Regelwerk sprengenden bzw. ausweitenden Künstler die Ausnahme. Wer mein, ohne Regeln auszukommen, läuft also Gefahr, sich zu überschätzen.)

Bottom line: Ohne Regeln geht es nicht. Und jeder, der in einer Situation sitzt, wo er nicht recht weiter weiß, der sehnt sich nach einer Regel, die ihn leitet. Warum also diese branchenweite Ambivalenz? Einerseits Regeln suchen für die eigene Anwendung, andererseits aber keine Regeln formulieren wollen, wenn “man” gefragt wird.

imageOhne Regeln ist das Verhalten ein Rumgeeiere wie hier von Ilker trefflich beschrieben:

“Ich gebe in einigen Methoden NULL zurück. Meistens genau dann, wenn ich wirklich damit ausdrücken möchte, dass etwas katastrophales passiert ist. Ich finde es sehr schwerwiegend, NULL als Zuweisung oder Rückgabe stehen zu lassen – aber ich mache es manchmal ganz bewusst.”

Ja, was denn nun? Keine Faustregel, aber “manchmal ganz bewusst”? Wie geht das? Bewusstsein erfordert (!) einen Raum, in dem es sich eben bewusst verortet durch Entscheidungen. Und die Wände dieses Raumes bestehen (zumindest zum Teil) aus… Regeln. Die mögen sehr speziell sein, aber immer noch sind es Regeln, die man dann auch äußern kann, um sie zur Diskussion zu stellen.

Thomas hatte das in seinem ursprünglichen Blogartikel getan:

“Außerdem erwarte ich von jeder Methode null als Rückgabewert für den Fall, dass keine Daten in der Datenbank gefunden wurden.”

Jede Methode (seines Repositories) liefert bei Erfolg ein Objekt und bei Misserfolg Null. So war seine Regeln. Ob die gut oder schlecht ist, sei mal dahin gestellt. Das wurde ja auch ausführlich diskutiert. Zumindest war das eine Regel basierend auf einer bewussten Entscheidung. Die hat er geäußert. Nur so konnte darüber ein Diskurs beginnen. Wunderbar.

Ilker hingegen sagt, er sei bewusst – eine Regel (außer der obigen Null-Regeln #1) mag er aber eben nicht benennen. Das finde ich sehr, sehr schade. Denn so – ich wiederhole mich – kommen wir eben nicht voran.

Oder? Hoppla, jetzt hab ich mich doch durch Ilkers Statement, er hätte keine (Faust)Regel verwirren lassen. Natürlich hat er welche. Die Regel #1 und auch noch seine persönliche Regel:

Null-Regel #2 (von Ilker; noch zu diskutieren): In Katastophenfällen darf Null zurükgegeben werden.

Das ist doch mal eine Aussage. Darüber kann man diskutieren. Aber nicht hier.

@Ilker: Vielleicht magst du ja in einem weiteren Blogartikel ausführen, was Katastrophenfälle sind und warum dann Null als Rückgabewert erlaubt ist und wie zwischen Null und Exceptions als Mittel zur Anzeige von Katastophenfällen entschieden werden sollte. Darüber würde ich gern mehr hören.

Ilker hat also Regeln (mindestens zwei), zieht sich aber darauf zurück, dass “die beliebte ‘It-Depends’ Weisheit” im Falle Thomas “alles niederstreckt”. Warum? Warum keine klare Aussage, keine Empfehlung mit Verweis auf eine seiner Regeln? Weiß Ilker nicht mehr weiter? Das glaube ich nicht.

Ich möchte ihm stellvertretend für uns alle zurufen: Nicht verzagen! Mach doch eine klare Aussage. Habe eine Präferenz. Zeige Kontur. Mach dich sichtbar – ja, und auch angreifbar. Haue einen Pflock in den Boden.

Denn niemand wird dich oder irgendwen für soetwas verhaften. Entweder ist die Empfehlung für den konkreten oder auch allgemeinen Fall richtig/praktikabel – oder es stellt sich im Diskurs heraus, dass sie es nicht ist. Dadurch können doch dann aber alle nur gewinnen. Und niemand steht deshalb schlechter da. Auch nicht der, der die Regeln/Empfehlung ausgesprochen hat.

Niemand muss ja auch seine Regel/Empfehlung kampflos ausgeben. Nur weil ein anderer damit nicht übereinstimmt, heißt das nicht, das man falsch liegt. Solange wir einen Diskurs führen, also sachlich bleiben, solange kommen wir voran – und können am Ende auch mal unterschiedliche Meinungen behalten. In der Malerei gibt es Schulen, in der Programmierung kann es die auch geben. Da könnte es z.B. die “Null geht gar nicht, nie, nimmer!”-Schule geben oder die “Null ist überhaupt kein Problem”-Schule oder die “Null mit Vorsicht”-Schule oder die “Null nur mit Vorsicht und mit folgenden Regeln”-Schule.

image Ich gehöre – soviel kann ich sagen – zur letzteren. Deshalb hier mein Pflock im Boden:

Null-Regel #3 (Ralfs Vorschlag): Null darf nur Rückgabewert sein, wenn Null zur selben Kategorie gehört wie ein Nicht-Null Rückgabewert.

Darüber können wir gern diskutieren. Einen Anfang habe ich hier gemacht. Also: Klare Aussage von mir, kein Rumgeeiere. Und jetzt die Argumente dagegen. Aus der Community. (Zur Regel #2 sage ich etwas, wenn Ilker sie begründet. Hier nur soviel vorab: Ich bin dagegen ;-)

Und jetzt noch ein letzter Schwenk zurück zum Allgemeinen. Wir brauchen also Regeln. Wir sollten uns der Reflexäußerung “Es kommt darauf an…” enthalten. (Auch das ist übrigens eine Regel ;-) Noch ein Pflock von mir im Boden.) Besser, wir schalten in solchen Situationen erstmal die Denkmaschine an. Analyse hilft.

Ebenfalls hilfreich ist allerdings auch: Fragen und Zuhören! Denn so mancher, der sagt “It depends”, leidet womöglich nicht unter mangelndem Selbstvertrauen oder Denkfaulheit, sondern schlicht unter Unwissen. Er weiß nicht genug, um eine Entscheidung zwischen den Alternativen klar treffen zu können.

Dem kann dann durch Nachfragen und genaues Hinhören abgeholfen werden. Wenn man sich denn als Befragter überhaupt interessiert. Womit wir bei einem weiteren Grund für “Es kommt darauf an…”-Antworten sind: Desinteresse. “Was interessiert mich das Problem des anderen? Ich hab schon selber genug Probleme. Wenn mir doch mal einer helfen würde…” usw.

Hieraus ergibt sich auch eine Empfehlung für Hilfesuchende: Wer fragt und “It depends” als Antwort bekommt, der sollte nicht zufrieden sein. “It depends” ist trivial und beliebig. Wer fragt, sollte die Antwort als Aufforderung verstehen, mehr über das Problem zu erzählen oder überhaupt mal festzustellen, ob der Befragte überhaupt ein Interesse an einer Antwort hat. (Von einer Kompetenz zur Antwort sehe ich hier mal ab. Jeder ist kompetent zumindest insofern, als dass er dem Fragenden ein Spiegel sein kann. Auch das hilft oft.)

Fazit: Es hilft also nichts, dass wir die Hände in die Luft werfen und sagen “Es kommt darauf an…” Diese Phrase können wir uns in Diskussionen sparen. Sie macht nur Sinn als Replik auf eine ebenso sinnlose allgemeine Frage. Beispielfrage: “Sollte man die Daten mit einem RDBMS oder einem ODBMS speichern?”, Antwort: “Es kommt darauf an…”

In solche einem Fall mag die allgemeine Frage allgemein mit einer Phrase beantwortet werden, um dadurch aufzuzeigen, dass schon die Frage schlecht formuliert war. In dem Fall ist “Es kommt darauf an…” aber sozusagen ein Stilmittel – dass sofort als solches aufgedeckt werden sollte: “Es kommt darauf an… Das sage ich, weil Ihre Frage zu allgemein ist. Erklären Sie mir bitte genauer, worum es geht.”

“Es kommt darauf an…” ist quasi immer richtig und hilft deshalb nicht. Wir müssen weg von dieser Phrase hin zu mehr Nachdenken und mehr Zuhören. Und daraus müssen sich mehr konkrete Regeln ergeben, die auf konkrete Fälle angewandt werden können. Ob das wenige oder viele, einfache oder komplizierte Regeln sind, ist erstmal egal. Wir brauchen sie als Fundament für “unsere Kunst”.

Niemand behauptet auch, dass die so bewusst erarbeiteten Regeln starr sein sollten. Im Gegenteil. Sie sollen lebendig bleiben im Rahmen eines Diskurses. Zwischendurch mal Ruhe ist auch gut. Einfach mal die Regeln lernen und anwenden, bevor man sie hinterfragt. Aber dann auch gern immer wieder Infragestellung. Die Zeiten ändern sich, also dürfen sich auch die Regeln ändern. Manche langsamer, manche schneller.

Unzweifelhaft ist jedoch, dass wir sie brauchen. Ich glaube sogar, dass wir als Branche unterspezifiziert sind mit Regeln. Deshalb habe ich auch www.clean-code-developer.de (CCD) mit gegründet. Und der Erfolg der Initiative gibt meiner Vermutung recht, würde ich sagen. Denn CCD ist eine Sammlung von Regeln und darauf stehen offensichtlich mehrere Tausend Entwickler, wenn ich mal die Mitgliedszahlen in den Foren und die vergebenen Armbänder zusammenrechne.

So, nach diesem Ausflug ins Grundsätzliche gern wieder zurück zum Konkreten: Da es beim Null-Problemo genauso “darauf ankommt” wie sonst im Leben, stellt sich immer noch die Frage: Worauf kommt es denn an? Was sind die Regeln für die Null-Verwendung? Was sind damit die Eigenschaften eines Szenarios, die geklärt werden müssen, um zu entscheiden, welche Regel zum Einsatz kommt?

Samstag, 1. Mai 2010

Sollte Architektur wirklich emergieren? [OOP 2010]

In Objektspektrum 3/2010 steht ein Artikel auf der Höhe der Zeit: “Emergente Architektur: Der machtlose Architekt”. Denn davon spricht man auch hier oder hier. Und woanders mag es auch Emergent Design heißen.

“Emergenz” scheint ein neues Zauberwort zu sein. Es bedeutet soviel wie Entstehung von etwas Ganzem, ohne dass dieses Ganze so geplant worden wäre. Eine Termitenbau entsteht auf diese Weise oder geordnete Menschenströme in einer Einkaufsstraße oder sogar die erfolgreiche Jagd eines Löwenrudels.

Klingt gut, oder? Wäre doch toll, wenn Softwareentwicklung nicht länger krampfhaft und bewusst versuchen müsste, der ewig nörgelnden Forderung nach einer sauberen Architektur nachzukommen, sondern sie irgendwie “wie von selbst” entstehen lassen, sie emergieren lassen könnte.

Zugegeben, eine schöne Vorstellung. Aber glauben tue ich an sie genauso wenig wie an die Rettung der Welt durch CASE, SOA oder O/R Mapper. Trotz aller Erkenntnisse der Komplexitätsforschung sehe ich weiterhin die Notwendigkeit zur Planung von Architektur. Denn:

  • Emergenz ist trivial: Wenn Systeme genügend unbekannt oder genügend groß in Bezug auf den Kenntnishorizont eines Teams sind, dann kann ihre Architektur nicht “auf einmal” geplant werden. Sie entwickelt sich vielmehr über die Zeit in Reaktion auf neue Erkenntnisse und Anforderungen. Jeder Entwicklungsschritt folgt dabei (hoffentlich) den lange bekannten Prinzipien “guter Architektur”. Jeder einzelne Architekt hat dann über die Zeit nur einen Teil zum großen Ganzen beigetragen.
    Emergenz ist letztlich also kein neues Phänomen, sondern nur ein modischer Begriff für Evolution. Weniger Rede von Emergenz und mehr von Evolution könnte helfen, nicht schon wieder nach einer neuen Silberkugel zu suchen.
  • Emergenz ist unvermeidbar: Auch wenn die Kenntnis über das zu realisierende System groß ist, endet die Verantwortung eines Architekten irgendwo. Er ist ja Architekt und nicht Entwickler. Und Planungspapiere sind kein Code. Bei der Umsetzung der Architekturplanung kann daher immer noch einiges passieren und passiert auch. Architekturvorstellungen werden selten 1:1 umgesetzt. Die Architektur eines Systems ist damit immer mehr oder weniger ungeplant und Resultat vieler kleiner Entscheidungen vor Ort während der Implementation.
  • Emergenz ist schwer planbar: Soll ein makroskopisches Ergebnis (z.B. Architektur) emergent entstehen, sind passende microskopische, einfache Regeln zu definieren. Solche Regeln a posteriori durch Analyse von Ergebnissen zu finden, ist eine Sache. Sie jedoch a priori zu postulieren, eine andere. Das makroskopische, am Ende recht simple Verhalten von Schwärmen hat schon Forscherjahre in der Analyse gekostet, auch wenn nur 3 Kernregeln dabei gerausgekommen sind. Was ist dann für so etwas komplexes wie Softwarearchitektur zu erwarten? Ich bin sehr im Zweifel, ob die Softwarekunst darauf schon eine Antwort hat. Entwickler mit TDD vor sich hinwerkeln zu lassen, mit S.O.L.I.D kräftig voran zu schreiten und darauf zu vertrauen, dass Featureteams es schon richten werden, halte ich für zuwenig. Damit sind zwar Richtschnüre auf der Microebene gespannt – doch die führen nicht so unausweichlich wie die Regeln eines Sardinenschwarms zu einem evolvierbaren großen Ganzen.

Architektur braucht, so glaube ich, auf unabsehbare Zeit immer noch ein gerüttelt Maß an expliziter Planung “in der Mitte”. BDUF ist out, soviel ist klar. Gesamtplanungen sind womöglich nicht mal machbar. Microplanung ist ebenfalls kontraproduktiv; sie zerstört Motivation und Effizienz. Doch “in der Mitte” gibt es Raum und Notwendigkeit für explizite Architekturplanung. Denken und Planen hilft, da bin ich mir sicher. Immer noch. Ameisen oder Sardinen mögen nicht planen müssen. Aber “große Maschinen”, die sich auch noch ständig ändern sollen, die deshalb auf der Metaebene konstant änderbar/evolvierbar sein müssen, solche “Maschinene” “sich ergeben zu lassen” durch lokale Anwendung überschaubarer Regeln… das halte ich für zumindest eine verfrühte Vorstellung.

Denn wahre Emergenz" bedeutet eben keine Planung des großen Ganzen. Niemand malt ein Architekturdiagramm. Niemand hat eine Vorstellung von der Form des Ganzen – sondern immer nur von seinem Verhältnis zur Umwelt. Viele kleinste Entscheidungen auf Microebene ergeben – oh, Wunder! – ein wahrhaft elegantes und zweckmäßiges Ganzes. (Wobei Zweckmäßigkeit von Software immer einschließt, dass die nicht nur heute vorhanden ist, sondern auch für morgige Anforderungen leicht hergestellt werden kann.)

Damit komme ich sozusagen zum philosophischen Teil meiner Position:

Keine Ameise versteht das Ganze ihres Staates. Kein Mensch versteht mehr das Ganze einer Volkswirtschaft. Dasselbe mag für ein genügend großes Softwaresystem gelten. Das Internet könnte dafür ein Beispiel sein. So ist das halt, wenn etwas sehr komplex wird.

Das bedeutet im Umkehrschluss jedoch, dass das, was da so groß und komplex ist, was über die Köpfe der Individuen hinaus gewachsen ist, keine (oder nur wenige) von den Individuen planbare Eigenschaften hat. Wir das an der Finanzkrise, wir sehen das an den Entwicklungen im und um das Internet und die neuen Medien.

Wie können womöglich noch etwas Emergiertes erkennen. Wir können das Ganze beobachten. Aber wir können ihm als “Rädchen im Getriebe” keine spezifischen Eigenschaften mehr verordnen. Klar, wir schrauben am Ganzen herum. Jede unserer Handlungen verändert das Ganze. Aber es in eine funktionale Richtung zu bewegen oder auf der Metaebene es Flexibel zu machen… das sind geradezu titanische Aufgaben, deren Lösung unabsehbar ist.

Was bedeutet das für Software, wenn wir uns für sie wünschen, dass ihre Architektur emergieren möge? Mir scheint es, dass Emergenz nur um den Preis eines Kontrollverlustes zu haben ist. Aber wer möchte den schon erleiden? Software soll sehr konkrete Zwecke erfüllen, Architektur ist dafür die Basis. Wenn Architektur dann jedoch “nur” emergiert, wenn Architekten machtlos sind und das Ganze “sich ergibt” aus regelhaften Einzelaktionen… wie stellt ein Team dann sicher, dass der durch den Kunden vorgegebene Zweck zeitig wie nachhaltig erfüllt wird?

image Ergo: Solange wir noch Ziele ansteuern, können wir uns nicht auf Emergenz verlassen. Softwareentwicklung ist kein Selbstzweck. Also kann ihr Ergebnis nicht komplett einer Emergenz anheim gestellt werden.

Das bedeutet nicht, dass wir nicht immer wieder prüfen sollten, wieviel Planung/Kontrolle wann angemessen ist. Wir sollen nach Microregeln suchen, die helfen, Makroeigenschaften “einfach so” herzustellen. Doch um explizite Architekturentscheidungen kommen wir nicht herum. Architekten werden nicht überflüssig und degenerieren auch nicht zu reinen Prozessmoderatoren.

Ein wenig Bescheidenheit mag allerdings angezeigt sein. Eine Haltung der Akzeptanz der Vorläufigkeit hilft. Etwas weniger Kontrolle haben wollen, schadet nicht. Kollektive Intelligenz fördern, ist sicherlich ein guter Ansatz. Aber Planen und Denken bleiben Kernaufgaben von Architekten.

Null oder nicht Null, das ist hier die Frage

Sollte man Null als Ergebnis einer Abfrage zurückgeben oder nicht? Diese Frage ergab sich anlässlich eines Blogartikels von Thomas Bandt, der in ein Problem gelaufen war, seiner Gewohnheit folgen zu können, eine Query-Methoden eines Repositories Null zurückliefern zu lassen:

“[Ich] erwarte […] von jeder Methode null als Rückgabewert für den Fall, dass keine Daten in der Datenbank gefunden wurden. Nun ist mir aber beim Testen meiner Repositories […] aufgefallen, dass Folgendes niemals null zurückliefert: […] return […].Select(…).ToList(); […]”

Letztlich hat Thomas zwar eine Lösung für sein Problem gefunden, doch ein Nachgeschmack bleibt. Ist das vielleicht nur eine Symptomkur? Ich würde sagen, ja.

Ob man nie Null zurückgeben darf oder nicht, will ich nicht entscheiden. Solche Allaussagen sind auch selten hilfreich. Soweit stimme ich mit einigen Kommentatoren des Blogartikels überein. Wie steht es allerdings in diesem Fall? Lässt sich im Konkreten doch vielleicht eine saubere Entscheidung treffen?

Für mich steht außer Zweifel, dass im Falle von Thomas´ Repositories die Entscheidung eindeutig für den Verzicht auf Null als Rückgabewert ausfallen sollte. Als Erklärung vier unterschiedliche Ansätze:

  • Philosophisch/Logischer-Blickwinkel: Eine Liste mit Resultaten und Null gehören unterschiedlichen Kategorien an. Eine Liste ist ein Container, Null ist… nichts oder nur ein generischer Wert, jedenfalls kein Container. Dass aber eine Methode Ergebnisse aus zwei Kategorien zurückliefert, halte ich für kategorisch falsch.
    Eine Liste mit Resultaten und eine Liste ohne Resultate (leere Liste) hingegen gehören beide derselben Kategorie Container an.
    In diesem Fall ist Null ganz kategorisch also nicht erlaubt. Anders mag das sein, wo eine Funktion object als Resultattyp hat. Der ist so allgemein, dass eine Zeichenkette, eine Zahl, eine Liste oder eben auch Null in seiner Hinsicht derselben Kategorie Wert angehörten.
  • Praktikscher Blickwinkel: Wer Thomas´ Repository-Query-Methoden benutzt, muss im Code eine Fallunterscheidung treffen. Falls eine Abfragebedingung keine Ergebnisse liefert, muss es zwangsläufig anders weitergehen als mit Resultaten, auch wenn vielleicht nur die Resultate gelistet werden sollen und eine leere Liste am Bildschirm für den Benutzer völlig ok wäre. Thomas´ Muster für Query-Rückgabewerte macht also im Zweifelsfall mehr Aufwand – ohne einen Gewinn zu bringen. Falls leere Liste und gefüllte Liste unterschiedlich behandelt werden sollten, ist die Prüfung auf Null und die auf Länge 0 gleich aufwändig.
  • Prinzipieller Blickwinkel: Ich würde sagen, ein Null-Ergebnis widerspricht dem Principle of Least Astonishment. Denn wenn ich eine Signatur sehe, die eine Liste als Rückgabewert definiert und dann kommt keine Liste, sondern Null zurück, dann bin ich erstmal ziemlich überrascht. Nicht, dass der Gedanke dahinter kompliziert wäre, nicht dass Thomas das nicht in einem XML-Kommentar erklären könnte – aber eine Überraschung bleibt es und deshalb auch ein zusätzlicher Dokumentationsaufwand.
    Auch ist eine Abfrage mit leerer Ergebnismenge keine Besonderheit. Sie rechtfertigt aufgrund ihrer Erwartbarkeit keine Sonderbehandlung durch Null oder gar eine Exception.
  • Analogischer Blickwinkel: Wenn ein Räuber mich zur Übergabe meines Geldes auffordert, dann gebe ich ihm besser mein Portemonais. Falls im Portemonais kein Geld ist, mag er zwar frustriert sein, doch er kann mich zumindest keines Widerstandes bezichtigen. Hätte ich hingegen geantwortet “Ich habe kein Geld.”, dann würde die Szene in jedem Fall sehr unschön werden, denke ich. Allemal würde er mir ohnehin nicht glauben.
    Die Moral von der Geschicht: Versuche der Aufforderung eines Räubers nicht differenziert nachzukommen. Antworte platt so, wie er es sich wünscht und du gleichzeitig klar machst, dass deine Antwort ehrlich ist. Er soll dann selbst aus dem Ergebnis etwas machen.

Soweit mal meine im Grunde doch einfache Lösung des Null-oder-nicht-Null-Problems. Im Zweifelsfall eher auf Null verzichten. Null ist eher “böse” so wie Goto “böse” ist. Und wer das nicht glauben mag, weil Null doch so einfach zu gebrauchen ist, der höre dazu den Erfinder von Null, Tony Hoare, mit seinem Vortrag “Null References: The Billion Dollar Mistake”.

image