Die Definition der Modellierungssprache war keineswegs so einfach und geradlinig wie hier beschrieben. Zuerst wurde nur ein Teil der Modellierungssprache entworfen und durch die Modellierung von Beispielanwendungen getestet. Wenn das Ergebnis nicht zufriedenstellend war, wurde das Metamodell modifiziert. Dabei können Tools eine große Hilfe darstellen. Durch MetaEdit+ erhielt diese Testphase einen agilen Charakter: Tests konnten schnell durchgeführt werden, so dass sofort erkennbar war, wie die Sprache in der Praxis aussieht. Dies verringert die Risiken, eine schwache Sprache zu entwickeln, oder eine zu mächtige Sprache, jedoch für den falschen Zweck. Die Werkzeugunterstützung für die Sprachentwicklung half auch sehr dabei, gute Abbildungen für die Codegenerierung zu finden.
Die Geburt des Codegenerators
Ein Codegenerator im Bereich der modellorientierten Entwicklung legt fest, wie Informationen aus Modellen extrahiert und in Code umgewandelt werden. Da die erstellten Modelle den Input des Generators darstellen, hängt dieser Prozess entscheidend von der Modellierungssprache ab. Ein Domänen-Framework oder andere verfügbare Bibliotheken können diese Aufgabe vereinfachen, indem sie das Abstraktionsniveau auf der Code-Seite anheben. In den einfachsten Fällen produziert jedes Modellierungssymbol einen bestimmten, fest definierten Code, einschließlich der Werte, die in das jeweilige Symbol als Argumente eingetragen worden sind. Ein Generator kann auch unterschiedlichen Code für ein Symbol erzeugen, abhängig von den Werten des Symbols, von Beziehungen zu anderen Symbolen sowie von weiteren Modellinformationen.
Im diskutierten Scheibenwischer-Beispiel begann die Arbeit an der Implementierung des Codegenerators mit der manuellen Entwicklung eines Prototyps. Ab einem bestimmten Komplexitätsgrad wird ein solcher Prototyp zur Implementierung eines Generators unverzichtbar, da er die notwendigen Quellcode-Fragmente bereitstellt, angereichert mit aufgabenbezogenem Know-how. Ausgehend von diesem Prototyp wurden die Quellcodemodule in generische und nicht-generische aufgeteilt. Während die letztgenannten zu generieren waren, bildeten die generischen Module den Hardware-Abstraction-Layer. Tatsächlich ermöglichte diese Schicht einen höheren Abstraktionsgrad in den anderen Quellcodemodulen.
Um den Generator für die verbleibenden Module zu implementieren, kam das Generator-Entwicklungswerkzeug „HyperSenses“ zur Anwendung, das einen interaktiven und modellbasierten Ansatz zur Definition von Codegeneratoren bietet. HyperSenses wurde an MetaEdit+ gekoppelt, indem die entsprechenden Metamodell- und Modelldaten importiert wurden. Für die Generatorentwicklung wurde zunächst das Metamodell in HyperSenses importiert, da es eine Definition der für die Codegenerierung variablen Elemente bereitstellt. Basierend auf diesem automatisch abgeleiteten Metamodell wurden so genannte „Code-Patterns“ definiert, indem Fragmente des prototypischen Quellcodes mit „Slots“ und Blöcken versehen wurden. Im Quellcode markieren Slots Variationspunkte, die während der Generierung mit konkreten Werten gefüllt werden, wie etwa ein Klassenname. Blöcke hingegen definieren größere Codeabschnitte, die entweder als Ganzes oder überhaupt nicht generiert werden. Diese Entscheidung hängt davon ab, ob alle enthaltenen Slots mit Werten gefüllt sind. Zusätzlich lassen sich Bedingungen für Blöcke spezifizieren. Des weiteren ist das Schachteln von Blöcken zulässig, so dass selbst komplexe Abhängigkeiten zwischen verschiedenen Codefragmenten beschrieben werden können (Bild 3). Slots und Block-Bedingungen werden durch Ausdrücke definiert, die auf Elemente des Metamodells verweisen. Auf diese Weise werden die ehemals spezifischen Quellcode-Fragmente zu parametrisierten und neutralisierten Bestandteilen des Zielcodes – zu Code-Patterns.
Zusätzlich zu reinen Modellierungskonzepten können zugehörige Regeln definiert werden. Diese Regeln schränken die Verwendung der Sprache ein und erzwingen so die Korrektheit der mit ihr erstellten Modelle. Ist z.B. der Geschwindigkeitssensor einer Scheibenwischersteuerung nur über einen Bus mit dem Hauptsystem verbunden, kann bei der Spezifikation einer solchen Verbindung der benötigte Bustyp (LIN, MOST, CAN) aus einer Liste ausgewählt werden. Eine weitere Regel kann besagen, dass ein Geschwindigkeitssensor nur eine Verbindung zu genau einem Bus haben darf. Eine weitere Gegebenheit im vorliegenden Fallbeispiel ist die Einschränkung, dass genau ein oder zwei Wischerarme an der Windschutzscheibe vorhanden sein müssen. Im Fall eines einzigen Wischerarms muss dieser mittig installiert sein, während zwei Wischerarme in den Einbaupositionen links und mittig oder links und rechts installiert sein können. In der Modellierungssprache hat ein Wischerarm eine Positionsinformation, die sich bei der Erstellung des Wischerarm-Elements selektieren lässt (Bild 2).
Die jeweilige Modellierungssprache wird durch die Definition ihres Metamodells formalisiert. Die Ausgestaltung des Metamodells hängt vom eingesetzten DSM-Tool ab. Es sollte zumindest ermöglichen, die Konzepte der Sprache zu definieren, ihre Eigenschaften, gültige Verbindungen zwischen einzelnen Sprachelementen, Strukturen der Modellhierarchie und Integritätsregeln. Auch die Unterstützung der Wiederverwendung von Modellen sowie von verschiedenen Ansätzen zur Modellintegration spielt eine wesentliche Rolle. Im vorliegenden Fall wurde „MetaEdit+“ verwendet, ein Werkzeug, das sowohl die Spezifikation von Modellierungssprachen erlaubt als auch automatisch die jeweils zugehörige Metamodell-Definition unterstützt.