Freitag, 12. Juli 2013

Systemanalyse – vielleicht doch erst mal eine Architektur

Praktisches Beispiel 1.3

Artikelübersicht
1. Teil Reengineering - Die Analyse des Altcodes.
2. Teil Requirements Engineering – erst einmal die Anforderungen definieren.
3. Teil Systemanalyse – vielleicht doch erst mal eine Architektur.
4. Teil Reengineering - Neu, strukturiert und auf lange Sicht schneller.
5. Teil Schon Vorhandenes nutzen wäre schneller gewesen
6. Teil Reengineering – Am Ende gab es nur noch eine Schnittstelle.


Ein weiteres Architekturmeeting diskutiert grundlegende Probleme der Architektur. Auch hier ist die Anwesenheit mehrerer Teammitglieder Garant für mehr Qualität. Jeder hat seine eignen Ideen, sieht Fehler und kann somit zu besserem Code beitragen.

Software wird nicht nur durch ein vergessenes Requiremens Engineering belastet, sondern auch durch einen fehlenden Architekturentwurf. Über die Jahre der "Codepflege" kann dieser aber auch im Chaos der "Verbesserungen" verschwunden sein. Es gibt keine Architektur, die den Code in kleine beherrschbare Strukturen unterteilt, die Verantwortlichkeiten benennt, so dass man schon weiß, wohin der entsprechende Code gehört.

Da wir ein relativ kurzes Stück Code besprechen, werden wir keine Schichtenarchitektur diskutieren, keinen Komponentenentwurf, auch keine Verteilung oder Sicherheitsprobleme, obwohl das sicherlich spannend und im Blick auf den weiteren Code sinnvoll wäre. Für dieses kurze Stück Code konzentrieren wir uns einfach auf zwei wesentliche Entwurfsregeln der Architektur.
  1. So einfach wie möglich.
  2. Nach Verantwortlichkeiten entwerfen.

Fangen wir mit der zweiten Regel an. Welche Verantwortlichkeiten finden wir? Der BestellGenerator wird mit ganz bestimmten Startbedingungen gestartet. Es gibt Parameterfolgen bei der Parameterübergabe, die nicht möglich sind und zur Ausgabe der Benutzerhilfe (Usage) führen. Wir sollten also ein Objekt schaffen, welches diese Startbedingungen zusammenfasst und gleichzeitig dafür verantwortlich ist, ob diese Bedingungen gültig sind.

In der main-Funktion wird uns ein String-Array übergeben, welches die auszuwertenden Parameter enthält. Zum Parsen dieser Parameter schaffen wir einen Parameterparser. Er durchsucht die Strings nach gültigen Eingaben ("-calculation", "-forecast") oder Eingabefolgen ("-month ", "-customer "). Damit haben wir auch gleich die gültigen Parameter festgelegt. Er zählt die gefundenen gültigen Eingaben und setzt die Benutzerhilfe, wenn er ungültige Eingaben findet.

Das Objekt mit den Startbedingungen wird einem Objekt übergeben, welches für die Ausführung der eigentlichen Operation verantwortlich ist. Dieses führt je nach übergebenen Zustand (CALCULATION, FORCAST, USAGE) eine spezifische execute-Methode aus. Deshalb erschaffen wir drei Objekte, eines zur Berechnung der Bestellungen, eines zur Vorhersage und eines, um die Benutzerhilfe auszugeben. Alle drei Objekte leiten wir von einem zentralen Operationsobjekt ab, welches abstrakt ist.




Es wäre durchaus möglich, dass der Calculation-Algorithmus und der Forcast-Algorithmus ähnlicher Art sind. Das ist uns hier nicht bekannt, aber innerhalb des Operation-Objektes ließe sich durchaus eine Templatemethode aufnehmen. Damit wären wir bei der Diskussion von Entwurfsmustern (Design Pattern). Mit diesen Mustern hat sich innerhalb der Programmierergilde eine gemeinsame Sprache herausgebildet, wo mit einzelnen Wörtern ganze Konzepte gemeint sind. Das ist in jedem Fall eine elegante Form der Verständigung, wenn sie denn auch wirklich bekannt sind. In einem Team wäre es deswegen gut, abzuklären, was die Teammitglieder unter diesem Entwurfsmuster verstehen. Deswegen hier nochmal der Verweis auf die Wikipedia. (Template Method Pattern)

In unserem Beispiel wurde abgeklärt, ob das Factory-Entwurfsmuster im Team bekannt ist. Ein Teammitglied hat das Problemfeld erläutert, in dem das Entwurfsmuster Anwendung findet und ein kurzes Codebeispiel vorgeführt. ( Factory Method Pattern) Jetzt kann davon ausgegangen werden, dass alle Teammitglieder vom gleichen Wissensstand ausgehen und den folgenden Code verstehen und entwickeln können. Die Idee hinter dem Factory-Entwurfsmuster ist die Entkopplung des Parsers vom BestellGenerator. Später können andere Parserimplementierungen leicht eingefügt werden.

Zum Schluss hat noch einer in der Runde eine ganz "neue Erkenntnis". Warum eigentlich selber machen? Ja, meint ein anderer, ich habe von Apache Commons CLI library gehört. Es ist immer besser, eine Library zu verwenden, die durch eine Community geformt wurde. Man muss nicht alles selbst tun. Alle Selbstentwicklungen, die ich bisher gesehen habe, hatten nicht die Qualität dieser Produkte. Und in diesem Fall wäre es sogar wesentlich billiger. Ob das Produkt geeignet ist oder nicht, muss natürlich evaluiert werden. Die damit zusammenhängenden Fragen möchte ich aber erst im übernächsten Post dieser Reihe klären.

Im nächsten Post geht es dann um die Eigenentwicklung und warum ein durchdachtes, geplantes und gemeinsames Entwickeln schneller und billiger ist als Eigenbrötlerei.

vorheriger Post dieses Themas     folgender Post dieses Themas


Print Friendly Version of this page Print Get a PDF version of this webpage PDF

1 Kommentar:

  1. Danke für den interessanten Artikel. Vielleicht wäre der Entwurf noch besser, wenn man der OrderGenerator einen anderen Namen gibt, damit die UI-Aspekte stärker von dem logischen Teil getrennt sind. Ein OrderGenerator sollte keine parse-Methode haben, er sollte UI-agnostic sein. Ich würde auf Anhieb bei einer Klasse mit diesem Namen eine generateOrder()-Methode erwarten. Momentan ist der OrderGenerator aber eher der Einsprungspunkt der Anwendung.

    Weiterhin kommt die Frage waum das OperationType enum existiert wenn es gleichzeitig die Operation-Klassen gibt?

    AntwortenLöschen