Agile Modellierung mit
UML
Loading

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“, [LOO01KLM+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.1

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 [HSSS96Sch04], der in der Telekommunikation verwendeten SDL [IT07bIT07a] 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.2

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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 Skriptsprache3

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