4 Prinzipien der Codegenerierung
Codegenerierung ist ein wesentlicher Erfolgsfaktor für den Einsatz von Modellen im Softwareentwicklungsprozess. Aus vielen Modellen kann Code für das Produktionssystem oder für
Testtreiber effizient generiert und damit die Konsistenz zwischen Modell und Implementierung verbessert sowie Ressourcen eingespart werden. Dieses Kapitel beschreibt grundlegende Konzepte,
Techniken und Probleme der Codegenerierung und skizziert eine Darstellungsform für Regeln zur Codegenerierung in Form von Transformationsregeln.
4.1 Konzepte der Codegenerierung
4.1.1 Konstruktive Interpretation von Modellen
4.1.2 Tests versus Implementierung
4.1.3 Tests und Implementierung aus dem gleichen Modell
4.2 Techniken der Codegenerierung
4.2.1 Plattformabhängige Codegenerierung
4.2.2 Funktionalität und Flexibilität
4.2.3 Steuerung der Codegenerierung
4.3 Semantik der Codegenerierung
4.4 Flexible Parametrisierung eines Codegenerators
4.4.1 Implementierung von Werkzeugen
4.4.2 Darstellung von Skripttransformationen
Die Möglichkeit, aus einem Modell ablauffähigen Code zu erzeugen, bietet interessante Perspektiven bei der Softwareentwicklung und ist teilweise sogar eine wesentliche Voraussetzung
für
- die Steigerung der Effizienz der Entwickler [SVEH07],
- die Trennung von Anwendungsmodellierung und technischem Code, die die Wartbarkeit und die Weiterentwicklung der Funktionalität sowie die Portierung auf neue Hardware und
Betriebssystemversionen besser unterstützt [SD00],
- Rapid Prototyping mit Hilfe von Modellen, die eine kompaktere Beschreibung des Systems erlauben, als es durch eine reine Programmiersprache wie Java möglich
wäre,
- schnelles Feedback durch Demonstrationen und Testläufe und
- einen wesentlichen Aspekt der Qualitätssicherung: der Generierung von automatisierten Tests.
Eine der Stärken der Generierung ist die schnelle Erstellung sich häufig wiederholender ähnlicher Codefragmente (oder „Aspekte“, [LOO01, KLM+97]). Gerade bei der Anbindung technischer Aspekte, wie etwa GUI, Peristenz oder
Kommunikation verteilter Systemteile sind häufig struktuell gleich und können sehr gut aus abstrakten Modellen abgeleitet werden. Das reduziert drastisch die Größe der manuell
zu erstellenden Artefakte. Dies wiederum führt zu weniger Programmierfehlern, größerer Konformität des generierten Codes zu Codierungsstandards.
Probleme heutiger Werkzeuge
Die Erzeugung von ablauffähigem Code aus einem Modell ist daher derzeit zurecht eine der wesentlichen Anstrengungen der Hersteller von Modellierungswerkzeugen. Dies gilt nicht nur für
UML-basierte Werkzeuge, sondern auch für Werkzeuge für ähnliche Sprachen, wie Autofocus [HSSS96, Sch04], der in der Telekommunikation verwendeten SDL [IT07b, IT07a] oder den in
Statemate und Rhapsody umgesetzten Statecharts [HN96]. Aufgrund dieser vielfältigen Anstrengungen ist davon auszugehen, dass sich
die Situation bei der Codegenerierung in den nächsten Jahren weiter verbessern wird.
Viele der heute existierenden Werkzeuge bieten bereits die Generierung von Code oder Coderahmen aus Teilen der UML an.
Die Erzeugung von Coderahmen aus Klassendiagrammen ist mittlerweile Stand der Technik. Dabei werden Hüllen für die Klassen erzeugt, die zumindest
Attributdefinitionen und Zugriffsfunktionen beinhalten. Die Rümpfe generierter Methoden sind manuell einzutragen. Da detaillierte Modelle im Projekt meist einer hohen Änderungsrate
unterworfen sind, müssen die manuell eingesetzten Coderümpfe nach jeder Generierung neu nachgetragen werden oder gehen verloren. Als Ausweg wird deshalb auch
„Roundtrip-Engineering“ [SK04] verwendet.
Roundtrip-Engineering erlaubt die wechselseitige Transformation von Code in Klassendiagramme und umgekehrt. Wesentlich ist dabei, dass beide Sichten manuell
änderbar sind, ohne dass die Änderungen in der jeweils anderen Sicht verloren gehen. Insbesondere bleiben Methodenrümpfe in der Code-Sicht erhalten auch wenn sie im Klassendiagramm
nicht sichtbar sind. Wenn aber eine möglichst kompakte Darstellung des Systems gewünscht ist, dann ist das eine Sackgasse. Sinnvoller ist es dann nur eine Darstellung anzubieten, die
graphische Klassendiagramme und Coderümpfe integriert. Die wesentlichen Hindernisse dafür sind das derzeit noch zu geringe Zutrauen des Entwicklers in den generierten Code, so dass ein
manueller Eingriff in den generierten Code noch gewünscht wird, und die nicht zufriedenstellend geklärte Frage, wie und wo Coderümpfe abgelegt werden, so dass sie vom Entwickler
effizient bearbeitet werden können.
Mit den ersten Compilern war die Situation jedoch ähnlich. Es wurde Assembler-Quellcode erzeugt, der manuell änderbar sein sollte. Es kann davon ausgegangen werden, dass mit
zunehmender Reife der Generierungstechnologie die Ebene des lesbaren Quellcodes unwichtiger wird und Bytecode direkt erzeugt werden kann. Dann wird es auch nicht notwendig sein, dass der
generierte Code Coding Guidelines erfüllt und gut lesbar ist.
Werden Coderümpfe wie beim Roundtrip-Engineering direkt in den generierten Code eingesetzt, so ist in diesen Coderümpfen kaum mehr eine Abstraktion
von der konkreten Realisierung von Attributen, Assoziationen, etc. möglich. Stattdessen muss der Entwickler die Form der Umsetzung und die daraus resultierenden Zugriffsfunktionen kennen.
Werden Coderümpfe aber ebenfalls generiert, so können zum Beispiel Attributzugriffe durch entsprechende get- und set-Methoden
ersetzt werden. Auch ist dann die Instrumentierung des Codes für Tests besser möglich.
Leider stimmt die dokumentierte oder den Analyse- und Refactoring-Techniken zugrunde liegende Semantik (im Sinne von Bedeutung, [HR04]) mit dem bei der Codegenerierung entstandenen Verhalten gelegentlich nicht überein. Dies ist ein generelles Problem , das einer sorgfältigen
Festlegung von Codegenerierung, Analysen, Refactoring-Techniken und der dokumentierten Semantik bedarf. Denn sonst ist es möglich, dass ein bezüglich der festgelegten Semantik
nachweislich korrektes Refactoring doch zu einem veränderten Systemverhalten führt.
Einfache Werkzeuge generieren oft eine starre Form von Code, ohne auf die spezifischen Bedürfnisse des Projekts einzugehen. Eine Parametrisierung der
Codegenerierung ist wünschenswert und an vielen Stellen auch notwendig, um zum Beispiel plattformspezifische Anpassungen in den Code einzubauen, die Nutzung von Frameworks, Speicher- und
Kommunikationstechniken zu erlauben oder die Optimierung der Umsetzung von Modellelementen zu ermöglichen.
Die möglichen Formen der Codegenerierung sind vielfältig und können nicht direkt antizipiert werden. Deshalb ist einerseits eine flexible Template- oder
Skriptsprache
In diesem Kapitel werden grundlegenden Konzepte zur Codegenerierung diskutiert und ausschnittsweise anhand der UML/P-Notation erläutert. Für ein weitergehendes Studium von
Gererierungstechniken wird auch [CE00] empfohlen. Der Abschnitt 4.1
erörtert Konzepte von Codegeneratoren, die auch die im Kapitel 7 diskutierte Verwendung der UML zur Modellierung von Testfällen
behandelt. In Abschnitt 4.2 werden Anforderungen wie Flexibilität, Plattformunabhängigkeit und Steuerbarkeit eines
Codegenerators diskutiert. Abschnitt 4.3 behandelt die Beziehung zwischen Codegenerator und Semantikdefinition der Sprache. Abschnitt 4.4 beschreibt, wie ein flexibler Codegenerator aussehen kann. Ein solcher flexibel anpassbarer Generator für die UML/P steht mit
[Sch12] zur Verfügung.
Bernhard Rumpe. Agile Modellierung mit UML. Springer 2012