Lifecycle-Optimierung Zukunftssichere Software-Architektur

Der langfristige Erfolg eines Embedded Systems ist nicht allein vom Erfolg bei funktionalen Anforderungen abhängig. Sieht man Embedded-Software in einem Lebenszyklus, stellt sich auch die Frage nach Anpassungsfähigkeit und Zukunftssicherheit. Hier kommen viele nichtfunktionale Anforderungen wie Modifizierbarkeit, Skalierbarkeit, Portierbarkeit, Konnektivität, Performance oder Testeignung ins Spiel. Wer die Entwicklung seiner Embedded-Software gut dokumentiert, hat einen ersten Schritt getan. Aber erst, wenn Entscheidungen zu Hardware, Software und zum Tooling bewusst im Rahmen einer durchdachten Embedded-Software-Architektur getroffen, dokumentiert und implementiert werden, lassen sich Entwicklungsprojekte im Bereich Embedded Systems zukunftsfest machen.

Das frühe Einbinden von Softwarearchitekten und entsprechende Architekturkonzepte sind im Bereich der Unternehmenssoftware und IT-Infrastruktur Standard. Bei Entwicklungen im Bereich der Embedded Systeme ist das bisher nur selten so. Als Argument für diese Praxis wird oft auf den hohen Zeit- und Kostendruck verwiesen.

Ein kurzsichtiges Argument, denn jedes Softwaresystem hat eine Architektur. Wird diese Architektur nicht explizit und bewusst modelliert, ergibt sie sich ungeplant und implizit aus der Vielzahl der unsystematisch und isoliert getroffenen Einzelentscheidungen der Entwickler. Das Problem dabei: Entstehen diese Strukturen ungeplant aus der Dynamik der Komponentenentwicklung heraus, tut dies der Funktion der Software zunächst selten Abbruch.

Die funktionalen Anforderungen sind ja meist spezifiziert und damit klare Aufgabe an die Teams. Eine klar strukturierte und dokumentierte Softwarearchitektur wird erst vermisst, wenn es später um Wartung, Skalierung oder Portierung geht. Bewusste Entscheidungen kann nur jemand treffen, der die Möglichkeiten dazu hat. Anders gesagt: Wo Entscheidungen »alternativlos« sind, braucht es keine Architekten. Doch gerade im Embedded-Bereich hat die technische Entwicklung neue Potenziale geschaffen, als da wären die ständig wachsende Zahl der Entwicklungswerkzeuge sowie die immer leistungsfähigere Hardware:

  • Leistung und verfügbare Ressourcen (Speicher etc.) nehmen zu.
  • Zahl und Varianz der physikalischen Schnittstellen wächst.
  • Die Varianz der Embedded Systeme reicht vom System-on-a-Chip bis zu funktionsfähigen PCs.

Doch auch auf dem Gebiet der Software tut sich etwas:

  • Betriebssysteme für Embedded Systeme werden leistungsfähiger und komplexer.
  • Zahl und Komfort der verfügbaren Programmiersprachen steigt.
  • Zahl der relevanten Entwurfsmuster nimmt zu.
  • Neue Techniken und die Gewohnheiten der Bediener revolutionieren die Bedienoberflächen (Touchpanels etc.).

Da die Zahl der Optionen bei Hardware, Software und Tooling zunimmt, lassen sich auch leistungsfähigere Systeme entwickeln. Dies aber setzt deren bewusste, zielgerechte Auswahl und Kombination voraus - denn mit den Freiheiten bei den Entscheidungen wächst das Risiko von Fehlentscheidungen. Unter Wettbewerbsdruck kann bereits die aufwendigere Kombination oder die Auswahl von weniger geeigneten Technologien zu gravierenden Wettbewerbsnachteilen und zum wirtschaftlichen Misserfolg von Produkten und Unternehmen führen.

Steigende Anforderungen über den Lebenszyklus

Embedded Systeme steuern, regeln und überwachen Geräte und Anlagen. Vielfach gleichen sie Herz und Hirn dieser Systeme und tragen ganz wesentlich zur Differenzierung der Produkte im Wettbewerb bei. Damit wächst der Druck auf die Hersteller. Eingebettete Systeme müssen heute hohe Anforderungen in verschiedensten Bereichen erfüllen:

  • Benutzererwartungen.
  • Der Wunsch nach einer trainingsarmen, einfachen und intuitiven Bedienung komplexester Anlagen erfordert den Einsatz moderner HMI-Entwicklungsmethoden und -techniken.
  • »Always online« - jederzeit Informationsvernetzung über das Internet.
  • Cloud-Technologien - universelle Ablage und Zugriff auf Daten und Historien.
  • Wettbewerbsdruck.
  • Schutz von Alleinstellungsmerkmalen im Bereich Embedded Systeme.
  • Standardisierung (auflösungsunabhängige Anzeige, Modularisierung, Diversifizierung durch Freischalten von Funktionen, etc.).
  • Längere Lebenszeiten von Designs (Facelift, Updates, Ersatzteile).
  • Umsetzung regulatorischer Vorgaben (Sicherheit, Energieverbrauch, etc.).

Die beste Lösung ist es, Entwicklerteams für ein Embedded System frühzeitig und projektbegleitend durch einen Softwarearchitekten unterstützen zu lassen. Dieser stellt bereits im Vorfeld der Entwicklung die richtigen Fragen. Neben den funktionalen Anforderungen sind genau hier die nichtfunktionalen Anforderungen vor dem Hintergrund einer Lifecycle-Prognose zu erfassen. Dafür empfiehlt es sich, die Anforderungen zunächst modellbasiert und möglichst abstrakt zu betrachten.

Diese Modelle schaffen eine Arbeitsgrundlage und erlauben es, das Entwicklungsprojekt ganzheitlich zu durchdenken und abzusichern. Eine der ersten Fragen zum Systemdesign: Was macht die Hardware, was macht die Software? Diese Grenze verschiebt sich, da die Software auf Basis leistungsfähigerer Hardware immer mehr Aufgaben übernehmen kann und dies in Bezug auf die Dauer des Lebenszyklus’ und die Anpassbarkeit große Vorteile bietet. Aber auch wenn die Grenzziehung zwischen Hard- und Software bereits geklärt ist und es »nur« um die Software geht, können in Zusammenarbeit mit Softwarearchitekten frühzeitig Entscheidungen getroffen werden, beispielsweise Softwarekomponenten mit dem Ziel der besseren Wartbarkeit bewusst getrennt zu halten.

Effektive HMI-Entwicklung

In der HMI-Entwicklung wirken sich die Architekturentscheidungen im Vorfeld erheblich auf die Arbeitsteilung der Teams, den Verlauf und die Ergebnisse des Projektes aus. Durch den Einsatz von Sprachen zur GUI-Beschreibung wie XAML (Microsoft, .NET), MycroXAML (Open Source, C++), SwiXML (Open Source, Java) und QML (Nokia, C++) lassen sich Funktion und GUI-Design leichter voneinander trennen.

In der Praxis bedeutet das, dass verschiedene Teams die Funktionen des Systems und die GUI-Gestaltung parallel iterativ entwickeln können. Da Design und Funktion der HMI-Software archtiekturell voneinander getrennt sind, lassen sich dann die parallel entstehenden Entwicklungsergebnisse reibungslos integrieren. Die Bedienoberflächen lassen sich ohne Änderungen in den darunterliegenden Software-Layern flexibel konfigurieren.

Nicht nur die Entwicklung eines GUI-Grunddesigns, auch die Realisierung von Produktvarianten, etwa für länder- oder kundenspezifische Versionen, ist damit sehr einfach umzusetzen. Die Aufteilung von Komponenten in der Architekturplanung wird besonders spannend, wenn es um sicherheitskritische Embedded Systeme geht. Die Herausforderung liegt darin, dass die Entwicklung des Systems und der Software normkonform erfolgen muss, um sie für einen SIL (Safety Integrity Level) zertifizieren zu können.

Jedes Unternehmen möchte die Risiken einer zeit- und kostenintensiven Zertifizierung, beispielsweise gemäß IEC 61508, minimieren. Der Ansatz der Softwarearchitekten ist stets die Reduktion der Teile des Systems, die als sicherheitskritisch eingestuft werden müssen. Die Kunst der Softwarearchitektur liegt nun darin, »Schnittmöglichkeiten« in der Software zu finden, um die sicherheitskritischen Programmteile von den nicht sicherheitskritischen Teilen zu trennen. Dabei können gängige Design-Patterns als Basis dienen.

Öfter mal was Neues

Zeit- und Kostendruck sind ein möglicher Grund für fehlende Softwarearchitektur. Ein anderer erscheint weniger dramatisch: Routine. Ein eingespieltes Entwicklerteam gilt als ideale Voraussetzung für ein Projekt, doch können Erfahrung und Routine die Lösungsfindung auch einschränken. Bewährte Lösungsansätze werden oft unhinterfragt wiederholt. Neue, möglicherweise besser geeignete und insbesondere flexiblere Technologien bleiben unberücksichtigt.

Oft wird dies in der Wahl der Programmiersprachen offenbar. Hierbei handelt es sich immer um Grundsatzentscheidungen mit weitreichenden Folgen - deshalb sollten sie bewusst und begründet gefällt werden. Eine wichtige Frage ist dabei, ob man innerhalb eines Projektes nicht durchgängig in einer Programmiersprache wie C++ bleibt, sondern ab einer bestimmten Ebene die Möglichkeiten und Flexibilität einer höheren Sprache verwendet, beispielsweise C#.

Um Routine zu durchbrechen und bewusste Technologieentscheidungen zu fällen, gehört es zu den Aufgaben eines Softwarearchitekten, neue Technologien zu evaluieren und auf Eignung für Projekte zu prüfen sowie neue Toolsets zur Verfügung zu stellen. Er muss künftig benötigte Komponenten identifizieren und geeignete Technologien für einzelne Komponenten auswählen.

Unter Einbeziehung der nichtfunktionalen Anforderungen kommt man auf diese Weise zu langfristig tragfähigen Lösungen. Ein Praxisbeispiel hierfür ist die Implementierung eines Persistenz-Layers in Embedded Systemen. Traditionell werden diese - vor allem aus Performance-Gründen - durch schlanke, eigenentwickelte Module realisiert.

Nicht selten kommt dabei auch spezielle Hardware wie etwa NVRAM-Komponenten zum Einsatz. Doch mehr und mehr setzen sich hier neue Technologien wie »SQLite« durch. Der etwas höhere Ressourcenverbrauch wiegt bei steigender Rechenleistung der Systeme inzwischen weniger schwer als die immensen Vorteile, welche die Entscheidung für diese standardisierten Programmbibliotheken bringt.

Der Zugriff auf den Speicher erfolgt bei SQLite über dieselben Mechanismen wie bei klassischen SQL-Datenbanken. Im Zusammenspiel mit gängigen Werkzeugen lässt sich so das Design des Datenmodells abstrahieren und modellieren. Auch die bewusste Entscheidung für eine Hochsprache in der Programmierung wirkt sich enorm positiv auf nichtfunktionale Anforderungen wie Flexibilität oder Erweiterbarkeit im Daten- und Speichermanagement aus.

Vorteile modellbasierter Entwicklung

Helfen können Softwarearchitekten auch bei der Auswahl von Methoden und Tools. Die dynamische Entwicklung heutiger Industrieprodukte macht den Bedarf für umfangreiche künftige Anpassungen bei der Entwicklung absehbar. Um diesen Anforderungen besser entsprechen zu können, hilft ein modellbasierter Entwicklungsansatz, um die Modularisierung mit klar definierten Schnittstellen zu erreichen.

Die Vorteile dieses Vorgehens haben sich in vielen Projekten bei Berner & Mattner in der Entwicklung von Funktionserweiterung gezeigt: Dank des modellbasierten Ansatzes konnten diese mit wenig Aufwand realisiert werden - und dies insbesondere auch von ursprünglich nicht beteiligten Entwicklern. Auch für den Bereich Testing bieten modellbasierte Verfahren und entsprechende Werkzeuge viele Vorteile (Bild 1).

Bereits in der Modellierungsphase können über spezielle Testplattformen im Modell-in-the-Loop-Test Anforderungen abgesichert und Spezifikationen verifiziert werden. Die hier entwickelten Testverfahren lassen sich dann in SiL- und HiL-Verfahren weiterverwenden. Selbst Mischformen, beispielsweise das gemeinsame Testen von Modellen und ersten Software- und Hardwarekomponenten, lassen sich einsetzen.

Das Arbeiten mit externen Teams wird unterstützt, weil diese ihre Entwicklungen gegen das Modell testen können: Verhält sich die Software wie das Modell, gilt die Aufgabe als erfüllt und eine Integration der entwickelten Komponenten ist sichergestellt. Für komplexe Embedded-Software sind mit dem Systementwurf bereits die Architektur der Software, die Designprinzipien und Design-Pattern festzulegen, um die Risiken zu reduzieren. Damit die Softwareentwicklung den Herausforderungen im Lebenszyklus eines Produkts langfristig gewachsen ist, helfen nur Abstraktion und Struktur.

Eine Softwarearchitektur sollte nicht als ein einmalig zu erstellendes Konzept in Form eines unveränderlichen Dokumentes missverstanden werden, das man nur selten wieder in die Hand nimmt. Es sollte bei jeder wesentlichen Änderung an der Software fortgeschrieben werden. Ohne dieses lebendige Dokument werden Abweichungen oft gar nicht bemerkt.

Vereinbarungen zu Architektur, Coding-Conventions, Schnittstellen, etc. müssen für die Entwickler verbindlich gemacht werden. Abweichungen davon sind zu begründen, zu diskutieren und dann explizit zu dokumentieren. Hierbei können Teams auch heute schon durch entsprechende Werkzeuge unterstützt werden. Das können umfangreiche Architektur-Analysetools im Build-Prozess oder aber auch »intelligente« Erweiterungen funktionsreicher Entwicklungsumgebungen sein.

Entwurfsmuster für zukunftsfähige Architekturen

Abgesehen von der Auswahl der richtigen Werkzeuge, Technologien und Programmiersprachen gibt es einige gängige Prinzipien, welche die Architektur modularisieren und damit im Kern verbessern können.

  • Partitionierung - damit ist die räumliche und zeitliche Abschottung verschiedener Ausführungs-bereiche gemeint, wie im angesprochenen Beispiel eine Trennung sicherheitskritischer und nicht-sicherheitskritischer Funktionen.
  • Isolated Functionalities - Softwaremodule werden den Funktionen einzelner Systemkomponenten zugeordnet und nur lose gekoppelt. So lassen sie sich besser einzeln überarbeiten.
  • Layers - Das System wird in Schichten aufgebaut. Dies verhindert zirkuläre Abhängigkeiten, und einzelne Schichten lassen sich austauschen.
  • Pipes and Filters - Softwaremodule werden anhand der zu erledigenden Datenverarbeitungen als Filter ausgelegt. Nach der schrittweisen Verarbeitung werden die Ergebnisse an den durch die Pipes definierten Filter weitergegeben. Dies ergibt ein System ohne globalen Zustand.
  • Model-View-Controller - Die Entkopplung der Präsentationsschicht von der datenverarbeitenden Schicht erhöht ebenfalls die Anpassbarkeit.
  • Gateway - Umsetzung technischer (externer) Schnittstellen in eine fachliche Sichtweise.
  • Watchdog - Die Überwachung der korrekten Programmabarbeitung durch eine unabhängige Instanz kann als Keep-alive-Variante oder auch mit komplexen Votern realisiert werden.

Die unbewusste Wahl einer Programmiersprache oder Schnittstelle kann sich nach Jahren rächen. Oft wurden diese Entscheidungen unter dem Zeit- und Kostendruck wenig dokumentiert oder begründet. Ist dann von den verantwortlichen Entwicklern niemand mehr greifbar, erhöhen sich Kosten und Risiken für Änderungen. Im schlimms-ten Fall wird der Hersteller zum Reverse-Engineering am eigenen Produkt gezwungen.