Von Plattformen und Plattitüden - Lippenbekenntnis

Page 1

ix.0611.100-103

16.05.2011

10:07 Uhr

Seite 100

Softwareentwicklung

REPORT

Von Plattformen und Plattitüden

Lippenbekenntnis Daniel Mölle

Softwareplattformen sollen nicht nur Entwicklungszeiten verkürzen und Fehler reduzieren, sondern auch die kreative Energie der Mitarbeiter in produktive Bahnen lenken, statt sie in immer wiederkehrenden Aufgaben zu erschöpfen. Im alltäglichen Projektgeschäft stehen allerdings diverse Faktoren dem Plattformgedanken entgegen.

V

iele Unternehmen stehen vor der Situation, dass sie im Laufe der Jahre eine Familie vergleichbarer Geräte oder Applikationen erstellen, die zugehörigen Softwareprojekte jedoch immer wieder „bei null“ anfangen. Es ist nur zu verständlich, dass diese Beobachtung bereits nach wenigen Wiederholungen des kostspieligen Prozedere dazu führt, dass der Ruf nach einer Softwareplattform laut wird. Ernst gemeinte Plattformen allerdings setzen einen gewissen Mehraufwand an Vorarbeit voraus, der in der Praxis häufig gescheut wird – der Plattformgedanke verkommt zum Lippenbekenntnis. Die Besonderheiten von Plattformprojekten zeigen sich in erster Linie in Aspekten der Architektur. Um den Unterschied zu klassischen Projekten ohne Plattformgedanken im Folgenden

besser beleuchten zu können, bedarf es zunächst einiger grundlegender Überlegungen zum Architekturbegriff.

Ein kurzes Vorwort zur Architektur Allgemein gesprochen besteht die Kernaufgabe der IT-Architektur in diesem Umfeld darin, eine Software für die Lösung der gesetzten Aufgaben derart zu strukturieren, dass das entstehende Gesamtsystem intellektuell und organisatorisch beherrschbar bleibt. Zwei der wichtigsten Mittel zum Erreichen dieser Zielsetzung sind Dekomposition, also die Zerlegung eines Systems in Komponenten mit klar definierten Aufgaben, und Abstraktion, also das Verbergen interner Details einer Komponente (oder

100

Hardware) vor den auf sie zurückgreifenden Komponenten. Besonders deutlich äußert sich das Duo aus Dekomposition und Abstraktion in Schichtenarchitekturen: Die Schichten bilden eine vertikale Hierarchie mit einem von unten nach oben zunehmenden Grad an Verallgemeinerung, und die Komponenten einer jeden Schicht sind das Resultat einer horizontalen Trennung von Aufgaben auf gleicher Abstraktionsebene. Häufig findet sich im Design der einzelnen Komponenten eine ähnliche Struktur: Eine Komponente besteht dann intern wieder aus einer Hierarchie kleinerer Bausteine, etwa Java-Klassen oder C-Modulen, mit klar definierten Zuständigkeiten. Zusätzlich ist es üblich, die öffentliche Schnittstelle einer Komponente von ihrer konkreten Implementierung zu trennen – ein weiterer Abstraktionsschritt mit vielen Vorteilen. Eine typische Dreischichtenarchitektur für eine Enterprise-Applikation könnte beispielsweise wie folgt strukturiert sein: Der unterste Layer kapselt Details der Datenhaltung, etwa Datenbanken und -verbindungen. Sie hat somit eine technische Ausrichtung, aber iX 6/2011

©

Copyright by Heise Zeitschriften Verlag


ix.0611.100-103

16.05.2011

10:07 Uhr

Seite 101

wenig fachlichen Bezug. Die mittlere Schicht hingegen fasst die (per Definition fachliche) Geschäftslogik zusammen. Hier wird das Vokabular der fachlichen Domäne reflektiert, etwa Kunden, Produkte, Aufträge, Lagerbestände et cetera. Die oberste Ebene konzentriert sich auf Aspekte der Präsentation, etwa eine grafische Benutzeroberfläche zur Eingabe und Verwaltung jener fachlichen Entitäten.

In erster Linie zeigen sich die Besonderheiten von Plattformprojekten in Aspekten der Architektur

Im Vergleich dazu könnte der Aufbau einer typischen Dreischichtenarchitektur für die Firmware eines eingebetteten Systems so aussehen: Die unterste Schicht stellt ein Hardware Abstraction Layer dar, besteht also aus Treibern für die eingesetzte Peripherie, deren Schnittstellen nach oben von den Details der eingesetzten Hardware abstrahieren. Wie im vorherigen Beispiel liegt der Fokus dieser untersten Ebene demzufolge auf technischen Details. Die mittlere Schicht hingegen beherbergt Komponenten, die sich auf abstrakte Aufgaben konzentrieren – beispielsweise auf die Erfassung von Messwerten, die Kommunikation mit anderen Geräten oder die Speicherung fachlicher Daten. In der obersten der drei Schichten werden die eigentlichen High-Level-Abläufe abgebildet, die der Erfüllung der angedachten Aufgaben dienen. Eine verbreitete Strukturierungsmaßnahme bei solchen Architekturen besteht in der zusätzlichen Einschränkung, dass Komponenten einer Schicht nur von Komponenten derselben oder der darunterliegenden Schicht abhängig sein dürfen. Diese Restriktion führt un-

ter anderem dazu, dass sich Komponenten des untersten Layer relativ leicht austauschen lassen, selbst wenn dies leichte Anpassungen an ihren Schnittstellen zur Folge hat: Die Änderung ist in ihren Auswirkungen einigermaßen begrenzt. Bei Embedded-Projekten kommt diese Eigenschaft vor allem dann zum Tragen, wenn man Software von einer Hardware auf eine andere portieren will. Im Idealfall genügt es, die Implementierung des Hardware Abstraction Layer auszutauschen, während man alle darüberliegenden Komponenten beibehalten kann. Ein weiterer gravierender Vorteil strenger Schichtenarchitekturen besteht darin, dass Komponenten aus den oberen Schichten ersetzt werden können, ohne dass dadurch irgendwelche Anpassungen an Komponenten der darunterliegenden Ebenen notwendig würden. Darüber hinaus äußert sich die saubere Trennung in einer drastisch verbesserten Testbarkeit.

Qualität erfordert auch Weitsicht In der Tat ist die durch Dekomposition und Abstraktion erreichbare Qualität eines Softwaresystems so offensichtlich erstrebenswert, dass es beinahe unmöglich ist, sich jemanden vorzustellen, der sie für sein Projekt nicht in Anspruch nehmen möchte. Aber wenn sich diese Qualität so einfach herstellen ließe, wie es der erste Abschnitt dieses Artikels oberflächlich suggeriert, dann stellt sich zwingend die folgende Frage: Wieso wird so häufig Software entwickelt, die sich eben gerade nicht als Plattform verwenden lässt, sondern nach einigen Jahren wieder von einer vollständigen Neuentwicklung abgelöst werden muss? Ein kurzer Blick auf die berühmten Ausprägungen von Softwarequalität soll helfen, dieser Frage auf den Grund

x-TRACT ●

Obwohl viele Firmen im Lauf der Jahre Softwareprojekte haben, die sich in weiten Teilen stark ähneln, entwickeln sie häufig alle Komponenten von Grund auf neu.

Eine naheliegende Lösung sind Softwareplattformen, die als Basis für die Wiederverwendung vieler Komponenten dienen können.

Erfolgreich sind Plattform-Projekte aber nur dann, wenn alle Beteiligten dieses Ziel konsequent verfolgen und es nicht zugunsten kurzfristig sichtbarer Erfolge aus den Augen verlieren.

zu gehen. Zentrale Aspekte der mittlerweile veralteten ISO/IECˇ9126 sind Funktionalität, Zuverlässigkeit, Benutzbarkeit, Effizienz, Änderbarkeit und Übertragbarkeit. Dabei besteht ein fundamentaler Unterschied zwischen den ersten vier und den letzten beiden dieser Ausprägungen. Funktionalität, Zuverlässigkeit, Benutzbarkeit und Effizienz sind vergleichsweise gut sichtbare Eigenschaften einer Software. Solange ein Gerät oder eine Applikation an den Anforderungen vorbeiläuft, den Dienst verweigert, unbedienbar oder schlichtweg zu langsam ist, wird die Abnahme ausgesetzt und die Entwicklungsarbeit verlängert (oder das Projekt abgebrochen). Zusätzlich gilt die Besonderheit, dass eine augenscheinlich funktionierende, zuverlässige, benutzbare und effiziente Software beinahe keinerlei Rückschlüsse auf die Qualität oder gar Ästhetik ihrer zugrunde liegenden Architektur gestattet. Änderbarkeit und Übertragbarkeit hingegen sind subtile architekturelle Eigenschaften. Sie zeigen sich an der Oberfläche frühestens dann, wenn eine (weitgehend) fertige Software zum ersten Mal einer größeren Änderung oder Portierung unterzogen wird – also meist erst Jahre nach Beginn des Projekts. Das Erzielen von Qualität in diesem Sinne erfordert somit nicht nur wesentlich mehr Umsicht und Erfahrung, sondern auch eine gewisse Weitsicht aller Beteiligten.

Bei Plattformprojekten bietet es sich an, die Unterschiede zwischen den einzelnen Ausprägungen der Software in DSLs zu beschreiben

Diese Diskrepanz zwischen kurzfristig sichtbaren Erfolgen einerseits und verborgenen Qualitäten andererseits zeigt sich unter anderem in einem weitverbreiteten Phänomen, das sich polarisierend – aber treffend – als „die Reuse-Lüge“ bezeichnen lässt: Weil die Wiederverwendbarkeit von Software zwar gemeinhin als Qualitätsmerkmal anerkannt, jedoch mitnichten trivial zu messen ist, wird sie wesentlich öfter deklariert als tatsächlich erreicht. So beginnen auch zahlreiche ArchitekturReviews mit einer positiven Antwort der Entwickler auf die Frage „Ist ihr Code modular?“, enden aber bereits 101

iX 6/2011

©

Copyright by Heise Zeitschriften Verlag


ix.0611.100-103

16.05.2011

10:07 Uhr

Seite 102

Softwareentwicklung

REPORT

nach dem Durchspielen eines ersten Portierungsszenarios mit der gegenteiligen Erkenntnis.

Struktur braucht Struktur – und Erfahrung Der Grund dafür, dass Änderbarkeit und Übertragbarkeit oft verfehlt werden, liegt nicht etwa in einer mangelnden Bereitschaft, das oben beleuchtete Duo aus Dekomposition und Abstraktion einzusetzen. Ausschlaggebend ist vielmehr der Umstand, dass es keineswegs leicht ist, eine saubere Strukturierung im Sinne dieser beiden Konzepte festzulegen und durchzuhalten. Jede Strukturierung ist zunächst durch Einschränkungen charakterisiert: A darf nichts von B wissen, C soll keine Annahmen über die Farbtiefe des Displays machen, D muss denselben Schnittstellenvertrag wie E einhalten und so weiter. Theoretisch gesehen macht eine Architektur aus einer allgemeinen Random Access Machine (oder einer Turing-Maschine), bei der jeder Teil der Software alles darf und kennt, ein mehr oder weniger projektspezifisches, beschränktes und vor allem besser beherrschbares Berechnungsmodell. Aus praktischer Sicht sind diese Maßnahmen zwingend erforderlich, um die Abhängigkeiten und die Komplexität im System in den Griff zu be-

kommen. Allerdings zeigen sich auf dem Weg zur Strukturierung oft drei Schwierigkeiten. Erstens lässt sich die Struktur einer Software nur dann in sinnvollem Maße festlegen, wenn dies auch bei ihren Randbedingungen erfolgt. Das ist kein Plädoyer für einen Wasserfallprozess, sondern im Gegenteil der zwingende Grund für ein iteratives Vorgehen in Projekten, bei denen diese Randbedingungen nur über einen längeren Zeitraum und mit vielen Interessenvertretern geklärt werden können – mit anderen Worten, in allen Projekten.

Zwischen kurzfristig sichtbaren Erfolgen einerseits und verborgenen Qualitäten andererseits besteht eine Diskrepanz

Die Randbedingungen betreffen vor allem Anforderungen, aber auch technische Fragen, etwa bezüglich der Hardware. So lassen sich bei einem Enterprise-Projekt keine sinnvollen Entscheidungen bezüglich konzeptioneller Datenbankschemata fällen, solange man nicht weiß, welche fachlichen Entitäten man überhaupt erfassen muss. Bei einem Embedded-Projekt hingegen ist es beispielsweise kaum

möglich, eine sinnvolle Schnittstelle für eine Kommunikationskomponente zu definieren, wenn zwei alternative Verbindungskonzepte mit gänzlich konträren Eigenschaften in der Diskussion sind. Um den Umgang mit derartigen Unsicherheiten geht es weiter unten. Zweitens verlangen Dekomposition und Abstraktion in komplizierteren Fällen besondere Umsicht. Ein Paradebeispiel hierfür sind grafische Benutzeroberflächen: Bei der Darstellung oder Eingabe fachlicher Daten müssen Business-Logik und Präsentationsschicht einer Enterprise-Applikation per Anforderung eng zusammenarbeiten, während man andererseits eine lose Kopplung zwischen diesen beiden Softwareteilen anstrebt. Die Lösung dieses Widerspruchs ist zwar möglich – etwa durch die Trennung zwischen Inhalt (Modellen) und Form (Ansichten) sowie den gleichzeitigen Einsatz generischer statt hartverdrahteter Dialoge –, erfordert aber ein Maß an Ausdauer und Disziplin, das längst nicht jeder erbringt.

Vom Einzelfall zur Plattform Drittens schlägt in diesem Zusammenhang wieder eine oben erörterte Tatsache zu Buche: In Phasen hohen Zeitoder Erfolgsdrucks gerät die Strukturierung in Gefahr, wenn ihre Verletzung

Zur Rolle von DSLs in Plattformprojekten Besonderer Beliebtheit erfreuen sich in den letzten Jahren Domain-Specific Languages – zu Recht. Gerade im Zusammenhang mit Plattformprojekten lässt sich festhalten, dass DSLs bei richtiger Anwendung enorme Vorteile bieten. Die Kunst beim Entwurf einer DSL für ein Projekt besteht darin, genau die Aspekte in der Sprache abzubilden, bei denen dieses Vorgehen der händischen Formulierung in regulärem Code (beispielsweise in C) oder in Metadateien zum Build-Prozess (etwa Makefiles) spürbar überlegen ist. Dabei sollte der Begriff „domain“ nicht darüber hinwegtäuschen, dass dies nicht nur für fachliche, sondern auch für technische Aspekte gilt. DSLs sind also nicht nur dafür geeignet, fachliche Artefakte wie BusinessProzesse auf einem höheren Abstraktionsniveau zu beschreiben; dasselbe können sie für technische Artefakte leisten. Aus vielerlei Gründen kann die Beschreibung technischer Entitäten in einer DSL sinnvoll sein. Ein Paradebeispiel ist die

Vermeidung von handgeschriebenem „Boilerplate Code“, also die Vermeidung vieler Codepassagen mit großer Ähnlichkeit. Hierzu müssen die Informationen, die die geringen Unterschiede zwischen diesen Passagen ausmachen, auf einem höheren Abstraktionsniveau formuliert und die entsprechenden Codefragmente daraus generiert werden. Ein händisches Ausprogrammieren der repetitiven Passagen hingegen wäre nicht nur eine Verschwendung kreativer Entwicklerenergie, sondern auch eine notorische Fehlerquelle. In fachlicher Hinsicht nutzt man DSLs unter anderem dazu, für den Kunden relevante Konstellationen und Abläufe derart zu formulieren (und in Code zu überführen), dass man Domänenexperten auch ohne Kenntnis der Programmiersprache oder sonstiger technischer Details einbeziehen kann. Bei Plattformprojekten bietet es sich an, die Unterschiede zwischen den einzelnen Ausprägungen der Software in DSLs zu beschreiben. Dieses Vorgehen gestattet es,

102

die Unterschiede ausdrücklich zu formulieren, statt sie implizit im Code zu verbergen (etwa durch #ifdef-Konstrukte, die bei umfangreichem Einsatz schwer wartbar sind). Auf fachlicher Ebene könnten die Entwickler beispielsweise die Features pro Ausprägung definieren – der Code und zugehörige Metadaten würde aus diesen Definitionen generiert. Auf technischer Ebene wiederum könnten sie Details zu den beteiligten Software- oder Hardwaremodulen formulieren, mit deren Hilfe der BuildProzess oder auch die Konfiguration von Treibern gesteuert werden. Hier zeigt sich, dass DSLs in Plattformprojekten zum Teil denselben Voraussetzungen unterliegen wie die eigentliche Software: Der sinnvolle Einsatz domänenspezifischer Sprachen setzt voraus, dass den am Projekt Beteiligten klar ist, inwiefern sich die diversen Ausprägungen – anders gesagt: die Instanzen – der Plattform voneinander unterscheiden werden. Gefragt ist somit einmal mehr ein genaues Verständnis der Variabilität.

iX 6/2011

©

Copyright by Heise Zeitschriften Verlag


ix.0611.100-103

16.05.2011

10:07 Uhr

Seite 103

kurzfristige und besser sichtbare Fortschritte ermöglicht. Das Nichteinhalten der Architektur zeigt sich häufig erst wesentlich später – etwa, wie oben angedeutet, bei einem Review zur Wiederverwendbarkeit. Die zentrale Herausforderung bei Plattformprojekten liegt in einer Potenzierung der aufgeführten Problemquellen, allen voran der erstgenannten: Randbedingungen. Weil es schon schwierig ist, eine Software angesichts in Bewegung befindlicher Anforderungen und Technologieentscheidungen zu strukturieren, gilt dies erst recht für eine Plattform, die den Anforderungen und Eigenschaften verschiedener oder gar zukünftiger Produkte gerecht werden soll.

Jede Strukturierung ist zunächst durch Einschränkungen charakterisiert

Eine übliche, aber problematische Antwort auf diese Herausforderung besteht darin, die von Unsicherheiten betroffenen Schnittstellen derart zu verallgemeinern, dass sie jede Eventualität gestatten. In der Praxis finden sich beispielsweise Datenbankschemata, die neben einigen konkreten Elementen ein spezielles Feld für die Einbettung beliebig großer binärer Blobs oder XML-Strings mit weiteren Informationen vorsehen. Diese Vermengung von Daten zweier grundsätzlich verschiedener Abstraktionsniveaus schlägt sich meistens in schlechtem Code nieder. Der Code reflektiert diese Vermengung, weil er sowohl mit den konkreten fachlichen Elementen als auch den technischen Spezifika der generischen Rohdaten umgehen können muss. Ein vergleichbarer Fall liegt bei Hardwaretreibern vor, deren Schnittstellen zu stark verallgemeinert wurden – etwa in der Form, dass eine den Treiber nutzende Komponente zur Laufzeit zunächst Details der tatsächlichen Hardware-Auslegung über spezielle Funktionen erfragen und Code für jede denkbare Antwort vorsehen muss, bevor sie den Treiber in sinnvoller Weise einsetzen kann. Das Überverallgemeinern einer Schnittstelle ist deshalb so kritisch, weil es ihre strukturierende Wirkung zunichte macht. Wenn die Schnittstelle einer Komponente alles zulässt, muss

jeder, der sie verwendet, auf alles gefasst sein. Der Irrtum, dass eine derart überzogene Verallgemeinerung eine valide Form von Abstraktion darstellen könnte, wird dadurch entlarvt, dass sie undicht (also eine „leaking abstraction“) ist. Zwar werden technische Details aus rein statischer Sicht vielleicht noch verborgen, allerdings müssen sie zur Laufzeit mühselig über die Schnittstellengrenzen nach oben publiziert werden. Die übergeordneten Komponenten erben somit die Verantwortung, mit den eigentlich zu verbergenden Details umzugehen – dies ist das Gegenteil von Abstraktion. Ein zweiter, nur geringfügig angenehmerer Weg bei der Konstruktion von Plattformarchitekturen verläuft über Erfahrungswerte: An Stellen, an denen größere Unsicherheiten herrschen, versucht man, zumindest die wahrscheinlichsten Ausgänge zukünftiger Entscheidungen abzudecken. Auch dieses Vorgehen ist aber wenig mehr als eine Form von Notwehr gegenüber der verzögerten Klärung von Anforderungen und anderen Randbedingungen. Die ideale Reaktion auf die hier diskutierte Herausforderung der unsicheren Randbedingungen ist ungleich anspruchsvoller. Sie besteht in einer von allen Interessenvertretern getragenen, ernsthaft durchgeführten Variabilitätsanalyse, die zwei hehren Zielen dient.

Varianten stets im Blick behalten In technischer Hinsicht hülfe eine solche Analyse dabei, ein klares Bild davon zu ermitteln, welche Einschränkungen der Softwarearchitekt annehmen darf und welche möglichen Varianten er berücksichtigen muss. Dies schafft die Strukturen bezüglich Anforderungen und Technologien, die für die Konzeption einer erfolgreichen Plattformarchitektur notwendig sind (die erforderliche technische Expertise vorausgesetzt). Natürlich kann die Analyse einige Iterationen durchlaufen und muss dies üblicherweise auch tun – wichtig ist dabei nur, dass man möglichst viele der zentralen Fragen und Risiken früh angeht, um dem Prozess der Architekturdefinition einen konkreten Weg zu ebnen. In organisatorischer Hinsicht kommt der Analyse eine weitere wichtige Funktion zu, nämlich die, die Projektbeteiligten mit offenen Augen durch

den Prozess der Plattformdefinition zu führen. Gerade für Interessenvertreter mit nichttechnischen Schwerpunkten ist meist kaum ersichtlich, welche Änderungswünsche welche Auswirkungen nach sich ziehen und welche Fragen zur Variabilität die Plattform am stärksten betreffen. Die zur Schaffung der Voraussetzungen für eine Plattform wichtige Zusammenarbeit zwischen verschiedenen Abteilungen setzt eine interdisziplinäre Arbeitskultur voraus, die sich nicht immer leicht etablieren lässt.

Die Vermengung von Daten zweier grundsätzlich verschiedener Abstraktionsniveaus schlägt sich meistens in schlechtem Code nieder

Eine Variabilitätsanalyse ist insofern anspruchsvoll, als sie relativ früh im Projekt drei unbequeme Forderungen stellt: Erstens müssen sich alle Interessenvertreter die Zeit nehmen, in der jeweiligen Rolle an der Analyse mitzuwirken. Dies ist aufgrund parallel laufenden Tagesgeschäfts oft schwierig zu erreichen. Zweitens muss das Management dazu bereit sein, den mit der Analyse verbundenen Aufwand hinzunehmen, auch wenn die positiven Folgen erst langfristig Sichtbarkeit erlangen. Diese Zukunftsorientierung ist vor allem in Kulturkreisen mit kurzfristigen Erfolgsmetriken schwer zu etablieren. Drittens ist die allgemeine Bereitschaft zur Entscheidungsfindung Voraussetzung dafür, dass die Arbeiten eine konkrete Richtung einschlagen können. Dieser dritte Punkt setzt zudem voraus, dass nicht messbare oder unterspezifizierte Anforderungen entweder präzisiert oder aufgegeben werden. Folglich erfordern ernst gemeinte Plattformprojekte von allen Beteiligten – quer durch alle Disziplinen – ein Bekenntnis zum Plattformgedanken. Dabei muss klar sein, dass der Weg zur Plattform keine gewöhnliche technische Anforderung darstellt, sondern budgetiert und von allen Interessenvertretern mit beschritten werden muss. (ka)

DR. DANIEL MÖLLE ist bei der Zühlke Engineering GmbH als Softwarearchitekt mit den Schwerpunkten eingebettete Systeme und .Net tätig. x 103

iX 6/2011

©

Copyright by Heise Zeitschriften Verlag


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.