Für die Erstellung von Softwareprojekten gibt es aus ökonomischer Sicht gewisse sinnvolle Vorgehensweisen.
Die Entwicklung größerer Softwareprojekte unterliegt den gleichen Regeln wie die Erschaffung großer
Hardwareprojekte, wie z.B. dem Bau eines Hauses. Die Vorstellung, ein Haus bauen zu wollen, ohne Plan und ohne
die Möglichkeit, auf genormte Bauteile zurückgreifen zu können, erscheint absurd. Trotzdem ist genau
das die tägliche Praxis bei der Programmierung. Leider gibt es für die Softwareentwicklung keine
Bauvorschriften, keine Baugenehmigung, ja noch nicht einmal die Position eines Architekten. Und das, obwohl die
Folgen einiger Programmfehler den Einsturz eines mittelgroßen Gebäudes leicht in den Schatten stellen.
Im Folgenden wird kurz dargestellt, was unserer Meinung nach bei der Softwareentwicklung oft falsch gemacht wird.
Dass etwas falsch gemacht wird, zeigen die vielen Zusammenbrüche gerade kleinerer Softwarefirmen. Bei
größeren Firmen sind es eben nur Projekte, die gescheitert sind, oder deren Fertigstellung sich endlos
hinauszögert.
In der Praxis wird häufig nur darauf geachtet, die Qualität der Programme aus Sicht der Kunden zu
gewährleisten. Die Qualität hinsichtlich der Erweiterbarkeit eines Programms, der Wiederverwendbarkeit
der Einzelteile oder der Wartbarkeit insgesamt wird oft als Nebensache betrachtet. Dabei sind es gerade diese Punkte,
die dem entstehenden Chaos im Sourcecode entgegenwirken.
Redundanzen im Sourcecode werden oft leichtfertig geschaffen und haben die unangenehme Eigenschaft, die
Unübersichtlichkeit und Fehleranfälligkeit exponentiell zu erhöhen. Denn Sourcecode, der nicht
vorhanden ist, kann auch nicht zum Absturz führen. Es zählt also zu den schwierigen Aufgaben bei der
Softwareentwicklung, unnötige Redundanzen auf allen Ebenen zu vermeiden. Wobei Redundanzen umso nachteiliger
sind, je höher die Ebene ist, auf der sie auftreten. Dies ist vergleichbar mit der Fehlentscheidung, die in
einer Firma getroffen wird. Je höher die Position desjenigen, der sie trifft, umso folgenschwerer der mögliche
Verlust für die Firma. Einer der Gründe für die Entstehung solcher Altlasten ist z.B. die Bequemlichkeit
vieler Entwickler. So ist es sicherlich einfacher, eine bestehende Routine zu kopieren und anzupassen, als sich
Gedanken darüber zu machen, wie man das Ganze allgemeiner machen könnte. Auch die Überprüfung von
Eingangsdaten auf ihre Gültigkeit wird häufig stark vernachlässigt. Dadurch wird dann oft bei der
Fehlersuche ein Vielfaches der gewonnengeglaubten Zeit verbraucht.
Auch nachträgliche Änderungen der Vorgaben, wie sie in der Praxis gang und gäbe sind, führen meist
durch massive Verletzungen der bis dahin entstandenen Programmstruktur zu Redundanzen und chaotischen Verhältnissen
im Sourcecode.
Als Folge der hier beschriebenen Fehler gleicht in vielen Softwarefirmen die unfreiwillig erreichte Lage einer
finanziellen Überschuldung, bei der man schlecht bezahlte Nebenjobs annehmen muss, um die anfallenden Zinsen
bezahlen zu können, und dadurch keine Zeit verbleibt, um durch Weiterbildung eine besserbezahlte Stellung zu
erhalten. Denn sind die Altlasten erst einmal da, wird man sie nur schwer wieder los.
Einige der genannten Ursachen lassen sich sicherlich durch etwas Disziplin entschärfen. Doch muss dieser Disziplin
eine ganze Menge praktischer Erfahrung vorausgehen, um überhaupt solche Problemsituationen erkennen zu können.
In der gängigen Programmierliteratur wird zwar immer gepredigt, das Heil läge in der Modularisierung und
Objektorientierung, etc., doch außer einigen praxisfernen Beispielen bleibt dem Ratsuchenden nichts anderes
übrig, als die gleichen Fehler wie seine Vorgänger noch einmal zu machen.
Im Prinzip würde es wohl ausreichen, zu Beginn der Realisierungsphase alle Vorgaben unverrückbar festzuschreiben,
um endlich einmal ein Softwareprojekt termingerecht abliefern zu können. Doch das ist einfacher gesagt als getan.
Denn in der Praxis ist dieser Idealzustand selten gegeben. Selbst bei genügend Erfahrung, Können und Disziplin
der Entwickler ist es kaum möglich, ein Softwareprojekt innerhalb der vorgesehenen Zeit fertig zu stellen, wenn sich
Vorgaben ändern oder nachträglich hinzugefügt werden. Sich ändernde Vorgaben sind zwar oft wegen
mangelnder Planung hausgemacht, doch häufig sind es auch die Ansprüche der Kunden, die sich im Laufe der
Entwicklungsphase ändern, oder irgendwelche unvorhersehbaren Ereignisse.
Sowohl die Tatsache, dass sich die Vorgaben während der Entwicklung ändern, als auch die Unmöglichkeit,
Termine bei sich ändernden Vorgaben einzuhalten, sind Normalfälle. Gerade die Realisierung von kundenspezifischen
Projekten wird vom zeitlichen Aufwand her oft völlig falsch eingeschätzt, was nicht selten in einer
Schadensersatzklage endet. Würde man allerdings den Preis für ein solches Projekt realistisch einschätzen,
wäre es schwierig, einen Kunden dafür zu finden. Man kann wohl weder den Entwicklern und Projektleitern, noch den
Kunden Vorwürfe machen, da normalerweise jeder versucht, sein Bestes zu geben. Außerdem sind eben alle
Beteiligten nur Menschen.
Woran liegt es also, wenn man in der Praxis trotz gewissenhafter Bemühungen immer wieder ins gleiche Dilemma
steuert? Die Ursache ist eindeutig zu spezielle Programmierung. Spezielle Routinen und wechselnde Anforderungen
sind ein unvereinbarer Widerspruch.
Man sollte bei der Programmierung bedenken, dass sich der Wert eines Moduls aus der Häufigkeit seiner
Verwendung (je öfter desto besser) und der Notwendigkeit von Anpassungen (je öfter desto schlechter)
bestimmt. Es ist offensichtlich, dass die genannten Eigenschaften umso besser zutreffen je allgemeiner ein Modul
ist. Dabei ist zu beachten, dass der Nutzen eines Moduls nicht linear, sondern exponentiell mit dem Grad seiner
Verallgemeinerung ansteigt!
Beispielsweise ist eine projektspezifische Routine weniger 'Wert' als eine projektunabhängige, denn wird
das betreffende Projekt eingestampft, so dienen die Projektsourcen allenfalls noch als Kopiervorlage, die
allgemeinen Routinen jedoch können unverändert für andere Projekte weiterverwendet werden.
Durch das Konzept der Verallgemeinerung wird die Lebensdauer und der Einsatzradius eines Moduls maximiert.
Wieso wird die Umsetzung dieses simplen Grundsatzes in der Praxis immer wieder misshandelt? Hier einige Erklärungsversuche:
-
Solange man sich innerhalb eines Projektes bewegt, ist kein unmittelbarer Vorteil einer allgemeineren Routine
erkennbar.
-
Es ist einfacher, ein Stück Code zu kopieren und abzuändern, als ein neues allgemeineres Modul anzulegen.
-
Ein Großteil der Entwickler beschäftigt sich mit dem Ändern von bereits hoffnungslos undurchschaubaren
Routinen, bei denen Verallgemeinerung gleichbedeutend mit Neuschreiben wäre.
-
Man muss erst einmal auf die Idee kommen, eine Routine allgemein verwendbar zu machen. Ziemlich schwierig, wo
doch meistens ein für den Umsatz so wichtiger Termin die Gedanken blockiert.
Ein Ausweg aus der Misere wäre eine Basis, die für beliebige Projekte verwendbar sein
müsste und die, trotz aller Anforderungen auf Projektebene, unangetastet bleiben kann. Um dies zu gewährleisten,
darf sie keine projektabhängigen Informationen beinhalten. Mit einer solchen Basis wären eine Menge der oben
genannten Probleme entschärft. Denn man spart sich mit der Programmierung der zur Verfügung gestellten
Funktionen auch die Fehlersuche und die Entstehung von Altlasten.
Mit CXI wurde ein Rahmen geschaffen, der als Basis für unterschiedlichste Softwareprojekte dienen kann.
Der Aufwand für die Fertigstellung eines Projektes wird dadurch deutlich reduziert, da bereits ein
Großteil des benötigten Programmcodes durch das CXI-System abgedeckt ist. Projektspezifische
Informationen finden sich nur noch auf der allerobersten Ebene. Dadurch wird vermieden, dass bei
nachträglichen Änderungen Wunden durch alle Programmebenen gerissen werden, die in Zeit raubenden
Debuggersitzungen zu verarzten sind.
Es vollzieht sich hier praktisch die gleiche Entwicklung wie seit einiger Zeit bei den GUI-Tools. Noch vor ein
paar Jahren entwickelten viele Firmen ihre eigenen Oberflächen. Dies geschah aus Mangel an vorhandenen,
standardisierten Oberflächentools. Erst seit Windows, PM oder Turbo Vision ist jedem klar, welche Vorteile
es bringt, auf genormte Standardmodule in diesem Bereich zurückgreifen zu können.
Mit dem CXI-System wird nun versucht, das Prinzip der Verallgemeinerung und die Vorteile von genormten Bauteilen
auch für Nichtoberflächenprogramme nutzbar zu machen. Auch hier gibt es genügend Aufgaben,
die schon tausendfach in ähnlicher Form gelöst wurden und die sich hervorragend für eine
Standardisierung eignen. Man denke z.B. an die Speicherung oder an den Austausch von Daten innerhalb eines
Rechners oder über Rechnergrenzen hinweg.
-
Das CXI-System ist in jeder Hinsicht hierarchisch geordnet. Künstliche Einschränkungen in der
Erweiterbarkeit wurden, soweit erkannt, ausgeräumt. Warum sind z.B. Windows- oder OS/2-INI-Dateien
zweistufig? Oder warum gibt es bei DDE die Unterscheidung zwischen Client und Server? Bei CXI sind
Datenbehälter beliebig tief schachtelbar. Es gibt auch keine Clients oder Server, sondern nur
gleichartige Meldungsempfänger. Wie man sieht, muss man selbst bei etablierten Schnittstellen immer
wieder unnötige Einschränkungen oder sinnlosen Ballast feststellen.
-
Es soll dem Anwender auf jeder Ebene so viel Arbeit wie möglich durch Automatisierung und die Schaffung
nützlicher Schnittstellen abgenommen werden. Es muss ihm möglich sein, sich auf sein eigentliches
Problem konzentrieren zu können. Z.B. sollte man bei der Speicherung von Daten nur noch angeben müssen,
WAS gespeichert werden soll, und nicht mehr, WIE die Daten abzulegen sind. Gleiches gilt für das Versenden
von Daten zwischen CXI-Meldungsempfängern. Egal ob diese sich innerhalb eines Programms, in verschiedenen
Programmen auf einem Rechner oder sogar auf verschiedenen Rechnern befinden, es ist immer die eine, gleiche
Funktion, die aufzurufen ist, um eine Nachricht zu versenden. Ähnlich wie beim Verschicken eines Briefes
ist es lediglich notwendig, einen Absender anzugeben und die Nachricht in einen 'Briefkasten' einzuwerfen.
Die Zustellung erfolgt dann automatisch durch das CXI-System.
-
Es ist sowohl möglich, das System um neue Hierarchiestufen zu erweitern, als auch bestehende Stufen
auszubauen. CXI wächst somit in zwei verschiedene Richtungen, erstens nach 'oben', wodurch neue, mächtigere
Schnittstellen geschaffen werden, und zweitens innerhalb jeder Ebene, z.B. durch die Portierung auf neue Betriebssysteme.
-
Mit jeder neuen Ebene im System wird ein besserer Automatisierungsgrad erreicht. Muss man sich z.B. auf der
tiefsten Messagesystemebene nach dem Versenden einer Message noch selbst darum kümmern, eine mögliche
Antwort zu identifizieren und auszuwerten, so wird dies auf der nächsthöheren Ebene durch die dort
vorhandenen CXI-Verarbeitungsknoten automatisch erledigt.
-
Um eine optimale Portierbarkeit zu erreichen, werden möglichst wenige Annahmen über zugrundeliegende
Fremdschnittstellen (Hardware, Software, Betriebssysteme, etc.) gemacht. Das heißt, dass notwendige
Portierungen mit minimalem Aufwand vollzogen werden können.
-
Um eine optimale Parallelisierung zu erreichen, werden keine Annahmen über die Anzahl der zugrundeliegenden
Prozessoreinheiten (PE's) gemacht. Dies wird dadurch erreicht, dass CXI-Programme aus einer Menge logischer
Verarbeitungsknoten bestehen, die beliebig auf die vorhandenen PE's verteilt werden können.
Es können sich alle Knoten sowohl auf einer PE befinden als auch auf mehreren.
Das CXI-Gesamtsystem besteht aus mehreren Ebenen, die jeweils unterschiedliche Problembereiche durch standardisierte
Schnittstellen abdecken. Im Folgenden werden alle diejenigen Ebenen beschrieben, die entweder bereits existieren,
gerade im Entstehen sind oder bereits ausreichend theoretisch erarbeitet wurden, um realisiert werden zu können.
Die Beschreibung erfolgt von der höchsten zur niedrigsten Ebene, also top-down.
Ebene 4 (in Planung)
-
Selbstorganisierendes Programmsystem, das sich selbstständig auf der zur Verfügung stehenden Hardware
verteilt, sich nach ökonomischen Gesichtspunkten anordnet und sich jederzeit an Änderungen der
Hardwaregegebenheiten anpasst.
-
Das System beobachtet selbständig die internen Abläufe und überwacht die zur Verfügung
stehenden Resourcen. Es ist daher in der Lage, Engpässe rechtzeitig zu erkennen und durch geeignete
Umstrukturierungsmaßnahmen zu beseitigen.
Ebene 3 (in Entwicklung)
-
Betriebs- und Entwicklungssystem für rechnerübergreifende Programmsysteme.
-
Programme auf dieser Ebene sind logische, hierarchisch strukturierte Gebilde aus Verarbeitungsknoten, die
mittels hierarchischer Messages (CXI-Datenbehälter) miteinander kommunizieren. Der Rahmen für die
Knoten wird vom CXI-System zur Verfügung gestellt.
-
Die Entwicklung eines Programms erfolgt auf dieser Ebene völlig unabhängig von der später
verwendeten Hardware.
-
Die Zuordnung des logischen Programmsystems zur verwendeten Hardware kann jederzeit dynamisch geändert
werden. Z.B. könnten alle Knoten eines Programms, die auf einem Netzwerk aus mehreren Rechnern laufen, durch einen einfachen Befehl dazu gebracht werden, sich auf einen neu hinzugekommenen Rechner zu überspielen.
Ebene 2 (Entwicklung weitgehend abgeschlossen)
-
Es steht ein Rahmen für standardisierte Verarbeitungsknoten zur Verfügung. Mit diesem werden immer
wieder auftretende Verwaltungsarbeiten, die beim Dialog zwischen solchen Knoten untereinander auftreten können,
erledigt.
-
Für den Informationsaustausch zwischen verschiedenen Rechnern existieren geeignete Kommunikationstreiber.
-
Es existieren eine Reihe von Serviceknoten. Diese werden zum Teil vom System selbst für die rechnerübergreifende
Kommunikation benötigt (Router, Connectionmanager, etc.), zum Teil stellen sie aber auch Dienste für die
Programmknoten zur Verfügung (Datenmanager, Servicemanager, etc.).
Ebene 1 (Entwicklung abgeschlossen)
-
Hierarchisch strukturierte Datenbehälter zum Speichern und/oder Versenden beliebiger Daten
(CXI-Datenbehälter).
-
Rechnerinternes Meldungssystem zum Versenden von CXI-Datenbehältern, wobei Schnittstellen für den
Informationsaustausch mit CXI-Meldungssystemen auf anderen Rechnern vorhanden sind.
-
Die Schnittstellen dieser Ebene können problemlos auch in 'herkömmlichen' Programmen verwendet werden.
Eine mögliche Anwendung für die oberen Ebenen des CXI-Gesamtsystems wäre z.B. die Erhöhung
des Auslastungsgrads von vorhandenen Rechnern. Es existieren mittlerweile Millionen von PC's und Unmengen an
LAN's und WAN's etc. Zusammen ergibt dies eine unvorstellbare Rechenleistung, die nur darauf wartet, angezapft
zu werden. Selbst bei Firmen, die noch einen Host besitzen, sind die inzwischen installierten PC's und Netzwerke
meistens deutlich leistungsfähiger als dieser. Theoretisch zumindest. Denn zur vollen Nutzung dieser
Kapazitäten wird geeignete Software benötigt, die sich derzeit nirgends finden lässt.
Die meisten Rechner im Netzwerk sind überwiegend damit beschäftigt, das Flugverhalten von Toastern zu
simulieren. Nachts werden die Maschinen mangels Beschäftigungsmöglichkeiten komplett abgeschaltet, und
jede neue Rechnergeneration wartet deutlich schneller auf den nächsten Tastendruck des Anwenders.
Nach unserer Meinung fehlt es ganz einfach an Entwicklungsplattformen, mit denen es möglich ist, rechnerübergreifende
Programmsysteme zu erstellen. Dies war einer der Aspekte, von denen wir uns bei der Entwicklung von CXI leiten ließen.
Die Forderungen, die sich dadurch an das zu bauende System stellten, wirkten sich sehr positiv auf die gesamte Planung aus.
Da sich häufig sehr unterschiedliche Rechnersysteme in einem Netz tummeln, konnte man nicht von den üblichen
Gegebenheiten bei der Softwareentwicklung ausgehen. Man musste also erst einmal alles Unverzichtbargeglaubte in Frage
stellen und sich auf die wahren Gegebenheiten besinnen. Die Planung fing also ein bis zwei Ebenen tiefer an als gewöhnlich.
Ein weiterer Aspekt, dessen Auswirkungen sich als sehr wertvoll herausstellten, war die Tatsache, dass keinerlei
Vorgaben existierten. Weder galt es, irgendeinen Termin einzuhalten, noch musste am Ende ein spezielles Produkt
vom Band rollen. Außerdem gab es keine historisch gewachsenen Altlasten, die den allgemeinen Anforderungen
wohl kaum gerecht geworden wären.
Es handelt sich bei CXI nicht nur um ein Programmiertool, eine gute Idee oder ein Programm zur Datenübertragung.
Vielmehr ist CXI ein ganzheitliches Konzept, das auf allen Ebenen der Programmerstellung versucht, dem Anwender so
viel Arbeit wie möglich zu ersparen. Wir hoffen, die Entwicklung von CXI in Zukunft noch schneller vorantreiben
zu können, um damit vielleicht einen kleinen Beitrag zur Überwindung der Softwarekrise zu leisten.
H.H. 1996
|