Zum Problem der Portabilität von Anwendersoftware:

Höhere Programmiersprache kein Garant für Kompatibilität

22.07.1977

MÜNCHEN (uk) - Bei der Aufgabe, Anwendersoftware auf eine andere Maschine zu übertragen, stellt sich bald heraus, daß die Verwendung einer höheren Programmiersprache kein perfektes Werkzeug für die Portabilität ist. Es gibt Zahlen, die besagen, daß für ein Programm mit 10 000 lines of code mindestens ein Aufwand von einem Mannmonat erforderlich ist, um dieses Programm auf einer anderen Maschine ablauffähig zu machen. Dieter Schulze von der Gesellschaft für Systementwicklung (GFS) beschreibt im folgenden Beitrag das Problem der Übertragbarkeit von Anwendungssoftware.

Die Bemühungen um Portabilität müssen sich auf zwei Schwerpunkte konzentrieren:

- die Erzielung von Maschinenunabhängigkeit durch Programm-Design und Programmiertechnik.

- den Übertragungsmechanismus einschließlich der erforderlichen Entwicklungs- und Teststrategie.

Der einfachste Weg, "portable" Software zu erstellen, wäre die strikte Beschränkung auf die Verwendung jener Komponenten der System- und anwenderorientierten Systemsoftware, die das "kleinste gemeinsame Vielfache" aus den einzelnen Systemen darstellen und damit voll portable sind. Dieses "kleinste gemeinsame Vielfache" ist aber nicht ausreichend, um Anwendersoftware herstellen zu können, da es Elemente gibt, die außerhalb des Gemeinsamen liegen und für die es in den einzelnen Systemen keine Alternativen gibt. Da die Anwendersoftware nur durch die Verwendung von Systemsoftware und anwenderorientierter Systemsoftware ablauffähig ist, ergeben sich daraus unterschiedliche Portabilitätsbedingungen.

Unterschiedliche, DB-Systeme erschweren die Übertragbarkeit

Hauptvoraussetzung für die Portabilität der Anwendersoftware in bezug auf die Systemsoftware ist ein übertragbares Coding. Ein solches Coding kann durch die Einhaltung folgender Bedingungen geschrieben werden, wobei die Verwendung einer höheren Programmiersprache vorausgesetzt wird:

- Verwendung nur der Statements, die auf jeder Zielmaschine sowohl syntaktisch als auch semantisch identisch sind, das heißt den gleichen Objektcode erzeugen

- Verwendung von Copy's für solche Code-Teile, die nicht portable, aber unbedingt erforderlich sind, weil sie sich in einem gegebenen System nicht anders darstellen lassen. Dabei werden die systemspezifischen Codeteile zur Umwandlungszeit in das portable Coding eingefügt, weil in der Copy-Bibliothek jeder Zielmaschine die speziellen Codeteile enthalten sind

- Berücksichtigung maschineninterner Parameter wie zum Beispiel Wortausrichtung, Anzahl gepackter Zeichen in einem Wort, unterschiedliche Möglichkeiten der Vorschubsteuerung etc.

- Verwendung eines "General-Purpose Macroprocessors", eines Editors oder eines "String Processors" zur Aufbereitung des Source-Code für eine bestimmte Zielmaschine.

Die Optimierung von portabler Anwendersoftware ist in bezug auf eine einzelne Zielmaschine unter Berücksichtigung dieser Faktoren allerdings nur noch sehr begrenzt möglich. Neben solchen Programmierregeln ist das Programm-Design von besonderer Bedeutung. Insbesondere wenn

- die Bedingungen von realen und virtuellen Betriebssystemen zu berücksichtigen sind

- mit unterschiedlichen DB-Systemen gearbeitet werden muß, wobei es besonders schwierig wird, wenn die Daten auch noch unterschiedlich strukturiert abgebildet werden müssen

- verschiedene TP-Monitore zu verwenden sind

- unterschiedliche Job-Control-Languages zur Verfügung stehen

Generatoren müssen portablen Code erzeugen

Trotz der unter Umständen beträchtlichen Restriktionen, die durch die verschiedene Systemsoftware bedingt ist, ergeben sich wesentlich größere Schwierigkeiten aus der Verwendung von anwenderorientierter Systemsoftware. Unter anwenderorientierer Systemsoftware soll im Sinne von Tools die Summe der verfügbaren Funktionen verstanden werden, die zwar nicht Bestandteil der Systemsoftware sind, aber zur Unterstützung und Erleichterung der Anwendungsprogrammierung quasi als Systemsoftware betrachtet und benutzt werden.

Ein Teil dieser Tools, der unverzichtbar ist, nicht portabel gemacht werden kann und durch den die eigentlichen Probleme entstehen, läßt sich wiederum in zwei Gruppen unterteilen:

- solche Tools, die als Objekt-Code zur Verfügung stehen und zur Anwendersoftware in irgendeiner Form zur Compile- oder Runtime dazugelinkt werden, und

- solche Tools, die erst Source-Code erzeugen wie zum Beispiel Preecompiler, Generatoren etc.

Für beide Fälle gilt als Voraussetzung für die Verwendung dieser Werkzeuge unter der Bedingung der Portabilität ein sehr gutes Programm. Design und exakte logische Schnittstellen zu allen, insbesondere zu den nichtkompatiblen Systemkomponenten. Für die zuerst genannten Tools kann Portabilität erreicht werden, wenn jede erforderliche Funktion auf jeder Zielmaschine verfügbar ist. Voraussetzung ist allerdings, daß die je Funktion zu benutzende Schnittstelle das "größte gemeinsame Vielfache" auf allen Zielmaschinen enthält und, daß die Verbindung zu den Tools auf rein logische Ebene beschränkt bleibt.

Die Precompiler, Programmgeneratoren etc. können natürlich, falls verfügbar, auf jeder Zielmaschine autonom eingesetzt werden. Es ist nur sicherzustellen, daß der erforderliche Input für die Tools in der Form portable sein muß, daß der erzeugte Source-Code logisch identisch ist. Eine Weiterentwicklung dieses Source-Codes ist nicht sinnvoll, da diese Weiterentwicklung dezentral erfolgen müßte. Deshalb sollten Source-erzeugende Tools nur auf einer bestimmten Quell-Maschine so eingesetzt werden, daß portabler Code erzeugt wird, der dann weiterentwickelt und auf die Zielmaschine übertragen werden kann.

Änderungsintensität kontra Kompatibilität

Für die Entwicklung portabler Anwendersoftware sind zwei Wege möglich:

- Die Anwendersoftware wird ohne Berücksichtigung von Portabilitätsanforderungen auf einer, bestimmten Maschine in der Regel für diese Maschine entwickelt. Anschließend wird die Anwendersoftware auf andere Systeme Übertragen.

- Bei der Konzipierung wird die Anwendersoftware so ausgelegt, daß sie mindestens für bestimmte, bekannte Systeme, möglichst aber ganz allgemein (maximal) portable ist.

Beide Wege unterscheiden sich lediglich in ihrem Aufwand, aber trotzdem keineswegs in der allgemeinen Vorgehensweise.

Der geringste Aufwand ist erforderlich, wenn vor der Programmentwicklung die Zielmaschinen bekannt sind. Er kann unter Umständen sehr beträchtlich werden, wenn bedingt durch das Programm-Design und Verwendung von nichtkompatibler Systemsoftware oder anwenderorientierten Systemsoftware beziehungsweise spezieller Bedingungen der verwendeten Job-Control-Language eine 1:1-Umstellung nicht möglich ist. Dabei wird unter 1:1-Umstellung lediglich das Umwandeln und Binden auf der neuen Zielmaschine verstanden. Bei Verwendung sehr spezieller Systemkomponenten, die auf der neuen Zielmaschine nicht oder nicht in der verwendeten Form zur Verfügung stehen, kann ein komplettes Redesign erforderlich werden.

Ein sehr großer Aufwand ergibt sich auch für solche Softwarepakete, die einer kontinuierlichen Weiterentwicklung und damit ständigen Änderung unter unterliegen.

Systemneutrale Schnittstellen

Grundsätzlich wird die Portabilität über Sources hergestellt, das heißt es wenden generell Sources auf die Zielmaschine übertragen. Dabei werden die Sources, die portable sind, zentral auf der Quell-Maschine verwaltet, während einzelne Teile, die systemspezifisch und somit nicht austauschbar sind, dezentral, das heißt jeweils auf der Zielmasche verwaltet werden. Das kann so erfolgen, daß entweder mittels Copy oder Unterprogrammtechnik, aber auf jeden Fall über systemneutrale Schnittstellen die systemspezifischen Teile zur Compile-bzw. Linkzeit zusammengefügt werden. Jobs beziehungsweise Proceduren etc. sollten auf jeden Fall dezentral verwaltet werden. Für das erstmalige Übertragen auf eine Zielmaschine ist ein iterativer Prozeß erforderlich, der aus folgenden Schritten besteht:

- Übertragen der fertig ausgetesteten Anwendersoftware auf die Zielmaschine sowie einmaliges Einrichten von Testdateien.

- Austesten auf der Zielmaschine bis zur völligen Fehlerfreiheit.

- Rückübertragung des Paketes auf die Quell-Maschine und erneuter Test oder Nachfahren der erforderlichen Änderungen auf der Quell-Maschine.

- Im Falle des Auftretens von Fehlern ist eine Korrektur und nach Fehlerfreiheit wieder die Übertragung auf die Zielmaschine usw. erforderlich.

- Existieren mehrere Zielmaschinen so muß dieser Prozeß jeweils für die n-1 Zielmaschinen wiederholt werden.

Aus dem enormen Aufwand, der mit solcher Vorgehensweise verbunden ist, ergibt sich sofort die Forderung, Programmänderungen nur auf einer der Quell-Maschinen auszuführen, und zwar in einer Weise, daß auf der Zielmaschine keine weiteren Tests mehr erforderlich sind und die Programme sofort ablauffähig sind. Einzige Einschränkung ist, daß sich etwas an den systemspezifischen Teilen ändert, die dezentral verwaltet werden. Das sollte eine Maschine sein, die, falls keine territorialen Bedingungen zu berücksichtigen sind,

- eine gute Bibliotheksverwaltung besitzt

- Timesharing und "Interactic Debugging Aid" hat

auch wenn dadurch möglicherweise Probleme der, Abwärts-Portabilität entstehen.

Bei der erforderlichen Übergabe neuer Versionen sollte insbesondere, wenn das Paket stark modularisiert ist und mit Copys arbeitet, nicht nur einzelne Teile, das heißt die Teile, die verändert wurden, übergeben werden, sondern das gesamte Paket. Fehler, deren Ursache in der falschen Verwaltung nicht zusammengehörender Versionen einzelner Teile liegen, werden damit garantiert vermieden, selbst wenn etwas erhöhter Rechenzeitbedarf bei der Installation einer neuen Version damit verbunden ist.

* Dieter Schulze ist Mitarbeiter der GFS Gesellschaft für Systementwicklung, München/Köln.