Skip to main content

Die Evolution der Abstraktion

Seit einiger Zeit erlebt die modellgetriebene Entwicklung ein gesteigertes Interesse. Die häufig immer noch im Software Engineering verwendeten 3 GL (third generation language, auch high-level programming language), wie z.B. ANSI C scheinen der steigenden Komplexität zunehmend weniger gerecht zu werden.

Die Hoffnung, die Verstehbarkeit auf Basis von grafischen Repräsentanzen zu erhöhen, ist die Haupt-Triebfeder.

Dementsprechend werden fleißig Bilder gemalt und Systemanteile grafisch dargestellt. Und tatsächlich helfen die grafischen Repräsentanzen dabei die Systeme besser zu verstehen. Wird das einige Zeit betrieben kommt eine andere Problematik wie ein Bumerang zurück.

Wie wird die kontinuierlich ansteigende Anzahl der grafischen Repräsentanzen, die nun redundant zum Code existieren, gepflegt und konsistent zum Code gehalten? Der notwendige Arbeitsaufwand übersteigt die Kapazitäten im Alltag.

Dieser Artikel soll aufzeigen, dass modellgetriebenes Engineering weit mehr ist, als eine grafische Repräsentanz. Er soll auch aufzeigen, dass die reine Erstellung einer grafischen Repräsentanz in einer Sackgasse mündet. Sie erhöht die Verstehbarkeit auf Kosten von erhöhter Redundanz und damit erhöhtem Pflegeaufwand. Damit verbunden sinkt die Arbeits-Effizienz.

Nur wenn redundante Anteile durch Werkzeuge automatisiert angepasst, Änderungen einer Komponente gegenüber dem Gesamtsystem automatisch korreliert, Tests automatisiert und Code generiert… also wo immer möglich Abläufe und Arbeitsschritte automatisiert werden, kann sich modellgetriebene Entwicklung langfristig erfolgreich durchsetzen.

In wie weit ein Modell sehr viel mehr ist, als eine Ansammlung von grafischen Repräsentanzen möchte ich in diesem Embedded Software Engineering Report darstellen. 

Komplexität

Wachsende Komplexität ist die wesentliche Ursache, warum wir mit einem Vorgehen nicht mehr die gewünschten Ergebnisse erzielen. Um zu verstehen warum und wie neue Arbeitsweisen und Prinzipien dem begegnen und auf welche Weise sie wirken, ist es hilfreich zu verstehen, wie Komplexität entsteht und sich auswirkt. Aus diesem Grund möchte ich zum Einstieg die Komplexität etwas näher betrachten.

Glaubt man den aktuellen Theorien zum Thema Komplexität, dann liegt das Hauptproblem in der Wirkkette:
Hidden Links -> Emergenz -> Dysfunktion.

Das bedeutet, verborgene Abhängigkeiten führen bei Änderungen eines Gesichtspunktes des Systems zu sogenannten emergenten Zuständen in Bezug zu anderen Gesichtspunkten des Systems. Ein Zusammenhang beider Gesichtspunkte ist nicht offensichtlich und bildet einen Hidden Link. Emergente Zustände sind Zustände, die nicht erwartet werden und damit auch das Verhalten innerhalb dieser Zustände nicht definiert ist. Dieses kann wiederum zu Fehlverhalten (Dysfunktion) führen, was im schlimmsten Fall Schaden verursachen kann.

Gehen wir noch einen Schritt zurück. Wie entstehen denn überhaupt die sogenannten Hidden Links?

∨ mehr Text anzeigen

Ein Basis-Mechanismus, der seit Jahrzehnten im Engineering eingesetzt wird, um steigender Kompliziertheit zu begegnen ist ‚Teile & Herrsche‘. Im Engineering unter anderem auch in Form von ‚hierarchischer Dekomposition‘ angewandt. Bei jeder Teilung einer Einheit in zwei Teileinheiten ergeben sich potentiell neue Schnittstellen. Wie in der Abbildung Nr. 1 zu sehen ist wächst bei zunehmender Teilung die Anzahl der neuen Schnittstellen polynom zur Anzahl der einzelnen Elemente.

Die Anwendung von ‚Teile & Herrsche‘ verringert also die Kompliziertheit eines einzelnen Teils, erhöht aber gleichzeitig die Kompliziertheit der Interfaces zwischen den Teilen.

Bisher haben wir die Interfaces lediglich auf einer Ebene betrachtet und sprechen aus diesem Grund nur von Kompliziertheit. In der Realität haben wir dieses Beziehungsgeflecht jedoch nicht nur auf einer Ebene, sondern parallel auf mehreren Ebenen. Erschwerend kommt hinzu, dass die Grenzen zwischen zwei Komponenten, bezogen auf verschiedene Ebenen und/oder Sichtweisen, nicht unbedingt gleich verlaufen. Zum Beispiel entsprechen logische Komponenten nicht exakt den physikalischen Komponenten. Analog sehr gut zu sehen bei der Darstellung von U Bahnnetzen. Die grafische Darstellung des Fahrplans entspricht nur sehr bedingt dem realen Verlauf der U-Bahn, dient aber dem besseren Verständnis.

Betrachten wir exemplarisch das Software Engineering, dann haben wir es in der Regel mit mindestens folgenden Ebenen zu tun:

  • Zeit
  • Datenfluss
  • Logisches Verhalten
  • Prioritäten
  • Varianten
  • Versionen
  • Betriebsmodi

Aus Applikationssicht kommen in der Regel noch weitere Ebenen hinzu, z.B. in Form von überlagerten Kontrollflüssen, wie beispielsweise Not-Aus, Software-Update oder Service & Diagnose Modus.

Auf jeder Ebene ergeben sich Interfaces einzelner Gesichtspunkte zueinander und die wenigsten davon sind in heutigen Systemen dokumentiert. Das Wissen über diese Interfaces befindet sich in der Regel in den Köpfen der Entwickler. Haben wir unser System häufig genug in Komponenten zerteilt, und ziehen sich nun Abhängigkeiten über mehrere der obigen Ebenen kreuz und quer über Komponenten hinweg, dann sind wir bei komplexen Systemen angelangt. Dann stellt sich die Frage, wie sich die Änderung einer Zeile Code potentiell hinsichtlich Varianten, Versionen, Betriebsmodi, zeitlichen Gesichtspunkten… auf das Gesamtsystem auswirkt. In diesem Bewusstsein explodieren Testaufwände und doch bleibt das Gefühl, nicht ausreichend getestet zu haben. So spüren wir heute die Komplexität in vollem Umfang.

Häufig wird vergessen, dass nach jeder hierarchischen Dekomposition der Schritt der Aggregation (Zusammensetzen einzelner Komponenten zu einem Gesamtsystem) folgen muss. Spätestens an dieser Stelle müssen alle Schnittstellen und vor allem deren Auswirkungen im Gesamtsystem wieder homogen zueinander passen. Wird ein Zusammenhang übersehen ist das der Einstieg in die Wirkkette Hidden Links -> Emergenz -> Dysfunktion.

Um einem Gedankengang grundsätzlich vorzubeugen: ‚Teile & Herrsche‘ ist immer noch unverzichtbare
Grundlage zum Managen von Kompliziertheit und Komplexität. Aber für letzteres benötigen wir darüber hinaus
Mechanismen, um die steigende Komplexität der Interfaces wieder zu beherrschen. 

Unser Gehirn als Engpass

Die Neurobiologie besagt, dass unser Gehirn auf der bewussten Ebene ca. 7 +/- 2 Artefakte und/oder Beziehungen in einem Augenblick überblicken (Begreifen) kann. Verglichen mit der Anzahl an potentiellen Artefakten und Schnittstellen komplexer Systeme ist das nicht sehr viel. Stellen Sie sich vor, Sie haben gerade 7 Artefakte parat und deren Zusammenhänge logisch durchdacht, dann fällt Ihnen ein 8. Artefakt ein. Im selben Moment fällt eines der vorherigen Artefakte, wie bei einem Schieberegister, aus Ihrem Fokus heraus und das geschieht, ohne dass unser Bewusstsein uns darauf aufmerksam macht. Wir merken für gewöhnlich nicht, dass wir in diesem Moment gerade etwas vergessen. Stattdessen befinden wir uns in dem Irrglauben alles berücksichtigt zu haben. Gibt es nun zufällig einen logischen Zusammenhang zwischen dem 8. neuen Artefakt und dem gerade herausgefallenen, haben wir eine potentielle Situation für die Entstehung eines ‚Hidden Link‘.

Wenn wir nun bedenken, dass heutige komplexe Systeme tausende an Artefakten haben, die über deutlich mehr, als 7 Ebenen potentiell in Beziehung stehen können, ist es naheliegend, dass es ein Trugschluss ist, dass unser Gehirn in der Lage ist, die möglichen Auswirkungen von Änderungen vollständig zu durchdringen.

Abgesehen davon versagt unser Gedächtnis bereits, wenn es die möglichen Zusammenhänge einer begrenzten Auswahl an Artefakten aus dem Stegreif auflisten sollte. Und jetzt stellen Sie sich noch die Entwicklung eines komplexen Systems auf Basis von vielen Gehirnen vor, in denen keines der Gehirne das Gesamtsystem mit all seinen potentiellen Zusammenhängen kennt, sondern immer nur Anteile des Systems.

Wenn also ein einzelnes Gehirn (selbst, wenn es ein optimales Gedächtnis hätte) nicht mehr alle Zusammenhänge kennt, bleibt die spannende Frage: Welche anderen Gehirne des Teams soll es zu Rate ziehen, um mit Sicherheit alle Abhängigkeiten herauszufinden?

Noch eines zeigt die Neurobiologie. Wahrscheinlich wäre unser Unterbewusstsein in der Lage uns aus dem Dilemma zu helfen, denn unser Unterbewusstsein scheint einem optimalen Gedächtnis sehr nahe zu kommen. (Thema Alpha Mode, siehe auch ESER No. 26: Unser Gehirn als Werkzeug) Nur ist die Menschheit noch nicht in der Lage deterministisch mit dem Unterbewusstsein zu arbeiten, und so lange müssen wir andere Wege gehen, wenn wir komplexe Systeme entwickeln möchten, die sich am Ende deterministisch verhalten sollen.

Ausweg aus dem Dilemma

Um steigender Komplexität effizient zu begegnen haben sich folgende Maßnahmen als grundlegend hilfreich herausgestellt.

  1. Strukturierung und Elimination von Ebenen und Beziehungen auf Basis von Architektur-Design
  2. Einschränkung der Ausprägung von Schnittstellen auf Basis von Contract-Based-Design (auch DbC Design by Contract - Entwurf gemäß Vertrag)
  3. Strukturierte Speicherung von Link-Beziehungen zwischen System-Artefakten und darauf basierenden Traceability-Analysen
  4. Anwendung von Abstraktion auf Basis von Musterbildung (Abstraktion und Standardisierung von Lösungsansätzen, z.B: durch höhere Notationen, wie UML)

Die 1. Maßnahme beruht darauf, über geeignete Ausprägung der Schnittstellen das Beziehungsgeflecht einfach und verstehbar zu halten. Diesen Aspekt werden wir an dieser Stelle nicht weiter verfolgen, was nicht bedeuten soll, dass er nicht eine hilfreiche Maßnahme ist, um Komplexität zu beherrschen (Siehe auch ESER No. 31: Archtitektur & Design)

Die 2. Maßnahme Contract-Based-Design ist eine hervorragende Möglichkeit Ausprägungen von Schnittstellen einzuschränken und/oder die Basis, diese automatisiert zu prüfen. Obwohl erste Ansätze bereits 1985 in der Programmiersprache ‚Eiffel‘ durch Bertrand Meyer eingeführt wurden konnte sich CBD noch nicht breitflächig durchsetzen. Notationen, wie UML in Verbindung mit Stereotypen, bieten sehr gute Voraussetzungen zur Anwendung von Contract Based Design und damit die Basis für eine weitere Verbreitung. Auch diesen Ansatz werden wir an dieser Stelle nicht direkt verfolgen, aber an der einen oder anderen Stelle tangieren.

Auch für die 3. Maßnahme, Analysen auf Basis von Traceability, liefert die modellgetriebene Entwicklung auf Basis von 4 GL Notationen gute Grundlagen. Z.B. kennt die Notation UML / SysML Linkbeziehungen zwischen Notationselementen. Mit Linkbeziehungen können Zusammenhänge deklariert und auf dieser Basis in Folge aussagekräftige Traceability-Analysen erzeugt werden. Um Linkbeziehungen speichern zu können benötigen die zu verlinkenden Elemente eineindeutige Identifier (UUID’s). 3 GL Notationen, wie C oder C++, haben keinerlei Metastrukturelemente mit denen diese abgebildet werden können. Auch die Editoren auf deren Basis diese Notationen angewandt werden liefern hier keine Lösung. Wie also kann z.B. eine Anforderung explizit zu einer C-Anweisung verlinkt werden? (Achtung: Die häufig anzutreffende Praxis des Verlinkens zu Commit Statements eines Config Management Systems oder anderen dynamischen Artefakten ist an dieser Stelle keine wirkliche Lösung, aber das ist ein ganz anderes Thema, welches an dieser Stelle den Rahmen sprengen würde) Auch diese mögliche Maßnahme wird nicht Bestandteil der folgenden Betrachtungen sein.

Folgend werden wir uns im Wesentlichen mit der 4. Maßnahme: Abstraktion durch Musterbildung und Metastruktur beschäftigen.

Komplexen Systemen lässt sich nicht mit simplen Methoden begegnen

Das Gesetz der erforderlichen Varietät (engl. Law of Requisite Variety) gehört zu den zentralen Erkenntnissen der Kybernetik. Es ist auch als Ashby’s Law mit der folgenden Aussage bekannt: ‚Die Varietät des Steuerungssystems muss mindestens ebenso groß sein, wie die Varietät der auftretenden Störungen, damit es die Steuerung ausführen kann.‘ Sinngemäß formuliert: ‚Eine Lösung ist immer ähnlich komplex, wie das Problem an sich‘.

Dieses impliziert: Wenn mit modellgetriebener Entwicklung komplexere Systeme entwickelt werden können ist
auch die Methode an sich komplexer. Das wiederum bedeutet, dass Kosten für Werkzeuge, Zeit für
Einarbeitung etc. vergleichsweise größer sind, als beim Vorgehen der strukturierten Programmierung auf Basis
von 3 GL Notationen. Das zeigt ein grober Vergleich der Anschaffungskosten einer entsprechenden
Entwicklungsumgebung:

  • Unstrukturierte Programmierung - Assembler Kosten einige 100€,
  • Strukturierte, prozedurale Programmierung - Compiler Kosten einige 1.000 €
  • Modellgetriebene Entwicklung - Modellierungs-Umgebungen Kosten an die 10.000, -€

In Bezug zum zeitlichen Aufwand für die Einarbeitung sehen die Verhältnisse ähnlich aus. Es kommt noch ein weiterer Effekt hinzu. Um komplexe Strukturen zu managen, steigt auch die Anzahl an Arbeitsschritten. Die Koordination eines Teams im Vergleich zu Einzelpersonen bedarf aufwändigerer Prozesse.

Der Nutzen von Prozessoptimierungen liegt in der Definition, Vereinheitlichung und Homogenisierung von Arbeitsschritten, die in ihrer Summe aber immer steigen. Kurz gesagt ich kenne nahezu keine Situation, in der die zu tätigenden Arbeitsschritte bei der Einführung von Maßnahmen, die steigender Komplexität begegnen, abgenommen hätten. Um so wichtiger ist es, diese Arbeitsschritte wo immer möglich zu automatisieren, sonst ist das Scheitern jeglicher Maßnahmen vorprogrammiert.

Unser Problem ist nicht Mangel an Arbeit, unser Problem ist Mangel an Vorhersagbarkeit auf Grund von Mangel an Struktur und Verstehbarkeit. Wird die Verstehbarkeit auf Kosten von mehr Arbeit erhöht ist das kein Ausweg. Häufig wird jedoch genau dieser erste Schritt als Einstieg in die Modellierung praktiziert.

MERKE: Wenn neue Methoden eingeführt werden, müssen hinzugekommene Arbeitsschritte wo immer möglich automatisiert werden.

Eine mögliche Lösung für schlechte Verstehbarkeit ist die abstrakte Darstellung von Sichtweisen auf das System. In diesem Sinn wird die UML häufig eingesetzt, um Sichtweisen auf Systeme grafisch darzustellen. Das erhöht ohne Frage die Verstehbarkeit und damit die Prognostizierbarkeit von Systemen und begegnet damit der Komplexität. Aber es wird mit Erhöhung der Redundanz bezahlt. Was das bedeutet schauen wir uns einmal an:

Verstehbarkeit und Redundanz

Die abstrakte Darstellung eines Systems ist eine der effizientesten Möglichkeiten die Verstehbarkeit zu erhöhen. Aber wie heißt es so schön, nichts auf der Welt ist kostenlos. Und auch in diesem Fall muss die Verbesserung der Verstehbarkeit mit der Erhöhung von Redundanz bezahlt werden.

Abstraktion zur Verbesserung der Verstehbarkeit wird seit Jahrzehnten erfolgreich eingesetzt, z.B. während einer Besprechung durch die Skizzierung einer grafischen Darstellung auf einem Flipchart. Oder durch die Erstellung einer parallelen Dokumentation von C-Code. Bei letzterem lässt sich die Grund-Problematik gut aufzeigen. In meinen Vorträgen stelle ich der Audienz gerne folgende Fragen über den Zustand ihrer Dokumentation:

Welche der folgenden Aussagen trifft am besten den Zustand Ihrer Dokumentation?

  1. Wir haben eine gute Dokumentation, die sehr hilfreich ist.
  2. Unsere Dokumentation ist sehr schlecht bis nicht existent.
  3. Unsere Dokumentation ist garnicht so schlecht. Das Problem ist die Inkonsistenz zum Code.

95% der Befragten behaupten in der Regel, dass die 3. Aussage am zutreffendsten ist. Was schließen wir daraus? Nicht die Dokumentation an sich ist das Problem, sondern der Aufwand für Wartung und Pflege, um sie konsistent zum Source-Code (zur Realität) zu halten.

Und jetzt stelle ich eine Behauptung auf die Sie evtl. verblüffen wird: ‚Durch die Anwendung der UML erhöhen Sie obiges Problem.‘

Warum?

∨ mehr Text anzeigen

Dazu müssen wir den Charakter von Notationen genauer betrachten.

  • 3 GL Notationen haben eine hohe Informationsdichte. Diese bewirkt eine schlechte Verstehbarkeit, jedoch im Gegenzug geringe Redundanz.
  • 4 GL Notationen haben eine geringere Informationsdichte. Diese bewirkt eine bessere Verstehbarkeit, die jedoch durch höhere Redundanz erkauft wurde.

In der Abbildung Nr. 2 sind drei unterschiedliche Sichtweisen (statisches Design, logisches Verhalten, zeitliches Verhalten) auf ein System auf Basis der UML dargestellt. Die separaten grafischen Darstellungen sind für das Verständnis des Systems äußerst hilfreich. In der Abbildung sehen wir z.B. dass das ‚EV_LONGPRESS‘ in allen drei Repräsentanzen enthalten ist. Ändert sich irgendetwas in Bezug zu diesem Event muss es potentiell in allen drei Darstellungen geändert werden. Ansonsten werden die Darstellungen zueinander inkongruent (fehlerhaft).

Die jeweiligen grafischen Repräsentanzen in Form eines UML-Diagramms stellen einen Gesichtspunkt des Systems anschaulich da,  vernachlässigen jedoch andere Gesichtspunkte. Diese müssen auf Basis anderer Diagramme spezifiziert werden, um das System vollständig zu spezifizieren. Wir können also davon ausgehen, dass die Erhöhung der Verstehbarkeit grundsätzlich mit der Erhöhung von Redundanz einhergeht und diese Redundanz muss gepflegt werden.

Blicken wir noch einmal auf die Frage bzgl. der Dokumentation. Seit Beginn Code zu abstrahieren (Dokumentieren), ist der Aufwand für die zusätzliche Pflege das Hauptproblem. Erstellen wir nun fleißig weiter Darstellungen, helfen diese zwar augenscheinlich das System zu verstehen, aber nur für kurze Zeit. Sie werden, wie in unserer Dokumentation zuvor, mit der Zeit veraltet und inkongruent und verlieren damit schleichend
wieder ihre Aussagekraft.

Außer: Die Pflege der redundanten Anteile wird automatisch durch ein Werkzeug durchgeführt. Die Techniken hierfür sind: zentrales Repository, Reverse-Engineering, Code-Generation, Roundtrip- Engineering und Co.

MERKE: Ohne werkzeuggestützte Automatismen, um Modellelemente und Code untereinander konsistent zu halten, ist es nur eine Frage der Zeit, wann die Modelle inkongruent werden. Versuche, dieses händisch zu tun, sind bisher immer gescheitert.

Langsam nähern wir uns der Vorstellung eines Modells und ich möchte noch einmal den Gedanken aufgreifen, dass eine Ansammlung von grafischen Repräsentanzen (Bildchen) noch lange KEIN Modell sind. Ein Modell unterscheidet sich von diesen dadurch, dass es korrelieren und interpretieren kann. Es kennt Gesetzmäßigkeiten und Metastrukturen (wie beispielsweise die UML oder SysML) und auf dieser Basis kann es werkzeuggestützt Artefakte gegeneinander korrelieren. Oder es kann die Zukunft vorweg nehmen, in dem es z.B. logische Spezifikationen simuliert. Was also ist ein Modell genau? 

Was ist ein Modell?

Die Automatisierbarkeit von Arbeitsschritten ist eine der mächtigsten Voraussetzungen von modellgetriebenem Engineering. Die grafische Repräsentanz von komplexen Zusammenhängen ist hilfreich, wird aber häufig überbewertet. Die für deren Pflege notwendigen Arbeitsschritte hingegen werden fast immer unterbewertet.

Hinzu kommt, dass eine grafische Repräsentanz immer nur einen Ausschnitt eines komplexen Systems verdeutlichen kann und nur in diesem begrenzten Bezug die Verstehbarkeit erhöht. Darüber hinaus gibt es unendlich viele weitere Aspekte bezüglich der Aggregation aller Repräsentanzen zum Gesamt-System, die in den einzelnen Repräsentanzen NICHT verdeutlicht werden. All diese Repräsentanzen haben gegenseitige Abhängigkeiten und müssen am Ende ein homogenes Gesamtsystem bilden. Unsere Gehirne werden schwerlich in der Lage sein all diese Aspekte und gegenseitigen Abhängigkeiten zu korrelieren. Hier setzt modellgetriebenes Engineering an.

Ich möchte es an einem Beispiel exemplarisch darstellen. Stellen wir uns vor es gäbe ein Modellelement ‚Dreieck’. Dieses wird in Form eines Musters mit Regeln und Gesetzmäßigkeiten auf Basis einer Metastruktur abgebildet. Diese Metastruktur würde nicht nur Seitenlängen und Winkel kennen, sondern auch Gesetzmäßigkeiten, wie rechtwinkliges oder gleichschenkliges Dreieck. Die Metastruktur würde auch so etwas, wie den ‚Satz des Pythagoras‘ kennen. Und natürlich gäbe es ein Werkzeug, das diese Metastruktur versteht und anwenden kann. Die grafische Repräsentanz ist nun nur eine von verschiedenen Darstellungen. Eine weitere kann ein Datensatz sein, in dem die Seitenlängen, die Winkel und weitere Informationen, z.B ob es sich um ein gleichseitiges, rechtwinkliges gleichschenkliges Dreieck handelt, abgelegt sind.

∨ mehr Text anzeigen

Legen wir z.B. zwei Seitenlängen und einen Winkel auf Basis eines Editors in einem Datensatz ab, kann das Modell mit Hilfe geeigneter Werkzeuge die zwei anderen Winkel, die Länge der 3. Seite und eventuell die Information, dass es sich um ein rechtwinkliges Dreieck handelt aus den gegebenen Informationen automatisiert ableiten. Das geht nur, wenn auf Basis des definierten Musters ‚Dreieck‘ Gesetzmäßigkeiten bekannt sind, die automatisiert angewandt werden können. Voraussetzung ist eine mächtige Metastruktur, die dieses abbilden kann. Das Werkzeug erlaubt die Eingabe der Daten in Form der grafischen Repräsentanz und ermittelt automatisch die technischen Artefakte. Aber es ermöglicht auch die Eingabe der technischen Artefakte und kann daraus die grafische Repräsentanz automatisch erzeugen. Beide Wege sind möglich.

So weit ergibt sich die Hilfestellung in der Transformation von verschiedenen Repräsentanzen. Aber es geht nocheinen wesentlichen Schritt weiter.

Ändern wir nun den Winkel A wird aus dem rechtwinkligen Dreieck evtl. ein gleichseitiges Dreieck. Sollte definiert sein, dass es sich in dieser speziellen Instanz eines Dreiecks um ein rechtwinkliges Dreieck handelt, kann das Modell die Daten gegeneinander korrelieren und uns eine Warnung generieren, dass nun Daten (evtl. Spezifikation und Implementation) in Konflikt stehen. Hier streifen wir bereits einen Aspekt des CBD (Contract Based Design).

Wir sehen also, ein Modell geht weit über die grafische Repräsentanz hinaus. Letztere ist nur ein möglicher Aspekt der Sichtweise. Die automatisierte Korrelation von Artefakten und deren Gesetzmäßigkeiten ist weitaus mächtiger, wird jedoch häufig unterschätzt und selten genutzt.

MERKE: Automatisierte Korrelation von Daten auf Basis von Metastrukturen ist einer der Hauptvorteile von modellgetriebener Entwicklung, um komplexe Systeme bei Änderungen kongruent zu halten. (Siehe auch Contract Based Design)

Die praktische Umsetzung

‚Hidden Links‘ und Include Beziehungen

Höhere Programmiersprachen kennen zur Deklaration und Verwendung von Variablen (Schnittstellen) zwischen Modulen so genannte Include Beziehungen der Header Files, in denen die Variablen definiert sind.

Wie wir gesehen haben ergeben sich in komplexen Systemen komplexe Beziehungen und die entsprechend korrekte Einbindung der Deklarationen erscheint vielen Entwicklern mühselig. Häufige Linker Fehlermeldungen immer wieder zu korrigieren erscheint lästig. Aus diesen Umständen resultiert eine häufig anzutreffende Praxis des globalen Include. In jedem Modul werden alle Deklarationen pauschal eingebunden (Siehe Abbildung Nr. 4). Somit ist es möglich aus jedem Modul zu jedem anderen Modul eine Schnittstelle auszuprägen. Abgesehen davon, dass die Anwendung von Include Beziehungen so niemals gedacht waren ebnet diese häufig anzutreffende Praxis wiederum die Basis für ein unstrukturiertes Wachstum an Beziehungen (Implizite Steigerung der Komplexität). Der ideale Nährboden für Hidden Links. 

Die auf zwei Dimensionen begrenzte Darstellung von 3 GL Notationen macht dieses Beziehungsgeflecht nicht explizit. Es existiert sozusagen unter Wasser. Statische Analysen können dieses Geflecht analysieren und nicht selten kommen Beziehungsgeflechte wie in Abbildung Nr. 5 dargestellt dabei heraus.

Architektur-Muster, wie beispielsweise das Schichten-Modell haben zum Ziel die Ausprägung von Interfaces nur im Kontext einer festgelegten Struktur zu ermöglichen. In Abbildung Nr. 6 ist solch eine Struktur zu sehen. Ein Zugriff von der obersten Ebene direkt auf die unterste Ebene wäre verboten, da es Potential für Hidden Links bietet.

Die grafische Darstellung derartiger Architekturen mit der Definition von Beziehungen, aus der dann eine entsprechende Include Struktur automatisch generiert wird hat folgende Vorteile:

  • Es definiert eine Beziehungs-Struktur
  • Es stellt diese Struktur grafisch dar (Bessere Verstehbarkeit)
  • Es generiert die sich daraus ergebende Include Struktur automatisch
  • Es beugt dadurch Hidden Links vor

Dabei ist in der Praxis ein Schritt sehr wichtig, die automatische Generierung der korrekten Include Struktur. Sie ist Voraussetzung, dass der Entwickler sich nicht mit Linker-Fehlern herumschlagen muss. Sollte doch ein Linker-Fehler in diesem Bezug entstehen entspricht die Beziehung nicht der definierten Architektur, ist also im Sinn der Struktur nicht erlaubt und darf so nicht ausgeprägt werden. Aus der parallel existierenden Grafik kann der Entwickler schnell sehen, wie er seine Beziehung ausprägen muss, um der definierten Struktur gerecht zu werden.

‚Hidden Links‘: Casting versus Ports

Stellen Sie sich vor ein Software Entwickler möchte in einem neuen System alte betriebsbewährte Software-Module wieder verwenden. Aber die Architektur im neuen System hat sich geändert und damit auch die Architektur der Schnittstellen. Eine häufig durchgeführte Praxis dieses Problem zu lösen sehen Sie in Analogie zur Hardware dargestellt in Abbildung Nr. 7.

Der Software Entwickler hat gelernt, es müssen sich lediglich an einem Punkt die Metalle der beiden Stecker berühren, dann funktioniert das Interface. Und was aus Hardware-Sicht stark nach ‚Bastelei’ aussieht ist aus der Sicht von Software Design absolut legitim und fachlich korrekt. Warum? Software kennt keine Physik. An dem Interface wird nichts korrodieren, es wird niemand daran ziehen. Also wird diese Art der Verbindung aus Sicht des Software Engineerings bis in alle Ewigkeit korrekt seinen Dienst verrichten. Die Software-Entwickler unter den Lesern werden sich evtl. fragen, was mit diesem Type Interface konkret gemeint ist. Ich spreche von C-Casting, eine häufig anzutreffende Praxis (Auszugsweise aus einem C-Lehrbuch, dargestellt in Abbildung Nr. 8).

Also dieses Interface wird bis in alle Ewigkeit korrekt seinen Dienst verrichten? Ist das wirklich so? Was passiert, wenn sich auf
einer der Seiten des Interfaces etwas ändert, z.B. der darzustellende Wertebereich? Hier liegt großes Potential für Hidden Links, die bereits zum Absturz von Raketen, Fehlsteuerung von Bahnsignalen etc. also Dysfunktion im klassischen Sinn, geführt haben.

Abgesehen davon, dass Casting möglichst nicht angewandt werden sollte bietet die UML eine andere Form von Schnittstellen, z.B. ‚Ports’. Auf Basis von Ports können Schnittstellen zum Einen flexibler, zum Anderen aber auch strukturierter implementiert werden. In Analogie könnte man einen UML-Port mit einem Steckverbinder vergleichen. Dieser hat u.A. einen Verpolschutz. Das stellt sicher, dass Leitungen nicht vertauscht werden können und sichert damit ein effizientes und sicheres an- und abstecken der Verbindung.

In diesem Sinn können Ports mit Stereotypen erweitert werden, in denen Artefakte des Interfaces wie folgt definiert sind.

  • Eineindeutige ID
  • Name
  • Beschreibung
  • Einheit physikalisch (km/h, kg, dm hPa …)
  • Genauigkeit physikalisch (- 0,1 km/h)
  • Einheit digital (Integer, Float, Double …)
  • Genauigkeit digital (Digital - z.B. Abtastrate, Bitauflösung, Reaktionszeit …)
  • Gültigkeitsbereich (Min. Max. Wertebereich, Negative-, Natürliche-, Rationale-Zahlen, Anzahl Dezimalstellen … )
  • Erwartete Reaktion, wenn Gültigkeitsbereich verlassen wird (Errorhandler Call mit Fehlernummer und Interface ID, Inhalt FFFF …)
  • Getter Setter Methoden

Werden nun zwei Module auf Basis eines Ports miteinander verbunden, dann kann ein Modell Check alle obigen Artefakte automatisiert checken und bei Verletzungen Warnungen ausgeben. Z.B. wenn km/h auf mph treffen. (Auch an dieser Stelle streifen wir wieder das Thema Contract Based Design)

Abstraktion

Greifen wir das Thema Abstraktion noch einmal praktisch auf. Werfen Sie doch bitte einmal einen Blick auf die Abbildung Nr. 10. Wieviel Streichhölzer sind dort abgebildet? Erscheint Ihnen das Zählen mühselig, dann werfen Sie doch einfach einen Blick auf die Abbildung Nr. 11 auf der folgenden Seite.

Kommen Sie auf 38 Streichhölzer, dann sollten Sie noch einmal genauer hinsehen. Eines der Pakete beinhaltet 6 Streichhölzer.

Was erkennen wir an diesem kleinen Experiment? Abstraktion erhöht die Verstehbarkeit erheblich. Aber: Abstraktion basiert auf Mustern und nur wenn diese Muster sinngemäß angewandt werden bieten sie den anvisierten Nutzen. In der Praxis erlebe ich die Anwendung der UML selten in einer ausreichend präzisen Form. Als Begründung wird dann immer angeführt, dass zu diesem Zeitpunkt noch nicht so sehr ins Detail gegangen werden soll. Hier wird ganz eindeutig Präzision mit Detaillierung verwechselt. Die UML kann sehr präzise angewandt werden, ohne dabei detailliert zu sein.

Unpräzise Anwendung von Notationen, um Modelle zu definieren, birgt viele Nachteile in sich. Folgend sind nur die mächtigsten aufgeführt:

  • Das Modell ist nicht simulationsfähig
  • Contract Based Design kann nicht angewandt werden
  • Es bietet Potential für Fehlinterpretation

Obige Punkte schränken den Nutzen von modellgetriebener Entwicklung extrem ein. Häufig stehen Aufwand zu Nutzen in einem negativen Verhältnis und die anfangs mit großer Akribie erstellten Modelle verstauben nach einigen Jahren in irgendwelchen Ordnern. Das ist schade, da enormes Potential nicht genutzt wird und es liegt nicht an der Methode an sich, sondern an einer unprofessionellen Anwendung der Methode.

MERKE: Die Verwechslung von Präzision und Detaillierung ist einer der Hauptgründe für nicht erfolgreiche Anwendung von modellgetriebenem Engineering.

Einem praxisorientierten Vorgehen eine ausreichende Präzision zu gewährleisten ist die sofortige und immerwährende Simulationsfähigkeit von Modellenn. Eine Simulation erfordert grundsätzlich einen hohen Grad an Interpretation des Modells. Interpretationsspielräume (Fehlende Präzision) werden sofort aufgedeckt.

Abstraktion in der Praxis

An dieser Stelle seien nur zwei Beispiele aufgeführt, wie durch 4 GL UML Notationselemente dutzende Zeilen an 3GL Code abgebildet werden können. Immer im Hinblick auf Präzision, nicht im Hinblick auf detailliert, im Sinn von den Fokus auf das Wesentliche zu lenken und sich nicht in Details zu verlieren.

Sehr schön ersichtlich, in Abbildung Nr. 13. Es kommt darauf an darzustellen, dass der Übergang von ‚Active‘ zu ‚Idle' nach 100 ms geschieht. Im korrespondierenden Code sind sehr viel mehr Details enthalten, die wesentliche Aussage ist nicht explizit zu erkennen.

Trotzdem ist die Zustandsmaschine bereits in diesem Detaillierungsgrad simulierbar und die Logik auf hohem Abstraktions-Niveau zu einer frühen Phase verifizierbar. Der CCode hingegen müsste noch mit vielen weiteren Details vervollständig werden bevor er kompilier- und ausführbar wäre.

Resümee & Aussicht

Man könnte die Entwicklung des Engineerings hinter der Modellierung auch als Evolution der Abstraktion bezeichnen. Angefangen von grafischen Darstellungen, um in Besprechungen die Verstehbarkeit von Code zu erhöhen (z.B. Flipchart - Zeichnungen, keine Wiederverwendbarkeit, Änderbarkeit) haben sich bis heute auf Basis von Metastrukturen und Taxonomie 4 GL Notationen, wie die UML entwickelt. Der Umgang mit ihnen wird wiederum durch mächtige Werkzeuge unterstützt. Der heutige Stand des Abstrahierens hat einen hohen Grad an Wiederverwendbarkeit, Änderbarkeit etc. erreicht. Es geht weit über die Abstraktion in Form von grafischen Repräsentanzen hinaus.

Häufig werden jedoch nur letztere eingesetzt. Das führt in Folge zwar dazu, dass einzelne Aspekte des Systems besser verstehbar sind und deren Komplexität besser beherrscht wird, aber Engineering wird nicht effizienter, weil der Aufwand die grafischen Repräsentanzen aktuell zu halten den Nutzen überschreitet.

Nur wenn:

  • Modelle simulationsfähig sind und damit die Verifikation von Systemen und Änderungen an komplexen Systemen in früheren Phasen möglich sind,
  • Systemartefakte systematisch auf Basis von Metastrukturen und Gesetzmäßigkeiten in Repositories gespeichert sind und gegeneinander automatisiert korreliert werden können,
  • die Aggregation von grafischen Repräsentanzen automatisiert korreliert werden können,
  • Änderungen über redundante Artefakte automatisiert ausgeprägt werden können,
  • grafische Repräsentanzen automatisch in Code transformiert und umgekehrt Änderungen im Code automatisch auf Modellebene transformiert werden können,

dann erhöht modellgetriebene Entwicklung nicht nur die Verstehbarkeit von komplexen Systemen, sondern auch die Effizienz in der Entwicklung. Dann können Modelle bei Änderungen die Zukunft der Realität vorwegnehmen. Das führt zu robusteren Systemen und reduziert das Auftreten von Fehlern in späten Phasen der Entwicklung, ein enormer Kosten- und Effizienzvorteil.

Nützlich zu kennen:

Emergenz: (lat. emergere„Auftauchen“, „Herauskommen“,„Emporsteigen“)
Herausbildung vonneuen (zuvor nicht definierten) Eigenschaften oder Strukturen eines Systems.

Dysfunktion:
Griechisch-lateinische Bezeichnung für Funktionsstörung.Polynom-Funktion: Ganzrationale Funktion in der Mathematik, eineSumme von Potenzfunktionen mit natürlichen Exponenten.

Aggregation:
Zusammenfassung mehrerer Einzelgrößen zu einer Gesamtgröße.

Präzise: (Lat. praecisus „abgeschnitten“, „kurz gefasst“)
genau, absolut, kurz.

Detailliert:
Im Sinn von ausführlich mit vielen Einzelheiten - (‚sich in Details verlieren‘ das wesentliche aus den Augen Verlieren)

DbC (Design by Contract):
Entwurf gemäß Vertrag ist ein Konzept mit dem Ziel des reibungslosen Zusammenspiels einzelner Programmmodule durch die Definition formaler Verträge zur Verwendung von Schnittstellen, die über deren statische Definition hinausgehen.

In diesem Sinn ist die modellgetriebene Entwicklung nicht nur ein hilfreiches, sondern zunehmend ein notwendiges Vorgehen, um steigender Komplexität zu begegnen.

Der Einstieg kann genau der Evolution entlang erfolgen, von der reinen Dokumentation über alle Evolutionsschritte hinweg. Alle Erfahrungen werden selber durchlebt, wenn der Weg bis zum Ende beschritten wird, was selten geschieht. Erfahrungsgemäß wird vorher abgebrochen mit der Begründung, dass modellgetriebenes Engineering ineffizient ist.

Da scheint der direkte Einstieg auf der höchsten Evolutionsstufe effizienter zu sein. Das wiederum ist ohne Schulung und Coaching und Unterstützung durch professionelle Werkzeuge unrealistisch. Aber dann garantiert es den Erfolg.

Gestatten Sie mir abschließend noch eine Anmerkung zu den Kosten. Für den Einstieg in modellgetriebenes Engineering auf der höchsten Evolutionsstufe müssen mit Kosten von ca. 10.000,- € pro Arbeitsplatz gerechnet werden (Beinhaltet Schulung, Coaching und Werkzeuge). Das klingt teuer aber verglichen mit den Personalkosten in Deutschland sprechen wir hier in etwa über einen Mannmonat. (Unsere Kunden, die sich auf der höchsten Evolutionsstufe befinden, sprechen über einenEffizienzgewinn von 200 % gegenüber herkömmlicher Programmierung.)

Die Entscheidung, ob Sie sich die notwendigen Investitionen in modellgetriebenes Engineering leisten sollten oder ob Sie sich leisten können darauf zu verzichten, hängt im Wesentlichen vom Stand der Komplexität des zu entwickelnden Systems ab. Natürlich haben auch andere Faktoren Einfluss, z.B. die Bereitschaft der Mitarbeiter diesen Schritt mit zu gestalten. Nur eines sollten Sie (aus meiner Erfahrung betrachtet) nicht tun, diesen Schritt halbherzig und unprofessionell durchführen.

In diesem Sinn wünsche ich Ihnen viel Erfolg in Ihren Projekten und würde mich freuen, wenn Sie mir Ihre Meinung mitteilen oder wie Ihre Erfahrungen mit modellgetriebenem Engineering sind.

Autor:

Andreas Willert
Haben Sie noch Fragen oder Anregungen zum Thema? Dann freue ich mich über eine E-Mail: awillert@willert.de

Herausgeber:

WILLERT SOFTWARE TOOLS GMBH
Hannoversche Straße 21
31675 Bückeburg
E-Mail: info@willert.de
Tel.: +49 5722 9678 - 60

Alle ESE-Reports im Überblick

Aktuelles Know-how und neueste Entwicklungen und Trends rund um das Thema Emedded Software Engineering

> zu den ESE-Reports

Hinweis: Unsere Webseite nutzt Cookies. Wenn Sie fortfahren, nehmen wir an, dass wir Ihre Erlaubnis haben Cookies zu setzen. Informationen zum Einsatz von Cookies sowie unsere Datenschutzbestimmungen finden Sie in unserer Datenschutzerklärung und über unser Impressum.