Erschienen in DESIGN & VERIFICATION 03/2001, S. 52-54 (pdf-Version in toolbox unter "details")
Vorwort
Dank populärer kommerzieller Entwicklungswerkzeuge wie Visual Basic von Microsoft ist praktisch jeder professionelle Programmierer mit dem Konzept des visuellen Programmierens vertraut. Echtes visuelles Programmieren bedeutet aber noch einiges mehr, als VB zu bieten hat. So müssen detaillierte Designdiagramme direkt in Programmcode umgesetzt werden. Und es kann auch nicht einfach irgendein Designdiagramm sein. Vielmehr muss es alle Aspekte des zu produzierenden Systems eindeutig darstellen können.
Einleitung
In Embedded-Systemen ist die Unified Modeling Language (UML) die Design-Methodik der Wahl. UML wird für sich allein betrachtet noch nicht unbedingt alle Design und Implementierungsaspekte lösen. Aber mit UML lässt sich die Lücke zwischen den schriftlich niedergelegten und oft nicht ganz eindeutigen Anforderungen der Endbenutzer, dem detaillierten Entwurf und dem letztendlichen System schon weitgehend schließen.
Hauptteil
Die Theorie UML stellt ein Instrumentarium visueller Modellierungstechniken bereit, mit denen sich ein Embedded-Softwaresystem in eindeutiger Weise beschreiben lässt. Die erzeugten Ansichten beschreiben die Architektur, das Systemverhalten und das Zusammenwirken der Elemente des entworfenen Systems. Sind diese Ansichten erst einmal erstellt, dann kann man High-Level-Code oder ablauffähige Programme erzeugen, die das Softwaredesign korrekt widerspiegeln. Mit geeignetem Software-Support lassen sich Veränderungen am Design, die durch manuelle Kodierung entstehen, dann auch in die Modelle zurückführen. UML ist eine grafische Darstellung und Syntax für die Beschreibung von Systemen, Bauelementen und deren Zusammenwirken (Kollaboration). Es ist insofern eine visuelle Sprache, als es die involvierten Aspekte visuell vermittelt. Doch für sich allein gesehen hilft es Programmierern nicht beim Schreiben von Programmen, da es eine visuelle Modelliersprache und keine visuelle Programmiersprache ist. Die Arbeit mit UML ist wie das Schreiben von Programmen in ‚C‘ ohne die Fähigkeiten eines Compilers. Der C-Code ist eigentlich nur das ‚Modell‘ der Software, die selbst erst durch Compilierung implementiert wird. Glücklicherweise erscheinen immer mehr UML-‚Compiler‘ auf dem Markt – samt Editoren, mit denen der Prozess des Zeichnens von Designdiagrammen automatisiert werden kann. Das sind die Werkzeuge, die UML für das Design und die Entwicklung von Embedded-Systemen so nützlich machen. Eines der Hauptziele dieser Werkzeuge besteht darin, die Modellierung und das Programmieren zu äquivalenten Tätigkeiten zu machen. Wenn man ein UML-Modell entwickelt, dann hat man zugleich auch ein Programm geschrieben, das dieses Modell implementiert. Die Compilierung eines UML-Modells ist ein Prozess mit zwei Schritten. Erstens kann man die Syntax und in einem gewissen Ausmaß auch die Semantik des Modells prüfen. Dies ist möglich, weil das Modell konsistent und formell definiert ist – der Editor sollte so beschaffen sein, dass er nichts erlaubt, was im Modell nicht zulässig wäre. Zweitens lässt sich das Modell in Code umsetzen. Es kann direkt als ablauffähige Datei compiliert werden, oder man kann Quellcode in einer High-Level-Programmiersprache produzieren.
Die Anwendung Eine solche UML-Entwicklungsumgebung ist Rhapsody von I-Logix. Rhapsody besteht aus einem Editor für fünf verschiedene Diagrammtypen – Ablaufdiagramme, Objektmodell-Diagramme, Anwendungsfall-Diagramme (Use-Case-Diagramme), Zustandsdiagramme (Statecharts) und Aktivitätsdiagramme. Der Editor kombiniert diese Diagramme zu einem Modell und sorgt für Konsistenz der verschiedenen Ansichten bzw. Darstellungsarten. Man kann das ganze Modell inspizieren oder es automatisch auf Konsistenz und syntaktische Korrektheit hin überprüfen lassen. Die Rhapsody-Umgebung erzeugt Code in C++, C und Java. UML definiert neun grafische Ansichten, die verschiedene Perspektiven des in Entwicklung befindlichen Systems wiedergeben. Diese Ansichten sind Klassendiagramme, Statecharts, Use-Case-Diagramme und Ablaufdiagramme. Jedes Diagramm, das für sich selbst notwendigerweise unvollständig ist, hilft in einem spezifischen Abschnitt des Entwurfsprozesses. Use-Case-Diagramme und Ablaufdiagramme können beispielsweise herangezogen werden, um das System zu analysieren und die Systemanforderungen zu bestimmen. Das Systemverhalten lässt sich mit Statecharts und Aktivitätsdiagrammen modellieren. Zwar bietet jedes Diagramm eine eigenständige Systemansicht, doch gibt es notwendigerweise Überlappungen in den Ansichten oder doch zumindest Abhängigkeiten zwischen ihnen.
Die Praxis Bei neun verschiedenen Typen von Designdiagrammen könnte man vermuten, dass UML einen erheblichen Lernaufwand für Programmierer bedeutet, die über wenig Hintergrundwissen im formellen Design mit visuellen Darstellungen verfügen. Zwar ist UML ziemlich umfangreich, doch man muss nicht den gesamten Sprachumfang verstehen, um ernsthafte Arbeit damit leisten zu können. Es ist vielmehr möglich, mit einer Basis-Untermenge von UML zu arbeiten, die einen großen Teil der Vorzüge des UML-Designansatzes bereitstellt, ohne viel Zeit und Aufwand darauf verwenden zu müssen, in allen Modellierungsansätzen versiert zu sein. Mit dieser Untermenge kann man sinnvoll einen Teil von UML einsetzen, indem man sich auf die Architektur des Systems, sein Verhalten und seine Wechselwirkungen mit anderen Teilen des Systems konzentriert. Ziehen wir die Architektur als Beispiel heran. UML stellt die Architektur eines Systems mit Einsatzdiagrammen (Deployment-Diagrammen) dar. Deployment-Diagramme bestehen nur aus einigen wenigen Basiskonstrukten. Jeder ‚Knoten‘ repräsentiert ein beliebiges physikalisches Objekt, das für die Software von Bedeutung ist, und ein ‚Interconnect‘ repräsentiert eine physikalische Verbindungen zwischen Knoten. Das ‚aktive Objekt‘ definiert die Aufgaben, die jedem Knoten zugeordnet sind. Knoten können mit aktiven Objekten kombiniert werden und Subsysteme bilden. Auch andere Typen von UML-Diagrammen wie die Objektmodell-Diagramme können für die Modellierung verschiedener Aspekte der Systemarchitektur herangezogen werden. Die Terminologie ist einfach zu erlernen und anzuwenden. Das Systemverhalten kann mit Use-Case-Diagrammen, Statecharts und Aktivitätsdiagrammen modelliert werden. Für jeden, der bereits Finite-State-Machines (FSMs) gebaut hat, ist der Schritt zur formellen Statechart-Darstellung und Syntax relativ einfach. Mit Ablaufdiagrammen zu spezifizieren, wie die Elemente des Systems zusammenwirken, hilft bei der Bestimmung der Systemanforderungen. Das ist ein besonders wichtiger Aspekt im Designprozess. Wenn die Anforderungen nicht genau und eindeutig definiert sind, ist auch ein perfekt entworfenes System nicht unbedingt brauchbar. So lassen sich die Grundlagen eines jeden Systems also schon mit drei Diagrammen repräsentieren: dem Objektmodell-Diagramm, dem Statechart und dem Ablaufdiagramm. Dem erfahrenen Ingenieur, der mit vertrauten Problemstellungen arbeitet, könnte eine Untermenge von dieser Größe immer noch als unnötig erscheinen. Aber sie bietet eine unfehlbare Methode, sicherzustellen, dass auch ein vergleichsweise einfaches System die Anforderungen vollständig erfüllt und korrekt implementiert ist. Dem weniger erfahrenen Ingenieur spart sie nicht nur Zeit und Mühe für die Fehlersuche, sie kann sogar den Unterschied zwischen Erfolg und Misserfolg eines Projekts ausmachen.
Beginn eines UML-Designs Use-Cases sind zwar für die Beschreibung des Basisverhaltens eines Systems nicht unbedingt erforderlich, doch sind sie ein guter Ausgangspunkt für den Beginn der Arbeit an einem Embedded-Design mit UML. Wie der Name bereits impliziert, sind Use-Cases eine strukturierte Methode für die Beschreibung der Benutzungsformen eines Embedded-Systems. Doch anders, als der Name sagt, sind sie mehr als nur einfache Beispiele für typische Verwendungsarten des Systems. Man kann sich einen Use-Case als ganze Klasse von Beispielen vorstellen. Individuelle Variationen in der Klasse werden als ‚Scenarios‘ bezeichnet. Man kann Scenarios entwickeln, wenn sie den Anwendern dabei helfen, die Anforderungen eines Systems genauer zu beschreiben, aber sie sind kein notwendiger Teil des Designprozesses. Betrachten wir beispielsweise ein einfaches Verkehrsampel-System, das aus drei Akteuren besteht – einem nach Norden fahrenden Auto, einem nach Süden fahrenden Auto und einem Polizisten. Das Use-Case-Diagramm beschreibt, wie jeder Akteur über eine Assoziation mit einer oder mehreren Systemfunktionen verknüpft ist, und zeigt, wie und unter welchen Umständen der Akteur mit dem System in Verbindung steht.
Mit Use-Cases lassen sich funktionelle Anforderungen für ein breites Spektrum an Verwendungsmöglichkeiten bereitstellen. Sie bilden die Brücke zwischen dem Benutzer, der das Vorfeld des Designprozesses verstehen und zu ihm beitragen kann, und den Entwicklungsingenieuren, die vor der schwierigen Aufgabe stehen, den oft unpräzisen und widersprüchlichen Pflichtenkatalog umzusetzen. In den Statecharts kommt das Verhalten mit der Architektur zusammen. Sie modellieren das Verhalten insofern, als sie die Systemzustände und die Ereignisse zeigen, die es dem System erlauben, von einem in den anderen Zustand überzugehen. Sie können aber auch die Struktur des Systems definieren. Statecharts sind den althergebrachten Zustandsübergangsdiagrammen (State Transition Diagrams) sehr ähnlich. Jedoch enthalten sie auch zusätzliche Strukturangaben und Randbedingungen wie Hierarchie, orthogonale Zustände, Ereignisangaben und Timing, so dass sie den Übergang von einem Zustand zum nächsten eindeutig definieren. Wer einmal mit State-Transition-Diagrammen oder gar FSMs gearbeitet hat, wird das Grundkonzept der Statecharts schnell verstehen. Wie das Statechart für die Verkehrsampel zeigt, kann die Ampel einen von vier Zuständen annehmen: Rot, Grün, Gelb und ‚Limbo‘ (Siehe Abb. 2). Limbo ist einer der drei möglichen Übergangszuständen – von Rot auf Grün, von Gelb auf Rot und von Grün auf Gelb. Der rote Pfeil zeigt jeden der möglichen Übergänge zwischen jedem dieser Zustände.
Objektmodellierungsdiagramme schließen die Lücke zwischen Architektur und Zusammenwirken. Sie stellen die Architektur insofern dar, als der Code in Anlehnung an die von den definierten Objekten dargestellte Grundstruktur aufgebaut sein wird, auch wenn man keine Codegenerierung oder objektorientierten Programmiersprachen verwendet. Außerdem zeigen sie das Zusammenwirken, da mit korrekt entworfenen Objekten die Absicht verfolgt wird, dass sie untereinander Meldungen weitergeben. Das Objektdiagram zeigt das Design der Objekte, welche die Verkehrsampel modellieren (siehe Abb. 3). Das Auto, der Steuerungsmechanismus und die Ampel selbst werden als Objektklassen repräsentiert. Diese Klassen enthalten sowohl Attribute (Daten) als auch Methoden (Code), die auf die Attribute einwirken.
Ablaufdiagramme stellt dar, wie die verschiedenen Komponenten eines Systems zusammenwirken. Sie zeigen die Lebenszyklen von Objekten auf vertikalen Zeitlinien. Die zwischen den verschiedenen Objekten im System weitergegebenen Meldungen werden durch horizontale oder schräge Linien von einer Instanz zur anderen oder von der Systemgrenze zu einer Instanz angezeigt. Mit nur drei oder vier Diagrammtypen kann ein breites Systemspektrum recht gut spezifiziert werden und umfasst damit einen überraschend großen Teil der heute gebauten Embedded-Systeme.
Codeerzeugung: Noch nicht der letzte Schritt Wer ein Tool wie Rhapsody zum Editieren von Designs und zur Generierung von Code verwendet, könnte durchaus meinen, dass damit die ganze Arbeit erledigt sei. Das Design ist syntaktisch korrekt, der Code spiegelt die Designanforderungen genau wider, und das Design läßt sich fehlerfrei compilieren. Aber es kann Anforderungen geben, die man lieber manuell codieren möchte oder für die bereits ein bewährter Code vorhanden ist. Ein Tool wie Rhapsody erlaubt ‚Reverse Engineering‘ von früheren Codes und das Einfügen eigener Methoden oder Funktionen in das Design. Mit Rhapsody sind das Designmodell und der Code ein und dasselbe.
Spätere Änderungen Besteht immer die Möglichkeit, zurückzugehen und das Design zu aktualisieren, nachdem man den Code geändert hat? Ein Design nicht zu aktualisieren, wird nicht immer ein Problem darstellen. Doch die meisten Entwickler ziehen es vor, Designdokumente zu führen, die das ins Feld gebrachte System zutreffend wiedergeben. In manchen Fällen kann dies sogar eine für das Projekt durch Unternehmensstatuten oder vom Gesetzgeber vorgeschriebene Maßnahme sein. Ein Prozess, den man als ‚Round-Trip-Engineering‘ bezeichnen könnte, ermöglicht, alle manuellen Änderungen am erzeugten Code ‚rückwärts‘ in die Designdiagramme zu integrieren. Beim Round-Trip-Engineering werden Codeänderungen oder ergänzungen herangezogen, in die UML-Designterminologie zurückübersetzt und die sich ergebenden Diagrammmodifikationen in die jeweiligen Designdiagrame eingeführt. Dank dieser Technik stellen die UML-Diagramme alle an der Software vorgenommenen Änderungen dar, bevor die ablauffähigen Module erstellt werden. Design und Implementierung bleiben so immer in Übereinstimmung.
Objekte und visuelle Sprachen Ohne Beschreibungen von Architektur, Verhalten und Zusammenwirken können visuelle Sprachen nur ein Stück weit führen. Das fundamentale Konzept und das verbindende Element für den Erfolg visueller Sprachen wie UML ist das Objekt. Es sind Objekte, die einen geradlinigen Ansatz für Modellierung und Codegenerierung erst möglich machen. Damit soll nicht gesagt werden, dass Objekte unbedingt nötig wären – Modellierung und Codeerzeugung sind gewiss auch ohne Objekte denkbar, aber sie wären viel schwieriger zu bewerkstelligen. Viele, wenn nicht alle Objekte in Embedded-Echtzeitsystemen weisen Verhaltensweisen auf, die mit Statecharts, Aktivitätsdiagrammen und dem Quellcode selbst beschrieben und analysiert werden können. Objekte wirken zusammen und erzeugen Systemfunktionen – seien sie nun passiv, wie ein Datenobjekt, oder aktiv, wie eine Aufgabe in einem Echtzeitsystem. Die UML-Darstellung bildet das Rückgrat für Dokumentation und Beschreibung der Architektur, Verhaltens und Kollaborationscharakteristika von Echtzeitsystemen. Rhapsody ermöglicht dem Entwickler, sich auf das Design zu konzentrieren und dabei die Implementierung und Dokumentation automatisch zu produzieren. Für den Benutzer besteht der Vorteil darin, dass es eine einzige Plattform für Analyse, Design, Implementierung und Tests gibt – was die Produktivität erheblich steigert und letztendlich die Zeit bis zur Marktreife verkürzt. Wenn auch die Arbeit mit UML nicht erfordert, alle UML-Diagrammtypen zu verwenden oder den resultierenden Code objektorientiert zu gestalten, sollte man dennoch die vom UML-Modellierungsansatz gebotene Chance nutzen und seine Systeme objektorientiert betrachten. Wer bereits Objekte und eine objektorientierte Programmiersprache benutzt, dem wird es noch leichter fallen, sich mit UML-Modellierungsdiagrammen zu befassen und sie in seinen Systemdesigns anzuwenden.
|
| |
|
 |
|