Wissensmanagement und Software Engineering - Reverse Engineering

    23. Juli 2001 von Dr. Bernhard von Guretzky

    Dieses Papier ist der zweite Teil einer Serie von Artikeln, in der die Bedeutung des Wissensmanagement für das Software Engineering beschrieben wird. Die diesem Ziel dienenden Schlüsseltechnologien sind `Expert Assistance`, das `Kooperative Arbeiten`, `Projektmanagement und Decision Support`, die `Wiederverwendbarkeit` und das `Reverse Engineering`. Dieser Teil ist dem `Reverse Engineering` gewidmet.

    If we would construct our buildings,
    our powerstations or aircraft
    in the same way we develop our software,
    civilisation the way we know it
    would come to an abrupt end.
    Edward Murphy

    Problemstellung

    Kaum ein großes und komplexes Computersystem ist ohne Bezugnahme auf andere, vergleichbare Systeme entwickelt worden. Zumindest das Systementwicklungs-Know-how findet Eingang, wenn nicht sogar Teile des Anforderungskatalogs, des Designs oder sogar des Programmcodes. Um die Erstellung von Software zu einer Ingenieursdisziplin zu machen, muss die Entwicklung neuer Systeme auf schon existierenden aufbauen, damit der technische Fortschritt sichergestellt wird. Oder anders ausgedrückt: Das für die Entwicklung eines existierenden Systems notwendige Wissen, das quasi dort `eingefroren` ist, soll bei Neu- und Weiterentwicklungen wieder zum Tragen kommen.

    Dieses Vorgehen kann mit dem Schlagwort `Modifikation statt Innovation` bezeichnet werden: Anstatt einen großen Entwicklungsschritt im Entwurf oder der Implementierung zu tun, besteht die Entwicklung vielmehr in einer Vielzahl von Modifikationen eines vorliegenden Systems. Software Engineering wird dadurch zu einer evolutionären statt revolutionären Disziplin wie andere Ingenieurswissenschaften auch.

    Mit der Verbreitung formaler Sprachen in der Systementwicklung ist es möglich geworden, den Prozess der Softwareentwicklung von der Formulierung der Anforderungen bis zur Erzeugung des Programmcodes schrittweise zu automatisieren. Diese Technik hat in überschaubaren Datenbankapplikationen bereits schon zu großen Fortschritten geführt. Hingegen ist die Entwicklung hochkomplexer eingebetteter Realzeitsysteme ein sehr kreativer und vielschichtiger Prozess, der sich - wenn überhaupt - eher in iterativen Schritten automatisieren lässt.

    Die Produktivität, gemessen in Programmzeilen pro Tag, ist im wesentlichen unabhängig von der verwendeten Programmiersprache. Sie wird vielmehr einerseits durch die Komplexität der Aufgabenstellung beeinflusst und andererseits durch das Know-how des Entwicklers bestimmt. Daher müssen radikal neue Ansätze zur Steigerung der Produktivität gesucht werden, wie etwa:

    • die Verwendung von `very high level languages` (vhll), die sowohl Designer als auch Programmierer von der Beschreibung der Datenstrukturen befreit
    • das `programming by example`, das die Gemeinsamkeiten von bereits implementierten Systemen und neuen Projekten bestimmt und auf deren Grundlage in den folgenden, schrittweisen Veränderungen ein System geschaffen wird, das schließlich den neuen Anforderungen genügt.

    Der hohe Grad von Komplexität und das eingeschränkte Abstraktionsvermögen des Menschen limitiert den Einsatz der vhll. Im vorliegenden Papier konzentriert sich die Diskussion daher auf die formale Beschreibung von komplexen Computersystemen und der sich daraus ergebenden Möglichkeiten der automatischen Programmerstellung durch `Umdrehung` des Entwicklungsprozesses. Die Aspekte der Verifikation und Validierung, die Generierung von Testsequenzen, die Dokumentation und Wartung werden hier nicht behandelt, sondern sind einer späteren Diskussion vorbehalten.

    2. Grundprinzipien der Systementwicklung

    Die Aufgabe, die ein Computersystem zu erfüllen hat, ist bestimmt durch die Anforderungen, die an das System im Vorfeld gestellt wurden. Erfüllt es diese Anforderungen nicht, so hat die Entwicklung ihren wesentlichen Zweck verfehlt. Je nach Komplexitätsgrad handelt es sich dabei um ein `stand-alone` - System, dessen Funktion durch äußere Parameter bestimmt wird, oder um vernetzte Einzelsysteme, die gegebenenfalls über Geräte mit der Außenwelt kommunizieren. Im letzteren Fall werden diese Geräte als `Umgebung` eines eingebetteten Computersystems (ECS) bezeichnet. Darüber hinaus sind ECS in den meisten Fällen Realzeitanwendungen, d.h. Antwortzeiten, sowie die Fähigkeit parallel eingehende Signale gleichzeitig zu verarbeiten spielen eine weitere wichtige Rolle. Im ersteren Fall handelt es sich typischerweise um Datenbankanwendungen, dessen Komplexitätsgrad und Qualitätsanforderungen erheblich geringer sind, woher auch die weitaus höhere Produktivität im Vergleich zur Entwicklung von ECS rührt. Die folgenden Überlegungen beziehen sich besonders auf eingebettete Computersysteme, was ihre Gültigkeit jedoch für die andere Klasse von Anwendungen in keiner Weise einschränkt.

    Die Implementierung eines Computersystems umfasst ein oder mehrere Computerprogramme (Software) und ein oder mehrere Zielsysteme (Hardware). Die Software kann somit als zielorientierte, `ablauffähige Spezifikation` des Computersystems betrachtet werden.

    Im Falle von eingebetteten Computersystemen wird eine Transformation der Anforderungen in eine zielorientierte, ablauffähige Spezifikation inklusive der Steuerung von Geräten wohl nur in den aller simpelsten Fällen möglich sein. Im Normalfall erfordert die Entwicklung eines ECS einen konzeptuellen, phasenorientierten Ansatz, der im wesentlichen darauf beruht, dass bei der Spezifikation sowohl allgemeine (i.e. `funktionale`) als auch implementierungs- und geräteabhängige (i.e. `nicht-funktionale`) Anforderungen berücksichtigt werden müssen. Die funktionalen Anforderungen allein führen zu einer von der Implementierung unabhängigen Systembeschreibung, dem sog. `essentiellen Modell` (essential model). Es umfasst

    • eine möglichst vollständige Beschreibung des Systemverhaltens im Normalfall und
    • eine Beschreibung von Ausnahmesituationen oder Wiederanlaufverhalten u.ä.

    Eine solche komplette Beschreibung des essentiellen Modells, die weder implementierungsspezifische Annahmen noch Hypothesen über das Verhalten der Umgebung enthalten darf, heißt `Spezifikation`.

    Das essentielle Modell muss dann um die implementierungsabhängigen, nicht-funktionalen Anforderungen erweitert werden. Die daraus abgeleitete Spezifikation wird als `physisches Modell` (physical model) bezeichnet, das neben einer funktionalen Beschreibung des Zielsystems auch implementierungsspezifische Punkte wie Performanz, Sicherheitseigenschaften und Fehlerbehandlung der Hard- und Software enthält. Die logische Validierung des physischen Modells und seine Umsetzung in eine verifizierbare und veränderbare Struktur wird als `Softwareorientiertes Design` bezeichnet, seine Umwandlung in eine zielorientierte, ausführbare Spezifikation heißt `Implementierung`.

    3. Abstraktion, Extraktion und Adaption

    Die Erstellung eines essentiellen Modells, in dem das logische Verhalten eines neu zu entwickelnden Computersystems - dem sog. `nominalen essentiellen Modell` -beschrieben ist, muss nicht notwendigerweise mit dem berühmten leeren Blattpapier beginnen. Voraussetzung dafür ist allerdings, dass auf ein physisches Modell eines ähnlichen Systems, dem sog. `aktuellen physischen Modell` (actual physical model), zurückgegriffen werden kann. Das neu zu erstellende `aktuelle essentielle Modell` kann aus dem aktuellen physischen Modell, das nominale essentielle Modell aus dem aktuellen essentiellen Modell abgeleitet werden. In den beiden abgeleiteten Modellen steckt somit das Know-how und das Wissen, das notwendig für die Entwicklung der Vorgängermodelle war. Dieser Ableitungsprozess erfolgt durch eine schrittweise Adaption der Unterschiede der funktionalen und nicht-funktionalen Anforderungen zwischen dem aktuellen = dem bereits vorhandenem, und dem nominalen = dem zu entwickelnden Computersystem. Der wesentliche intellektuelle Aufwand steckt also in der Abstraktion des aktuellen essentiellen und physischen Modells unter Einbeziehung von Wissen über:

    • den Entwicklungsprozess (Software Engineering) selbst,
    • über das Fachgebiet, für das dieses System entwickelt wird (Anwendungswissen),
    • die beteiligten Systeme oder Produkte (Produktwissen) und
    • sogenanntes Kontext- bzw. organisationales Wissen

    Der Erfolg der in Abbildung 2 visualisierten Prozedur von Abstraktion, Extraktion und Adaption zur Ableitung eines nominalen essentiellen und physischen Modells hängt von geeigneten Spezifikationssprachen ab. Zwei Klassen solcher formaler Sprachen werden dabei unterschieden. Die sog. modellorientierten Sprachen wie Strukturierte Analyse, Zustandsdiagramme oder Petrinetze dienen zur Spezifikation von:

    • Hierarchien und Ereignisstrukturen
    • Datenobjekten
    • Datenverarbeitung (`abstract data types`)
    • Ereignisverarbeitung (`abstract machines`)

    Dagegen dienen die sog. eigenschaftsorientierten Sprachen wie Prolog, temporale und modale Logik zur Spezifikation von:

    • logischen oder zeitlichen Abhängigkeiten
    • Fakten oder Regeln
    • Invarianten oder
    • Bedingungen und Grenzwerten

    Netze sind eine natürliche Art, Strukturen, Abhängigkeiten und Beziehungen von realen Objekten darzustellen. Da besonders in eingebetteten Realzeitsystemen mehrere Hierarchieebenen modelliert werden müssen, können Netze dazu benutzt werden, die Prozesskommunikationen zwischen Objekten und die zugehörigen Daten- und Kontrollflüsse aufzuzeigen.

    Der Zyklus von Abstraktion, Extraktion und Adaption kann durchaus mehrere Male durchlaufen werden, bis das `passende` nominale physische Modell abgeleitet worden ist. Dieser Zyklus ist damit dem Prototyping nicht unähnlich.

    4. Abstraktion des physischen Modells

    Die Abstraktion eines aktuellen physischen Modells aus einem ablauffähigen Computersystem ist selbst ein iterativer Prozess, in dem quasi die Entwicklungsschritte umgedreht werden:

    1. Auftraggeber und Auftragnehmer für das künftige System erstellen gemeinsam einen Anforderungskatalog, auf dessen Basis eine Designspezifikation vorzugsweise in einer formalen Sprache erstellt wird.
    2. In einer Reihe von Entwicklungsschritten wird dann diese Spezifikation in eine ausführbare Spezifikation umgewandelt.

    In dem oben angedeuteten Prozess muss dann folgendes Problem gelöst werden:

    1. Gegeben ist eine Problembeschreibung und ein (aktueller) Anforderungskatalog mit der dazugehörigen Implementierung, also dem ablauffähigem Code in einer beliebigen Programmiersprache.
    2. Gesucht ist ein physisches Modell, das in einer formalen Sprache das Verhalten des Computersystems beschreibt und ein zugehöriger möglichst vollständiger und widerspruchsfreier Anforderungskatalog.

    Die formale Systembeschreibung ist also aus der Implementierung abzuleiten. Diese Ableitung kann als eine schrittweise Abstraktion betrachtet werden, deren Ausgangspunkt der Quellcode und deren Ergebnis die formale Systembeschreibung ist. Ein solcher Prozess ist vergleichbar mit einer Recompilation, die auf der Basis von ablauffähigem Maschinencode manipulierbaren Quellcode erzeugt. Der Abstraktionsprozess basiert dabei auf

    • Wissen über die verwendete Programmiersprache und den dabei üblichen best practices. Das Ergebnis ist eine erste Abstraktion der Implementierung.
    • Wissen über Designmethoden. Das Ergebnis ist eine formale Designspezifikation.
    • Wissen über die ursprünglichen Anforderungen an das System

    In einem zweiten Abstraktionsschritt werden dann die wesentliche Entscheidungen im Entwicklungsprozess (`bifurcation points`) festgehalten: Warum wurde sich für eine bestimmte Methode bei der Implementierung entschieden? Warum wurden Alternativen verworfen? Diese Informationen, die meist nur kurzfristig in den Köpfen der Designer und Programmierer verbleiben, sind nicht nur für das spätere Produktmanagement (Wartung und Unterstützung) von entscheidender Bedeutung. Das Fehlen dieses Wissens vermindert darüber hinaus die Möglichkeit der Wiederverwendung von Objekten in nachfolgenden vergleichbaren Projekten.

    Ist auf diese Weise nun eine formale Systembeschreibung erstellt worden, so kann daraus wieder in iterativen Schritten ein ausführbares Programm erstellt werden. Schrittweise werden so die Anforderungen in eine zielorientierte Spezifikation transformiert. Dieser Transformationsprozess berücksichtigt die in den Anforderungen meist noch nicht enthaltenen Informationen

    • über verwendete Daten und ihre inneren Strukturen,
    • wie auf Ereignisse und Umgebungszustände zu reagieren ist,
    • über Kontrollflüsse oder Prozeßsynchronisation und
    • über die Programmstrukturen

    Darüber hinaus müssen Anforderungen an die Performanz des Gesamtsystems berücksichtigt werden sowie Anforderungen, die sich aus den gekoppelten Geräten und der verwendeten Entwicklungsumgebung (Betriebssystem, Programmiersprache etc.) ergeben. Das Ergebnis dieser ausführbaren Spezifikation ist der `Beweis` des nominalen Anforderungskatalogs.

    5. Extraktion eines essentiellen Modells

    Es liegt auf der Hand, dass bei dem Zyklus Abstraktion - Extraktion - Adaption die Anwendungsgebiete und die Anforderungen, die Kontexte also der aktuellen und nominalen Systeme ähnlich sein müssen: Auf der Basis eines datenbankbasierten Decision Support Systems (DSS) wird sich kein Unterstützungssystem entwickeln lassen, das Piloten vor feindlichen Raketenstellungen warnt; die Unterschiede wären zu groß, um einen technischen Fortschritt mit dieser Methode erzielen zu können. Hingegen lassen sich Teile von verschiedenen Systeme verwenden, um eine breitere Basis für ein neues System zu schaffen. So lassen sich beispielsweise die Methoden, die üblicherweise in DSS verwendet werden, auch in Onboard-Systemen einsetzen, um Piloten Entscheidungsmöglichkeiten in einem konkreten Bedrohungsszenario vorzuschlagen.

    Ausgehend von einer nun vorliegenden ablauffähigen formalen und damit manipulierbaren Spezifikation lassen sich jetzt interaktiv neue funktionale und nicht-funktionale Anforderungen in die nominale Systembeschreibung einbringen. Auf Basis der formalisierten Spezifikation des aktualen Systems, des zugehörigen Anforderungskatalogs und des Kontextwissens können das aktuale physische Modell und das essentielle Modell extrahiert werden.

    6. Adaptierung der Modelle

    Die wesentliche Aufgabe im Reverse Engineering besteht darin, ein vorliegendes Modell so zu adaptieren, dass es gewissen neuen Anforderungen entspricht. Um es den nominalen Anforderungen anpassen zu können, muss eine Verbindung zwischen dem zu implementierenden, dem sog. `internen` Modell und dessen externer Darstellung, welches die nominalen Anforderungen dann tatsächlich auch erfüllt, hergestellt werden. Während die externe Darstellung also beschreibt, was das nominale System tut, wird im internen Modell beschrieben, wie es getan wird.

    Formal betrachtet geht es dabei um folgenden Prozess: Essentielle und physische Modelle sowie Spezifikationen (Design, Anforderungen) können als Elemente eines abstrakten Raumes betrachtet werden. Die Adaption eines internen Modells mitsamt dessen externer Darstellung durch Manipulation der Eigenschaften und Anforderungen ist dann nichts anderes als die Abbildung fi eines Systems S auf seine Eigenschaften e1,...,en, wobei ei Element eines Raumes E der möglichen Realisierungen und deren Umgebung ist, also aller möglichen `Instanzierungen` des Zielsystems, die die vorgegebenen funktionalen und nicht-funktionalen Anforderungen erfüllen. n bezeichnet dabei die Anzahl der Iterationsschritte, bis die nominalen Anforderungen erfüllt sind. In mathematischer Schreibweise sieht das dann folgendermaßen aus: fi (S) = ei , i = 1,...,n

    Ein Modellinterpreter kann dann durch semantische Interpretation oder numerische Simulation die Instanzierung eines Modells fi (S) ableiten, ohne das System selbst für eine reale Plattform zu implementieren.

    Der erste Iterationsschritt bei dieser Modellmanipulation ist der Vergleich mit den aktuellen Modelleigenschaften und den nominalen Anforderungen, die auf folgenden Annahmen beruhen:

    • Regularität: Die Unterschiede in der externen Darstellung eines Modells lassen sich eins-zu-eins auf Unterschiede der internen Modelle zurückführen.
    • Linearität: Die Unterschiede zwischen der externen Darstellung und des internen Modells sind unabhängig von implementierungsspezifischen Parametern.
    • Reihenfolge: Im allgemeinen sind viele Veränderungsschritte notwendig, damit das nominale System den Anforderungen vollständig genügt. Da diese Adaptionen sich jedoch gegenseitig beeinflussen, der gesamte Prozess damit nicht-linear ist, sind zusätzliche Iterationsschritte notwendig, damit das Zielsystem tatsächlich `konvergiert` (d. h. sich den Anforderungen annähert), ist die Reihenfolge der einzelnen Adaptionsschritte zu beachten.

    Die Annahmen der Regularität und Linearität führen zu einer Stetigkeit im Adaptionsprozess, d.h. kleine Änderungen der Anforderungen haben auch nur kleine Veränderungen im Systemverhalten zur Folge.

    Die richtige Reihenfolge (`sequencing`) setzt Implementierungs- und Kontextwissen voraus. In jedem Adaptionsschritt muss der Modellinterpreter überprüfen, wieweit das Modell fi(S) bereits mit dem nominalen Modell übereinstimmt. Erweist sich fi(S) noch als inadäquat und zu restriktiv ist ein weiterer Iterationsschritt notwendig

    [Standard] Namensnennung 3.0 Deutschland - Weitergabe unter gleichen Bedingungen 3.0 Deutschland
    Lizenziert unter einer Creative-Commmons Lizenz

Kommentare

Das Kommentarsystem ist zurzeit deaktiviert.