Musterlösung: 01 - Die Anforderung-Logik Lücke
Aufgabe 1 - Erklären
Wie ist es dir ergangen mit der Aufgabe? Ich könnte es verstehen, wenn du dich damit schwer getan hast. Erstens überhaupt “ein Essay schreiben”, zweitens die Darstellung auch noch besonders einfach in der Sprache halten. Das waren schon zwei ordentliche Herausforderungen und ich würde mich wunder, wenn du weniger als 60 Minuten dafür gebrauchst hast.
Ich selbst habe für die folgende Musterlösung auch einige Anläufe nehmen müssen. Mit 60 Minuten war es dabei nicht getan. (Aber eine größere erwartete Bearbeitungsdauer wollte ich auch nicht in der Aufgabe nennen, um dich nicht gleich abzuschrecken.)
Wie so oft, ist das Ergebnis gerade wegen der begrenzten Zeit dann etwas länger geworden. Mit mehr Zeit wäre ja Gelegenheit, Redundanzen herauszukürzen oder knappere, elegantere Formulierungen zu finden.
Andererseits ist eine Erklärung, die sich an Laien richtet, quasi notwendig länglicher, weil weniger an Begriffe und Konzepten vorausgesetzt werden kann. Man muss dann mehr mit Beispielen/Analogien arbeiten, um das Abstrakte für sie zumindest halbwegs greifbar zu machen.
Wie dein Ergebnis am Ende aussieht, ist für den Zweck der Aufgabe jedoch zweitrangig. Schön, wenn es gut lesbarer Text herausgekommen ist. Wichtiger jedoch ist aus meiner Sicht das, was vor und während dem Schreiben passiert ist.
Für eine Erklärung musstest du erstmal selbst dein Verständnis der Begriffe “Entwurf” und “Modell” aufbauen und schärfen.
Und dann musstest du für die Anforderung ELI5 dein Verständnis nochmal transformieren in eine laienverständliche Form. Du musstest auswählen und ordnen und auch noch in Worte fassen, was dir “intuitiv klar ist”.
Um diesen Prozess ging es mir bei dieser Aufgabe. Ein Prozess, der beim Lernen im Allgemeinen und bei der Vermittlung von Programmierkenntnissen im Besonderen viel zu selten durchlaufen wird, finde ich. Denn auf diese Weise findet Lernen viel intensiver statt. Auf diese Weise erst eignest du dir den Stoff nämlich wirklich an. (Zumindest gilt das für Stoff, dessen Verständnis du nicht unmittelbar durch Tun überprüfen kannst.)
Nach dieser Vorrede hier nun erstmal mein Versuch:
Vom Nutzen der Modellierung für die Programmierung (ELI5)
Spielst du manchmal mit einer Puppe oder mit einem Spielzeugauto oder mit einer Dinosaurierfigur? Oder hast du womöglich sogar ein Puppenhaus oder einen Kaufladen oder Bauernhof, die du in deinem Zimmer aufbauen kannst zum Spielen?
Super, denn dann weißt du auch, was ein Modell ist. Eine Puppe ist ein Modell eines Menschen, ein Kaufladen ist ein Modell eines Supermarktes, weil Puppe und Kaufladen in vielen Dingen einem Menschen bzw. einem Supermarkt sehr ähnlich sind - aber sie sind eben viel kleiner und es fehlt ihnen auch in anderer Hinsicht so einiges.
Dennoch macht es Spaß, mit einer Puppe oder einem Kaufladen zu spielen, oder? Die haben ja auch Vorteile, z.B. dass sie dir zur Verfügung stehen, wenn du es willst. Oder ein Spielzeugauto ist viel billiger als ein echtes. Oder eine Dinosaurierfigur gibt es überhaupt, während echte Dinosaurier gar nicht mehr leben. Du könntest einen echten Dinosaurer nicht mal im Zoo besuchen, während du auf einem echten Bauernhof allerdings Urlaub mit deinen Eltern machen könntest.
Modelle gleichen dem, was sie darstellen, einerseits also sehr; wenn du damit spielst, ist es fast so, als würdest du z.B. wirklich ein Auto haben oder einen Bauernhof. Andererseits sind Modelle handlicher und günstiger. Dein Eltern können dir z.B. ein Spielzeugauto kaufen, aber für ein echtes müssten sie ganz lange sparen und du müsstest auch erstmal erwachsen werden, um es fahren zu dürfen.
Ein Modell ist also eine tolle Sache. Du kannst mit etwas spielen, was dir sonst nicht zugänglich wäre. Du kannst dir damit vorstellen, wie es wäre, z.B. einen echten Bauernhof zu haben, ohne deshalb gleich umzuziehen. Mit einer Puppe kannst du dir vorstellen, wie es wäre, ein Baby zu haben, ohne deshalb gleich wirklich ein eigenes Kind oder auch nur ein kleines Geschwister bekommen zu müssen. Modelle sind also total bequem und billig.
Wenn man nun programmiert, dann baut man im Grunde eine Art Maschine. Die besteht zu einem Teil aus einem Computer, zum anderen Teil besteht sie aus einem Rezept, das der Computer abarbeitet, um irgendetwas zu tun, z.B. als Roboter euren Rasen zu mähen oder beim Spiel auf deinem Smartphone eine Figur zu bewegen. Dieses Rezept heißt Programm oder Software.
Ein Auto ist auch eine Maschine. Für die hast du ein Modell, mit dem du dir vorstellen kannst, wie es wäre, ein richtiges Auto zu haben.
Genauso kann man als Programmierer für eine Software-Machine, die man bauen will, zunächst auch erstmal nur ein Modell herstellen; damit ist jedoch weniger der Computer gemeint, sondern vor allem das Programm, das er abarbeiten soll. Dieses Modell kann dann natürlich nicht das, was die echte Software-Maschine einmal tun soll - aber es sieht ihr eben doch ähnlich und ist viel billiger.
Mit so einem Programm-Modell hat es ein Programmierer einfacher, sich vorzustellen, wie es wäre, wenn er die spätere Software-Maschine wirklich hätte. Das ist total nützlich, weil es sehr, sehr schwierig und teuer ist, richtige Software-Maschinen zu bauen.
Einen Unterschied gibt es aber zwischen einem Spielzeugauto als Modell und einem Modell für eine Software. Das Spielzeugauto-Modell wird dem echten Auto nachempfunden; es gibt zuerst das echte Auto und dann das Modell. Beim Programmieren macht man es anders herum: Da baut man zuerst ein Modell oder auch zwei oder drei, um danach das echte Programm dem Modell nachzuempfinden.
Auf diese Weise kann sich ein Programmierer sparen, erst eine total komplizierte Software-Maschine zu bauen, um dann zu merken, dass sie doch nicht so geworden ist, wie er es gerne gehabt hätte. Besser ist es, er stellt erstmal nur ein Modell her und beschäftigt sich damit, um ein Gefühl dafür zu bekommen, wie es wäre, die echte Maschine zu haben. Wenn ihm das nicht gefällt, macht er einfach ein neues Modell. An so einem Modell kann er sich halt eine Menge Dinge überlegen, ohne viel Arbeit zu haben: Wie soll die Maschine aussehen? Wie soll sie bedient werden? Aus welchen Teilen soll die Maschine bestehen? Wie sollen die Teile zusammengesteckt werden, damit die Maschine leicht zu bauen ist?
Natürlich möchte ein Programmierer auch mega gern mit der echten Software-Maschine arbeiten, so wie du am liebsten in einem echten Kaufladen etwas kaufen oder verkaufen würdest. Wenn der Programmierer allerdings zu früh anfängt, seine Software-Maschine zu bauen, dann hat er sich vielleicht noch gar nicht alles ausgedacht, was dazu nötig ist. Dann wäre es später voll schwierig, die echte Maschine umzubauen, wenn ihm etwas Neues einfällt, was sie können soll oder wie sie etwas anstellt. Auch deshalb ist es hilfreich, dass der Programmierer sich erstmal nur mit einem Modell beschäftigt. Das könnte ja aus soetwas wie Knete oder Lego oder auch nur Papier sein, damit er ganz schnell neue Ideen ausprobieren kann.
Vielleicht hast du das ja auch schon gemacht: Statt ein Spielzeugauto zu kaufen, hast du eines aus Lego selbst gebaut. Und als es dir nicht mehr gefallen hat, hast du es umgemodelt oder eine Rakete aus den Legosteinen gebaut.
Genau das sollten Programmierer auch tun, wenn sie eine Software-Maschine bauen müssen. Sobald sie dann ein schönes Modell haben, können sie es ja “in echt” bauen. Auf diese Weise wird es auch viel leichter, die echte Maschine zu bauen. Die Programmierer müssen sich weniger ärgern, weil sie sich vor allem während des Modellbaus vertan haben, wenn es leicht ist, etwas zu korrigieren.
Modelle machen also das Programmieren leichter und günstiger.
Reflexion
Ich fand es schwierig, eine griffige Analogie für ELI5 zu finden. Mit dem Spielzeug bin ich dann zufrieden gewesen. Vorher hatte ich es u.a. mit Rezepten und einem Bauplan fürs Haus probiert. Das fühlte sich für das Sprachniveau dann letztlich aber nicht so passend an.
Natürlich ist auch dieser Text nicht wirklich für 5jährige geeignet. Wichtiger ist, dass er möglichst wenig Jargon enthält und versucht, den Begriff Modell und die Vorteile des Modellierens anschaulich zu machen. Was ist die Absicht dahinter, wenn man sich nicht negativen Konotationen und UML-Feuerwerk beirren lässt?
Diese Absicht kommt im Text hoffentlich gut rüber: Modelle erlauben es, dass man sich etwas vorstellen kann, ohne es real in den Händen zu halten. Man soll ohne großen Aufwand ein Gefühl für etwas bekommen.
Was an Echtheit fehlt, ersetzt die Imagination. Das ist Sinn und Zweck von Modellen, weil sie dadurch eben viel, viel einfacher herzustellen sind als “the real thing”. Und weil das viel, viel einfacher ist, kann man sich mehr Modelle leisten als “real things” - bzw. es sind Veränderungen an Modellen einfacher, schneller, günstiger als an “real things”.
Dass Modellen viele Eigenschaften des Echten fehlen, kann mithin keine Kritik sein. Es ist vielmehr ihr Vorteil und Hauptzweck. Es geht um Abstraktion. Statt Echtheit und “high fidelity” bekommt man etwas anderes. Das sind Handlichkeit, Vereinfachung, Flexibilität und Fokus. Die sind allesamt sehr nützlich, wenn man Anforderungen in Code umsetzen soll.
Code ist so komplex, dass man sich nicht einfach auf ihn stürzen kann, sobald man meint, die Anforderungen verstanden zu haben. Besser, du machst dich als Programmierer mit dem, was der Code tun soll und wie er strukturiert sein könnte, erstmal anhand von Modellen vertraut. Du kannst dir damit einige Tränen sparen!
Aufgabe 2 - Modellieren
Beim Modellieren ist alles erlaubt - nur kein Code. Das Modell soll einerseits halbwegs “lebensecht” sein, andererseits soll ihm Wesentliches fehlen, um den Aufwand klein zu halten und sich nicht Details zu verlieren. Skizze statt Gemälde, so könnte man vielleicht sagen.
Lösungsansatz
Ich weiß schon, dass das Programm über die Console bedient werden soll.
Außerdem ist klar, dass das Programm irgendwie die Besucherdaten über seine Laufzeit hinweg speichern muss. Der Auftraggeber will den Laptop zwischen den Parties ausschalten; ausschließlich im Hauptspeicher können die Gästedaten also nicht gehalten werden.
Auf der Festplatte könnten die Daten in einer Datenbank (z.B. RDBMS mit SQLite) gehalten werden oder sogar noch einfacher in einer Textdatei. Eine überschlägige Rechnung ergibt, dass ca. 15.000 Besucher über all die Jahre mit dem Programm begrüßt werden sollen. Das ist nicht zu viel, um sehr pauschal in einer Textdatei gespeichert zu werden. Eine 1,5MB Textdatei könnte bei Programmstart in den Hauptspeicher geladen werden. Sie könnte auch während der Programmlaufzeit ständig erweitert werden, damit keine Daten bei einem Programmabsturz verlorengehen. Wahrscheinlich könnte die Datei sogar für jeden Gast geladen werden, ohne dass eine Performanceeinbuße zu befürchten wäre. (Das kann ich mir als ein “Forschungsthema” für eine spike solution merken, falls später beim Modellieren eine Entscheidung davon abhängt.)
Das Speicherformat innerhalb einer Textdatei könnte für jeden Besucher dessen Namen und seine Besuchsanzahl festhalten.
Modell
Software hat viele Stakeholder. Deren Ansprüche an ein Modell können sehr unterschiedlich sein. Auftraggeber bzw. Anwender möchten mit einem Modell ein Gefühl dafür bekommen, wie sich der Umgang mit der Software später anfühlen wird. Für Entwickler hingegen ist es vor allem interessant, ein Gefühl dafür zu bekommen, wie die Software aufgebaut ist und ihr Verhalten erzeugt.
Es scheint mir deshalb angemessen, nicht nur ein Modell, sondern mindestens zwei zu bauen.
Oberfläche
Das Oberflächenmodell könnte im einfachsten Fall aus einem Text wie dem folgenden bestehen. Der ist zwar nicht interaktiv, aber er demonstriert das Verhalten:
1 $ helloworld.exe
2 Name: Janine
3 Hello, Janine!
4 Name: Peter
5 Welcome back, Peter!
6 Name:
7 Name: Mike
8 Hello my good friend, Mike!
9 CTRL-C
10 $
- Es ist zu sehen, dass es verschiedene Begrüßungen gibt.
- Das Layout von Abfragen, Eingaben und Ausgaben ist zu sehen.
- Ein Betrachter sieht, was passiert, wenn jemand keinen Namen eingibt.
- Es ist klar, wie das Programm zu beenden ist.
Das vermittelt ohne jeglichen Programmieraufwand schon einen guten Eindruck dafür, wie sich das Programm zur Laufzeit anfühlt.
In anderen Szenarien könnte die Codierung eines Prototyps für die Benutzerschnittstelle angezeigt sein. Das lohnt allerdings nur, wenn dessen Code um Größenordnungen weniger umfangreich ist, als der später wirklich benötigte. UI Mockup Werkzeuge aller Art haben hier auch ihren Zweck.
Ginge es um eine graphische Benutzeroberfläche, könnte ich z.B. mit Balsamiq Mockups ein visuelles Modell so herstellen:
Dazu hätte ein Auftraggeber sicherlich eine Meinung, könnte Feedback geben - und all das, ohne auch nur eine Zeile Code zu schreiben.
Aber um diese Art Modelle geht es mir ja in diesem Buch nicht. Die liegen auf der Hand.
Interna
Das Problem bei dieser Hausaufgabe ich das Modell für dich als Entwickler, d.h. ein Modell für die Interna des Programms. Wie kann Code modelliert werden, der am Ende ja nur aus Text in Dateien besteht?
Ich könnte mit Dateien beginnen. Warum nicht aufschreiben, auf welche Dateien der Code am Ende aufgeteilt werden sollte? Technisch reicht eine einzige, z.B. program.cs. Aber dann ist mit einem Modell nichts gewonnen.
Aber es gibt vielleicht “Themen”, deren Code in unterschiedlichen Dateien liegen könnte, z.B.
benutzerschnittstelle.csdatenspeicherung.csprogram.cs
Die Ausgabe auf der Console ist etwas ganz anderes, als die Datenspeicherung. Die Logik dafür zu trennen, macht bestimmt Sinn. Und der Rest passiert dann in program.cs, der Datei, die es in C# sowieso gibt, um die Funktion Main() zu beherbergen.
Die Liste der Dateien ist ein Modell. Jemand, der die Logik schreibt, wird dadurch schon etwas angeleitet. Etwas Entscheidendes fehlt allerdings noch: die Verbindungen zwischen diesen Codebausteinen. Die Logik, die auf die Dateien verteilt wird, muss ja irgendwie zur Laufzeit zusammenarbeiten.
Eine simple Beziehung könnte schon die Reihenfolge der Dateien in einer Liste ausdrücken. Dann könnte Ausführung laut obiger Liste z.B. mit Logik in benutzerschnittstelle.cs beginnen, danach geht es weiter bei datenspeicherung.cs und schließlich in program.cs. Aber das hört sich nicht plausibel an, oder? Näher läge es, bei program.cs zu beginnen.
Außerdem soll wahrscheinlich Logik nicht nur einmal in benutzerschnittstelle.cs ausgeführt werden, nachdem z.B. etwas in program.cs passiert ist. Deshalb ist eine Reihenfolgenbeziehung zu wenig. Die Verbindungen zwischen der Logik in den Dateien müssen flexibler sein.
Mit Text lassen sich Verbindungen zwischen Elementen allerdings schwer flexibel und verständlich beschreiben. Besser ist es, das Medium zu wechseln und visuell zu werden.
Die Linien drücken erstmal nur aus, dass es überhaupt Beziehungen zwischen den Dateien gibt. Allerdings kann jetzt mehrfach Logik aus derselben Datei im Spiel sein.
Aber worin bestehen diese Beziehungen? Wenn die Abarbeitung von Logik nicht einfach von einer Datei in die nächste fließt, sondern hin und her, dann geht das nur über Funktionsaufrufe. Die Verbindungslinien stehen also ganz pauschal dafür, dass Logik aus der einen Datei Logik in einer anderen mittels einer Funktion aufruft, die ihr von dort bekannt ist.
Wenn das Modell hilfreich sein soll, dann braucht es also noch etwas mehr Detail in Form von Funktionsaufrufen: Welche Datei ruft wann welche Funktion in welcher anderen auf? Das kann z.B. so aussehen:
Von einer Funktion ist klar, in welcher Datei sie sich befindet: Main() steckt konventionshalber als Eintrittspunkt für das Programm in program.cs. Welche anderen Funktionen es gibt und wie sie auf die Dateien verteilt sind, ist dann meine Sache. Das festzulegen, ist ein Teil der kreativen Leistung während des Entwurfs. Die Dateinamen geben ja aber schon einen Hinweis darauf, wie ich meine, dass die Verteilung aussehen könnte.
Was du in dem “Sequenzdiagramm” siehst, ist eine Möglichkeit der Verteilung. Ich behaupte nicht, dass es die beste ist. Um die Güte geht es hier nicht, sondern darum, wie ein Modell überhaupt aussehen könnte. Nur darüber solltest du dir erstmal Gedanken machen.
Reflexion
Erfüllt das, was ich produziert habe, die Anforderungen an ein Modell?
- Ein Modell soll deklarativ sein. Das bedeutet, es beschreibt nicht das Wie, sondern das Was. Vor allem enthält es keine Logik. Das ist der Fall. Ich habe nicht enthüllt, wie genau die Daten dargestellt, geladen, transformiert werden. Dass Daten geladen werden, ist zu sehen. Wie Daten geladen werden, welche Logik dafür nötig wäre oder sogar welches Datenformat benutzt würde, ist nicht zu sehen.
- Ein Modell soll eine Liste von Funktionen liefern, die in der Codierung mit Logik gefüllt werden. Das ist auch der Fall. Mindestens fünf Funktionen sollte der Code zu diesem Modell am Ende aufweisen. Sogar deren Signaturen sind definiert.
- Ein Modell soll die Beziehungen zwischen den Funktionen deutlich machen. Das ist auch der Fall. Da ist die Aggregationsbeziehung, die beschreibt, welche Funktionen in einer Datei zusammengefasst werden sollen.1 Da ist die Abhängigkeits- oder Nutzungsbeziehung zwischen den Funktionen: Welche Funktion ruft welche andere auf? Da ist die Teilenbeziehung: Welche Funktionen teilen sich Daten?2 Das ist die Sequenzbeziehung: Welche Funktion folgt welcher anderen in der Nutzung?
Ob die Mittel der Darstellung für das Modell die besten sind, ob das Modell ein Gutes ist, sei dahingestellt. Formal erfüllt das Obige jedoch die Kriterien für ein Modell. Und ich würde sogar sagen: Selbst dieses Modell ist besser als keines.
Die Qualität des Modells besteht darin, dass es mich zwingt, mir Gedanken zu machen. Ich muss mir die Software vorstellen, wenn auch nur sehr grob. Unter Kenntnis dessen, wie ein Computer funktioniert und welche Logik mir zur Verfügung steht, kann ich im Kopf simulieren, was passieren würde. Das kann ich vergleichen mit dem, was ich an Verständnis während der Anforderungsanalyse erarbeitet habe.
Wenn dir das schwer gefallen ist, verstehe ich das gut. Auch mir ist dieses Modell schwer gefallen. Allerdings lag das daran, dass ich versucht habe, alles zu vergessen, was ich dir eigentlich sagen möchte über Modellierung. Ich habe mich zurückgenommen, um näher an deiner Situation zu sein. Du liest das Buch ja wahrscheinlich, weil du noch keine größere Erfahrung mit dem Softwareentwurf hast. Auf welche Ideen kommst du da? Das habe ich mir versucht vorzustellen.
Deshalb auch nochmal: Es kommt hier vor allem darauf an, dass du dir ernsthaft Mühe gegeben hast. Hast du versucht, die Definition für ein Modell umzusetzen? Mehr ist nicht wichtig gewesen bei dieser Übung.
Denn wenn dein Modell der Definition folgt, dann bist du weiter, als ohne. Dann hast du mehr als einen Container für Logik - aka Funktion -, was es dir schon viel leichter macht, die Logik zu finden. Logik in kleine Happen teilen, damit sie verständlicher und testbarer wird, ist das Ziel.
Dass ein Modell vieles ungesagt lässt, dass es die Lösung unterspezifiziert, ist selbstverständlich. Das gehört zu seinem Zweck und ist kein Kritikpunkt. Dass du modellierst, ist mithin auch nicht im Widerspruch zu jedem Anspruch der Agilität. Nur, weil du gerade nicht in die Tasten haust, bedeutet das nicht, dass du nicht dabei bist, Wert für den Kunden herzustellen. Es kommt halt aufs richtige Maß an.