Dieser Fachbeitrag ist ein Service der InfraSoft Profis für Ihre professionelle Softwareentwicklung. Portierbarer Code Am Beginn von Entwicklungsprojekten stellt sich oft die Frage, wie weit das zu erzielende Ergebnis portierbar sein soll. Mit anderen Worten, genügt es, wenn die Software hier und jetzt auf genau diesem Rechner lauffähig ist? Oder ist es notwendig, die Übertragung der Software in andere Umgebungen zu einem späteren Zeitpunkt einzuplanen? Die Gründe für eine allfällige Portierung können vielfältig sein: Zum Beispiel kann ein Hardwarewechsel zur Performancesteigerung gewünscht werden, ein Upgrade oder gar Wechsel des Betriebssystems anstehen oder der Einsatz einer neuen Entwicklungsumgebung fällig sein. Jedenfalls sagt einem allein der gesunde Hausverstand, dass man bei den kurzen Innovationszyklen der IT-Produkte gut daran tut, die Portierbarkeit von Software von vorneherein im Auge zu behalten. Es gibt aber noch einen weiteren Grund, der für die Erstellung von portierbarem Code spricht – die Qualität der erzeugten Software. Wird nämlich auf die Portierbarkeit geachtet, dann setzt das ein sehr sauberes Arbeiten voraus. In weiterer Folge bringt das, dass der Code leichter wartbar ist. Die Erzeugung von portierbarem Code hat also eine Art Katalysatorfunktion für die Qualität der Software. Im Folgenden finden Sie eine Übersicht der Fälle, in denen Portierungen notwendig werden. Ergänzend werden praktische Hinweise gegeben, was in diesen Fällen zu beachten ist und wie portierbarer Code am besten zu erzeugen ist. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 1 von 10 1. Was ist portierbarer Code? Unter Codeportierung versteht man generell das Adaptieren von Programmcode für den Einsatz in einer anderen Systemumgebung. Unter einer Systemumgebung ist dabei eine bestimmte Kombination von Computer, Betriebssystem und Entwicklungstool zu verstehen. Daraus ergeben sich - grob gesprochen - zumindest drei sehr unterschiedliche Arten von Portierung: die Portierung von Computer zu Computer, die Portierung von einem Betriebssystem auf ein anderes und nicht zuletzt der Wechsel der Entwicklungsumgebung. Bei einer konkreten Portierungsaufgabe können natürlich auch beliebige Kombinationen dieser Unteraufgaben auftreten. Natürlich ist gemäß obiger Definition jeder Code portierbar - was jedoch als wesentliche Codeeigenschaft im Zuge einer Portierung auftritt, ist die Schwierigkeit oder eben die Leichtigkeit des Portierungsprozesses. Unter "portierbarem Code" versteht man daher generell Code, der mit verhältnismäßig geringem Aufwand an eine andere Umgebung angepasst werden kann. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 2 von 10 2. Die klassischen Portierungsfälle Je nachdem, welche Art der Portierung erwünscht oder notwendig ist, kann diese verschiedene Gründe haben: 2.1. Wechsel der Hardwareplattform Gründe für einen Wechsel der Hardwareplattform: Typischerweise wird man die Hardware wechseln wollen, um gestiegene Performanceanforderungen erfüllen bzw. eine erhöhte Last abdecken zu können. Andere Gründe könnten eine erhöhte Ausfallssicherheit der neuen Hardware sein; auch firmenpolitische Gründe, etwa Verträge mit Hardwareherstellern, können hier ausschlaggebend sein. Es wäre zum Beispiel denkbar, eine Webapplikation, die auf einem oder mehreren Intel Windows 2000 Servern läuft, auf eine IBM RS/6000 oder eine Sun E10K zu portieren. Ein solcher Wechsel des Computers zieht in den meisten Fällen auch einen Wechsel des Betriebssystems mit sich - das Hauptaugenmerk während der Codierung sollte daher auf der Betriebssystemunabhängigkeit (siehe Abschnitt 2.2.) liegen. Speziell zu beachten ist: Bei einem Wechsel der Hardwareplattform ist das geänderte Laufzeitverhalten besonders zu beachten. Ob die Software nun auf einem schnelleren Prozessor läuft, die IO-Operationen rascher vor sich gehen oder der Code gar zum ersten Mal auf einem Multiprozessor-System eingesetzt wird – alle diese Änderungen ziehen nach sich, dass sich der Code in subtiler Weise anders verhalten wird. Insbesondere bei Programmen, die Multithreading und Multiprocessing nützen und die bisher nur auf Singleprozessor-Computern gelaufen sind, kann und wird es aller Erfahrung nach zu Laufzeitfehlern kommen. Fehler, die bisher nicht aufgetreten sind, weil Singleprozessor-Computer den Code niemals wirklich gleichzeitig haben laufen lassen, Multiprozessor-Computer hingegen sehr wohl. Andere Fehlfunktionen können sich ergeben rund um: • Fließkommaoperationen: sofern nicht beide Hardwareplattformen IEEE-kompatibel sind und selbst dann kann es kleine Unterschiede geben. • Die Codegeschwindigkeit: jeder Prozessor hat andere Stärken und Schwächen in der Abarbeitung von Maschinensprache-Befehlen. Im Zusammenspiel mit verschiedenen Compilern ergibt sich hier eine Vielfalt von möglichen Situationen. • Das Datenalignment: darunter versteht man die Anordnung und Lage der Daten im Speicher. Was bei einem Computer zulässig ist, kann auf einem anderen Computer zu einer Exception führen, und auf einem Dritten zwar funktionieren, aber langsamer als nötig. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 3 von 10 Alle oben angeführten Beispiele haben eines gemeinsam: sie ziehen vor allem Aufwand in der Test- und Qualitätssicherungsphase nach sich. Diese Punkte proaktiv (???) zu beachten, wäre schwierig. Das einzige, was wirklich mit Nachdruck empfohlen werden kann, ist, sofern irgendwie möglich, das frühzeitige Testen von multithreaded Code auf Multiprozessor-Computern., Ferner ist festzuhalten, dass ein Großteil der hier genannten Problembereiche auch für Virtual Machine (VM) Umgebungen wie Java auftritt. Die VM erlaubt zwar, dass der Code unverändert auf der Zielhardware laufen kann. Die genannten Änderungen im Laufzeitverhalten treten zumeist dennoch auf. 2.2. Wechsel des Betriebssystems Gründe für einen Wechsel des Betriebssystems: Ein Betriebssystemwechsel hat entweder einen Hardwarewechsel zur Ursache, oder das verwendete Betriebssystem wird nicht mehr vom Hersteller unterstützt und muss daher langfristig ausgetauscht werden. Oft, aber nicht immer, kann mit einer Nachfolgeversion vom selben Hersteller gerechnet werden. Die Nachfolgeversion ist meistens soweit wie irgend möglich kompatibel zur Vorgängerversion. Speziell zu beachten ist: Mit dem Wechsel des Betriebssystems ist oft auch ein Wechsel der Entwicklungsumgebung verbunden. Daher gelten hier auch alle im Abschnitt 2.3. angeführten Überlegungen. Darüber hinaus ist man bei einem Wechsel unter Umständen mit einem völlig neuen Betriebssystem-API konfrontiert. Ebenso kann es vorkommen, dass man ein verändertes Konzept vorfindet, nach dem Resources im Betriebssystem verwaltet werden. Nachfolgend finden Sie einige prominente Beispiele für Teile von Betriebsystemen, die sehr unterschiedlich ausfallen können: • - File System: Wie wird konkurrierender Zugriff auf Files geregelt? Wie funktioniert das File Locking? Welche Attribute können mit Files assoziiert werden? Sind Filenamen case-sensitive oder nicht, wie lang dürfen sie maximal sein? Gibt es überhaupt ein Directory/Folder-Konzept? Gibt es Links im File System und wie sind sie implementiert? © InfraSoft GmbH – Die PROFIS www.infrasoft.at 4 von 10 • - - Multithreading (MT) API: Existiert MT überhaupt? Wenn nicht, muss auf Multiprocessing gewechselt werden. Wie schnell ist MT im Vergleich zu Multiprocessing? Welche Synchronisierungs- und Kommunikationsmechanismen gibt es? (Mutex, Semaphor, Synchronised Blocks...) • Objekt- und Komponentenkonzept: Viele moderne Betriebssysteme bzw. Umgebungen bieten Möglichkeiten, Objektorientierte Komponenten direkt vom Betriebsystem verwalten bzw. ansprechen zu lassen und auch Betriebssystemservices selbst als Objekte abzubilden. Beispiele sind COM/COM+ in Windows, das .Net Framework in Windows, Beans und EJBs in Java, CORBA-Objects unter gewissen Linux Desktops. Diese (WER ??) fallen naturgemäß höchst unterschiedlich aus und es kann mit einer gewissen Bestimmtheit gesagt werden, dass der Einsatz dieser Objektmodelle den Wechsel der Betriebssystemumgebung oft extrem erschwert. Einzige prominente Ausnahme hier ist CORBA - ein vom Betriebsystem unabhängiger Standard, der sich allerdings vor allem mit Remote Objects beschäftigt und weniger mit der Komponentenorientierung innerhalb einer Maschine. In diese Kategorie fällt auch die Art des API selbst. Die meisten Betriebssysteme bieten ein klassisches prozedurales C-API. Auf diesem aufsetzend gibt es zumeist C++ Klassenbibliotheken, die das C-API kapseln und eine höhere Abstraktionssicht schaffen (etwa für Windows: MFC). Diese C++ Klassenbibliotheken sind jedoch zumeist fix an das Betriebssystem-API gebunden und nicht portabel. Andere (modernere) Betriebssysteme/Umgebungen bieten zuweilen direkt ein Objektorientiertes Interface an, wie etwa BEOS (C++), Java VM (Java), .Net Framework (vor allem C#) oder Mac OS X Coca (Objective C). Die Tatsache, dass in diesem Bereich auf Portierbarkeit und Standards von Herstellerseite oft sehr wenig Rücksicht genommen wird, hat durchaus firmenpolitische Gründe: man möchte dem Kunden den Umstieg auf Konkurrenzprodukte nicht unbedingt leicht machen. • Speicherverwaltung: Je nachdem, ob das Betriebssystem und die Hardware Paging und Memory Mapping unterstützen oder nicht, kann es nötig sein, verschiedene Strategien bei der Belegung von Speicher anzuwenden. Zum Beispiel stellt sich die Frage, ob „malloc“ und „free“ verwendet werden können, oder ob mit Memory Handles und Memory Locking gearbeitet werden muss. • Hardwareverwaltung und Treiberkonzept: Treiberspezifischer Code ist bei einem Umstieg zumeist komplett auszutauschen. Es ist so gut wie unmöglich, Treiber hardwareunabhängig zu programmieren, denn sie bilden ja selbst die Abstraktionsschicht, die auf der Hardware sitzt. • Netzwerk APIs: Zwar hat sich heute der de facto Standard TCP/IP durchgesetzt, jedoch sind die verschiedenen TCP/IP Protocol Stacks und die TCP/IP APIs durchaus recht unterschiedlich. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 5 von 10 2.3. Wechsel der Entwicklungsumgebung Gründe für einen Wechsel der Entwicklungsumgebung: Ein solcher Wechsel wäre etwa der Wechsel des C++ Compilers und damit zumeist auch der Wechsel der mitgelieferten Bibliotheken (sowohl der C++ Runtime Library als auch der Betriebssystemanbindung). Für einen Wechsel dieser Art gibt es wohl die meisten guten Gründe und er wird wohl auch am häufigsten passieren (Compiler steht im Folgenden immer auch für Entwicklungsumgebung): • Der Hersteller des alten Compilers stellt den Support ein oder verschwindet vom Markt (je nachdem wie alt ein Programm im Dienst wird, desto wahrscheinlicher wird dieses Szenario). • Der alte Compiler wird nicht hinreichend gewartet und kann nur mühsam an neue APIs "angekoppelt" werden. • Der neue Compiler produziert schnelleren oder besseren Code. • Es soll die Einhaltung von Standards bzw. die Korrektheit des Codes überprüft werden: Dazu übersetzt man das Projekt mit Compilern unterschiedlicher Hersteller (die alle den C++ ISO-Standard befolgen) und bessert solange alle Fehler aus, bis alle Compiler zufrieden sind. Diese Strategie kann vor allem in der C++ Entwicklung nur wärmstens empfohlen werden. Speziell zu beachten ist: Hinweise, was bei einem Wechsel der Entwicklungsumgebung zu beachten ist, finden Sie im nachfolgenden Abschnitt 3. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 6 von 10 3. Der Einsatz von Java, C, C++ und C# Wer heute das Wort "portierbar" hört, denkt in erster Linie an Java und neuerdings vielleicht auch an C#. Ersteres ist nicht ganz richtig, die zweite Annahme wäre völlig verfehlt. Grundsätzlich ist festzuhalten, dass Java bei weitem nicht die einzige Möglichkeit ist, portierbaren Code zu erzielen. Es gab portierbaren Code schon zu Zeiten von C (und auch davor), also lange vor der Erfindung von Objektorientierten Sprachen und Virtual Machines. C und C++ eignen sich ausgezeichnet zur Entwicklung von betriebsystem- und maschinenunabhängigem Code. Die grundsätzliche Richtung bei der Verwendung von C/C++ sollte sein: soviel als möglich mit den ISO-standardisierten Runtime Libraries abdecken. D.h. zum Beispiel im Falle von Windows: Wann immer möglich "malloc" und "free" den betriebssystemspezifischen Funktionen wie "LocalAlloc" und "GlobalAlloc" vorziehen. Im Bereich MultiByte Charactersets "wcstombs" statt "WideCharToMultiByte" verwenden. Als Container besser "std::vector" und "std::deque" anstelle von MFC spezifischen Containern wie etwa "CArray". Als dynamische String-Klasse "std::string" anstelle etwa von "CString" verwenden. Beim File-IO besser "fopen" bzw. "fstream" statt "OpenFile" anwenden. Es gibt natürlich Bereiche im Betriebssystem, die nicht von der Standard Runtime Library abgedeckt werden, wie etwa Multithreading oder Filesharing. In diesen Fällen führt es am besten zum Ziel, kleine Wrapper Objects über die Betriebssystemfunktionen zu schreiben, die in einem H-File definiert werden und in einem CPP-File implementiert werden. Kommt es nun zu einem Wechsel von Betriebssystem und/oder Umgebung, so ist es ein leichtes, ein weiteres CPP-Implementierungsfile (das die Konstrukte des neuen Betriebssystems verwendet) zu schreiben und beim Übersetzen das neue File in den Code einzubinden. Generell abzuraten ist von der übermäßigen Verwendung von „#ifdef“-Konstrukten. Die oben beschriebenen Wrapper machen diese in den allermeisten Fällen überflüssig und resultieren in viel leichter lesbarem Code. Ein Grundproblem in der Entwicklung von portablem Code in C++ ist die Tatsache, dass viele C++ Programmierer nicht genau wissen, welche Klassen bzw. Funktionen nun Teil des C++ ISO-Standards sind und welche nicht. Hier kann nur empfohlen werden, die Entwickler mit verschiedenen Compilern/Entwicklungsumgebungen zu versorgen. Damit kann (wie oben beschrieben) getestet werden, ob man sich auf ein herstellerspezifisches Konstrukt verlässt oder, wie erwünscht, nur die Standardkonstrukte verwendet. Ferner sollte im Entwicklungsteam eine Grundhaltung geschaffen werden, die unabhängige Standards gegenüber "Herstellerstandards" bevorzugt. Ist erst einmal das Bewusstsein für die Problematik vorhanden, werden die Entwickler anfangen, sich selbst weiterzubilden und bald selbst genauer einschätzen können, was portabel ist und was nicht. Teilweise kann man eine solche Atmosphäre schon durch Verwendung der richtigen Vokabeln schaffen: Inserieren Sie zum Beispiel besser einen "C++ Programmierer" als einen "Visual C++ Programmierer". © InfraSoft GmbH – Die PROFIS www.infrasoft.at 7 von 10 Zum Thema Java ist zu sagen, dass es damit wirklich oft am leichtesten ist, portablen Code zu schreiben. In vielen Fällen ist es nicht einmal nötig, für die Zielumgebung neu zu übersetzen. Es ist jedoch keineswegs so, dass sich das Programm dann unter allen Betriebssystemen gleich verhält - wie schon erwähnt gelten selbstverständlich die meisten Überlegungen bezüglich unterschiedlicher Hardware – besonders Multithreading-Programme können beim Wechsel auf Multiprozessor-Computern für unangenehme Überraschungen sorgen. Andere Features (wie etwa das Verhalten von Shared Files) ändern sich ebenfalls von Betriebssystem zu Betriebssystem. Man braucht also auf jeden Fall eine umfangreiche und sorgfältige Testphase nach einer Portierung (selbst wenn die Portierung nur aus einer Neukompilierung bestanden hat). Ferner ist zu berücksichtigen, dass auch und vor allem bei Java oft Änderungen in der JavaKlassenbibliothek stattfinden, die nicht ISO-standardisiert ist. Diese Änderungen ziehen ebenfalls Portierungsaufwand nach sich. Java genießt nicht die Sicherheit eines ISO-Standards, für jeweils zumindest 5 Jahre stabil und unverändert zu bleiben. Ein besonderes Merkmal von Java ist seine Dominanz im Webserver-Bereich (wobei unter Webserver auch verwandte bzw. für Webserver benötigte Technologien wie Enterprise Java Beans, Message Beans, Message Services und ähnliches verstanden sein sollen). So gibt es etwa mit dem J2EE-"Standard" (ein Sun de facto Standard) eine Umgebung, die Webservices, XML-Parser, verteilte Transaktionen, Remote-Object-Services (in Form von EJB), Datenbankanbindung mit ConnectionPooling, Java Server Pages (analog zu ASP), Servlets (ein CGI-Pendant) und vieles mehr anbietet, was man sich auf einem (Web-)Server wünschen könnte. Es gibt mittlerweile eine Vielzahl von Herstellern, die diesen Standard oder Teile davon unterstützen und so genannte Application Server anbieten, wie etwa BEA WEB Logic, IBM WebSphere, JBoss, Tomcat u.a.. Für die Entwicklung von Webapplikationen kann ein solcher Application Server nur empfohlen werden - man erhält damit eine One Shop Solution. Ferner kann Java am Server seine Stärken besonders gut ausspielen und seine Schwächen besonders gut verbergen. Im Falle, dass man zum Beispiel von einer Intel-basierten Serverfarm unter BEA WEB Logic mit Oracle als Datenbank auf eine RS/6000 mit IBM WebSphere und DB2 als Datenbank portieren muss, wird der Hauptaufwand in kleinen Anpassungen an den anderen Application Server und die andere Datenbank bestehen - diese Anpassungen sind jedoch praktisch unumgänglich und erfordern natürlich wiederum umfangreiche Tests bezüglich Lastverhalten, Isolationslevels bei DB-Transaktionen, etc. In jedem Fall gibt es keinen derartig umfangreichen und weithin unterstützten Standard für C++ (oder jede andere Programmiersprache - mit Ausnahme vielleicht von COM-Komponenten unter Windows 2000 Server, früher MTS). Eine Entwicklung einer größeren Webapplikation komplett unter C++ erscheint deshalb nach Stand der Dinge im Augenblick nicht sinnvoll. Wer vor Herstellerabhängigkeit keine Angst hat, könnte ASP oder ASP.Net im Verein mit COM+ oder .Net Framework und C# ins Auge fassen. Jedoch widerspricht dies dem Portabilitätsgedanken insofern, als man sich damit auf Windows-Server und auf Intel-kompatible Maschinen festlegt. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 8 von 10 C++ ist nach wie vor besonders stark im „Fat Client“-Bereich und kann hier auch seine Stärken optimal ausspielen. Alles über portablen C++ Code Gesagte gilt hier. Zuweilen kann es schwierig sein, einen Abstraktionslayer über der GUI-Funktionalität des Betriebssystems zu bauen oder zuzukaufen. Es gibt hier zwar eine Menge an Anbietern, aber die Qualität ist durchaus variabel. Eine möglichst genaue Evaluierung vor dem Produktkauf ist dringend anzuraten. Erfolgreiche Produkte, die in C/C++ codiert sind und die für mehrere teils recht unterschiedliche Plattformen zu haben sind, wie etwa Internet Explorer (Windows und Mac OS), Microsoft Word/Excel/Powerpoint (Windows und Mac OS), Netscape (Windows / Linux / ...), Adobe Photoshop (Windows / Mac OS (X)), diverse Computerspiele wie etwa Warcraft III, Quake und andere, Lightwave 3D (Windows / Max OS / ehemals Amiga OS) unterstreichen die Machbarkeit und die Erfolgswahrscheinlichkeit dieses Ansatzes. Jedoch ist, wie gesagt, ein nicht unerheblicher Aufwand in den GUI-Layer zu investieren. Besonders geeignet ist C++ für alle Programme, die arm an User Interfaces sind. Das sind zum Beispiel Database Engines, Middlewarekomponenten, Game & Simulation Engines, Steuer- und Überwachungsprogramme, Network Renderer, Compiler, etc... In diesem Fall vermeidet man das Problem, einen full-fledged GUIAbstractionlayer zu kaufen oder entwickeln zu müssen. Das Programm kann bei weitestgehender Ausnutzung der umfangreichen Standard Runtime Library portabel codiert werden. Nicht abgedeckte Betriebssystemfunktionalitäten können wie beschrieben in Wrapper ausgelagert werden. Das resultierende Programm kann dann (bei guter Codierung) Portabilität mit höchstmöglicher Performance optimal vereinigen. Zu C# ist zu sagen, dass es zwar auf einer Virtual Machine (VM) Architektur aufsetzt und daher theoretisch auch auf anderen Betriebssystemen laufen könnte. Für alle praktischen Belange kann jedoch davon ausgegangen werden, dass es nur auf Windows- und Intel-kompatiblen Computern läuft. Bisher existiert erst eine einzige Firma, die angekündigt hat, die VM auf Linux zu portieren. Es ist jedoch weder klar, wann das der Fall sein wird, noch wie umfangreich der Support sein wird. Ebenfalls unklar bleibt vorerst, wie erfolgreich die Firma mit diesem Produkt sein wird und wie lange das Produkt tatsächlich leben wird. Deswegen kann man C# Code im Augenblick eher das Gegenteil von Portierbarkeit bescheinigen: Er läuft nur auf Windows/Intel-Computern, und mit an Sicherheit grenzender Wahrscheinlichkeit ist man auf Microsoft-Compiler und Entwicklungsumgebungen angewiesen (ein Phänomen, das auch schon bei der COM-Objekttechnologie zu beobachten war). Die daraus resultierenden Nachteile sind unter anderem: • Keine Möglichkeit, Sprach- bzw. Programmkonstrukte durch den Einsatz von Compilern verschiedener Hersteller zu prüfen • Herstellerabhängigkeit, mangelnder Konkurrenzkampf (und daher möglicherweise suboptimale Produkte und überhöhte Preise) • Fixierung der Programmierer auf Herstellerspezifische Konstrukte und Technologien. Ein späterer Einsatz von Standardtechnologien könnte auf Akzeptanzprobleme im Entwicklungsteam stoßen. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 9 von 10 4. Zusammenfassung Portablen Code zu schreiben muss nicht nur produktspezifische oder marktpolitische Gründe haben. Die Entwicklung von portablem Code kann auch dazu dienen, Fehler frühzeitig zu erkennen, zum Beispiel durch die Prüfung des Codes mit mehreren unabhängigen Entwicklungstools/Compilern. Diese Vorgangsweise hilft Programmierern dabei, sauberen Code zu schreiben. Sie werden sich dessen bewusst, was herstellerspezifisch und potentiell kurzlebig bzw. was standardisiert und stabil ist. Was die unterschiedlichen Sprachen und Entwicklungsumgebungen betrifft, lassen sich folgende Empfehlungen abgeben: Für den serverseitigen Einsatz, vor allem im Nahfeld von Webapplikationen, erscheint augenblicklich Java im Verein mit J2EE die optimale Umgebung, vor allem auch im Hinblick auf Portabilität, zu sein. Für den „Fat Client“-Bereich kann C++ nur wärmstens empfohlen werden. Durch bewussten Einsatz von Standard Runtime Libraries anstelle der direkten Verwendung von Betriebssystem-Services lässt sich auch hier ein C++ Programm weitestgehend portabel halten. Ein eventuell erhöhter Aufwand in der Codierung wird hier zumeist durch eine erleichterte Wartungs- und Portierungsphase mehr als wettgemacht. Ergänzend zu diesem Text steht Ihnen auf der InfraSoft Website ein Glossar zur Verfügung, in dem Sie die meisten der hier verwendeten Begriffe finden. Über das aktuelle Angebot an weiteren, kostenlosen Fachbeiträgen zur Softwareentwicklung informieren Sie sich bitte unter www.infrasoft.at/service. Harald Nowak Wien, im August 2003 Der Autor ist Mitarbeiter der InfraSoft, einem Unternehmen, das auf komplexe Softwareentwicklungen spezialisiert ist. Die Experten der InfraSoft haben langjährige Erfahrungen in der Entwicklung und verfügen über fundierte Kenntnisse in Design, Analyse, Realisierung, Test und Projektmanagement. Für individuelle Beratungen zur Entwicklung von Softwarelösungen und die Bereitstellung von Realisierungsteams wenden Sie sich bitte an [email protected]. © InfraSoft GmbH – Die PROFIS www.infrasoft.at 10 von 10