% infospk2.dem % LaTeX package LJour2 1.0: demonstration file % (c) Springer-Verlag HD %---------------------------------------------------------------------- % Demo-article of Informatik Spektrum % that starts on page 21, hence the page counter is set to that value. % % The article is written in German hence it calls for a pgljour2 format % i.e. PostScript fonts, German hyphenation, LaTeX, two column layout. % % You can process it with a normal cljour2 format as well. Just ignore % the error message upon startup and the bad linebreaks resulting % from the wrong hyphenation table. % \documentstyle[deutsch]{pgljour2} \setcounter{page}{21} \makeatletter \def\subsubsection{\@startsection{subsubsection}{3}{\z@}% {-18dd plus-4pt minus-4pt}{-1pt}{\normalsize\it}} \makeatother %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Eine Alternative zu \obeylines und \obeyspaces, bzw. zu % \begin{verbatim}. % Harald Kirsch 8.88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \def\SPACE{\vrule width0pt \hskip0.5em} \def\NEWLINE{\leavevmode \unskip \vrule width 0pt\par} \def\NoPara{\parskip=0pt \parindent=0pt \everypar={}} {\catcode`\^^M \active \catcode`\ \active% \gdef\InputFormat{\NoPara\catcode`\^^M\active\let^^M=\NEWLINE% \catcode`\ \active\let =\SPACE}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Umgebung, in der die Formatierung der Eingabe die der Ausgabe % bestimmt. (vgl. modula.doc) \newenvironment{HardForm}{\InputFormat}{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Umgebung fuer selbst formatierende MODULA- und PASCAL-Programme. % Kommentare werden in \rm gesetzt, alles andere in \tt. % Geschachtelte Kommentare wie in MODULA werden nicht unterstuetzt. % (vgl. modula.doc) % {\catcode`\* \active \global \def \STAR {*} } {\catcode`\( \active \global \def \LBRA {(} } \newenvironment{Modula} {\def \Skip##1{}% \def \Con {\it (*\Skip}% \def \Coff {*)\tt \Skip}% \def \IFNX {\ifx\TMPCHAR\TMPTEST\let\TMPFALSE=\TMPTRUE\fi\TMPFALSE}% \def \IFN##1##2##3{\let\TMPTEST##1\let\TMPTRUE##2\let\TMPFALSE##3% \futurelet\TMPCHAR\IFNX}% \expandafter \def \LBRA {\expandafter\IFN\STAR{\Con}{(}}% \expandafter \def \STAR {\IFN{)}{\Coff}{*}}% \catcode`\* \active% \catcode`\( \active% \InputFormat\normalsize\tt}{} %\lefthyphenmin 2\righthyphenmin 2 \makeatletter % borrow a few things from the german.sty \def\allowhyphens{\penalty\@M \hskip\z@skip} \def\set@low@box#1{\setbox\tw@\hbox{,}\setbox\z@\hbox{#1}% \setbox\z@\hbox{\dimen@\ht\z@ \advance\dimen@ -\ht\tw@ \lower\dimen@\box\z@}% \ht\z@\ht\tw@ \dp\z@\dp\tw@} \def\save@sf@q#1{{\ifhmode \edef\@SF{\spacefactor\the\spacefactor}\else \let\@SF\empty \fi \leavevmode #1\@SF}} \def\@glqq{\save@sf@q{\set@low@box{''\/}\box\z@\kern-.04em\allowhyphens}} \def\glqq{\protect\@glqq} \def\@grqq{\save@sf@q{\kern-.07em``\kern.07em}} \def\grqq{\protect\@grqq} \makeatother \let\typeset=\relax \def\labelitemi{$\bullet$} \def\sectcounterend{.} \def\CRC{\par\addvspace\baselineskip\noindent{\bf Computing Reviews Classification: }\ignorespaces} \journalname{Informatik-Spektrum} \begin{document} \title{Probleme des Software-Engineering} \subtitle{Die Programmiersprache -- Werkzeug des Softwareentwicklers} \titlerunning{H. Klaeren: Probleme des Software-Engineering} \authorrunning{H. Klaeren: Probleme des Software-Engineering} \author{H. Klaeren} \institute{Universit\"at T\"ubingen} \date{\vskip -12.85pt} \maketitle \begin{abstract} Nach einem kurzen Abri{\ss} \"uber die Entstehung des Software-Engineering zeigen wir beispielhaft, wie schwierig es sein kann, im Softwarebereich Sicherheitseigenschaften zu garantieren, die in klassischen Bet\"atigungsfeldern der Ingenieure selbstverst\"andlich scheinen. Wir diskutieren Ursachen f\"ur dieses Ph\"anomen und gehen dabei auch auf Ausbildungsfragen kurz ein. An\-schlie\-{\ss}end zeigen wir auf, in welcher Beziehung die Programmiersprache als wesentliches, aber oft zu wenig beachtetes Werkzeug des Software-Ingenieurs Sicherheitseigenschaften garantieren kann. Den bislang von den Praktikern aus Effizienzgr\"unden wenig gesch\"atzten funktionalen Programmiersprachen kommt hier eine besondere Bedeutung zu. \end{abstract} \keywords{C, Datentypen, FORTRAN, funktio-\linebreak nale Programmierung, imperative Sprachen, Mariner I,\linebreak Mo\-du\-la-2, Pascal, Programmieren im Kleinen, Stabilit\"at} \bigskip \begin{transsummary} After a short review of the genesis of software engineering we give an example of the difficulties in the software realm with safety properties that seem commonplace in classic engineering domains. We discuss some reasons for this phenomenon, also briefly mentioning some educational problems. We then show in what respect a programming language as the essential but frequently not esteemed enough tool of the software engineer can ensure safety properties. Very important in this respect are functional programming languages, although up to now they are, for effiency reasons, not very much favoured by practitioners. \end{transsummary} \transkey{C, data types, FORTRAN, functional programming, imperative languages, Mariner I, Modula-2, Pascal, programming in the small, stability} \CRC{D.1.0, D.2.2, D.3.0} \strich \section*{Vorwort} Wir wollen hier zun\"achst auf einige grunds\"atzliche Schwie\-rig\-kei\-ten aufmerksam machen, die bei der \"Ubertragung von ingenieursm\"a\ss{}igen Verfahren auf Software auftreten, und diskutieren an\-schlie\-\ss{}end Eigenschaften von Programmiersprachen, die in diesem Zusammenhang hilf\-reich sind. Geht man davon aus, da\ss{} die Qualit\"at einer Arbeit auch durch die Qualit\"at des dazu verwendeten Werkzeugs nachhaltig beeinflu\ss{}t wird, kommt der Programmiersprache als dem Hauptwerkzeug des \glqq Soft\-ware-In\-ge\-nieurs\grqq{} sicher gro\ss{}e Bedeutung zu. Da\ss{} es tats\"achlich Unterschiede zwischen Software-Engineering und den klassischen Ingenieursdisziplinen gibt, erkennt man z.B. an den \glqq Garantie\grqq -Bestimmungen f\"ur Software, sie schlie\ss{}en n\"amlich in der Regel im Gegensatz zu Garantiebestimmungen f\"ur andere Ingenieursprodukte jede Garantie aus. Die Software-Industrie beginnt selbst schon, diesen Sachverhalt ironisch zu kommentieren, wie das folgende authentische Beispiel zeigt~\cite{shore}: \begin{quotation}\em Wir behaupten nicht, da\ss{} Interactive EasyFlow zu irgendetwas gut ist -- wenn Sie das denken, prima, aber das ist Ihre Entscheidung. Wenn Interactive \linebreak EasyFlow nicht funktioniert, egal. Wenn Sie eine Million verlieren, weil Interactive EasyFlow durchdreht, fehlt die Million Ihnen, nicht uns. Wenn Sie diese Ausschlu\ss{}bestimmung nicht m\"ogen, egal. Wir behalten uns das Recht vor, das absolute rechtlich zul\"assige Minimum zu tun, bis zum Nichts (inklusive). Dies ist im Grunde dieselbe Ausschlu\ss{}bestimmung wie bei allen anderen Softwarepaketen, aber unsere ist auf gut Deutsch und die der anderen im Advokatenlatein. \end{quotation} \section{Die sogenannte Software-Krise} In der Anfangszeit der Computer-Entwicklung und -An\-wen\-dung sah man in der Software allgemein kein Problem (s.~z.B.~\cite{metro}); die interessanten Fragen lagen eindeutig auf dem Hardware-Sektor. Der Computer galt, wie F. L. Bauer \cite{bauerzh} es heute formuliert, als eine Art \glqq vollautomatische Handkurbel-Rechen\-maschi\-ne\grqq . Das dr\"uckt sich auch in den damaligen Bezeichnungen \glqq Rechenautomat\grqq{} bzw.\ \glqq automatische Rechenmaschine\grqq{} aus. Auch die ersten kommerziell vertriebenen Rechner wurden vom Hersteller praktisch ohne jede Software ausgeliefert, was f\"ur heutige Verh\"altnisse unvorstellbar ist. Dieses Vorgehen war nur deshalb m\"oglich, weil die damaligen Computer einerseits noch ziemlich \"uberschaubar waren und andererseits auch nur f\"ur ganz eng umgrenzte Anwendungen (z.B. numerische Algorithmen) eingesetzt wurden. Die Charakteristika aus der Fr\"uhzeit der Computer (etwa 1942--1948): \begin{itemize} \item Programme waren Nachbildungen von Algorithmen, die aus der Mathematik bekannt waren. \item Konstrukteure, Programmierer und Benutzer bildeten \linebreak eine im we\-sent\-li\-chen geschlossene Gruppe mit durchweg gleicher Vorbildung. \item Die Programme behandelten eine eingeschr\"ankte Problemklasse und griffen nicht unmittelbar in irgendwelche Handlungsabl\"aufe ein. \end{itemize} \noindent In diesem Szenario war nat\"urlich kein Bedarf f\"ur \glqq Software-Engineering\grqq ; die bekannten Techniken aus der Mathematik bzw.\ der Elektrotechnik (oder gar Mechanik) reichten v\"ollig aus\footnote{ Dieselben Charakteristika findet man auch heute noch durchweg in der universit\"aren Programmierausbildung wieder, was einer der Gr\"unde sein mag, warum Software-Engineering so schwer lehrbar ist.}. Sp\"atestens in den sechziger Jahren wurde es aufgrund der Fortschritte auf dem Hardware-Sektor m\"oglich, Systeme zu entwickeln, die so komplex waren, da\ss{} sie sich durch blo\ss{}e Umsetzung mathematischer Algorithmen in Computerprogramme offensichtlich nicht mehr beschreiben lie\ss{}en. Ein Beispiel ist das SAGE-System von 1951 (\glqq Semi-automated ground environment\grqq \cite{whirlwind}) ein fr\"uher SDI-Urahn. Dieses System bestand aus einem Netz von Radarstationen, die mit einem Rechner verbunden waren, und sollte automatisch vor einem feindlichen Fliegerangriff warnen. Es stellte sich an diesem Beispiel wie an zahlreichen anderen heraus, da\ss{} Programmieren eben nicht nur aus der Umsetzung bekannter Algorithmen in eine Computersprache besteht, sondern da\ss{} in den meisten F\"allen Algorithmen erst einmal {\em gefunden\/} werden m\"ussen. Hierzu ist als wichtigste Voraussetzung die {\em pr\"azise Spezifikation\/} des Problems notwendig. Im SAGE-Beispiel etwa war zun\"achst einmal zu kl\"aren, was eigentlich ein Flugzeug ist, d.h.\ inwiefern sich seine Radarsignale von denen eines Vogelschwarms oder anderer Flugobjekte unterscheiden. Dann ist zu kl\"aren, wodurch sich ein feindliches Flugzeug von einem eigenen unterscheidet etc.\ Diese Fragen sind au\ss{}erordentlich schwer zu beantworten und blieben im SAGE-System ungel\"ost. Noch 1960 hat ein SAGE-Nachfolger, das {\em Ballistic Missile Early Warning System\/}\footnote{Die Abk\"urzung dieses Systems ist \glqq BMEWS\grqq , was sich auch als \glqq bemuse\grqq (=\glqq irritieren\grqq ) aussprechen l\"a\ss{}t.} den aufgehenden Mond als einen feindlichen Raketenangriff gemeldet \cite[p.~122--123]{licklider}. Da\ss{} die Problematik bis heute im wesentlichen ungel\"ost ist, beweisen der Abschu\ss{} eines britischen Gazelle-Hubschraubers durch das britische Kriegsschiff Cardiff im Falklandkrieg \cite{cardiff} und der Abschu\ss{} eines iranischen Verkehrsflugzeugs durch den amerikanischen Kreuzer Vincennes im Golfkonflikt \cite{vincennes1,vincennes2}\footnote{Der Vincennes-Zwischenfall er\"offnet eine neue Dimension: Die Software hat hier, zumindest was die Kursangaben des Verkehrsflugzeugs angeht, richtig gearbeitet; es war die Komplexit\"at der Benutzerschnittstelle mit vier separaten alphanumerischen Bildschirmen, die zu dem Fehler gef\"uhrt hat.}. Wir haben oben drei wesentliche Merkmale der Fr\"uhzeit der Programmierung erw\"ahnt; stellen wir dem jetzt gegen\"uber, was danach cha\-rak\-te\-ri\-stisch wurde und bis heute gilt: \begin{itemize} \item In den meisten F\"allen ist der Computer nur Teil einer ganzheitlichen Probleml\"osung; die genaue Beschreibung und Aufteilung der Aufgabe sowie geeignete Algorithmen zu ihrer maschinellen L\"osung m\"ussen erst gesucht werden. \item Maschinenhersteller, Programmierer und Benutzer der Rechner bzw.\ Programme sind verschiedene Menschengruppen mit unterschiedlicher Vorbildung. Dies hat Kommunikationsprobleme zur Folge. \item Der Einsatzbereich der Programme ist un\"uberschaubar; die Pro\-gram\-me greifen z.T.\ unmittelbar in praktische Handlungsabl\"aufe ein. \end{itemize} \section{\glqq Software-Engineering\grqq{} zur L\"osung der Soft\-ware-Krise} Von F. L. Bauer \cite{bauer93} wurde aus diesen Gr\"unden im wesentlichen der folgende Gedanke vorgetragen: Wenn es wahr ist, da\ss{} die Entwicklung komplexer Soft\-ware-Sy\-ste\-me unsystematisch geschieht und wenn andererseits bekannt ist, da\ss{} die Ingenieurswissenschaften sich traditionell mit der Entwicklung komplexer Systeme besch\"aftigen, dann sollte man doch versuchen, auch Soft\-ware-Sy\-ste\-me nach ingenieursm\"a\ss{}igen Prin\-zi\-pien und Regeln zu erstellen. Im Nachgang zu der ber\"uhmten Konferenz des NATO Science Committee 1968 in Garmisch-Partenkirchen \cite{garmisch}, die von F. L. Bauer vorbereitet und durchgef\"uhrt wurde, ist das neue Schlagwort \glqq Software-Engineering\grqq{} begeistert aufgenommen worden und hat seitdem seinen festen Platz in der Informatik. Was verstehen wir heute unter \glqq Software-Engineering\grqq ? Wir zitieren die Definition aus dem \glqq IEEE Standard Glossary of Software Engineering Terminology\grqq \cite{stdgloss}: \begin{description} \item[{\bf Software Engineering}]{\em \ldots die Anwendung eines systematischen, disziplinierten, quantifizierbaren Ansatzes auf \linebreak Entwicklung, Betrieb und Wartung von Software, d.h.\ die Anwendung der Ingenieurskunst auf Software. } \end{description} \noindent Zur Arbeitsweise eines Ingenieurs noch eine Definition nach der Encyclopedia Britannica: \begin{description} \item[{\bf Engineering}]\em \ldots die sch\"opferische Anwendung wissen\-schaft\-li\-cher Prin\-zi\-pien auf Entwurf und Entwicklung von Strukturen, Maschinen, Apparaten oder Herstellungsprozessen im Hinblick auf eine gew\"unschte Funktion, Wirtschaftlichkeit und Sicherheit von Leben und Eigentum \ldots \end{description} \noindent Der Ingenieur wendet also seine Kenntnisse der naturwissenschaftlichen Grundlagen kreativ an, um ein Produkt mit be\-stimm\-ten definierten Eigenschaften unter einem wirtschaftlich vertretbaren Kostenaufwand herzustellen. \subsection{Beispiel einer gew\"unschten Eigenschaft: Stabilit\"at} Wenn wir im Augenblick einmal von den Eigenschaften absehen, die die gew\"unschte {\em Funktion\/} beschreiben (sog.\ {\em funktionale Eigenschaften\/}) und deshalb speziell auf ein bestimmtes Software-Produkt zugeschnitten sind, bleiben noch diejenigen, die mit Wirtschaftlichkeit und Sicherheit bzw.\ Qua\-li\-t\"at zu tun haben und auf alle Software-Produkte anwendbar sind. Hier werden in der Software-Engineering-Literatur u.a.\ folgende Eigenschaften genannt: \begin{quote}\em Zuverl\"assigkeit, Korrektheit, Robustheit, Stabilit\"at, \linebreak Datensicherheit, Wiederherstellbarkeit, Wartbarkeit, An\-pa\ss{}\-barkeit, Lesbarkeit, Modularit\"at, Normengerechtigkeit, Kompatibilit\"at, Wirt\-schaft\-lich\-keit, \"Uber\-trag\-bar\-keit, Effizienz, Konsistenz, Verf\"ugbarkeit, Kontrollierbarkeit, Transparenz, Flexibilit\"at, Ausfall-\linebreak sicher\-heit, Benutzerfreundlichkeit, \ldots \end{quote} \noindent Aus dieser noch nahezu beliebig zu verl\"angernden Liste von Eigenschaften, die sich zum Teil gegenseitig widersprechen und in der Literatur durchaus unterschiedlich definiert werden, greifen wir die {\em Stabilit\"at\/} heraus. Dies geschieht nicht etwa, weil Stabilit\"at eine besonders wichtige Eigenschaft von Software ist, sondern weil man hier sehr gut Gemeinsamkeiten wie auch Unterschiede beim Vergleich von allgemeinen Ingenieurstechniken und Softwaretechnik darstellen kann. Beginnen wir mit einem Auszug der Definition von Stabilit\"at aus \glqq Meyers En\-zy\-klo\-p\"a\-di\-sches Lexikon\grqq , der vielleicht auch das beschreibt, was man unter Software-Stabilit\"at zu verstehen hat: \begin{quotation}\small \begin{description} \item[Stabilit\"at] (lat.) allgemein Best\"andigkeit, Festigkeit, Dauerhaftigkeit. \begin{description} \item[\it in Physik, Chemie, Technik] Bez. f\"ur \end{description} \begin{enumerate} \item die Best\"andigkeit eines beliebig zusammengesetzten und durch innere Kr\"afte zusammengehaltenen Systems auch bei \"au\ss{}eren Einwirkungen, sofern diese eine bestimmte St\"arke nicht \"uber\-schrei\-ten. \item die Eigenschaft eines physikalischen oder technischen Zu\-stands oder Vorgangs, bei einer aus einem stabilen $\uparrow$Gleich\-ge\-wicht herausf\"uhrenden St\"orung dieser entgegenzuwirken und nach Aufh\"oren der \"au\ss{}eren Einwirkung bzw.\ infolge auftretenden R\"uck\-stellungs\-kr\"aften in den stabilen Gleich\-ge\-wichts\-zu\-stand zur\"uckzukehren. \end{enumerate} \end{description} \end{quotation} \noindent Offensichtlich kann mit \glqq Software-Stabilit\"at\grqq{} nur der zweite Punkt in dieser Erkl\"arung gemeint sein. \subsubsection{Aerodynamische Stabilit\"at.} Am Beispiel der aerodynamischen Stabilit\"at, speziell der {\em Querstabilit\"at\/}, wollen wir be\-trach\-ten, wie Ingenieure eine Stabilit\"at von Systemen konstruktiv erreichen. Es geht hierbei um Drehungen um die L\"angsachse des Flugzeugs. Jede \"Anderung in der Querlage des Flugzeugs soll eine Gegenkraft verursachen, die das Flugzeug in seine normale waagerechte Stellung zur\"uck\-f\"uhrt. Das zu diesem Zweck ausgenutzte Naturgesetz besagt, da\ss{} die f\"ur den Auftrieb ma\ss{}gebliche Fl\"ache eines Tragfl\"ugels durch seine Projektion auf die Waagerechte gegeben ist. Stellt man also die Tragfl\"ugel V-f\"ormig an, wie in Abbildung 1 \"ubertrieben dargestellt, f\"uhrt eine \"Anderung in der Querlage dazu, da\ss{} die f\"ur den Auftrieb wirksame Fl\"ache auf der Seite gr\"o\ss{}er wird, die sich geneigt hat. Dadurch entsteht die ge\-for\-der\-te R\"uckstellkraft. \begin{figure} \begin{picture}(80,70) \put(120,20){\circle*{20}} \put(120,20){\line(-2,1){80}} \put(120,22){\line(-2,1){80}} \put(120,20){\line(-1,0){80}} \put(40,20){\vector(0,1){20}} \put(120,20){\line(2,1){80}} \put(120,22){\line(2,1){80}} \put(120,20){\line(1,0){80}} \put(200,20){\vector(0,1){20}} \end{picture} \end{figure} \begin{figure} \begin{picture}(80,80) \put(120,20){\circle*{20}} \put(120,20){\line(-1,0){90}} \put(120,22){\line(-1,0){90}} \put(30,20){\vector(0,1){30}} \put(120,20){\line(1,0){55}} \put(175,20){\vector(0,1){10}} \put(120,20){\line(4,5){55}} \put(120,24){\line(4,5){55}} \end{picture} \caption{ } \end{figure} Nat\"urlich wird ein Flugzeug auch um die anderen beiden Achsen stabi\-li\-siert. Das Schulflugzeug {\em Cessna 150\/} ist aerodynamisch derart stabil, da\ss{} man Anf\"angern halb scherzhaft empfiehlt, in absoluten Paniksituationen f\"ur kurze Zeit auf jeden weiteren Eingriff in die Steuerung zu verzichten; das Flugzeug nimmt dann von selbst wieder die \glqq richtige\grqq{} Fluglage ein (gen\"ugende Flug\-h\"o\-he nat\"urlich vorausgesetzt). Der geplagte PC-Benutzer von heute w\"urde sich \"ahnlich stabile Computerprogramme w\"unschen. \subsubsection{Gewollte Instabilit\"at?} Aerodynamische Stabilit\"at ist eine n\"utzliche Eigenschaft, besonders wenn man an die Fliegerausbildung oder an Verkehrsflugzeuge denkt. Man sollte eigentlich annehmen, da\ss{} es nur aerodynamisch stabile Flugzeuge gibt bzw.\ jeweils ein besonders hoher Grad an aerodynamischer Stabilit\"at erzielt wird. Das ist jedoch nicht so! Zum einen reduziert eine starke V-Stellung der Tragfl\"ugel nat\"urlich auch im normalen Flugzustand den Auftrieb auf beiden Seiten, w\"ahrend der Luftwiderstand in voller H\"ohe erhalten bleibt. Ein zu hohes Ma\ss{} an Stabilit\"at beeintr\"achtigt also die Wirt\-schaft\-lich\-keit (\glqq Effizienz\grqq ). Bei speziellen Anwendungen, z.B. beim Kunstflug oder beim Luftkampf k\"onnen die stabilisierenden R\"uckstellkr\"afte au\ss{}erdem dazu f\"uhren, da\ss{} die gew\"unschten schnellen Bewegungen nicht m\"oglich sind. Kunstflugmaschinen sind deshalb sehr wenig stabil oder sogar {\em aerodynamisch indifferent\/}, d.h.\ die Tragfl\"achen sind vollkommen waagerecht angeordnet. Moderne Kampfflugzeuge sind in der Regel sogar {\em aerodynamisch instabil\/}; sie haben eine negative V-Stellung der Tragfl\"achen. Ein Flug mit solchen Maschinen ist ein Balanceakt, der h\"ochste Konzentration des Piloten verlangt; daher \"ubernimmt in der Regel heute ein Bordcomputer die Stabilisierung. Halten wir kurz fest: \begin{quote}\em Stabilit\"at und Wendigkeit bzw.\ Effizienz widersprechen einander (d.h.\ es gibt hier einen \glqq Trade-off\grqq , wie man auf Neudeutsch sagt); der zu w\"ahlende Kompromi\ss{} h\"angt von der geplanten Anwendung ab. \end{quote} \subsection{Stabile Software?} Schauen wir nun, ob es Software-Stabilit\"at geben kann und wie sie ggf. aussehen k\"onnte. \subsubsection{Das Mariner-Ungl\"uck.}\label{mariner} Eine der beliebtesten Anekdoten in der Software-En\-gi\-neer\-ing-Welt ist das Mari\-ner-Un\-gl\"uck \cite{mariner}. Als am 22.6.1962 die erste Venus-Sonde {\em Mariner I\/} starten sollte, mu\ss{}te die 18,5 Millionen Dollar teure Rakete vier Minuten nach dem Start wegen offensichtlich unberechenbarem Flugverhalten zer\-st\"ort werden. Als offizielle Begr\"undung wurde eine Verklemmung der Atlas-Tr\"agerrakete mit der oberen Stufe, einer Agena-Rakete, angegeben. Kurz dar\-auf tauchten jedoch Ger\"uchte auf, da\ss{} es sich in Wirklichkeit um einen Software-Fehler gehandelt hatte. Die Geschichte wird normalerweise so er\-z\"ahlt: \begin{quotation} Die Software f\"ur den Mariner I war in FOR\-TRAN hergestellt. W\"ahrend des Starts sollte in einer Schleife irgendeine Aktion dreimal ausgef\"uhrt werden. Das schreibt man in FORTRAN z.B.\ so: \vspace{1ex}\begin{tt} \begin{tabular}{ll} & DO 3 I=1,3\\ & $\vdots$ \raise 3pt\hbox{\em (Beschreibung der Aktion)\/}\\ 3 & CONTINUE \end{tabular} \end{tt} \vspace{1ex}\noindent Die {\tt DO}-Anweisung bedeutet in FORTRAN: {\em \glqq F\"uhre die Anweisungen zwi\-schen hier und der mit\/ {\tt 3} markierten Anweisung nacheinander aus f\"ur $I=1$ bis $I=3$.\grqq } Leider hatte sich der Programmierer jedoch vertippt und, was aus naheliegenden Gr\"unden von den Menschen unentdeckt blieb, geschrieben: \vspace{1ex}\begin{tt} \begin{tabular}{ll} & DO 3 I=1.3\\ & $\vdots$ \raise 3pt\hbox{\em (Beschreibung der Aktion)\/}\\ 3 & CONTINUE \end{tabular} \end{tt} \vspace{1ex}\noindent Nun hat FORTRAN folgende Eigenschaften, die sich insgesamt zu einem h\"a\ss{}lichen Effekt summieren: \medskip \begin{enumerate} \item Leerstellen (\glqq Spaces\grqq ) werden als Rauschen betrachtet und spielen gar keine Rolle; insbesondere dienen sie nicht dazu, W\"orter voneinander zu trennen. \item Variablen brauchen nicht deklariert zu werden. \item Es gibt keine sogenannten \glqq Schl\"usselw\"orter\grqq{} zur Einleitung bestimmter Sprachkonstrukte. Die Unterscheidung zwi\-schen Wertzuweisungen und anderen Ty\-pen von Anweisungen wurde z.B.\ da-\linebreak durch getroffen, da\ss{} man feststellte, ob ein\linebreak Gleichheitszeichen in der Anweisung vorkam \linebreak und, falls ja, ob sich rechts davon genau ein g\"ultiger {\em Term\/} befand. Waren beide Bedingungen erf\"ullt, handelte es sich um eine Wertzuweisung. \end{enumerate} \medskip \noindent Auf diese Weise wurde aus der beabsichtigten Schlei\-fe die Zu\-wei\-sung des Werts {\tt 1.3} an die Variable {\tt DO3I}.\footnote{Die Vorg\"ange sind in \cite{ceruzzi} (pp.~202--203) richtiggestellt. Der Fehler lag in Wirklichkeit in einem St\"uck Software, das die Geschwindigkeit der Rakete aufgrund der Abtastdaten eines Bodenradars ermitteln sollte. Beim \"Ubertragen einer handgeschriebenen Gleichung in die programmierte Fassung wurde ein Querstrich \"ubersehen, der eine Durchschnittsbildung \"uber die letzten Me\ss{}werte vorschrieb. Durch die fehlende Gl\"attung der Me\ss{}werte wurden stark schwankende Geschwindigkeiten der Rakete vorget\"auscht, die dann durch Korrektursignale der Software tats\"achlich hervorgerufen wurden. Das Programm kam \"ubrigens nur zum Einsatz, weil das Bordradar ausgefallen war, das diese Funktion normalerweise \"ubernehmen sollte. Ein NASA-Angestellter bemerkt jedoch in \cite{mercury}, da\ss{} der dem Mariner-Problem zugeschriebene Fehler in FORTRAN-Bahnberechnungsprogrammen f\"ur das Mercury-Raumfahrtprogramm aufgetreten ist, zum Gl\"uck aber schon vor dem Flug bemerkt wurde. } \end{quotation} Offensichtlich ist hier die Forderung nach Stabilit\"at in grober Weise nicht erf\"ullt, denn eine winzige \"Anderung hat katastrophale Folgen. Nat\"urlich kann man diesen Fehler nicht den FORTRAN-Entwicklern anlasten, denn FORTRAN war eine der ersten h\"oheren Programmiersprachen \"uberhaupt. Compilerbau-Techniken waren noch g\"anzlich unbekannt, und es fehlte den Entwicklern die Erkenntnis, da\ss{} die Definition einer Programmiersprache besondere Sorgfalt verlangt. Au\ss{}erdem zeigt die heutige Programmiersprachenlandschaft, da\ss{} sich FORTRAN durchaus in guter Gesellschaft befindet. Als Beispiel zeigen wir das Mariner-Codest\"uck in drei modernen Programmiersprachen: \begin{enumerate} \item\ \vspace{-\baselineskip} \begin{Modula} FOR (i$=$1; i$<=3$; ++i) f(i); \end{Modula} \item\ \vspace{-\baselineskip} \begin{Modula} FOR i := 1 TO 3 DO f(i); \end{Modula} \item\ \vspace{-\baselineskip} \begin{Modula} FOR i := 1 TO 3 DO f(i) END; \end{Modula} \vspace{-\baselineskip} \end{enumerate} Hierbei haben wir die Aktion durch eine Funktion {\tt f(i)} dargestellt. In der vorgestellten Version sind die Codest\"ucke korrekt. Setzen wir jedoch jeweils an das Ende der ersten Zeile ein Semikolon, geschieht folgendes: Bei C, der ersten Sprache, l\"auft eine leere Schleife ab; danach wird die Aktion {\tt f} genau einmal f\"ur das Argument ${\tt i}=4$ ausgef\"uhrt. Auch bei Pascal, der zweiten Sprache, l\"auft zun\"achst eine leere Schleife ab; danach wird die Aktion {\tt f} mit einem undefinierten Wert\footnote{Die Sprachdefinition l\"a\ss{}t diesen Wert undefiniert. In der Praxis wird, je nach Implementierung, {\tt i} vermutlich entweder 3 oder 4 sein.} von {\tt i} einmal ausgef\"uhrt. Nur bei dem dritten Beispiel, Modula-2, bleibt die Schleife korrekt. Zu bemerken w\"are, da\ss{} wir das Ph\"anomen der Stabilit\"at auf einer {\em Meta-Ebene\/} diskutiert haben, indem wir uns auf den Proze\ss{} der \"Ubersetzung eines Programms in die Maschinensprache beschr\"ankt haben. Es bedarf wohl keiner besonderen Betonung, da\ss{} es m\"oglich ist, auch in einer \glqq unstabilen\grqq{} Programmiersprache \glqq stabile\grqq{} Programme zu schreiben (und umgekehrt). Der R\"uckzug auf die Meta-Ebene geschah hier, um nicht zus\"atzlich zur Programmiersprache auch noch ein Anwendungsproblem ansprechen zu m\"ussen. \section{Wodurch unterscheidet sich Software von klassischen Bet\"atigungsfeldern der Ingenieure?} Das kleine Beispiel hat vielleicht bei manchen den Glauben ersch\"uttert, da\ss{} die Stabilit\"at von Software praktisch erreichbar ist. Es ist in der Tat oft genug von Ingenieuren argumentiert worden, da\ss{} Software Engineering eben {\em nicht\/} mit denselben Methoden und Techniken funktionieren kann wie die traditionellen Ingenieursdisziplinen. Wir wollen kurz einige Gr\"unde anf\"uhren, warum diese Argumentation nicht so einfach von der Hand zu weisen ist. \subsection{Naturwissenschaftliche Grundlagen} Die klassischen Ingenieursdisziplinen haben naturwissenschaftliche Er\-kennt\-nis\-se \"uber die {\em Naturgesetze\/} zur Grundlage; diese Naturgesetze kann der Ingenieur nicht \"uber\-win\-den. Insofern gibt es eine Kontrolle der Ingenieurst\"atigkeit: Wer das Unm\"ogliche versucht, wird durch die Naturgesetze eines Besseren belehrt. Die Notwendigkeit der Erlernung und Beherrschung der naturwissenschaftlichen und mathematischen Grundlagen ist allgemein derart anerkannt, da\ss{} niemand sich ohne die erforderliche Ausbildung als Ingenieur bet\"atigen wird; andererseits geh\"oren Mathematik, Physik, Chemie wegen ihrer allgemein anerkannten N\"utzlichkeit und Notwendigkeit zum unabdingbaren Standardprogramm der Sekundar-Schulausbildung. Demgegen\"uber gibt es auf dem Software-Sektor anscheinend keine Naturgesetze; alles, was denkm\"oglich ist, erscheint auch machbar. Wer hier das Unm\"ogliche versucht, kann mit etwas Gl\"uck ziemlich lange damit durchkommen. Charakteristisches Merkmal von Software-Systemen, die das Unm\"ogliche versuchen, ist ihre gewaltige und st\"andig zunehmende Komplexit\"at. Wir f\"uhlen uns an einen Ausspruch von Alan Perlis \cite{epigrams} erinnert: \glqq In seeking the unattainable, simplicity only gets in the way.\grqq Dabei ist es keineswegs so, da\ss{} es f\"ur die Software-Erstellung keine Grundlagen einer den Naturgesetzen gleich-\linebreak kommenden Qualit\"at g\"abe; die theoretische Informatik beweist, zur\"uckgehend auf G\"odel und Turing, da\ss{} bestimmte Fragen aus prinzipiellen Erw\"agungen heraus unm\"oglich\linebreak durch ein Programm beantwortet werden k\"onnen; von anderen Fragen, die theoretisch l\"osbar sind, beweist sie, da\ss{} sie einen prohibitiv gro\ss{}en Rechenaufwand verlangen. Solches Grundlagenwissen ist aber von v\"ollig anderer Art als physikalische Gesetze. Auch ist es unter den Programmierern noch nicht \"uberall verbreitet und es wird in den Schulen nicht allgemein gelehrt. Wenn in den Schulen \"uberhaupt Informatik gelehrt wird, wird darunter meist nur eine Einf\"uhrung in die Handhabung des Computers verstanden, bestenfalls verbunden mit einem Programmierkurs. Sch\"uler eines T\"ubinger Informatik-Kurses etwa, gefragt, ob sie Informatik studieren wollten, antworteten, da\ss{} sie bereits jetzt alles \"uber ihren Computer w\"u\ss{}ten, was sie brauchten, und da\ss{} sie sich nicht vorstellen k\"onnten, was es da im Studium noch zu lernen g\"abe. So kann der Traum vom Software-Engineering nat\"urlich nicht wahr werden! Ganz im Einklang damit gibt es zahlreiche Leute, die glauben, da\ss{} bereits die Beherrschung der Syntax einer Programmiersprache sie zu Programmierern macht. In vieler Hinsicht \"ahnelt die heutige Software-Praxis dem Zustand der Ingenieurswissenschaften zur Renaissancezeit, als mit unglaublicher Imagination und Raffinesse immer wieder versucht wurde, ein \glqq Perpetuum mobile\grqq{} zu konstruieren, und man das Nicht-Funktionieren der Apparaturen auf die mangelnde handwerkliche Qualit\"at der Ausf\"uhrung zur\"uckf\"uhrte. Hat man den zweiten Hauptsatz der Thermodynamik einmal verstanden, sieht man dagegen die Fruchtlosigkeit dieser Bem\"uhungen sofort ein. Wenn heute auf dem Software-Sektor \"ahnlich Unm\"ogliches versucht wird und nat\"urlich nicht funktioniert, schiebt man die Schuld auf ein paar fehlende Megabyte Hauptspeicher oder ein paar fehlende Megahertz Prozessortaktfrequenz.\newpage \subsection{Gegensatz analoge Welt und digitale Welt} {\em Klassische Ingenieursdisziplinen\/} operieren weitgehend in einer {\em analogen Welt\/}; sie haben mit {\em stetigen Funktionen\/} zu tun. Der Begriff der stetigen Funktion dr\"uckt gerade das Prinzip aus, da\ss{} kleine \"Anderungen kleine oder doch wenigstens verh\"altnism\"a\ss{}ig kleine Auswirkungen haben. So wird z.B.\ ein Stab, auf den man nach und nach immer gr\"o\ss{}ere Biegekr\"afte aus\"ubt, innerhalb eines bestimmten Bereichs seine Form in genauer Entsprechung zu der aus\-ge\-\"ub\-ten Kraft ver\"andern. Nat\"urlich gibt es Unstetigkeitsstellen, wenn z.B.\ die Kraft dazu f\"uhrt, da\ss{} der Stab bricht; aber es geh\"ort zum Hand\-werk des Ingenieurs, die zahlenm\"a\ss{}ig wenigen Unstetigkeitsstellen zu erkennen und im normalen Betrieb seiner Konstruktion zu vermeiden. In der Regel hat man es mit stetigen Funktionen zu tun. Im {\em Software-Engineering\/} haben wir es demgegen\"uber von Hause aus mit einer {\em digitalen Welt\/} zu tun. W\"ahrend in einem analogen Modell die modellierende Gr\"o\ss{}e ein {\em direktes Abbild\/} der entsprechenden physikalischen Gr\"o\ss{}e ist, wird in einer digitalen Darstellung eine pysikalische Gr\"o\ss{}e durch eine {\em symbolische Beschreibung\/}, z.B.\ Zahlen in einer bestimmten Notation, dargestellt. Der Begriff stetige Funktion spielt hier keine Rolle, es herrscht vielmehr maximale Unstetigkeit. Wenn man in einer 64-bit-Bin\"arzahl eine einzige Stelle von 0 zu 1 \"andert, entsteht nicht unbedingt eine \glqq ganz \"ahnliche\grqq , sondern unter Umst\"anden eine weit entfernte Zahl. Selbst kleinste \"Anderungen k\"onnen schon im Zahlenbereich also gr\"o\ss{}te Auswirkungen haben. In der Software ist es erst recht so. Diese Bemerkungen w\"urden im Grunde auch auf die Computer-Hardware zutreffen, die jedoch im Gegensatz zur Software als ausgesprochen zuverl\"assig gilt. Wie Parnas \cite{sdi} aber richtig bemerkt, ist die Computer-Hardware hochgradig repetitiv ausgelegt, d.h.\ sie besteht aus vielen Kopien sehr kleiner digitaler Subsysteme. Jedes dieser Subsysteme kann analysiert und ersch\"opfend getestet werden, so da\ss{} ein ersch\"opfender Test der gesamten Hardware nicht n\"otig ist. Dieser Redundanz-Effekt der im Raum abgewickelten repetitiven Hardware-Struktur mu\ss{} in der Software u.U.\ anders bewerkstelligt werden. \section{Beitrag der Programmiersprachen zur Software-Stabilit\"at} Wir wollen an dieser Stelle diskutieren, wie weit die Programmiersprache als wesentliches Werkzeug des {\em Software-Ingenieurs\/} zur Stabilit\"at beitragen kann. Wir meinen, da\ss{} der Programmiersprache in dieser Funktion h\"aufig zu wenig Beachtung geschenkt wird.\footnote{Von McCarthy wird immer wieder gern der Ausspruch zitiert: \glqq Es spielt keine Rolle, welche Sprache Sie verwenden, sie sind beide sehr gut\grqq{}, wobei er zwei LISP-Dialekte meinte.} Im Software-Engineering unterscheidet man zwischen {\em Programmieren im Gro\ss{}en\/} und {\em Programmieren im Kleinen\/}: \subsection{Programmieren im Gro\ss{}en} Gr\"o\ss{}ere Programme werden normalerweise nicht als monolithische Bl\"ocke konstruiert, sondern in {\em Module\/} unterteilt, die jeweils getrennt programmiert werden, m\"oglicherweise sogar von verschiedenen Programmierern. Unter Programmieren im Gro\ss{}en versteht man die Anlage einer Modulstruktur und die genaue Abstimmung der Schnittstellen zwi\-schen den einzelnen Modulen. Ein wichtiges Problem beim Programmieren im Gro\ss{}en ist, die \glqq richtigen\grqq{} Schnittstellen zu finden und konsistent einzuhalten. Hier kann sicherliches vieles von dem sinnvoll eingebracht werden, was heute unter dem Stichwort {\em \glqq objektorientiertes Programmieren\grqq \/} diskutiert wird, aber bereits viel fr\"uher durch die Theorie der abstrakten Datentypen vorbereitet wurde. Ein landl\"aufiges Vorurteil ist, da\ss{} man zum objektorientierten Programmieren eine objektorientierte Programmiersprache (meist C++) braucht. Dies ist nicht so, man kann selbst im Assembler objektorientiert programmieren. Hilfreich ist aber zumindest eine moderne Programmiersprache wie Ada oder Modula-\nolinebreak 2, die das Programmieren im Gro\ss{}en insoweit unterst\"utzt, als Schnittstellenbeschreibungen innerhalb der Programmiersprache m\"oglich sind und automatisch \"uberpr\"uft werden. Der gr\"o\ss{}te Teil des Programmierens im Gro\ss{}en findet jedoch noch au\ss{}erhalb der Programmiersprache statt und soll hier nicht weiter betrachtet werden. \subsection{Programmieren im Kleinen} Programmieren im Kleinen ist Programmieren innerhalb eines einzelnen Moduls. Fehler, die ein Programmierer dabei macht, kann man (u.a.) in die folgenden beiden Klassen einteilen: \begin{description} \item[{\bf Syntaktische Fehler}] sind Fehler im Satzbau oder in der Rechtschreibung der Programmiersprache. Sie werden sp\"ates\-tens dann erkannt und angemahnt, wenn wir versuchen, dieses Programm zu \"ubersetzen. \item[{\bf Semantische Fehler}] sind Fehler in der {\em Bedeutung\/} des Programms. Hier hat der Programmierer etwas anderes hingeschrieben als er gemeint oder beabsichtigt hat. Diese Fehler sind h\"aufig schwer zu finden und grunds\"atzlich nicht automatisch zu entdecken. \end{description} \noindent Es lohnt sich daher, Programmiersprachen so zu entwerfen, da\ss{} {\em m\"oglichst viele se\-man\-ti\-sche Fehler in syntaktische Fehler verwandelt\/} werden und somit hoffentlich maschinell festgestellt werden k\"onnen. Dann kann z.B.\ das oben geschilderte Mariner-Problem nicht mehr so leicht auftreten. (Man beachte, da\ss{} hier in Wirklichkeit ein {\em Rechtschreibfehler\/} vorlag, der jedoch aufgrund der Sprach\-de\-fi\-ni\-tion von FORTRAN nicht maschinell bemerkt werden konnte und somit zu einem semantischen Fehler wurde!) Dazu sind die in den folgenden Abschnitten diskutierten Konzepte sinnvoll; im Grunde lassen sie sich alle unter dem Stichwort {\em Redundanz\/} zusammenfassen: Durch von der Programmiersprache erzwungene \glqq Zutaten\grqq{} wird die Redundanz der Algorithmenbeschreibung k\"unstlich erh\"oht, so da\ss{} eine Konsistenz\"uberpr\"ufung m\"oglich wird. (Auch hier bekommen wir, wie in der Aerodynamik, die Stabilit\"at nicht zum Nulltarif.) Am Mariner-Beispiel haben wir prototypisch vorgef\"uhrt, wie so etwas aussehen k\"onnte. In Anlehnung an das bereits l\"anger propagierte \glqq defensive Fahren\grqq{} sollte man das {\em defensive Programmieren\/} (z.B.\ \cite{LiGu86}, Kap.~5) viel st\"arker betonen und dementsprechend auch \glqq defensive Programmiersprachen\grqq{} empfehlen. \vspace{-7pt} \subsubsection{Reservierte Schl\"usselw\"orter.} Wenn man verhindert, da\ss{} die Schl\"usselw\"orter der Sprache (z.B. {\tt DO}) auch als Bezeichner f\"ur Da\-ten\-ob\-jek\-te vorkommen k\"onnen, sind viele Fehler bereits ausgeschlossen. Die Schl\"usselw\"orter haben etwa die gleiche Funktion wie {\em Wegweiser\/} in Stra\ss{}enverkehr: Wenn man sich geringf\"ugig verirrt hat, k\"onnen sie auf den rechten Weg zur\"uckhelfen. Das (falsche) Mariner-Problem w\"are nicht aufgetreten, wenn {\tt DO} ein Schl\"usselwort der Sprache FORTRAN und \glqq Space\grqq{} ein Trennsymbol gewesen w\"are. \vspace{-7pt} \subsubsection{Datentypen.} Da\ss{} es Daten unterschiedlicher Typen gibt, ist uns aus dem Alltagsleben bekannt; so kann man etwa Zahlen addieren, w\"ahrend diese Operation f\"ur Buchstaben keinen Sinn ergibt. Praktisch alle Programmiersprachen erlauben es, Daten unterschiedlicher Typen zu verwenden und bei vielen gilt es als ein Fehler, wenn versucht wird, Operationen ausf\"uhren, die f\"ur diesen Typ nicht vorgesehen sind. In der Regel wird n\"amlich schlicht eine Ver\-wechs\-lung vorliegen, wenn ein Programmierer z.B.\ versucht, eine Buchstabenvariable zu einer Zahlvariablen zu addieren. Eine Ausnahme bildet hier die Programmiersprache C, die (in der Definition nach Kernighan und Ritchie \cite{kr}) zwar auch Datentypen unterscheidet, aber dieser Unterscheidung praktisch nur {\em erkl\"arenden\/} Wert beimi\ss{}t. Es wird als v\"ollig normal erachtet, wenn man zu einem Buchstaben z.B.\ die Zahl 32 addiert und das Ergebnis dann wom\"oglich durch ein logisches \glqq und\grqq{} mit einer weiteren Zahl verkn\"upft. C ist eine Programmiersprache mit gro\ss{}em Gewicht auf Wendigkeit und Effizienz und wenig Liebe f\"ur Stabilit\"at. Das ist aber auch nicht weiter verwunderlich, denn die Konstrukteure von C betrachten diese Sprache als eine \glqq niedrige\grqq , also stark der Ma\-schi\-ne verwandte Sprache \cite{kr} und insofern als eine Art Luxus-Assembler. Eine solche Sprache wird aber typischerweise von Experten verwendet, die in der Regel wissen sollten, was sie tun (siehe Kunstflug!). F\"ur den Anf\"anger ist sie nicht zu gebrauchen. Im \"ubrigen verlangt man aber auch von Kunstfliegern und Trapezartisten die Einhaltung bestimmter Vorsichtsma\ss{}nahmen. Anerkennenswert sind deshalb die Versuche des ANSI-Komitees, die Sprache u.a.\ durch ein sch\"arferes Typkonzept sicherer zu machen; die resultierende Sprache ANSI-C wird jedoch von C-Programmierern h\"aufig als \glqq Anti-C\grqq{} verspottet und entsprechend wenig geliebt. Um so wichtiger ist die Aussage von D.~Ritchie \cite{ritchie_hopl}, da\ss{} er die Pr\"azisierungen von ANSI-C sehr begr\"u\ss{}t und selber C-Programme nur noch in ANSI-C schreibt. \vspace{-7pt} \subsubsection{Deklarationen.} Viele Programmiersprachen bestehen darauf, da\ss{} alle Variablen usw., die im Programm verwendet werden, auch {\em deklariert\/} werden. Auch hierdurch k\"onnen zahlreiche Ver\-wechs\-lun\-gen und Tippfehler erkannt werden. Im \glqq Mariner-Beispiel\grqq{} w\"are etwa eine fehlende Deklaration f\"ur den Bezeichner {\tt DO3I} angemahnt worden und h\"atte somit das Augenmerk auf die Fehlerstelle gelenkt. \vspace{-7pt} \subsubsection{Logische, \"ubersichtliche Syntax.} Es d\"urfte allgemein anerkannt sein, da\ss{} die Programmiersprache C nicht unbedingt \"uber eine logische, \"ubersichtliche Syntax verf\"ugt. Kernighan und Ritchie haben eher Wert darauf gelegt, vollen Zugriff auf die M\"oglichkeiten der Maschine mit minimalem Tippaufwand zu erhalten. Aber auch die sonst sehr ger\"uhmte und f\"ur Ausbildungszwecke gerne verwendete Sprache Pascal ist in dieser Beziehung nicht vollkommen, wie wir am \glqq Semikolon-Problem\grqq{} gesehen haben. \subsection{Funktionaler Ansatz} Das Hauptproblem bei Programmiersprachen wie C, FORTRAN und Pascal sind jedoch die {\em Seiteneffekte\/}. Wir nennen diese Art von Programmiersprachen {\em imperative\/} Programmiersprachen, weil sie dem Rechner im einzelnen vorschreiben, was er zu tun hat. Das Programm lebt in einem {\em Zu\-stands\-raum\/}, der durch die jeweiligen Inhalte der Programmvariablen gegeben ist. Die genaue Bedeutung einer Programmanweisung ist dann nicht nur vom Inhalt dieser Anweisung selbst, sondern auch vom Zustandsraum abh\"angig und damit implizit von der gesamten Geschichte der Pro\-gramm\-aus\-f\"uh\-rung seit dem Start des Programms. Das macht Aussagen \"uber das Programm extrem schwierig. Es schockiert immer wieder, mit welcher Leichtigkeit und Selbstverst\"andlichkeit folgende \"Ubungsaufgabe selbst von Anf\"angern in der Pascal-Programmierung ge\-l\"ost wird: \begin{quotation}\em Schreiben Sie ein Pascal-Programm mit einer\linebreak Funktion\\ \centerline{\tt f(x:Integer):Integer}\\ so da\ss{} bei der Anweisung\\ \centerline{{\bf if } {\tt f(x) = f(x)} {\bf then} \ldots {\bf else} \ldots}\\ der {\bf then}-Zweig niemals betreten werden kann. \end{quotation} \noindent Die interessante Frage hierbei ist doch, wie man noch logisch \"uber ein Programm argumentieren kann, bei dem $f(x)\not=f(x)$ gilt oder wenigstens gelegentlich gelten kann!\footnote{In Pascal mu\ss{} man immerhin noch Funktionen bem\"uhen, um Seiten\-effekte zu erhalten. In C ist auch dies problemlos innerhalb einfacher arithmetischer Ausdr\"ucke m\"oglich.} John Backus, der Vater von FORTRAN, hat sich in seiner \glqq Turing Award Lecture\grqq \cite{Ba78} stark daf\"ur gemacht, die imperativen Programmiersprachen und das mit ihnen verbundene {\em Zu\-stands\-den\-ken\/} jetzt zu verlassen und durch sogenannte {\em funktionale\/} oder {\em applikative\/} Programmiersprachen zu ersetzen. Solche Programmiersprachen gab es selbstverst\"andlich schon vor dem Vortrag von Backus, auch wenn die in diesem Zusammenhang oft aufgef\"uhrte Sprache LISP gerade kein Paradebeispiel f\"ur eine funktionale Sprache ist. Bei einer funktionalen Sprache steht der mathematische Begriff der {\em Funktion\/} bzw.\ der Funktionsanwendung ({\em Applikation\/}) im Vordergrund. Wir stellen den Unterschied an einem Beispiel dar. Zu programmieren sei die Verkettung {\tt Append} zweier Zeichenreihen, mit z.B.\ {\tt Append("{}abc"{},"{}def"{}) =\linebreak \pagebreak "{}abcdef"{}}. Als erstes betrachten wir eine imperative L\"o\-sung in Mo\-dula\,-2. Ein kleines Problem am Rande ist, da\ss{} es in Modula-2 (ebenso wie in Pascal) nicht m\"oglich ist, Zeichenketten als Resultat einer Funktion zur\"uckzugeben. Wir definieren {\tt Append} daher mit drei Parametern, wobei der erste Parameter der Ausgabeparameter ist. Die verbotene Anweisung {\tt u := Append(v,w)} simulieren wir also durch den Aufruf {\tt Append(u,v,w)}: \begin{Modula} PROCEDURE Append(VAR u: ARRAY OF CHAR; v,w: ARRAY OF CHAR); VAR i: CARDINAL; BEGIN FOR i := 0 TO HIGH(v) DO u[i] := v[i] END; FOR i := 0 TO HIGH(w) DO u[HIGH(v)+1+i] := w[i] END END Append; \end{Modula} \bigskip \noindent Wie man sieht, beschreiben wir in Modula-2 ausf\"uhrlich die \"Anderung des Pro{}gramm{}zu{}stands: In das Feld {\tt u} wird zun\"achst der Inhalt von {\tt v} hineinkopiert und anschlie\ss{}end der Inhalt von {\tt w}. Die R\"uckgabe des Ergebnisses {\tt u} geschieht durch einen Seiteneffekt. Es liegt ein starkes Gewicht auf der Frage \glqq Wie?\grqq . Wir m\"ussen eine Hilfsvariable definieren und sogar die Reihenfolge des Kopierens der einzelnen Buchstaben genau festlegen, obwohl uns diese Frage gar nicht interessiert. Betrachten wir nun eine L\"osung in der funktionalen Sprache HOPE: \begin{Modula} dec Append: list(char) X list(char)\newline ~~~~~~~~~~~~$\rightarrow$list(char); --- Append(nil,w) $\Leftarrow$ w; --- Append(a::v,w) $\Leftarrow$ a::Append(v,w); \end{Modula} \bigskip \noindent Zun\"achst f\"allt auf, da\ss{} die L\"osung in HOPE wesentlich k\"urzer ist; das h\"angt jedoch zum Teil damit zusammen, da\ss{} es in HOPE Zeichenreihen als vordefinierten Datentyp mit \glqq eingebauter\grqq{} Konkatenation {\tt ::} gibt. Wesentlicher ist, da\ss{} das HOPE-Programm auf dem {\em Funktionsbegriff\/} aufbaut. {\tt Append} wird als eine Funktion deklariert, die aus zwei Zeichenreihen eine dritte konstruiert. Es gibt keine Seiteneffekte. Das Hauptgewicht liegt auf der Frage \glqq Was?\grqq : Die zweite Zeile besagt, da\ss{} die Verkettung der leeren Zeichenreihe mit einer Zeichenreihe {\tt w} wiederum {\tt w} ergibt. Die dritte Zeile sagt folgendes: \glqq Wenn das erste Argument aus einem einzelnen Zeichen {\tt a}, gefolgt von einer Zeichenreihe {\tt v} besteht, ist das Ergebnis das Zeichen {\tt a}, gefolgt von {\tt Append(v,w)}\grqq . Auf welche Weise der Computer diese Vorschrift erf\"ullt, ist ihm selbst \"uberlassen; es ist daher wesentlich mehr Raum f\"ur Optimierungen gelassen als bei imperativen Programmiersprachen. Da es keine Seiten\-effekte mehr gibt, ist die Bedeutung eines Programmst\"ucks nicht mehr von der Geschichte der Programmausf\"uhrung \pagebreak abh\"angig. Bei der Auswertung eines Ausdrucks der Form $f(x_1,\ldots,x_n)$ spielt es daher keine Rolle, in welcher Reihenfolge die $x_1,\ldots,x_n$ ausgewertet werden. Insbesondere k\"onnten diese Argumente auf einer Maschine mit Parallelverarbeitungsm\"oglichkeit auch {\em gleichzeitig nebeneinander\/} berechnet werden. In einem imperativen Rahmen ist es dagegen aufgrund der Seiteneffekte wesentlich schwieriger, M\"oglichkeiten zur Parallelverarbeitung zu erkennen. Eine weitere Eigenschaft funktionaler Sprachen, die wir hier nicht kommentieren k\"onnen, obwohl sie auch von gros\-sem Interesse f\"ur Software-Engineering-Belange ist, ist die M\"og\-lich\-keit der Definition von {\em Funktionen h\"oheren Typs\/}, also Funktionen, die nicht nur andere Funktionen als Argumente akzeptieren, sondern auch Funktionen als Resultate liefern k\"onnen. Der interessierte Leser sei etwa auf \cite{hinze} verwiesen. \vspace{0.3cm} \section{Schlu\ss{}folgerungen} Betrachten wir Software-Engineering etwa im Sinne der eingangs aufgef\"uhrten IEEE-Definition, so mu\ss{} man konstatieren, da\ss{} wir in den fast 25 Jahren erhebliche Fortschritte gemacht haben. Produktion von Software ist heute in der Tat in disziplinierter, me\ss{}barer und pr\"ufbarer Art und Weise m\"oglich und weitgehend auch \"ublich. Trotzdem k\"onnen wir noch nicht wirklich Software nach ingenieursm\"a\ss{}igen Regeln im wesentlichen fehlerfrei herzustellen. Ein Grund hierf\"ur mag sein, da\ss{} im Bereich Informatik eine Grundlagenausbildung in der Schule noch fehlt, die das Niveau der Ausbildung in den Naturwissenschaften erreicht und nicht alle Software-Praktiker ein Informatik-Studium absolvieren, in dem sie die Grundlagen der Softwaretechnik lernen k\"onnten. Ein anderer Grund ist sicher, da\ss{} unsere {\em Werkzeuge\/}, also vor allem die Programmiersprachen, noch nicht perfekt genug sind. C.~A.~R.\ Hoare sagt in \cite{clothes}: \vspace{0.2cm} \begin{quotation} \em \glqq Eine unzuverl\"assige Programmiersprache, die unzuverl\"assige Programme erzeugt, stellt ein wesentlich gr\"o\ss{}eres Risiko f\"ur unsere Umwelt und unsere Gesellschaft dar als unsichere Autos, giftige Pestizide oder Unf\"alle in Kernkraftwerken.\grqq \end{quotation} \vspace{0.2cm} \noindent Speziell die funktionalen oder sogar noch allgemeiner die {\em deklarativen\/} Programmiersprachen k\"onnen, sofern sie mit hinreichender Effizienz praktisch angeboten werden, zu leichter handhabbaren, austauschbaren und verst\"andlichen Modulen f\"uhren und so im Sinne eines \glqq Baukastensystems\grqq{} die ingenieurgem\"a\ss{}e Konstruktion gro\ss{}er Pro\-gram\-me erm\"oglichen. \vspace{0.3cm} \begin{acknowledgement} Herrn Prof.\ F.~L.\ Bauer, mit dem ich w\"ahrend der HOPL-II-Konferenz eine Vorversion dieses Beitrags ausf\"uhrlich durchdiskutieren durfte, m\"ochte ich f\"ur zahlreiche Anregungen herzlich danken. \end{acknowledgement} \newpage \begin{thebibliography}{Literatur} \bibitem{Ba78} Backus, J.: \newblock Can programming be liberated from the von {N}eumann style? {A} functional style and its algebra of programs. In: ACM Turing Award Lectures -- The First Twenty Years, p. 63--130. Reading, MA: Addison-Wesley, 1987 \newblock (first published in Commun.\ ACM {\it 21}, 613--641 (1978)) \bibitem{bauerzh} Bauer, F.L.: \newblock Informatik und {A}lgebra. \newblock In: Broy, M. (Hrsg.) Informatik und Mathematik, p. 28--40. Berlin: Springer 1991. \newblock Vortrag beim Festkolloquium \glqq 20 Jahre Institut f\"ur Informatik\grqq , Z\"urich 1988 \bibitem{bauer93} Bauer, F.L.: \newblock Software {E}ngineering -- wie es begann. \newblock Inf. Spektrum {\it 16}(5), 259--260 (1993) \bibitem{ceruzzi} Ceruzzi, P.: \newblock Beyond the Limits -- Flight Enters the Computer Age. \newblock Cambridge, Mass.: MIT Press 1989 \bibitem{whirlwind} Everett, R.E.: \newblock Whirlwind. \newblock In: \cite{metro}, p. 365--384 \bibitem{hinze} Hinze, R.: \newblock {Einf\"uhrung} in die funktionale Programmierung mit Miranda. \newblock Stuttgart: Teubner 1992 \bibitem{clothes} Hoare, C.A.R.: \newblock The emperor's old clothes. \newblock In: ACM Turing Award Lectures -- The First Twenty Years, p. 143--161. Reading, MA: Addison-Wesley 1987 \newblock (first published in Commun.\ ACM {\it 24}(2), 75--83 (1981)) \bibitem{stdgloss} {Institute of Electrical and Electronic Engineers} (Hrsg.): \newblock Standard Glossary of Software Engineering Terminology. \newblock IEEE Standard 610.12-1990, 1990 \bibitem{kr} Kernighan, B., Ritchie, D.M.: \newblock The C Programming Language. \newblock Englewood Cliffs: Prentice Hall 1978 \bibitem{licklider} Licklider, J.C.: \newblock Underestimates and overexpectations. \newblock In: Chayes, A., Wiesner, J. (Hrsg.) ABM: An Evaluation of the Decision to Deploy and Anti-Ballistic Missile. London: Harper \& Row 1969 \bibitem{LiGu86} Liskov, B., Guttag, J.: \newblock {Abstraction and specification in program devel\-opment }. \newblock The MIT electrical engineering and computer science series. Cambridge, Mass.: MIT Press 1986 \bibitem{metro} Metropolis, N., Howlett, J., Rota, G.-C. (eds.): \newblock A History of Computing in the Twentieth Century. \newblock New York: Academic Press 1980 \bibitem{garmisch} Naur, P., Randell, B. (Hrsg.): \newblock Software Engineering. Report on a conference sponsored by the NATO Science Committee. Garmisch, Germany, 7th to 11th October 1968. \newblock Bruxelles: NATO Scientific Affairs Division 1969 \bibitem{mariner} Neumann, P.G.: \newblock Risks to the public in computer systems. \newblock ACM Software Eng. Notes {\it 11}(5), 17 (1986) \bibitem{cardiff} Neumann, P.G.: \newblock Risks to the public in computers and related systems. \newblock ACM Software Eng. Notes {\it 12}(1), 3 (1987) \bibitem{vincennes1} Neumann, P.G.: \newblock Risks to the public in computers and related systems. \newblock ACM Software Eng. Notes {\it 13}(4), 3 (1988) \bibitem{vincennes2} Neumann, P.G.: \newblock Risks to the public in computers and related systems. \newblock ACM Software Eng. Notes {\it 14}(1), 6--9 (1989) \bibitem{mercury} Neumann, P.G.: \newblock Risks to the public in computers and related systems. \newblock ACM Software Eng. Notes {\it 15}(1), 20 (1990) \bibitem{sdi} Parnas, D.L.: \newblock Software aspects of strategic defense systems. \newblock Commun. ACM {\it 28}(12), 1326--1335 (1985) \bibitem{epigrams} Perlis, A.: \newblock Epigrams on programming. \newblock SIGPLAN Notices {\it 17}(9), 7--13 (1982) \bibitem{ritchie_hopl} Ritchie, D.: \newblock Response to a question by {H.\ Klaeren}. \newblock ACM Conf.\ History of Programming Languages II (to appear) \bibitem{shore} Shore, J.: \newblock Why {I} never met a programmer {I} could trust. \newblock Commun. ACM {\it 31}(4), 372--375 (1988) \end{thebibliography} \begin{small} \noindent Eingegangen 25.5.1993; in \"uberarbeiteter Form 10.1.1994\\[2mm] Prof. Dr. Herbert Klaeren\\ Wilhelm-Schickard-Institut f\"ur Informatik\\ Arbeitsbereich Programmierung\\ Eberhard-Karls-Universit\"at T\"ubingen\newline Sand 13, D-72076 T\"ubingen\par \end{small} \end{document} \bye