Dieses Blog durchsuchen

Dienstag, 17. Januar 2012

Die Aufwärmphase vor der Projektvorstellung

Eigentlich hatte ich zwar im letzten Beitrag versprochen, dass ich als nächstes das erste Projekt vorstellen werde. Aber ich wollte erstmal noch meine Vorgehensweise bei allen kommenden Projekten erklären.
Mir kommt es ja auf Konsistenz an, die ich bei allen Projekten anstrebe.

Die Vorstellung der Projekte
Jedes Projekt wird nach folgendem Schema vorgestellt werden:
  • The Big Picture
    Unter dieser Überschrift werde ich meine Vorstellung von der zu entwickelnden Software präsentieren. Was soll sie am Ende mindestens können? Was sind meine persönlichen "must-have"-Features? Es wird eben ein grober Überblick gegeben, um Appetit zu wecken. ;-)
  • Herausforderungen und mögliche Schwierigkeiten
    Jedes Projekt wird das ein oder andere Feature enthalten, was ich so noch nie zuvor implementiert habe. Das könnte also Schwierigkeiten machen oder eben sehr knifflig sein. Diese möglichen Stolpersteine werde ich hier aufzählen.
  • Der erste Schritt
    Jedes Projekt fängt erstmal klein an. Daher definiere ich unter diesem Punkt die Features der ersten Iteration.
Gemeinsamkeiten aller Projekte
  • Sie tragen einen weiblichen Name. (Die Erklärung, weshalb das so ist, habe ich ja schon im letzten Beitrag geschrieben.)
  • Die Root-Bezeichnung meiner Namespaces wird entweder die Initialen CGO oder SachsenCoder tragen.

    Ich tendiere aber zu SachsenCoder. Das erscheint mir weltweit eindeutiger zu sein.
  • Die Projekte werde ich bei github veröffentlichen. (Hoffentlich klappt das auch alles so. Ich habe bisher nur lokale Git-Repositories verwendet. *g*)
    Innerhalb der github-Umgebung werde ich primär alle Texte auf Englisch verfassen. Das macht sich besser, falls doch mal jemand an dem Projekt mitmachen will. So ist es dann wenigstens international verständlich. (Auch, wenn mein Englisch sicher nicht ganz so erstklassig ist. *g*)
  • Alle Projekte werden als Basis .NET-Framework 4.0 verwenden.
  • Die Sprache selber wird C# sein. (Das ist die einzige Sprache, dessen Syntax mir wirklich gut gefällt!)
  • Alle Projekte werden im AppKata-Stil aufgezogen und nach der Spinning-Strategie angegangen. Das heißt, es gibt viele überschaubare Iterationen auf den Weg zum Big Picture und darüber hinaus. Jede Iteration soll einen kleinen, aber echten Nutzen hervorbringen. Jede Iteration wird je nach Komplexität in unterschiedlich kleine Slices aufgeteilt, damit ich/man von den Anforderungen nicht gleich erschlagen wird und ein Problem zeitnah gelöst werden kann.
    Ich halte dieses Vorgehen für unerlässlich, um die Motivation aufrecht zu halten.
  • Spätestens nach jeder Iteration (oder dem ein oder anderen Slice) werde ich öffentlich darüber reflektieren, wie es gelaufen ist. Stellten sich die voraussichtlichen Schwierigkeiten wirklich als Hürde heraus? Wenn ja, warum? Wenn nein, warum nicht? Ist die Motivation noch gegeben oder steuere ich auf eine Lustlosigkeit zu? Bin ich mit der entwickelten Lösung zu Frieden? Entspricht sie den gegebenen Anforderungen? Gibt es Möglichkeiten der Verbesserung? Kann ich diese Verbesserungen umsetzen oder komme ich da an eine Know-How-Barriere?
    Diese Art der Reflektion soll mir dabei helfen, die Sachen, die ich da entwickelt habe, nochmal bewusst zu machen. Es soll auch verhindern, dass ich in eine "Frickel"-Ebene abdrifte.
  • Die Entwicklung wird weitgehend gebloggt werden. Das heißt, die Lösungsfindung mache ich quasi öffentlich. So, als wenn ich laut denke oder jemanden meinen Lösungsweg erkläre. (Sicher werden mir dabei auch selber eventuelle Denkfehler auffallen.) Zudem gibt es anderen die Möglichkeit, die Entwicklung von Anfang an nachzuvollziehen. (Kann ja sein, dass am Ende wirklich geile Tools dabei rauskommen. Dann ist es doch fantastisch, wenn gerade sowas verständlich dokumentiert ist. Das ist ja im Open-Source-Bereich nicht selbstverständlich.)
Unter'm Strich soll die Entwicklung einen professionellen Charakter bekommen.

Montag, 16. Januar 2012

Endlich mal was auf die Beine stellen!

Mit der Überschrift möchte ich mir selbst einen mentalen Arschtritt verpassen. Es ist ja nun schon fast ein Jahr her, als ich meinen letzten Blog-Post veröffentlicht habe. Und so kann ich nicht gleich mit der Tür ins Haus fallen, sondern muss erstmal den Leser auf das Kommende einstimmen.

Eigentlich habe ich noch viele Blog-Post-Entwürfe rumliegen, die alle davon handeln sollten, dass die Event-Based-Components doch nicht so prickelnd sind, wie man sie sich vorstellt.
Die Ironie daran ist eigentlich die, dass mir kaum ein ernsthafter Kritikpunkt einfallen wollte. Die einzige ernsthafte Kritik, die mir eingefallen ist, ist die schlechtere Code-Navigierbarkeit innerhalb von Visual Studio. (Z.B. beim Debuggen. "Gehe zu Definition" wird da nicht so schön funktionieren.)
Auch sollte man bei den EBC stehts eine visuelle Abbildung synchron zum Code mitführen. Da ist eben etwas Disziplin gefragt.

Und das war es eigentlich auch schon. Alles andere sind eher gravierende Vorteile gegenüber den herkömmlichen Praktiken, die so in aller Munde sind. (Wenn man ehrlich zu sich selber ist, merkt man das auch.)
Ich stellte das bei meiner "Micro-Pattern-Trilogie" auch fest. Man konnte alles schön voneinander getrennt halten. Aber sie waren zu schwergewichtig und brachten zu viel Rauschen mit. Damit war das Ding für mich gestorben.

Nun hat sich in der Zeit aber sehr viel getan. Die EBC sind sehr schlank, flexibel und aussagekräftiger geworden. EBC sind nun viel mehr ein Implementationsdetail. Der eigentliche Überbegriff für das Ganze heißt nun ganz einfach "Flow-Design". Es ist einfach ein Paradigma, wie man ein Business-Problem ganz einfach angehen kann. Wie das am Ende in der Programmiersprache XYZ umgesetzt wird, spielt keine Rolle. Die Art, wie es am schönsten in C# umgesetzt werden kann, ist eben das, was sich EBC nennt. (Wobei das eigentlich keinen extra Name bräuchte. Zumal ja die heutigen EBC kaum noch was mit der Ursprungsdefinition zu tun haben.)

Hierfür möchte ich noch zwei hervorragende Videos zu der neuen und erfrischenden Art der "Flow-Based"-Entwicklung vorstellen.

Das erste Video hatte ich damals live mitverfolgt. Das fand ich besonders motivierend, weil die alte EBC-Denke dort quasi gar nicht mehr auftaucht. Das zeigt sich besonders darin, dass es in der normalen Form keine Substantive mehr gibt. Es gibt also keine "Täter" mehr, wie z.B. einen "UserRegistrator" oder ähnliche abenteuerliche Gebilde, wo man letztlich nicht weiß, was er alles tut.
Stattdessen gibt es "Tätigkeiten", also echte "Funktionseinheiten". Eine Funktionseinheit könnte z.B. "Register_User" heißen. So benennt man dann z.B. auch die Klasse. Das ist das, was mir an dem neuen Konzept am Besten gefällt! Benennt man eine Klasse nach ihrer Funktion in der Verbform, ist definitiv klar, was sie tut. Im besten Fall tut sie nur diese eine Sache! Bei einem "UserRegistrator" weiß man leider nicht genau, was er alles tut. Da steckt die Funktionalität in einzelnen Methoden, welche eventuell weitreichende Abhängigkeiten haben, die gar nix mehr mit dem eigentlichen Kontext zu tun haben. Und das verleitet dazu, dass man Verantwortlichkeiten mischt.



Das zweite Video zeigt quasi an einem praktischen Anwendungsfall, wie der Entwicklungsprozess mit "Flow-Design" aussieht. Hier kommt auch gut zur Geltung, dass ein "Flow-Design" wunderbar evolviert.



Soviel erstmal zu der kleinen Einführung.
Um zum Ausgangspunkt zurückzukommen: Ich muss (und will) endlich mal ein privates Projekt auf die Beine stellen! Unter Zuhilfenahme von "Flow-Design".

Projektideen habe ich da mehr als genug:
  • Ein Bildverwaltungsprogramm
    Das soll so in die Richtung wie Picasa oder die Windows Live Fotogalerie gehen. Aber mein Programm soll flexiblere und besser anpassbare Slideshows ermöglichen. Auch soll es mit sehr vielen Dateien mühelos umgehen können. (Das ist nicht immer selbstverständlich bei den Lösungen, die es da so gibt.) Aber das eigentliche Killerfeature sollen ja Smartalben sein! Die vermisse ich nach wie vor in Picasa und bei der Windows Live Fotogalerie. (Der Photoshop Elements Organizer bietet zwar Smartalben an, aber die kann man nicht schachteln.) Generell sollen alle erdenklichen Filtermöglichkeiten möglich sein ... beliebig komplex. Was die Software in erster Linie nicht bieten soll, sind diverse Social-Features und Bildbearbeitungsfunktionen. Gesichtserkennung ist auch erstmal nicht geplant. (Das sind aber Sachen, die per Flow-Design leicht nachrüstbar sein sollten.) Die Verwaltungsaspekte sollen hier im Vordergrund stehen.
  • Einen Editor und Player für interaktive Stories
    Sowas finde ich einfach "nice to have". ;-)
    Ich stelle mir das so vor, dass man einfach beginnt, eine Geschichte zu schreiben. Und während dieses Vorgangs kann man dann intuitiv die dynamischen Aspekte der Storie festlegen. (Charaktere, Handlung, Interaktion, etc.) Man soll nicht schon vorher wissen müssen, was man alles braucht oder was dynamisch werden soll, wenn man eine solche Geschichte beginnt. Ein Tool, was so in die Richtung geht, aber in meinen Augen noch nicht so richtig den Punkt getroffen hat, ist z.B. Twine. Das fühlt sich noch zu sehr nach Scripting an. Und übersichtlich ist das bei komplexeren Stories auch nicht gerade. Oder wenn noch Variablen ins Spiel kommen. Oder wenn man seine Charaktere im Blick behalten will, etc.
  • Ein Tool für einfachere Softwareentwicklung
    Davon träumt sicher jeder Softwareentwickler! ;-D
    Ehe ich da viel dazu erzähle ... ich denke da an eine Mischung aus Code Bubbles und FlowStone. Quasi ein Softwaremodellierungstool.
  • Eine Wuala-Alternative
    Denn Wuala unterstützt ja keinen Speichertausch mehr. :-(
  • Ein Automatisierungstool
    Ja, sowas Ähnliches wie FinalBuilder. Nur nicht so Feature-Complete und universell wie dieses Tool derzeit zu sein scheint. Einfach ein Tooling, was meine kleinen Automatisierungsanforderungen komfortabel erfüllt. (Ein bisschen Templating, d.h. Platzhalter durch echte Werte ersetzen; Dateiverwaltungskram; Commandline-Tools ausführen; etc.) Das Tool könnte "nebenbei" entstehen. Je nachdem, welche Automatisierung ich gerade gebrauchen könnte.
Tja, an Ideen mangelt es nicht. Ich will aber realistisch sein: Das Softwareentwicklungstool und die Wuala-Alternative wird es voraussichtlich nicht (sofort?) geben. Das entwickelt man auch mit Flow-Design nicht mal eben so in der knappen Freizeit.
Bei den anderen Programmen sehe ich da aber schon realistische Ziele.
Was alle Programme (hoffentlich) gemeinsam haben werden, ist Folgendes:
  • Ein modernes, einfach zu handhabendes (G)UI. Heutzutage muss man wirklich keine hässlichen GUIs mehr hinnehmen oder einem User anbieten. Die Tools für Mac OS sehen immer so stylisch aus. Warum sollte das nur Mac OS exklusiv sein?
  • Jedes Tool versuche ich penibel im Flow-Design-Stil zu entwickeln. Also erst der grafische Entwurf und dann der Code. (Das wird für mich eine disziplinarische Herausforderung werden, weil ich sonst alles gleich im Code entworfen habe.) Als Tool für die Diagramme werde ich hier yEd verwenden.
  • Sie werden frei wie "Freibier" und sicher auch frei wie "frei veränderbar" sein. ;-)
    Ich verfolge kein finanzielles Interesse. Die Tools entwerfe ich, weil ich sie sehnlichst brauche. Ich will nicht länger warten, bis sie mal irgendjemand irgendwann programmiert. Und warum sollte ich die Tools am Ende nicht anderen zur Verfügung stellen?
Was erwarte ich von dem Vorhaben?
  • In erster Linie, wie bereits erwähnt, brauche ich die Tools, weil mir die existierenden Lösungen nicht das bieten, was ich wirklich brauche. (Oder weil andere Lösungen zu komplex und/oder zu teuer sind.)
  • Ich will meine Fähigkeiten als Entwickler ausbauen, sodass mir die Flow-Design-Methodik in Fleisch und Blut übergeht. Ich möchte nicht mehr in die alte OOP-Denke verfallen.
  • Kann es für den Arbeitsmarkt bessere Referenzen geben, als selbst entwickelte Software inklusive Dokumentation von deren Entstehungsprozess?
  • Ich möchte eben auch einfach mal in der Freizeit etwas Produktives machen. Bisher bin ich nur auf Arbeit wirklich produktiv und entwerfe Software. Aber da hat man eben immer den Zeitdruck; muss die Anforderungen so umsetzen, wie sie gefordert sind und die resultierenden Tools bringen einem selbst keinen Nutzen. Es ist eben irgendwie einfach nur Arbeit, die man macht. (Es macht zwar trotzdem Spaß, aber so richtig kann man sich irgendwie nicht entfalten.) Ich will einfach auch mal selber die Anforderungen definieren und Tools entwickeln, die mir persönlich sehr viel bringen. Und das ohne BWLer im Rücken, aus deren Sicht es ja keine Probleme gibt und alles "straight forward" ist. Ohne BWLer, für die Softwareentwicklung nur ein notwendiges, unberechenbares Übel in der Kostenkalkulation ist.
  • Das Flow-Design verspricht eigentlich echte Wiederverwendbarkeit, da es nur Input- und Outputabhängigkeiten gibt. Ich hoffe, dass ich da auch viele Funktionseinheiten in anderen Projekten verwenden kann.
Was sind die persönlichen Herausforderungen und Risiken für mein Vorhaben?
  • Durchhaltevermögen! Das ist definitiv die größte Herausforderung der ich mich stellen muss. Ich weiß schon jetzt, dass es sicher Phasen geben wird, wo ich mal definitiv keinen Bock haben werde, irgendwas zu programmieren. Ich denke, das ist aber ganz natürlich. Man ist schließlich kein Roboter. Ich hoffe nur, dass solch eine Phase nicht dauerhaft eines meiner Vorhaben zerstört!
  • Durch meine hohen Anforderungen an die Usability werde ich endlich mal gezwungen, mich mit Drag & Drop, (dynamischen) Kontextmenüs und sonstigen GUI-Spielereien auseinanderzusetzen. Auch, was die prinzipielle Gestaltung der Oberfläche anbelangt. Da muss ich selber hartnäckig bleiben und darf mich nicht zu schnell mit einer ungewollten Lösung abfinden. Daher muss ich vorher penibel meine exakte Vorstellung dokumentieren und mich dran halten.
  • Ich muss mir einheitliche Konventionen schaffen und mich penibel dran halten! Auf Arbeit ertappe ich mich oft, dass ich mit diesem Grundsatz breche. Oft aus Bequemlichkeit oder Zeitdruck.
Was gibt es sonst noch zu wissen?
  • Ein Framework zu benutzen, ist für mich ein notwendiges Übel, um schnell Resultate zu bekommen. Für mich gibt es im Entwicklungsprozess aber nix Schlimmeres, als vor Problemen zu stehen, die mit dem Framework zu tun haben. Die Probleme entstehen, weil man oft nicht genau weiß, wie man ein Framework richtig benutzt. Oder man steht vor einem merkwürdigen Verhalten, was man nicht versteht und nicht nachvollziehen kann. (Das ist die Bug- und Fehlerquelle Nummer eins.) Daher meide ich auch den exzessiven Gebrauch von Framework-Features, die ich nicht verstehe oder nachvollziehen kann. Da erfinde ich das Rad lieber neu und weiß dann wenigstens, wie es funktioniert. Das werde ich auch bei meinen Projekten so handhaben. Mit der Strategie bin ich bisher sehr gut gefahren. (Außerdem ist es DAS, was mir überhaupt am Programmieren gefällt: Wenn man mal selber etwas implementieren kann und es hinterher noch tadellos funktioniert.)
  • Ich werde nach Möglichkeit offene Libraries für Programmteile verwenden, wo ich selber einfach nicht die Zeit oder das nötige Know-How habe, um eine solche Funktionalität selber zu implementieren. (Z.B. Gesichtserkennung oder sowas.)
  • Um meine grafischen Fähigkeiten etwas zu schulen, werde ich mich dieser Quelle bedienen:  http://2dgameartforprogrammers.blogspot.com/
    Da dreht sich zwar alles um Spielegrafik, aber gerade was die Shading-Grundlagen anbelangt, kann man das Wissen sicher auch universell für GUIs einsetzen.
  • Die Codenamen meiner Projekte werden weibliche Vornamen tragen!
    Ich habe lange überlegt, wie ich meine Projekte nennen könnte. Zuerst dachte ich an Tierbezeichnungen. Aber fast jede Software trägt ja irgendwie eine Tierbezeichnung als Codename. (Ubuntu & Co. lässt grüßen. *g*)
    Davon will ich mich abgrenzen. Software ist in meinen Augen in jeder Hinsicht weiblich und nicht tierisch! ;-) Und vor allem möchte ich Namen für meine Software haben, die man sich auch gut merken und aussprechen kann. (Schließlich werden diese Namen ein Bestandteil des Namespaces. Da möchte ich keine cryptischen Bezeichnungen drin haben. *g*)
Im nächsten Beitrag werde ich dann sicher mein erstes Projekt vorstellen. Da bin ich selber sogar schon ganz gespannt drauf. :-D

Montag, 7. Februar 2011

Welches Paradigma passt zu Dir?

Im Internet werden ständig sinnlose und anstrengende Glaubenskriege geführt. Das fängt damit an, welches Betriebssystem besser ist und geht dann weiter, welcher Browser cooler ist.
Diese Diskussionen kennt sicher jeder zur Genüge.

Nun müsste man meinen, dass wir als Softwareentwickler innerhalb unseres Bereiches vernünftiger wären. Tja, schön wär's. Da gibt es fast noch hitzigere Debatten, welche Sprache oder welches Paradigma besser ist.
Auch diese Diskussionen werden eher subjektiv, als objektiv geführt.
Man hört aber immer öfter heraus, man solle die Sprachen und Paradigmen wie Werkzeuge betrachten. Und so soll man eben immer das Werkzeug auswählen, welches zu einer bestimmten Problemstellung passt.

Nun haben wir aber das große Glück, dass mittlerweile fast alle größeren bekannten Programmiersprachen Multiparadigmensprachen sind. Damit sollte sich die Wahl der "richtigen" Sprache beinahe erledigt haben. Oft liest man auch von den vernünftigeren Diskutanten, dass man die Sprache wählen soll, dessen Syntax einem besser gefällt. Soweit, so gut!

Und wie ist das mit den Paradigmen? Da bleiben noch viele stur und möchten anderen gerne ihr eigenes bevorzugtes Paradigma aufdrängen. Der große Vorreiter unserer Zeit ist wohl die OOP. "Denn alles andere ist ja out und von vorgestern!"
Und leider wird einem dieses Paradigma wirklich oft aufgezwungen. Da braucht man sich nur mal die Bibliotheken rund um .NET oder Java anzugucken. Da geht wirklich nix mehr ohne OOP.

Was ist aber, wenn man nicht immer objektorientiert denken kann bzw. will? Was ist, wenn einem dieses objektorientierte Zeug Komplexe bereitet oder gar Denkblockaden auslöst?

Das klingt absurd? Sowas ist Unsinn? Der Softwareentwickler ist einfach nur zu dumm für OOP?

Dann sind Linkshänder aus der Sicht eines Rechtshänders sicher auch nur zu dumm, um mit der rechten Hand zu schreiben. Sollen sie doch gefälligst lernen, mit der rechten Hand zu schreiben. Immerhin kann die Mehrheit der Menschen auch mit der rechten Hand schreiben.
Zum Glück wurde diese Einstellung aus den Köpfen der meisten Menschen verbannt. (Auch, wenn bis dahin viele Linkshänder zur Rechtshändigkeit gezwungen wurden. Ich wollte früher als Kind auch mit Links schreiben ... aber mit spiegelverkehrter Schrift. Ich sollte dann aber mit der rechten Hand schreiben ... was ich auch heute noch tue. Ob das meine geistige Entfaltung beeinträchtigt hat, kann ich nicht klar sagen. *g*)

Warum ist das aber noch nicht in den Köpfen der Softwareentwickler angekommen?
Paradigmen werden immer noch wie Werkzeuge behandelt, die nur für ein bestimmtes Problem in Frage kommen und bei anderen wiederum nicht in Frage kommen (dürfen!).

Gerade in der OOP wird mit Dogmen umher geworfen, wo man meinen könnte, man hat die zehn Gebote vor sich. Da gibt es dann sogar Kampagnen, wie z.B. die "Anti-If-Kampagne", wo ich in dem Moment nicht weiß, ob ich lachen oder weinen soll. Früher war das böse "goto" das Übel allen Übels und musste bekämpft werden. Oh, das hat man auch erfolgreich durchgesetzt! Oder traut sich heute noch jemand ein wohl überlegtes "goto" in seinen Quellcode zu setzen, wenn es dem besseren Verständnis oder gar der Performance dient? Das macht kaum noch jemand, weil viele Angst haben, als unfähig bezeichnet zu werden.
Und nun versucht man das Selbe mit dem "if-then-else"-Konstrukt. Denn es gibt ja dafür die heilige Polymorphie. Und wer die nicht in seinem Programm verwendet, ist doch von vorgestern und unfähig.

Aber ich schweife etwas ab.

Der Punkt ist aber, dass man offenbar versucht, ein bestimmtes Paradigma zu DEM global gültigen Paradigma zu erheben. Dabei fragt aber keiner, ob man damit überhaupt zurecht kommt, oder nicht. (Gibt es überhaupt noch Frameworks, die nicht objektorientiert aufgebaut sind? Das ist eine ernsthafte Frage. Mir fällt da höchstens spontan die normale Win32-API ein.)

Dazu möchte ich ein Zitat einstellen, was mir sehr gut gefallen und mich dazu veranlasst hat, diesen Beitrag zu schreiben. Es ist auf der Seite "OOP Criticism" unter der Überschrift "One Mind Fits All?" zu finden:
...I was always told that OO was an intuitive way of thinking. Although I develop daily in OO languages, I do find OO rather unintuitive (although I manage). ... If I analyze a problem, I draw tables not objects and classes, I think in tables, those are much more intuitive to me. Even when I program in OOP, I rely as much as possible on tables. ...it's nice to see that I'm not the only one who 'thinks' in tables. ...
Es geht doch am Ende genau darum: Welches Paradigma passt zu Dir?
Einer denkt in Bildern, ein anderer in Tabellen und wieder ein anderer denkt in Wörtern oder etwas ganz Anderes.

Vielleicht sollten wir in Zukunft diesbezüglich offener und toleranter sein.
Es gibt eben nicht DAS Paradigma. Es gibt auch nicht DAS Paradigma für ein bestimmtes Problem.
Es kann nur DAS Paradigma geben, was DU in einem bestimmten Kontext für richtig hältst und womit DU am Besten zurecht kommst.

Wenn man in diesem Punkt die Freiheiten lässt, kann auch eine Entwicklung statt finden. Zum Einen kann man sich persönlich entwickeln, wenn man sein passendes Paradigma sucht. Zum Anderen kann man aber auch die Softwareentwicklung aktiv verändern. (Vielleicht entstehen dadurch sogar noch ganz andere Paradigmen?!)

Softwareentwicklung ist ein kreativer Prozess! Und Kreativität muss sich frei entfalten können! :-)

Samstag, 5. Februar 2011

Warum versucht man die Welt zu modellieren?

Inspiriert durch den letzten Beitrag von Ralf Westphal "Mehr vom Selben hilft nicht mehr", dachte ich mir, dass es durchaus sinnvoll sein kann, der Kernaussage noch mehr Ausdruck zu verleihen. Ganz im Sinne von "Spread the word!"

Längere Zeit vorher beschäftigte ich mich auch mal mit Konzepten, wie z.B. Funktionale Programmierung und Data Oriented Design.
Und ich sagte so zu mir: "Verdammt! Recht haben sie!"

Es geht seit der Erfindung des ersten Computers um Datenverarbeitung. Und das möglichst effizient und seiteneffektfrei!

Warum ist das aber in Vergessenheit geraten? Haben wir schon lange den Boden unter den Füßen verloren?
Das kann man wohl annehmen. Dank *hust* der Objektorientierten Programmierung (OOP) programmiert man nicht mehr, sondern modelliert nur noch. Es wird alles Erdenkliche in Klassen beschrieben und durch Objekte ins Leben gerufen. Ob das nun sinnvoll ist, oder nicht. Egal! "OOP ist ja sooo geil und überhaupt kann man damit viel besser die Welt beschreiben."
Ja, man kann damit wunderbar die Welt beschreiben und modellieren. Damit wirbt zumindest jedes mir bekannte OOP-Buch.
Gerade, um den Leser für Vererbung zu begeistern, werden wirklich immer diese trivialen Beispiele, wie z.B. die Tierklassen, Autoklassen, Baumklassen, etc. aufgeführt.
Aber ganz ehrlich: Derartigen trivialen Nonsens habe ich bisher noch nie in meinen Softwareprojekten vorgefunden. In der Software-Realität gibt es eher "Tierautos mit Blättern dran". Das liegt ganz einfach daran, dass man viele Dinge im Businessproblem nicht so einfach klassifizieren kann, wie es einen die OOP-Autoren gerne schmackhaft machen wollen. Objekte müssen miteinander interagieren und Daten austauschen, denn nur darum geht es letztlich wieder: um die Datenverarbeitung.

Aber auch dafür hat sich die OOP-Gemeinde einige Konstrukte ausgedacht, die sich Entwurfsmuster "schimpfen". Überhaupt wurde der Trend eingeleitet, man solle nicht mehr "ableiten" und "vererben", sondern "komponieren". Dies sei flexibler, sagt man. (Was ich auch nicht bestreiten will.)

Doch sehe ich die Entwurfsmuster eher als Krücke. Nach dem Motto: Not macht erfinderisch.
Und, dass diese Entwurfsmuster nur ein Notnagel sein können, sieht man z.B. am "Visitor Pattern" oder dem "State Pattern". Die mögen ja wunderbar funktionieren, aber den Quellcode darf man hinterher nicht verstehen, geschweige denn debuggen wollen.

Tja, das hat alles nicht mehr den Eindruck, als wolle man Daten verarbeiten, sondern als wolle man geschickt mit einem Netzwerk aus Objekten um die Daten herumtanzen, ohne diese direkt zu berühren.

Es denkt doch keiner mehr an den Prozessor und an den Speicher.

Die OOP widerspricht immer noch der Arbeitsweise der gegenwärtigen Rechner. Denn im Rechner sind noch immer die Daten vom Code getrennt. Der Prozessor kennt keine Klassen, Objekte und erst recht keine Entwurfsmuster. Das wäre ja alles kein Problem, wenn die Zugriffszeiten auf den Arbeitsspeicher nicht den Prozessor unnötig ausbremsen würden.

Ganz ehrlich: Ich würde kein Prozessor sein wollen, der ein OO Programm bewältigen muss. ;-)

Warum versucht man also die Welt - das Businessproblem - in ein OO-Schema zu pressen, welches der Compiler wieder halbwegs entfrickeln (Code von Daten trennen) muss, damit es der Prozessor dann mehr schlecht als optimal lösen "darf"?

Und wie man dem Beitrag von Ralf entnehmen kann, geben die OOP-Gurus zu verstehen, dass die Mehrheit nach so vielen Jahren noch immer nicht richtig OO programmieren kann.

Ja, da muss man wirklich fragen, wessen Problem das ist? Ich brauche diese "Religion" OOP nicht wirklich, um meine Business-Probleme auf Arbeit zu lösen. Das habe ich jedoch leider eher spät gemerkt, weil ich auch auf den OOP-Zug aufgesprungen bin, der sehr gut beworben wurde. Hinterher fand ich die Codebasis aber trotzdem nicht schön. Vielmehr war alles so aufgeblasen und ich verlor den Überblick.

Ich frage mich aber wirklich, warum die OOP-Gurus so hartnäckig an der Objektorientierung festhalten. Geht es dabei nur um das Modellieren der Welt?
Wäre es nicht sinnvoller, ein Paradigma zu wählen, welches dem Programmierer gleichermaßen entgegen kommt, wie der Hardware? Wenn man nicht mehr versuchen würde, die Business-Probleme 1:1 mit Objekten zu beschreiben, sondern die Probleme grundlegend abstrahieren würde, sodass diese einfacher zu fassen und für die Hardware optimal beherrschbar sind?

Vielleicht hat man damals die Idee - den Code von den Daten getrennt zu halten - zu schnell verworfen. Denn gerade die Rechnerarchitektur zeigt uns doch, wie die Daten am besten verarbeitet werden können. Und solange sich die Architektur nicht ändert, ist es IMHO keine gute Idee, weiterhin die Daten mit dem Code zu mischen.

Ich bin zumindest gespannt, wohin die Reise gehen wird. Spätestens mit den ersten Quantenrechnern dürfte sich noch so Einiges ändern. ;-)

Sonntag, 11. Juli 2010

Ansichten ändern sich!

Es ist nun schon eine Weile her, als ich hier einen Beitrag geschrieben hatte. Ich nutzte die Zeit, um mit der MPT ein wenig Erfahrung zu sammeln. Dies tat ich mit einem Projekt auf Arbeit.

Naja, es funktionierte schon alles so, wie ich mir das gedacht hatte. Jedes Objekt war im Grunde unabhängig voneinander und der Datenfluss geschah eher passiv. Eigentlich genau das, was ich wollte, oder?
Nun ja, nicht ganz.
So bereitete mir z.B. die Idee des Transmitters in einem Anwendungsfall ziemliche Probleme:
Nehmen wir an Objekt A ist ein Transmitter für irgendeinen Wert X.
Objekt B und Objekt C empfangen diesen Wert X.
Objekt B fordert den Wert X an. Diesen Wert bekommt Objekt B von Objekt A. Aber auch Objekt C bekommt diesen Wert X, weil es ja ebenfalls als Empfänger für diesen Wert registriert ist.

Das scheint soweit OK zu sein, oder? In meinem Fall war dies aber nicht gewollt, weil das unaufgeforderte Empfangen des Wertes X eine Ereigniskette ausgelöst hat, die nicht hätte ausgelöst werden dürfen.
Also, wenn Objekt A den Wert X anfordert, darf ihn nicht Objekt B bekommen. Und wenn Objekt B den Wert X anfordert, darf ihn nicht Objekt A bekommen.
Das ist ein ziemliches Dilemma, welches einen schon mal verzweifeln lässt.
Meine erste Idee war es ja, bei den Objekten A und B eine Flag-Variable einzuführen, welche in der Empfangsroutine prüft, ob der Wert X überhaupt angefordert wurde.
Doch das schlug ich mir schnell wieder aus den Kopf, denn so eine "Prüfung" verschmutzt die Businesslogik. Zudem wissen die Objekte gar nicht, was um sie herum geschieht. Diese Flag-Variable würde aber indirekt andeuten, dass dieses Objekt etwas über seine Umgebung weiß. Und das wäre schlecht!

Ich überlegte lange, wie ich das Problem lösen könnte. Dann kam mir die Idee! Man könnte ja einfach ein Objekt dazwischen schalten, welches wie ein Ventil funktioniert. Man schaltet es z.B. einfach zwischen Objekt A und Objekt B. Die Anforderung von Objekt B geht durch das "Ventil". Dabei wird in dem "Ventil" ein Flag gesetzt, welches den Empfang von Wert X erlaubt. Es ist somit "offen". Wenn dann der Wert kommt, wird der Wert an Objekt B durchgereicht und das Ventil wird wieder geschlossen. Bei einem unaufgeforderten Empfang wird der Wert einfach abgewiesen und Objekt B bekommt davon gar nix mit.

Nachdem ich das so eingebaut hatte, funktionierte alles wieder problemlos. Die Ventile sorgten für den gewünschten Datenfluss und die Businesslogik hatte sich absolut nicht geändert. Genial!

Unzufrieden, trotz entkoppelter Objekte
Die Anwendung funktionierte, aber mir war unwohl bei dem Gedanke, dass noch mehr Funktionen in die Software fließen sollten.
Wie kann das sein? Die Entkopplung sollte ja eigentlich das Gegenteil bewirken und Sicherheit bei der Implementation neuer Funktionen erzeugen. Ein Grund für die Unsicherheit war wohl auch das oben geschilderte Szenario.
Viel schlimmer war aber gerade die totale Isolierung der einzelnen Businessobjekte zueinander. Das heißt, ich konnte aus einem Objekt heraus nicht die Kommunikationsstrecke verfolgen.
Wollte ich also wissen, was passiert, wenn ich auf einen bestimmten Button klicke, so kam ich zwar zur entsprechenden Aufrufmethode, doch dann war da eine Sackgasse. Der Isolation sei "Dank", stand da in den jeweiligen Methoden nur die Floskel "Say.Carefully(MacheIrgendwasSinnvolles, this)".
"Ach ja, toll! Und welches Objekt ist jetzt nochmal dafür zuständig, diese Sache auszuführen?" fragte ich mich des öfteren.
Denn leider steht man hier wirklich in der Sackgasse. Man kann nicht einfach zur Definition von "MacheIrgendwasSinnvolles" springen, um den Programmfluss nachzuvollziehen. Das ist der Preis, den man für die Isolation bezahlt. Und der ist teuer!
Um also zu wissen, welches Objekt auf dieses Ereignis reagiert, muss man sich die Verdrahtung angucken. Gut, jetzt hat man das verantwortliche Objekt lokalisiert. Man geht in die Klasse und sucht sich die entsprechende Methode. Die Freude hält nicht lange an, denn in der Methode steht auf einmal der Aufruf "Say.Carefully(INeedEinenBestimmtenWert, this)". "OMG!"
Aber zum Glück ist es an der Stelle tatsächlich nicht wichtig, wo der Wert herkommt. Ich suche in der Klasse schnell die passende Receive-Methode und fahre mit der Programmverfolgung fort. In der Receive-Methode wird Business-Logik ausgeführt. Ein neuer Wert wird darin berechnet. (Um Missverständnissen vorzubeugen: Diese Werte sind natürlich auch Objekte. Es sind aber eben spezielle Value-Objekte und keine primitiven Datentypen! Ich bin auch dabei, mir abzugewöhnen, primitive Datentypen direkt zu transportieren, weil diese einfach nichts aussagen und zudem nicht erweiterbar sind.)
Weiter geht's: Am Ende dieser Methode steht dann also wieder "Say.Carefully(SendNeuerWert, this)".
Jetzt geht das Geeier wieder los. "Wer nimmt den Wert entgegen und was passiert damit?". Also wieder zurück und von "oben" drauf gucken, weil ja das Objekt für sich isoliert gewesen ist.
So geht das dann immer weiter. Besonders "lustig" wird es dann, wenn man wirklich einen Bug lokalisieren muss und die Zeit drängt. Da springt man hin und her ... hoch und runter. Wenn man Glück hat, findet man den Bug.

Eine gewisse Ordnung, und trotzdem Chaos
Alles hat im Grunde eine ordentliche Struktur, aber für mich ergibt sich ein Gefühl von Chaos, dass ich auf Dauer nicht zu bändigen vermag. Ursache dessen ist gerade diese Isolation der Objekte! Aus einem Objekt heraus kann ich nicht einfach auf den Programmfluss schließen. Und weil die Objekte äußerlich von nix abhängig sind (fehlende Konstruktorargumente), weiß ich ja nicht mal, ob diese Objekte überhaupt benötigt werden. Ist ein bestimmtes Objekt für einen bestimmten Vorgang unerlässlich? Vielleicht ja? Vielleicht nein? Welche Events von dem Objekt müssen verdrahtet werden, damit die Software funktioniert? Welche davon sind optional?
All das sagt das Objekt, von außen betrachtet, nicht aus.
Ich sehe mir bei einem Softwareprojekt nicht zuerst an, wie die Objekte verdrahtet sind. Der naive Ansatz, den ich immer verfolge, wenn ich wieder mal wissen will, wie etwas funktioniert, ist Folgender:

Im Grunde haben alle meine Anwendungen ein quasi statisches Hauptformular. Dieses nehme ich mir her und im Entwurfsfenster sehe ich es dann mit all seinen Buttons usw. Wenn ich wissen will, welche Funktion sich hinter einem Button verbirgt, klicke ich doppelt drauf und springe in die entsprechende Routine. Bei der MPT beginnt dann jenes Szenario, welches ich oben dargestellt hatte.
Und DAS macht keinen Spaß! Das Formular ist zwar dadurch wunderbar entkoppelt, aber für sich gesehen ist es absolut sinnlos, weil es nix über die Funktionalität der Software aussagt. Nun kann man sich darüber streiten, ob man so beginnen sollte, eine Software zu lesen. Aber, hey! Eine User-Story beginnt schließlich so: "Wenn ich auf den Button klicke, dann ...!" Und dann beginnt die Business-Logik zu fließen. Aber bei der MPT fließt erstmal nix, sondern man kommt gerade an dieser Stelle zum Stillstand, wo es interessant wird. In meinen früheren Projekten ist an der Stelle tatsächlich die Story geflossen. (Auch wenn da in der Anfängerphase(!) eine furchtbare Struktur zum Vorschein kam und die Domänen häufig gemischt waren, wirkte diese weit weniger chaotisch, als die MPT! Denn man konnte wenigstens hintereinander weg dem Programmfluss folgen! Und das ist absolut wichtig, wenn man Software verstehen will!)

Zurück zu den Wurzeln
Eine totale(!) Entkopplung, also Isolation von Objekten, mag ja auch ihre Vorteile haben. Aber mir hat sie in der Praxis das Verstehen meiner eigenen Software nur erschwert. Denn wie gesagt: Ich gucke in erster Linie nicht auf den "Schaltplan", also danach, wie die Objekte miteinander verknüpft sind. Man hat schließlich immer noch Quellcode vor sich, den man wie eine Geschichte lesen können soll.
Das geht aber NICHT, wenn man hier nur isolierte Klassen vor sich hat.
So konnte das nicht weiter gehen! Immer dieses "von Sackgasse zu Sackgasse" springen machte absolut keinen Spaß!
Was würde also dagegen sprechen, Objekten wieder die gewohnte Abhängigkeit zu verleihen? Sie also miteinander lose(!) zu koppeln? Nix würde dagegen sprechen! Die lose Kopplung würde einen aber wieder zu einem lesbaren Programm verhelfen! Und das ist mir wichtiger, als auf biegen und brechen meine Klassen total zu entkoppeln. Das nützt mir nix, wenn ich die Software am Ende nicht vernünftig lesen kann. Schlimmer noch, wenn sich der Lesefluss so anfühlt, als ob ich von einer "goto-Anweisung" zur nächsten "goto-Anweisung" springe. Man nennt das "Spaghetti-Code". Genauso fühlt sich aber auch das Nachvollziehen des MPT-Codes an!

Dependency Injection neu entdeckt: DIY-DI
Dependency Injection (DI) ist mir nicht unbekannt. Durch Misko Hevery, einem regelrechten DI Enthusiasten, hatte ich die Thematik so richtig vertieft. Warum hatte ich aber das Prinzip der DI nicht weiter verfolgt? Im Grunde hatte mich die manuelle Objekterzeugung abgeschreckt. Sowas kann dann schon mal unübersichtlich und komplex werden. Natürlich gibt es auch DI-Frameworks, welche einem die Arbeit abnehmen sollen.
Wenn ich aber eines hasse, dann sind es irgendwelche Frameworks, von denen man sich wieder abhängig macht. Frameworks, wo im Hintergrund irgendwas "Magisches" passiert, kann ich nicht leiden. Ich möchte in meinem Quellcode jede Kleinigkeit nachvollziehen können. Dass ich da beim .Net-Framework mit einem relativ hohen Abstraktionsgrad leben muss, ist mir da schon genug "Magie". Da brauche ich nicht noch irgendein mysteriöses Framework, wo ich nicht weiß, was da im Detail passiert.

Nun bin ich da aber vor kurzem bei Misko Heverys Blog auf einen Artikel gestoßen, der in mir wieder das Interesse für DI geweckt hat: Do it Yourself – Dependency Injection (DIY-DI). (Der eigentliche "Erfinder" dieser Idee ist aber Chad Parry und sein originaler Beitrag befindet sich dort.)
Als ich mir die Präsentation und das PDF dazu durchgelesen hatte, war mir schlagartig klar, dass ich meine Software zukünftig SO und nicht anders entwickeln möchte! Das ist genau das, was ich unter sauberen Quellcode verstehe.
DI ist im objektorientierten Bereich nun mal ein probates Mittel, um Ordnung in seine Struktur zu bekommen. Wenn ein Objekt auf andere Objekte angewiesen ist, damit es funktionieren kann, sollte es dies doch äußerlich kenntlich machen. Das gibt eine gewisse Transparenz und zugleich eine enorme Sicherheit für den Programmierer. Man sieht sofort, mit welchen Objekten das Zielobjekt unmittelbar interagiert und man weiß, dass das Objekt voll funktionsfähig ist, wenn es die geforderten Objekte injiziert bekommt. (Zumindest sollte das so sein. Stichwort: "Law of Demeter")

So habe ich auf Arbeit damit begonnen, mein derzeitiges Projekt nach DIY-DI zu migrieren. Und mir bereitet es erstmals wieder Freude, Funktionalität hinzuzufügen.
So begann meine Überlegung: "Das Business-Model benötigt kein User Interface, um zu funktionieren. Aber ein User Interface benötigt ein Business-Model, um zu funktionieren."
Das erscheint auch logisch. Spinnt man das noch eine Ebene weiter, so benötige ich als Benutzer das User Interface, um die Software bedienen zu können! Das ist Fakt!
Ich, als Mensch, bin ja auch nicht isoliert von meiner Umwelt. Die Umwelt ist zwar nicht abhängig von mir, aber ich von ihr. So brauche ich z.B. die Luft zum Atmen, usw.

Um zur Software zurück zu kommen, injizierte ich also einen "MainPresenter" in meine "MainForm". Und über den "MainPresenter" fordere ich nur die Dinge an, die für das User Interface von Belang sind. Der "MainPresenter" ist von diversen Service-Objekten abhängig, die er benötigt, um die Anforderungen vom User Interface erfüllen zu können.
So hatte ich schon einige Funktionalitäten von der MPT-Architektur umgestellt. Alles ist auf einmal so einfach nachvollziehbar geworden. Der Aufruf, "Gehe zu Definition" in Visual Studio, ist mir endlich wieder von Nutzen, weil ich mit dessen Hilfe wirklich hintereinander weg die komplette Aufrufhierarchie nachvollziehen kann.

Das soll es erstmal soweit gewesen sein. Die totale Entkopplung ist für mich einfach nicht mehr attraktiv.