Follow my new blog

Sonntag, 14. Oktober 2012

Flow Operationen automatisch registrieren

Flow Designs zu implementieren, ist nun einen ganzen Schritt einfacher geworden. Endlich habe ich nämlich Zeit gefunden, die Flow Runtime mit etwas mehr "Intelligenz" zu versehen.

Bisher bestand die Implementation eines Flow Designs aus drei Teilen:

  • Flow
  • Operationen
  • Bindung

Als Beispiel für einen Flow hier der für die Umformatierung einer Datei in ganz einfacher Weise. Ihre Zeilen sollen auf eine neue maximale Länge gebracht werden:

/
.run, Zeilen_lesen
Zeilen_lesen, Umbrechen
Umbrechen, Zeilen_schreiben

Die Operationen sind Methoden, die wohl ganz angemessen auf zwei Klassen verteilt werden können:

class Textdatei {
  private string _dateiname;

  public string[] Zeilen_lesen(string dateiname) {…}

  public void Zeilen_schreiben(string[] zeilen) {…}

class Formatierung {
  public static string[] Umbrechen(string[] zeilen) {…}

Gebunden werden die Operationen an den Flow über die Konfiguration der Flow Runtime:

var td = new Textdatei();

var config = new FlowRuntimeConfiguration()
                   .AddStreamsFrom("umbrechen.root.flow", Assembly.GetExecutingAssembly())

                   .AddFunc<string, string[]>("Zeilen_lesen", td.Zeilen_lesen)
                   .AddAction<string[]>("Zeilen_schreiben", td.Zeilen_schreiben)
                   .AddFunc<string[], string[]>("Umbrechen", Formatierung.Umbrechen);

using(var fr = new FlowRuntime(config)) {
  fr.Process(".run", args[0]);
  fr.WaitForResult();
}

Das funktioniert wunderbar. Doch es ist bei der Konfiguration umständlich. Die stellt nämlich auch einen Widerspruch zu DRY dar. In ihr werden ja Dinge wiederholt, die anderswo schon stehen. Vor allem ist es aber mühsam, in der Konfiguration die Signaturen der Operationsmethoden anzugeben. Das macht die dynamische Natur der kleinen Flow DSL quasi nutzlos.

Damit ist nun Schluss!

Jetzt ist die Konfiguration viel, viel einfacher. Sie schrumpft im Grunde auf zwei Zeilen Code, die sich im Verlauf der Evolution einer Anwendung kaum mehr ändern müssen:

var config = new FlowRuntimeConfiguration()
                   .AddStreamsFrom("umbrechen.root.flow", Assembly.GetExecutingAssembly())
                   .AddOperations(new AssemblyCrawler(Assembly.GetExecutingAssembly()));

Eine Zeile liest den Flow, eine weitere Zeile lädt alle Operationen.

Der AssemblyCrawler durchläuft alle Typen der ihm übergebenen Assemblies und schaut, ob die Operationsmethoden definieren. Wenn ja, registriert er sie automatisch. Berücksichtigt werden Klassen, die mit einem von drei Attributen markiert sind:

[InstanceOperations]
class Textdatei { … }

[StaticOperations]
class Formatierung { … }

Klassen, die mit [StaticOperations] gekennzeichnet sind, werden auf statische Methoden überprüft, Klassen, die mit [InstanceOperations] markiert sind, werden zuerst instanziert, um dann auf Instanzmethoden überprüft zu werden. Und schließlich gibt es noch [EventBasedComponent], um Instanzen zu registrieren, die Output über Events hinausgeben.

Relevant als Operationen sind in jedem Fall nur Methoden, die den Signaturen entsprechen, die auch über AddAction<>() und AddFunc<>() registriert werden können. Einen Unterschied gibt es dabei jedoch: Output-Ports, die über Continuations definiert sind, haben nicht mehr die Namen ".out0" und ".out1", sondern die der Continuation-Parameter.

Der Crawler macht die Registrierung aller Operationen in den übergebenen Assemblies sehr einfach. Wer jedoch etwas mehr Kontrolle haben möchte, kann mit Attributen markierte Klassen auch von Hand registrieren:

var config = new FlowRuntimeConfiguration()
                   .AddStreamsFrom("umbrechen.root.flow", Assembly.GetExecutingAssembly())
                   .AddInstanceOperations(new Textdatei())

                   .AddStaticOperations(typeof(Formatierung)); 

Ich habe jetzt einige Tage mit dieser Form der einfachen Konfiguration gearbeitet… und möchte sie nicht mehr missen. Jetzt endlich kann ich mich wirklich auf Flow und Operationen konzentrieren. Jetzt endlich löst die Flow Runtime ihr Versprechen ein, simpler und gleichzeitig leistungsfähiger als EBC-Verdrahtung zu sein.

Hier geht's zum Download der aktuellen Flow Runtime NPantaRhei.

Sonntag, 7. Oktober 2012

Was andere schon richtig machen - Halden vermeiden


Das ist Wim Wenders. Er ist einer der bekanntesten zeitgenössischen deutschen Regisseure mit Weltruf. Von ihm können wir als Softwareentwickler etwas lernen.

Als Regisseur ist es seine Aufgabe, gewisse Ziele zu erreichen: Er hat ein inhaltliches/künstlerisches Ziel, er hat ein Terminziel und er hat natürlich auch ein Budgetziel. Gerade Termin und Geld zwingen dazu, die Produktion genau zu planen. Das beginnt beim Drehbuch, denn ohne Drehbuch ist ja ungewiss, was an Drehorten, Schauspielern, Bühnbild und schließlich Zeit und Geld überhaupt nötig wäre. Auf dessen Basis entsteht dann ein Drehplan. Der sagt, was wann wie wo genau zu drehen ist, so dass die kosten minimal sind. Was im Drehbuch wie in einer Theaterstück in einer für die Geschichte passenden Reihenfolge steht, wird dafür in Teile zerlegt und neu gemischt. Szenen am selben Ort zu unterschiedlichen Zeiten im Film, werden zusammengelegt, so dass der Drehort nur einmal besucht werden muss. Und was am Ende passiert, wird an den Anfang gelegt. Der Dreh ist mithin nicht chronologisch.

Das bedeutet, etwas das früh gedreht wird, aber erst spät im Film auftaucht, muss 100% so gedreht werden, dass es später passt. Der Regisseur muss also genau wissen und dem ganzen Team klar machen, was vorher passiert sein wird, damit die früh gedrehten späteren Szenen auch brauchbar sind. Sie liegen dann nach der Aufnahme auf Halde. Nicht nur steckt in ihnen jetzt Kapital, sie zwingen den Rest des Drehs auch in eine Form, der sie anschlussfähig macht.

Der nicht-chronologische Dreh ist damit eine lokale Optimierung im Sinne des Geld-/Zeitbudgets - und stellt ansonsten nur eine Belastung dar: Die Continuity steht vor einer großen Herausforderung, um visuelle Sprünge zwischen aneinander geschnittenen Einstellungen zu vermeiden, die mit großem Abstand gedreht wurden. Die Schauspieler stehen vor großen Herausforderungen, da sie Präsenz in ihren Rollen "auf Zuruf" ganz ohne Kontext herstellen müssen. Der Regisseur steht vor der großen Herausforderungen, das Ganze in seinem Zusammenhang und seiner Entfaltung allen Beteiligten immer wieder präsent zu machen, auch wenn jeden Tag nur beliebige Ausschnitte gedreht werden.

Als Resultat entsteht eine wachsende Halde von Takes, deren Qualität im Rahmen eines Ganzen erst im Schnitt deutlich wird. Nicht nur wird sich dann erst erweisen, ob alles so anschlussfähig ist, wie geplant.

Insofern kann denn auch das Drehbuch als Halde angesehen werden. Es ist ein Plan für die Herstellung einer Wirkung beim Zuschauer. Ob der aufgeht, zeigt sich ebenfalls erst im Schnitt.
Monatelang wird Geld in ein Drehbuch investiert, ohne dass man weiß, ob das Endresultat dem künstlerischen Anspruch gerecht wird. Wochenlang wird dann Geld in einen Dreh investiert, ohne dass man weiß, ob der in Summe das Drehbuch angemessen umsetzt und im Schnitt das gewünschte Ergebnis entstehen kann.

Während seiner ersten 10 Filme hatte Wim Wenders versucht, diese Unsicherheiten durch viel Planung zu kompensieren. Er hatte Drehbücher nicht nur umgesetzt, sondern auch geschrieben. Nicht umsonst war er Mitgründer des Filmverlags der Autoren. Damit vermied er Reibungsverluste zwischen Regisseur und Drehbuchautor. Seine Planung begann also schon bei der Idee.

Während des Drehs dann hatte er - wie er heute während eines Colloquiumgesprächs an der Hamburger Hochschule für Musik und Theater berichtete - alles genau vorausgeplant. Jede Einstellung, jeder Auftritt, jeder Abgang, alles hatte er spätestens am Vorabend eines Drehs genaustens ausgetüftelt. Damit sollten Reibungsverluste zwischen Schauspielern und ihm oder auch der Technik während des Drehs reduziert werden. Es galt ja, die knappe Drehzeit bestmöglichst zu nutzen.

So war das. Bis zum Film "Paris, Texas".

Da machte er es anders. Motiviert hatte ihn seine Erfahrung mit der Inszenierung eines Theaterstücks. Denn im Theater wird anders gearbeitet. Es gibt nur eine Einstellung, es gibt nur eine chronologische Darstellung. Und hat das Stück begonnen, muss der Regisseur auf die Schauspieler vertrauen. Während der ganzen Vorstellung kann er nicht mehr eingreifen.

"Paris, Texas" hat Wim Wenders dann anders gemacht.

Das Drehbuch war nur halb fertig bei Drehbeginn. (Eine zweite Hälfte existierte nur für die Geldgeber. Sie war nie für die Produktion bestimmt, sondern ein Fake.)

Und der Dreh verlief streng chronologisch.

Das Ergebnis? Ein Film der von der Kritik gelobt und mit der Goldenen Palme in Cannes ausgezeichnet. Das Ergebnis lässt sich also sehen - und das ganz ohne Aufhäufung von Halden. Für Wim Wenders ist klar, dass der Film seine Qualität nur erhalten konnte, weil eben nicht zwanghaft ein Ende vor Drehbeginn vorgedacht worden war und sich die Schauspieler mit ihren Figuren entwickeln konnten. Das Geheimnis für das gute Ergebnis, ja, das bessere Ergebnis als bei vorhergehenden Filmen besteht für ihn mithin in der Vermeidung von Halden. Er hat in nichts investiert, von dem er nicht wusste, ob es so später gebraucht werden würde. Er hat sich mit keiner Halde von Vorproduziertem die Möglichkeit zur Reaktion auf Entwicklungen während des Drehs eingeschränkt.

Mir scheint das eine kopierenswerte Haltung. Auch in der Softwareentwicklung sollten wir es vermeiden, ein ausgefeiltes Drehbuch von Anfang bis Schluss zu schreiben. Vor Beginn der Entwicklung zunächst ein Backlog satt zu füllen, versenkt Geld in Anforderungen, von denen nicht sicher ist, wann, wie und ob sie später umgesetzt werden sollten, ob sie einem Anwender wirklich den intendierten Nutzen bieten. Ein pralles Backlog schränkt durch die Investitionen auch die spätere Reaktionsmöglichkeit ein. Denn was im Backlog steht, muss ja umgesetzt werden. Immerhin steckt da ja einige Mühe drin. Die darf nicht umsonst sein. Wenn in Wochen oder Monaten Neues auftaucht, dann hat sich das hinten anzustellen. Mit einem ausführlichen Backlog gilt das Prinzip "First come, first serve".

Ebenso sollte die Softwareentwicklung vermeiden, Code auf Halde zu produzieren. Der nicht-chronologischen Drehreihenfolge beim Film entspricht eine Entwicklungsreihenfolge, die sich von Befindlichkeiten der Softwareentwicklung leiten lässt. Wenn die meint, es müsse zuerst eine Infrastruktur aufgesetzt werden, ein Persistenzframework geschrieben, ein Security-API entwickelt werden, bevor auch nur ein Anwender etwas in die Hand bekommt… dann produziert sie Code auf Halde. Von dem weiß auch niemand, wann, wie, ob er mal Nutzen entfalten wird.

Zum Glück vertritt die Agilitätsbewegung diese Sichtweise schon länger. Sie ermahnt, Code nicht auf Halde zu produzieren, sondern nur in nützlichen Inkrementen. Sie ermahnt, nicht zuviel in Vorabplanung von Anforderungen und Entwürfen zu investieren. In der Projektrealität ist das allerdings immer noch nicht überall angekommen. Deshalb finde ich es motivierend, aus ganz anderer Richtung davon zu hören, wie die Reduktion von Halden erfolgssteigernd wirken kann. Dass selbst die Filmproduktion davon profitiert… Wer hätte das gedacht?

Vielen Dank, Wim Wenders, für diese Plauderei aus dem Nähkästchen.


PS: Woody Allen hat übrigens auch erkannt, dass Drehbuchhalde und Takehalde sich abträglich auf das künstlerische Ziel auswirken können. Er stellt sie zwar noch komplett her - doch er erlaubt sich spätere Korrekturen. In den Verträgen seiner Schauspieler steht, dass sie - wenn ich es recht erinnere - bis zu einem halben Jahr nach Drehschluss noch für Nachdrehs zur Verfügung stehen müssen. Für Woody Allen kann sich einfach im Schnitt herausstellen, dass Haldenmaterial in seiner Qualität ungenügend ist. Dann bessert er aufgrund der gewonnenen Erkenntnisse einfach nach.
Das scheint mir auch in Linie mit der Agilität zu sein. Woody Allen hat erkannt, dass sich Ziel und/oder Weg mit der Zeit durch die Produktion verändern können. Das überrascht ihn nicht mehr, sondern er weiß es und trifft also vertragliche Vorkehrungen.

Donnerstag, 4. Oktober 2012

Gesucht: dreckige Realität

In einem Blogartikel hat Matthias Bohlen seinen Ansatz beschrieben, die Form eines Softwaresystems zu entwerfen. Leider hat mich die Lektüre unbefriedigt zurückgelassen.

Dass Matthias einen anderen Ansatz verfolgt als ich, erklärt das allerdings nicht. Warum sollte mich das auch stören? Der Entwurf hat mich ja nicht in frustriert-sprachloses Erstaunen versetzt. Also erwächst aus der Andersartigkeit seines Ansatzes eher energievolle Spannung. Ich werde seinem Entwurf auch einmal meinen gegenüberstellen. Dabei kann ich wieder für mich etwas lernen. Sie können für sich vergleichen. Und vielleicht ergibt sich daraus auch noch ein konstruktives Gespräch.

Nein, der Ansatz ist es nicht, der mich frustriert hat. Es war eher die Aufgabe. Aber auch wiederum nicht konkret die Bankendomäne, sondern die, hm, Präsentation und der Scope. Beides war so typisch. Nämlich typisch – sorry to say, Matthias – flach.

Ich habe es schon so oft gesehen in Büchern und Artikeln: Da wird eine Technologie oder Methode vorgestellt anhand eines Beispiels, bei dem es einfach funktionieren muss.

Bis zu einem gewissen Grad ist das auch legitim oder sogar nicht zu vermeiden. Auch ich habe schon so Technologien oder Methoden vorgestellt; manchmal liegt es an der Zeit, die zur Verfügung steht. Gerade deshalb bin ich da aber vielleicht auch sensibel. Ich möcht es besser machen für Sie und auch für mich.

Das Problem bei einer flachen Aufgabenstellung, bei Anforderungen, die eine Technologie oder Methode quasi zum Selbstgänger machen ist schlicht, dass man sich in die Tasche lügt. Das kann dem Präsentierenden selbst nicht gefallen. Und es ist natürlich unschön für die Leserschaft.

Ja, das ist es, das hat mich bei Matthias Lösung gestört. Das unselige, weil schon so oft zitierte Überweisungsszenario ist so trivial, dass sich damit ja fast jede Methode erfolgreich demonstrieren lässt. Ein “normal” objektorientierter Ansatz hätte dabei genauso sinnvoll dargestellt werden können wir ein prozeduraler oder ein funktionaler. Ich kann jedenfalls nicht erkennen, dass Matthias’ DCI-Ansatz einem anderen überlegen ist.

Damit will ich keine Aussage über seinen Ansatz machen. Bei der Größenordnung an Aufgabe macht er für mich schlicht keinen deutlichen Unterschied. Er funktioniert. Klar. So wie der “normale” objektorientierte Ansatz auch vorher funktioniert hat.

Was wir bei Matthias sehen ist eine Momentaufnahme eines kleinen Szenarios. Und wenn wir in ein Buch zur Objektorientierung oder zu DDD schauen, dann sehen wir dort auch Momentaufnahmen. Da hat jemand lange an Code gearbeitet, ihn fein ziseliert – und präsentiert das kunstvolle Ergebnis.

Nur ist so leider nicht die Realität. Die ist dreckig und hektisch und nicht so strukturiert in ihren Anforderungen. Außerdem sind die deutlich umfänglicher. Da gibt es Seiteneffekte. Da müssen nicht-funktionale Anforderungen berücksichtigt werden. Und da verändert sich so einiges über die Zeit.

Wir brauchen mehr Demonstrationen von Technologien und Methoden, die es damit aufnehmen. Auch und gerade, wenn es um Methoden geht. Denn ob eine Technologie funktioniert oder nicht, das lässt sich leicht selbst feststellen. Zur Laufzeit gibt es gewöhnlich blitzschnell Feedback. Doch ob eine Methode funktioniert bzw. ob man sie richtig anwendet, das ist viel schwieriger festzustellen. Womöglich stellt sich das erst nach Wochen oder Monaten heraus, wenn man sich damit in eine Ecke gepinselt hat.

Matthias’ Lösung kommt mir insofern “erschlichen” vor. Das Problem ist so abstrakt, isoliert dargestellt, dass sich quasi alles wie von selbst fügt. Erklärungen sind kaum nötig. Jeder nickt sofort, wenn da die Rollen aufgetischt werden… und jeder hält es dann für ganz natürlich, dass ein Konto das andere auffordert etwas zu tun.

Aber das kann doch nicht Matthias’ Ernst sein. In welcher Bankenwelt sollen denn Konten direkt miteinander sprechen? Auch wenn ich kein Banker bin, hat das für mich keinen Rückhalt in der Realität der Bankdomäne. Deshalb scheinen mir die Rollen Quellkonto und Zielkonto “erschlichen”. Wie bei einer petitio principii, wo das zu Beweisende vorausgesetzt wird. Oder so ähnlich wie die Antwort auf die Frage aus Ottos Quizparodie, wer denn der berühmte Maler in Rembrandts Haus sei.

Aber nochmal: Damit will ich Matthias´ Ansatz nicht per se kritisieren, sondern nur sagen, dass ich seinen Wert anhand des flachen Beispiels noch nicht erkennen kann. Wo die Anwendungsfälle so klein sind, dass Objekte und Rollen auf der Hand liegen, kann ich jede Methode rechtfertigen, die Objekte und Rollen favorisiert.

Um mich zu überzeugen braucht es also etwas Größeres und Dreckigeres. Etwas, das nicht schon für eine Methode analysegerecht kleingehackt ist.

Aus diesem Grund habe ich schon vor längerer Zeit in Anlehnung an die kleinen Code Katas größere Application Katas beschrieben. Einige finden sich hier: http://clean-code-advisors.com/ressourcen/application-katas. Technologisch sollten sie keine Herausforderungen darstellen. Aber methodisch kann man sich an ihnen abarbeiten. Deshalb liegen sie in mehreren Iterationen vor.

Wie passt darauf der Ansatz von Matthias? Wie flott segelt er durch diese Anforderungen? Wie leicht lässt sich eine DCI-Struktur über die Iterationen verstehen und verändern?

Diese Fragen gelten aber natürlich nicht nur für Matthias. Jeder, der eine Methode für die Softwareentwicklung im Ärmel hat, kann sich daran probieren. “Normale” Objektorientierung genauso wie Funktionale Programmierung oder der de facto Stil eines Teams. Ich selbst demonstriere Flow-Design immer wieder an solchen Beispielen im Rahmen von Artikeln oder im Seminar “Agile Architektur” der Clean Code Developer Akademie.

Doch die AppKatas sind weit weg von Matthias’ Aufgabenstellung. Da mag es schwer fallen zu sehen, was ich mit “mehr dreckige Realität” meine. Deshalb hier meine Version seines Überweisungsszenarios, als ganze Anwendung mit einem UI und persistenten Daten.

Application Kata - Banküberweisung

Auch das ist natürlich immer noch eine Spielzeugvariante dessen, was in Banken tatsächlich läuft. Aber es sind zumindest mehr Facetten darin enthalten, so dass es schwieriger wird, seinen Entwurfsweg zu finden. Die Entscheidungen sind nicht vorgekaut. Ein wie immer geartetes Modell – um das es ja beim Entwurf geht – liegt nicht auf der Hand.

Also, das ist eine Art von Herausforderung, wie ich sie häufiger formuliert und dann angegangen sehen möchte. Alles andere ist Spielkram.

 

PS: Wer sich beklagen möchte, in der Aufgabenstellung seien zu viele Dinge nicht ausformuliert und deshalb sei es schwierig zu entwerfen, der kann gern in den Kommentaren hier Fragen stellen. Dann konkretisiere ich als “Kunde” :-)

Mittwoch, 26. September 2012

Form Follows Feasibility

Code verändern, ist schwer. Wer kämpft sich schon gern durch einen Dschungel aus Legacy Code? Viel schöner ist die Entwicklung auf einer grünen Wiese. Code neu schreiben, ist demgegenüber leicht.

Wenn es in Projekten knirscht, weil die Last der Brownfield Codes erdrückend ist, ist Neuentwicklung allerdings nur selten eine Option. Der Aufwand wäre gewaltig; dafür gibt es kein Geld und keine Zeit.

Aus dem Morast scheint dann nur der trübe Weg langwieriger Refaktorisierungen zu führen. Wochen und Monate arbeitet sich das Team daran ab. Spaß macht das nicht. Motvierend für andere ist das auch nicht. Wenn die Codebasis an einem solchen Punkt ist, leidet das Produkt unter doppelt schlechter Qualität: nicht nur die des Codes lässt zu wünschen übrig, sehr wahrscheinlich ist auch die Qualität des Teams – oder zumindest seine Attraktivität – suboptimal.

Natürlich kann Software nicht dauernd neu geschrieben werden. Aber wenn es soviel leichter ist, Legacy Code neu zu schreiben, statt ihn zu ändern, warum gibt es dann kein Bemühen, der Leichtigkeit des Greenfield näher zu kommen?

Ich meine, darum sollte sich der Entwurf bemühen. Die Softwarearchitektur sollte die Machbarkeit der Neuentwicklung als nicht-funktionale Anforderung sehen, ohne die Nachhaltigkeit nicht zu erreichen ist.

Zunächst einmal wird Code natürlich zum Bug Fixing und für neue Anforderungen erweitert. Das geht auch eine ganze Zeit gut. Aber wie lange? Niemand weiß das genau. “Es kommt halt darauf an…” Das ist wahr – nur führt diese weise Haltung gewöhnlich eben zu dem monolithischen Code, der dann nicht mehr mit vertretbarem Aufwand veränderbar ist.

Deshalb glaube ich, dass die Entscheidung, wie lange an Code rumgeschraubt werden sollte, weniger weise, weniger emotional ausfallen sollte, sondern viel pragmatischer und regelhafter.

Hier mein Vorschlag:

  1. Eine Codebasis sollte in Komponenten von max. 10.000 LOC aufgeteilt werden.
  2. Eine Codebasis sollte in Services von max. 60.000 LOC aufgeteilt werden.

Unter Komponenten verstehe ich hier binäre Codeeinheiten mit separatem Kontrakt auf derselben Plattform. Komponenten machen also keinen Aufwand bei der Kommunikation untereinander.

Unter Services hingegen verstehe ich Gruppen von Komponenten mit einem separatem gemeinschaftlichen Kontrakt – allerdings auf u.U. unterschiedlichen Plattformen. Die Kommunikation zwischen Services ist also kein no-brainer mehr.

Die Aufteilung in Komponenten und Services dieser Größe schlage ich vor, weil sich für mich damit Grenzen machbarer Neuentwicklung ergeben.

Komponenten neu entwickeln

Eine Komponente von 10K LOC [1] kann ein Team in einem Monat [2] neu entwickeln, wenn es hart auf hart kommt. Das scheint mir ein überschaubarer Zeitraum aus Sicht des Managements. Eine Entscheidung dafür sollte das Geschäft nicht aufs Spiel setzen.

Eine Software wird von vornherein komponentenorientiert entwickelt. Das Team beobachtet das Wachstum der einzelnen Komponenten. Seien wir ehrlich: dabei kontinuierlich den Komponentencode sauber zu halten, ist eher eine Idealvorstellung. Kleinere Refaktorisierungen werden vorgenommen – aber wenn größere notwendig werden, ist dafür eher keine Zeit. Die werden vertagt… Also kommt der Tag, an dem eine Komponente 10K LOC umfasst und eigentlich so richtig refaktorisiert werden müsste.

An dem Punkt entscheidet sich das Team nun jedoch für eine komplette Neuentwicklung. Statt mühselig Code zu säubern, wird auf der grünen Wiese neu angefangen – im Rahmen des Komponentenkontrakts. Der resultierende Code ist dann nicht nur sauber, sondern rein ;-) Damit meine ich, dass Refaktorisierung nur zu Clean Code zweiter Wahl führt, weil sie sich im Rahmen des Existierende bewegt. Das schränkt die Kreativität ein, das behindert die Innovationsmöglichkeiten. Ein Beginn auf der grünen Wiese hingegen ist frei von solchen Altlasten. Da ist alles erlaubt und denkbar – solange der ursprüngliche Kontrakt eingehalten wird.

Services neu entwickeln

Einen Service von 60K LOC kann ein Team in 6 Monaten neu entwickeln, wenn es hart auf hart kommt. Das ist kein ganz kurzer Zeitraum, das entscheidet man nicht zwischen Tür und Angel – doch es ist immer noch viel überschaubarer als die Neuentwicklung einer kompletten Anwendung von 500.000+ LOC. 6 Monate sind absehbar. 6 Monate sind in vielen Teams ein Releasezyklus oder gar weniger.

Der Trick bei den Services ist nun, dass ihre Neuentwicklung noch mehr Freiheitsgrade bietet. Nicht nur kann die interne Struktur über Komponentengrenzen hinweg rein gemacht werden, nein, es kann sogar ein Plattformwechsel stattfinden. Damit ist die Bedingung für die Möglichkeit kontinuierlicher Innovation geschaffen. Denn die hängt nicht nur an den Fähigkeiten der Entwickler, sondern auch am technologischen Fortschritt.

Wer sich vor 5 Jahren einmal für Java entschieden hat, muss dann nicht bis zum Lebensende (der Software) alles in Java entwickeln. Für jeden Service kann vielmehr immer wieder neu entschieden werden, ob ein Plattformwechsel Vorteile bietet. Eine Entscheidung ist möglich, weil die Servicegrenze in der Architektur überhaupt gezogen wurden – und weil darauf geachtet wurde, die Größe im Rahmen machbarer Neuentwicklung zu halten.

Günstig mag ein Plattformwechsel sein, wenn eine andere Plattform bessere technische Möglichkeiten bietet. Aber der Wechsel kann auch durch Erhaltung der Attraktivität der Codebasis motiviert sein. Plattformen unterliegen Moden. Um dauerhaft Entwickler für die Mitarbeit zu begeistern, mag es angezeigt sein, Plattformmoden zu folgen. Wer will denn heute eine große Cobol-, Fortran-, PHP- oder VB6-Codebasis pflegen? Durchschnittlich attraktiv sind C# oder Java oder Ruby oder Python – dahinter lauern aber schon Scala, Groovy, Clojure, Erlang, F#, JS und andere.

Nur wer “Sollbruchstellen” im Code in Form von Servicegrenzen vorsieht, hat die Chance, technologisch kontinuierlich uptodate zu bleiben.

Heute wird vielen Softwaresystemen eine solche Grenze nachträglich durch den Wunsch nach mobile applications aufgezwungen. Da entsteht plötzlich ein zusätzlicher Service in Form einer App. Da tritt nach Jahren mal wieder – gezwungenermaßen – eine neue Plattform auf den Entwicklungsplan. Da entsteht plötzlich Attraktivität. Leider sind damit aber auch viele Teams überfordert, weil sie jahrelang keine Übung gehabt haben im Plattformwechsel oder gar auch nur im Neuanfang auf einer grünen Wiese.

Fazit

Refaktorisierungen zur Herstellung und Erhaltung evolvierbarer Stukturen sind nicht überflüssig – aber überbewertet, würde ich mal sagen. Viel öfter sollte Neuentwicklung statt Refaktorisierung gedacht werden. Dazu bedarf es aber klarer Grenzen, in denen Neuentwicklung auch machbar ist. Ich habe hier mal zwei solche Grenzen unterschiedlicher Granularität vorgeschlagen. Ob die bei diesen LOC und diesen Zeiträumen verlaufen sollten, sei dahingestellt. Da mag sich jedes Team seine eigenen Grenzen setzen. Dass es jedoch Komponenten- und Servicegrenzen geben sollte, da bin ich sicher. Wir brauchen diese beiden Horizonte.

Der Servicehorizont liegt mir besonders am Herzen. Denn einer der größten Übelstände der Softwareentwicklung scheint mir derzeit die Erstarrung durch Konsolidierung und Homogenisierung. Dem muss entgegen gewirkt werden. Vielfalt muss möglich sein. Denn Vielfalt bedeutet natürliche Lebendigkeit. Nur so ist Innovation kein Kraftakt alle Jubeljahre, sondern jederzeit möglich.

Die Herausforderung für die Softwarearchitektur besteht also darin, die Form der Software so zu entwerfen, dass auch echte Reinigungen machbar sind.

Fußnoten

[1] Die LOC habe ich mal über den Daumen für ein Team von 5 Entwicklern berechnet, das jeden Tag pro Entwickler im Schnitt 100 LOC Produktionscode herstellt. Bei 20 Arbeitstagen/Monat ergibt das 10.000 LOC.

[2] Den Monat Aufwand für eine machbare Neuentwicklung einer Komponente bzw. die 6 Monate für einen Service meine ich nicht wörtlich. Was ein Unternehmen für machbar bei Neuentwicklungen hält, soll es selbst entscheiden. Mir scheint ein Monat für eine Komponente jedoch nicht ganz unrealistisch. Und ein halbes Jahr für die Möglichkeit eines Plattformwechsels, hören sich auch nicht so schlecht an, oder? Wenn möglich, können Services aber natürlich auch kleiner gehalten werden. 3 Monate für eine Neuentwicklung wären besser als 6.

Dienstag, 25. September 2012

Vorsicht Co-Evolution!

In zwei Teams habe ich es in der letzten Woche gesehen: Dass die Entwicklung eines Teams behindert wird durch die Software. Und wenn ich an andere Teams denke, dann kann ich das selbe Muster sehen, glaube ich.

Ein Team beginnt die Entwicklung einer Software. Die Software bekommt dann eine Form, wie sie das Team denken kann und die Projektkultur zulässt. Da die Architektur- oder allgemeiner Entwurfskompetenz leider, leider im Allgemeinen recht schlecht ausgebildet ist, entsteht keine gute Struktur im Sinne von Evolvierbarkeit. Am Anfang ist das allerdings noch nicht schlimm.

Über die Zeit wird das natürlich nicht besser. Der Druck im Projekt steigt tendenziell, was gewöhnlich zu einer Erosion des wie auch immer ausgeprägten Anspruchs an Strukturqualität führt.

Wo die Strukturen eines Softwaresystems nun aber nicht ausgeprägt und auf Evolvierbarkeit angelegt sind, ist es schwer, sich darin zurecht zu finden. Je schlechter sich die Struktur entwickelt und je umfangreicher solche monolithische Codebasis wird, desto schwerer wird es, neue Teammitglieder einzuarbeiten. Immer mehr Domänen-Know-How ist nötig, immer mehr Erfahrung mit der Codebasis. In einem wachsenden, eng verwobenen Ganzen schrumpfen die Inseln der Unabhängigkeit, die sich separat verstehen ließen.

Team und Code stehen mithin in einer Co-Evolution. Das Team beeinflusst die Codestruktur. Und die Codestruktur beeinflusst das Team. Das ist mir jetzt klar geworden.

Dass das Team für die Codestruktur, für die Evolvierbarkeit verantwortlich ist, liegt auf der Hand. Es gibt Ansätze, mit denen sich die Evolvierbarkeit verbessern lässt. Die einzuführen kostet natürlich etwas Mühe. Das geht nicht von heute auf morgen. Aber es ist machbar. Es winkt eine längere Lebensdauer der Software bei größerer Lukrativität.

Und was, wenn man nichts für die Evolvierbarkeit tut? Na, dann wird es halt immer zäher, an ihr etwas zu verändern.

Soweit der übliche Gedankengang. Die Motivation für die Evolvierbarkeit kommt dabei aus der Codebasis. Ob und wie viel man für Evolvierbarkeit tut, hängt vom Schmerzempfinden ab. Tun Änderungen schon weh genug, dass sich die Mühe für mehr Evolvierbarkeit lohnt? In vielen Teams empfindet es das Team so – aber das Management spürt nicht das selbe.

Jetzt ist mir aber ein weiteres Symptom einer nur noch schwer evolvierbaren Codebasis klar geworden. Und dieses Symptom könnte geeignet sein, die Schmerzschwelle des Managements zu überschreiten. Meine Beobachtung ist, dass schwer evolvierbare Softwaresysteme zu schwer evolvierbaren Teams führen.

Ein Team erzeugt (unbewusst) immer Softwarestrukturen, die seinen Anspruch an die eigene Evolvierbarkeit widerspiegeln. Ich denke, auch das ist eine Ausprägung von Conway´s Law. Monolithische Software ist daher nicht nur eine Folge mangelnden Architekturverständnisses, sondern auch mangelnden Anspruchs an die Organisation.

Monolithisch gedachte Organisation führt zu monolithischer Software. Monolithische Software erhält umgekehrt die monolithische Organisation. Denn eine andere kann den Softwaremonolithen nicht weiterentwickeln.

Flexibel gedachte Organisation führt allerdings nicht automatisch zu evolvierbarer Software. Dazu muss die Kompetenz können, evolvierbare Softwarestrukturen herstellen zu können.

Und was ist eine monolithische Organisation? Eine, die auch Konstanz, auf Starre, Rigidität ausgerichtet ist. Dazu gehört das Äußere: Wie lange sind Mitarbeiter in einem Projekt? Wie fixiert ist die Organisationsstruktur? Wie groß sind die Puffer (Geld, Zeit, Motivtion)? Dazu gehört aber auch das Innere: Wie alt ist das Know-How der Mitarbeiter? Wie alt sind Tools und Technologien? Wie homogen ist die Systemlandschaft?

Als Ergebnis der Co-Evolution von Team und Software habe ich nun aktuell in zwei Fällen gesehen, dass das Team sich nicht weiterentwickeln kann. Es ist fixiert auf einen Technologiestack. Es ist fixiert auf eine große, nicht ersetzbare, sondern in ihrer chronischen Krankheit nur noch palliativ pflegbaren Codebasis. Es ist isoliert vom Markt der Softwareentwickler. Denn in so einem Team will niemand arbeiten. Wer bei Sinnen ist, lässt sich nicht auf eine große, monolithische Codebasis eingefroren in der technologischen Zeit von vor 10 Jahren ein. Ich wüsste jedenfalls nicht, wie groß die Anreize sein müssten, damit ich mich dafür erwärmen könnte. Und die faktische Schwierigkeit, Entwickler zu finden, deutet darauf hin, dass es andere genauso sehen. Das Gehalt ist ohnehin begrenzt – Schmerzensgeld gibt es also nicht genug. Und andere Nettigkeiten vom lockerem Umgangston über Konferenzbesuche bis zur Teamparty reizen offensichtlich auch nicht genug. Die fehlenden Anreize “coole Technologien” und “da lässt sich noch richtig was im Code bewegen” können dadurch nicht kompensiert werden.

Zähigkeit im Code drückt sich in Zähigkeit in der Teamentwicklung aus. Dem Management muss man also nichts von Cyclomatischer Komplexität o.ä. erzählen. Es reicht, wenn es sieht, dass die dringend benötigten Leute nicht an Bord kommen. Wenn Codequalität keinen Anreiz darstellt, etwas in der Softwareentwicklung zu verändern, dann hilft vielleicht die Aussicht, dass wenn nicht schon heute so doch über kurz oder lang das Team stillsteht. Denn dann ist weder Wachstum noch Innovation möglich.

Vorsicht also: Es gilt nicht nur, dass ein Team den Code produziert, der ihm entspricht. Darüber hinaus gilt vielmehr, dass Code zu einem Team führt, der ihm entspricht.

Wer eine Vorstellung davon hat, wie sein Team aussehen und sich entwickeln soll über 5, 10, 20 Jahre, der tut gut daran, von ihm entsprechenden Code herstellen zu lassen.

Samstag, 22. September 2012

Slack ist nicht alles

Slack sei das ultimative Tool für Kaizen – soll Arne Rook in einem Vortrag bei Immobilienscout24 in Berlin gesagt haben. Davon berichtet Stefan Haas in seinem Blog-Artikel “Slack is a Culture Shock”.

Dass Slack - also Spielraum, Freiraum, Autonomität - ein sehr wichtiger Aspekt jeder Arbeit ist, finde ich auch. Voll ausgelastete und allemal überlastete Systeme haben schlicht keine Puffer. Wenn es anders kommt als geplant, knirscht es sofort oder explodiert gar. Und ohne Slack gehen Motivation und Innovation zurück. Wer könnte auf die aber verzichten?

image

Als Lektüre zum Thema empfehle ich Spielräume von Tom DeMarco, Drive von Dank Pink und Why Work Sucks and How to Fix It von Ressler und Thompson.

So weit bin ich also ganz dabei. Slack ist wichtig, ja, unverzichtbar. Ohne Slack keine Selbstorganisation. Ohne Slack keine kreative kontinuierliche Verbesserung.

Aber Slack ist nicht alles.

In einem traditionellen Unternehmen über Slack zu sprechen, mag wie Ketzerei klingen: “Menschen sollen mit (mehr) Freiraum besser arbeiten? Nein, nein, das kann nicht sein.” Solcher Widerstand löst dann schnell den Missionarsreflex aus: “Ich bringe euch das Heil mit Slack; wenn ihr das nicht einsehen wollt, dann erst recht.”

Leider geht dabei zweierlei unter:

  • Menschen müssen es durchaus lernen, mit Freiräumen umzugehen.
  • Menschen brauchen ein Ziel.

Slack zunächst einmal zulassen, d.h. Spielraum vor allem in Bezug auf Zeit geben, aber auch beim Geld, bei Entscheidungen, bei der Arbeitsplatzausgestaltung oder –ortswahl, bei der Fortbildung usw. ist nur ein erster Schritt. Im zweiten muss dieser Spielraum auch genutzt werden. Da sehe ich aber immer wieder Zögern oder gar Unfähigkeit.

Zug zum Spielraum

In vielen Unternehmen klagen die Mitarbeiter über einen Mangel an Spielräumen. Das soll natürlich verbessert werden. Aber ich kenne auch eine ganze Reihe von Unternehmen, in denen es Spielräume gibt – die ungenutzt bleiben. Da wird Zeit gewährt für “Forschung” – nur nimmt sie sich niemand. Da steht Geld für Fachliteratur bereit – nur nutzt das niemand, um Bücher oder Zeitschriften Abos zu kaufen. Da wird sogar Fortbildung angeboten, womöglich um weitere offizielle Qualifikationen zu erlangen – aber keiner macht sich auf den Weg.

Paradiesische Zustände führen also nicht automatisch zu Entfaltung und Aufblühen. Warum? Weil Menschen es aus unterschiedlichen Gründen eben lernen müssen, sie zu nutzen. Was das für Gründe sein mögen, darüber will ich hier nicht spekulieren. Und ich will auch nicht in Zweifel ziehen, dass die Spielraumangebote ehrlich gemeint sind. Was nun? Ist doch schade um den schönen Slack, der da ungenutzt bleibt.

Mein Vorschlag: Die Nutzung von Slack sollte immer wieder nachgefragt werden. Man muss an den Menschen ziehen. Pull ist also nicht nur für die Softwareentwicklung ein wichtiges Prinzip. Auch die Mitarbeiterentwicklung braucht es. Immer wieder muss der Slack-Geber klar machen, dass er wünscht, dass der Spielraum genutzt wird.

Fragen wie “Warum hast du den Slack nicht genutzt?” sind da allerdings weniger hilfreich als “Was hast du in deinem Slack gemacht?” Erstere sind nämlich wieder mehr oder weniger subtil drohend/kontrollierend, Letztere hingegen interessiert und in sich wiederum freistellend.

Slack-Nutzung vorleben und Slack-Nutzung interessiert nachfragen, das scheint mir sehr wichtig, um Menschen anzuleiten, mit Freiräumen umzugehen.

  • Was hast du zuletzt “erforscht” in der Zeit, die dir das Unternehmen dafür bietet?
  • An welchem Fach-/Sachbuch liest du gerade, das du dir von dem Literaturbudget des Unternehmens gekauft hast?
  • Was hast du auf der letzten Fortbildung gelernt, die die das Unternehmen ermöglicht hat?
  • Wie hast du deinen Entscheidungsspielraum genutzt, den dir das Unternehmen bietet?

Das Medium, um Zug in dieser Weise auszuüben, ist für mich “die Runde”, also ein ungezwungenes, allerdings fokussiertes Treffen. Zeit für solche Runden ist im Wochenkalender für alle vorzusehen. Das ist Führungsaufgabe. Und da wird dann nachgefragt, ausgetauscht und Slack gelebt.

Zugziel

Zu glauben, dass durch Slack einfach alles besser würde, weil Menschen dann von selbst aufblühen, finde ich naiv. Ich habe ein optimistisches Menschenbild, doch dass “einfach so” nur durch Freiraum alles gut würde, glaube ich nicht. Er ist wichtig, nur eben nicht allein seligmachend.

Vor allem nützt er nichts, solange unklar ist, wofür er gut sein soll. Was tun mit dem ganzen Slack? Wohin die Energie, die dadurch frei wird, richten? Wohin blicken?

Ohne ein klares Ziel geht es nicht. Wer mag, kann auch Vision oder Mission dazu sagen. Oder auch Zweck. Stefan Haas hat das nur nebenbei angesprochen: “In an environment, where the purpose is clear…”, da werde Slack zur Wunderwaffe.

Leider treffe ich so selten auf Teams, Abteilungen, Unternehmen, die ein wirklich klares Ziel haben. Und ich meine 1 Ziel, 1 Mission, 1 Zweck. Wirklich nur 1. Für alle. Und auch noch sonnenklar.

Der Mangel an klarem Ziel scheint mir sogar noch ein größeres Problem zu sein als der Mangel an Slack. Ich sehe sogar die Gefahr, dass Slack als ein weiteres Mittel gesehen werden könnte, die Unklarheit oder Ambivalenz in Bezug auf ein Ziel zu kaschieren. Doch das kann nur nach hinten losgehen – und würde den Slack als Schuldigen anprangern.

Slack ist auch nur ein Mittel, um das 1 Ziel besser zu erreichen. Genauso wie Selbstorganisation oder Scrum oder ein Team Room oder Collective Code Ownership oder was sonst noch in der Softwareentwicklung.

Aber zu welchem Zweck soll dieses Mittel eingesetzt werden? Solange darüber unterschiedliche Meinungen herrschen, ist nicht zu erwarten, dass das Mittel sein Potenzial entfaltet. Dasselbe gilt für Kaizen. Wohin soll denn eine Organisation sich verbessern? Verbesserung ist kein Selbstzweck. Sie muss dem Organisationszweck dienen. Doch welcher ist das?

Ganz, ganz weit oben auf der Prioritätenliste steht für mich deshalb immer wieder die Zweckdefinition. Wofür gibt es das Unternehmen, die Abteiltung, das Team, das Projekt? Ohne glasklaren Zweck entsteht keine Kohärenz in dem, was die vielen Menschen in einer Organisation tun.

Und weil dabei Menschen eine Rolle spielen, kann diese Frage nicht beantwortet werden ohne zu klären, was diese Menschen eigentlich für sich selbst wollen. Der Zweck einer Organisation muss mithin immer im Einklang mit den Bedürfnissen der sie konstituierenden Menschen stehen.

Das, so scheint mir, ist noch ein größerer Kulturschock für viele Manager. Sich klar werden darüber, was man selbst will und was die Organisation will? Und dann auch das in Einklang bringen mit dem, was die Mitarbeiter wollen?

Ja, ich glaube, ohne geht es nicht mehr. Zumindest, wenn man ernsthaft besser werden will. Und wenn man ernsthaft CSR betreiben will. Die beginnt nämlich wie vieles andere auch bei sich selbst, bei den Mitarbeitern des eigenen Unternehmens.

Wenn ich es in einem Satz sagen sollte, dann vielleicht so: Purpose first, slack second.

Sonntag, 9. September 2012

Wieviel Entwurf ist genug Entwurf?

Endlich die Antwort auf die Frage, wie viel Entwurf einer Implementierung vorausgehen sollte.

Immer wieder wird darüber ja gerätselt. Seit agile Softwareentwicklung aufgekommen ist, herrscht Unsicherheit. Ein “Big Design Up-Front” (BDUF) ist zu vermeiden. Heißt das jedoch, dass gar nicht mehr entworfen werden soll? [1]

Wie ist dieses Dilemma aufzulösen?

Ich versuche es mal mit einer Analogie:

Mit dem Entwurf ist es wie mit der Gesunderhaltung: Wenn man nicht aufpasst, dann gibt es kein Halten.

Wann haben Sie genug für Ihre Gesundheit getan? Schon genug Sport getrieben? Schon genügend Vorsorgeuntersuchungen machen lassen? Schon genügend Blicke in den Körper werfen lassen mit Ultraschall, CT usw.? Schon genügend Blutanalysen machen lassen? Schon ausreichend auf die Ernährung geachtet? Und wie ist’s mit der spirituellen Seite der Gesundheit?

Es ist ein Fass ohne Boden, was man alles für die Gesundheit tun kann. (Nicht umsonst gibt es eine wachsende Gesundheitsindustrie.) Also müssen Sie Ihren Aufwand bewusst begrenzen. Sie können nicht den ganzen Tag darauf verwenden.

Aber es wäre auch falsch zu sagen, dass Sie nichts dafür tun müssten, weil sich alles von allein ergibt. Ich hoffe, da sind wir uns einig.

Das bedeutet, Sie tun am besten täglich ein bisschen. Vielleicht sind das nur 15-30 Minuten “Fitnesstraining” irgendeiner Art. Schon ein regelmäßiger forscher Spaziergang soll ja Wunder wirken. Dazu ein bisschen Obacht bei der Ernährung. Und dann noch alle Jahre wieder ein paar Vorsorgeuntersuchungen. Plus etwas Meditation zwischendurch.

Was bedeutet das für den Entwurf in der Softwareentwicklung?

  • Entwerfen Sie regelmäßig
  • Entwerfen Sie in einer Timebox

In der Regelmäßigkeit steckt die Wiederholung. Es gibt also keinen einmaligen Entwurf, der alles vorherbestimmt. Entwerfen ist vielmehr eine kontinuierliche Aufgabe wie Codieren. Bei neuen Erkenntnissen, muss auch neu entworfen bzw. der bisherige Entwurf überprüft und angepasst werden.

Und in der Timebox steckt die Begrenzung, damit Entwurf kein schwarzes Ressourcenloch wird. Es stimmt ja: Bubbles don´t crash. Und mit einem Entwurf ist noch kein Kunde glücklich gemacht worden. Deshalb muss das Entwerfen immer wieder ein Ende haben, um es in auslieferbaren und nützlichen Code zu überführen, zu dem der Kunde Feedback gibt – das wiederum Einfluss auf den Entwurf haben kann.

Ist Ihnen das genug Empfehlung zur Menge des Entwurfs bei der Softwareentwicklung?

Wenn nicht, dann hier konkrete Zahlen. Die werden Sie natürlich provozieren. Die meine ich auch nicht so, dass sie für alle Softwareprojekte heute und in Zukunft gelten. Natürlich nicht. Aber ich meine sie trotzdem ernst, sozusagen als Tendenz und Denkanstoß:

  • Entwerfen Sie am Anfang eines Projektes max. 2 Tage.
  • Entwerfen Sie anschließend jede Woche max. 4 Stunden.
  • Entwerfen Sie außerdem jeden Tag max. 2 Stunden.

Und das jeweils im Team.

Wie klingt das? Konkret, oder? Und nicht gerade BDUF. Sondern agil, weil kontinuierlich. Außerdem steckt da Kommunikation drin, weil das Team zusammen entwirft (Collective Design Ownership). Und es wird Architekturbewusstsein verkörpert.

Sie sehen, die Antwort auf die immer wieder gestellte Frage ist eigentlich ganz einfach. Wieviel Entwurf ist nötig? Im Schnitt sind es ca. 2-3 Stunden pro Tag. That´s it. Nicht die schiere Menge Entwurf ist wichtig, sondern die Regelmäßigkeit.

Fragt sich jetzt nur, was man während dieser Zeit tut? Aber das ist ein Thema für ein anderes Mal.

Fußnoten

[1] Was Entwurf nun genau ist im Vergleich zum Codieren, lasse ich mal dahingestellt. Soviel sollte aber klar sein, dass beim Entwurf eben kein Code geschrieben wird. Das heißt nicht nur, dass die Programmiersprache dabei keine Rolle spielt, sondern auch, dass das Abstraktionsniveau über der Programmiersprache liegt. Flow-Charts und Structogramme sind für mich daher eher keine Entwurfsmittel, sondern nur graphische Programmiersprachen.