Modellbasierte Anwendungsentwicklung mit .NET

Know-how  –  Kommentare

Im .NET-Umfeld gibt es bis heute keine Frameworks, die durchgängig modellbasierte Techniken einsetzen. Doch ermöglichen gerade diese, speziell bei betrieblichen Anwendungen, einen hohen Produktivitäts- und Qualitätsgewinn in der Entwicklung. Aus dem Grund hat der Autor wesentliche Erfahrungen aus der Java- in die .NET-Welt überführt.

Unter modellbasierter Anwendungsentwicklung versteht man ein Vorgehen, das wesentliche Teile der Anwendung in einem Modell festlegt. Das Modell kann eine beliebige Darstellung haben (etwa Text), in der Regel werden jedoch Diagramme auf Basis der UML (Unified Modeling Language) oder von Ähnlichem verwendet.

Ziel ist es, durch die Ableitung aus Modellen den Kodieraufwand zu reduzieren und die Qualität zu erhöhen. Als angenehmen Nebeneffekt lassen sich die Diagramme wunderbar für die Dokumentation und als Einführung für neue Entwickler einsetzen, da sie das System aus der Vogelperspektive beschreiben.

Der größtmögliche Gewinn durch eine Modellierung ergibt sich deshalb, wenn sich immer wiederkehrende Aspekte möglichst einfach darstellen lassen. Fatal ist jedoch der Versuch, jedes noch so kleine Detail modellieren zu wollen, denn dann ist das Modell keine Abstraktion mehr und wird sogar unübersichtlicher als Programmcode. Das gilt insbesondere für grafische Modelle.

Auf die Frage nach "modellbasierter Entwicklung" bekommt man mit ziemlicher Sicherheit eine Antwort, die das Wort "Codegenerierung" enthält. Das ist zugleich ein oft vorgebrachter Kritikpunkt an modellbasierter Entwicklung: Übermäßiger Einsatz von Codegenerierung führt schnell in eine "Einbahnstraße", denn wenn generierter Code doch einmal manuell zu ändern ist, gibt es keinen Weg zurück. Das Modell (Diagramm) und die Anwendung laufen auseinander – das Modell wird wertlos.

Normalerweise wird dem begegnet, indem man die Codegenerierung so konfiguriert, dass eine manuelle Anpassung des generierten Codes nicht notwendig ist. Abgesehen von der enormen Komplexität, die in solchen "Templates" stecken kann und die nur wenige im Team beherrschen, lassen sich damit trotzdem niemals alle Fälle abdecken. Gleichzeitig wird der Entwickler von der Vielzahl der Modellierungsmöglichkeiten erschlagen.

Auch die ebenfalls gerne verwendete Variante, "geschützte" Bereiche im generierten Code einzuführen, die bei einer Neugenerierung erhalten bleiben, hat ihre Tücken. Es geht darum, spezielle Kommentare zu nutzen, um solche Bereiche zu markieren. Löscht oder ändert der Entwickler derartige Kommentare aus Versehen, werden die Anpassungen beim nächsten Generatorlauf fatalerweise entfernt – ohne dass er das überhaupt bemerkt.

Einzig das "Generation Gap"-Entwurfsmuster scheint eine sinnvolle Alternative zu sein. Dabei generiert der Entwickler typischerweise abstrakte statt konkreter Klassen. Anpassungen lassen sich dann in Subklassen vornehmen. Das ist ein Pluspunkt für die Kombination aus modellbasierter Entwicklung und .NET, denn mit partiellen Klassen, wie sie C# im Gegensatz zu Java kennt, kann man die Spezialisierung noch wesentlich eleganter lösen. Man teilt eine konkrete Klasse in zwei Teile (Dateien) auf: Eine wird ausschließlich generiert, die andere ausschließlich manuell bearbeitet. Das entspricht der Arbeitsweise diverser Editoren in Visual Studio, zum Beispiel dem für WPF-Formulare (Windows Presentation Foundation).

Mehr als Codegenerierung

Eine modellbasierte Entwicklung muss jedoch nicht zwangsläufig zu ausuferndem generierten Code führen: In der obigen Definition ist von "Generierung" nirgends die Rede. Ganz im Gegenteil kommt der Entwickler fast ohne generierten Code aus, wenn er die Herangehensweise nur umkehrt.

Nimmt man den oft überstrapazierten Vergleich mit einem Bauplan für ein Haus, würde doch niemand auf die Idee kommen, daraus für jeden einzelnen Bauarbeiter einen exakten Handlungsplan für jeden Tag und jeden Arbeitsschritt abzuleiten, auszudrucken und an die Handwerker zu verteilen. Die einzelnen Gewerke und der Bauarbeiter können stattdessen die Regeln selbst und anhand des Bauplans die meisten Schritte für sich ableiten. Es genügt vollkommen, den Bauplan zu verteilen und in dem einen oder anderen Fall noch eine Ergänzung oder Konkretisierung beizufügen.

Dieses Vorgehen entspricht einem "generischen Ansatz", bei dem man Komponenten wie einem Eingabefeld durch eine Erweiterung beibringt, selbst in das Modell zu schauen und sich entsprechend zu verhalten. Den Ansatz verfolgt zum Beispiel das TREND-Framework der Gebit Solutions, für die der Autor arbeitet: Statt aus den Modellen zur Entwicklungszeit Code zu generieren und das Modell dann zu "vergessen", stellt es die semantische Information des Modells zur Laufzeit zur Verfügung. Es verwirft lediglich die Information, wo auf dem Bildschirm welches Element grafisch angeordnet ist, und wandelt den Rest in eine kompakte sowie maschinell gut verarbeitbare Darstellung um. Die Anwendung lässt sich nun generisch anhand des Modells konfigurieren, indem das Framework etwa eine Menüleiste nach den im Modell definierten Anwendungsfällen aufbaut.

Nun sei die Frage gestellt, was genau man überhaupt sinnvoll in Geschäftsanwendungen modellieren kann. Die Erfahrung zeigt, dass Modellierung vor allem in drei Bereichen wesentliche Vorteile bietet:

  • bei Geschäftsobjekten und ihrer Persistenz,
  • bei Anwendungsabläufen (Screenflows, Workflows), und
  • beim Anwendungsrahmen.