Dieser Gastartikel ist ein Beitrag zum ScienceBlogs Blog-Schreibwettbewerb. Alle eingereichten Beiträge werden im Lauf des Septembers hier im Blog vorgestellt. Danach werden sie von einer Jury bewertet. Aber auch alle Leserinnen und Leser können mitmachen. Wie ihr eure Wertung abgeben könnt, erfahrt ihr hier.
Dieser Beitrag wurde von Markus eingereicht.
———————————————————————————————————————–
Wenn jemand erfährt, dass ich im Fachbereich Softwaretechnik
(oder im Englischen "Software Engineering") meine Doktorarbeit
geschrieben habe, dann wird das meistens mit einem "Aha." und einem freundlichen
Lächeln quittiert. Ich vermute, dass die betreffende Person das dann abheftet
unter "Hat was mit Computern zu tun" und sich gegebenenfalls vornimmt
auf mich zurück zu kommen, wenn der eigene Rechner mal wieder streikt. Im
Zusammenhang mit dieser Wahrnehmung soll der berühmte Informatiker Edsger W.
Dijkstra mal gesagt haben "Computer Science is no more about computers
than astronomy is about telescopes". (Die Informatik hat mit Computern nur
so viel zu tun wie Astronomie mit Teleskopen.) Unabhängig davon ob diese
Zuschreibung nun stimmt oder Folklore ist, verdeutlicht der Satz ein Problem,
das vermutlich viele Berufe haben: Die Allgemeinheit hat ein eher vages Bild
davon, was jemand, der diesen Beruf ausübt eigentlich so macht. Florian hat in
den vergangen Jahren hier viel, viel geschrieben, durch das ich eine Menge über
Astronomie lernen konnte. Und es hat sich dabei eher selten explizit um
Teleskope gedreht. Nun möchte ich für die Softwaretechnik einmal versuchen,
einen kleinen Einblick in diese Disziplin zu geben. Und dabei wird es praktisch
gar nicht um Computer gehen…
Womit beschäftigt sich die Softwaretechnik eigentlich?
Kurz gesagt beschäftigt sich Softwaretechnik mit der
ingenieursmäßigen Entwicklung von Software. (Mit dieser Definition ist man auch
ganz nah dran an der englischen Bezeichnung Software Engineering.) Das ist ganz
ähnlich wie bei anderen Ingenieursberufen. Maschinenbauingenieure beschäftigen
sich mit dem Entwurf und der Konstruktion von Maschinen und industriellen
Anlagen. Bauingenieure kümmern sich um die Planung und den Bau von Gebäuden.
Und Softwaretechniker oder Softwareingenieure entwerfen und entwickeln
Software. Nun ist bei industriellen Anlagen oder Hochhäusern für jeden
einsichtig, dass man Experten benötigt um sowas zu konstruieren. Seinen
Gartenschuppen zimmert vielleicht noch ein jeder auf eigene Faust zusammen.
Aber bei größeren Projekten lässt man das lieber die Profis machen. Um zu
verstehen, warum es sinnvoll und sogar notwendig ist, das bei Software genauso zu
handhaben, muss man zunächst ein wenig über Software und deren Entwicklung im
Allgemeinen wissen.
Warum ist das sinnvoll?
Software steckt längt nicht nur dort, wo es offensichtlich
ist, also in Desktop-Rechnern, Tablet-Computern, Spielkonsolen, Handys, usw.
Mittlerweile steckt in fast jedem Gerät, das einen elektronischen Anteil hat
auch ein Stückchen Software: Kaffeemaschinen, Kühlschränke, Ampelanlagen,
Armbanduhren, Klimaanlagen, und so weiter. Das gilt auch und vor allem für
Autos und für Flugzeuge. Seit Ende der Achtziger Jahre haben Passagiermaschinen
in den meisten Fällen kein mechanisches Notfallsystem für die Steuerung mehr an
Bord. Das heißt die Steuerklappen sind nicht mehr über Stahlseile, Schubstangen
oder Ähnliches mit dem Steuerknüppel im Cockpit verbunden. Alles funktioniert
rein elektronisch mit der Hilfe von Software. Und in modernen Autos stecken
hunderte von eingebetteten „Controllern“. Kleinstrechnern, die bestimmte
Funktionen steuern: Elektrische Fensterheber, Bremsen, Airbags, ESP… Wenn man
sich das vor Augen führt, dann wird schnell klar, dass die Software, die in
diesen Geräten läuft besser gut funktionieren sollte. Damit stellt sich
automatisch die nächste Frage: Ist es eigentlich schwierig korrekt
funktionierende Software zu entwickeln? Und wenn ja, warum?
Warum ist Softwareentwicklung schwierig?
Software wird in den allermeisten Fällen geschrieben. Man
schreibt ein Programm, das der Computer dann ausführen kann. Das hat
Ähnlichkeit mit einem Kochrezept. Zum Beispiel „Öffne Datei X. Suche darin Wert
Y. Zeige Y zusammen mit Ausgabe Z auf dem Bildschirm an.“ Das klingt erstmal
recht simpel, aber es gibt viele Faktoren, die das Schreiben solcher Rezepte
erschweren. Zum Beispiel Interaktivität, Komplexität und Größe:
Interaktivität
Allerdings braucht man schon noch ein bisschen mehr
Flexibilität als bei Kochrezepten, denn Software ist meist darauf ausgelegt,
dass sie interaktiv ist, dass sie also auf Eingaben des Benutzers reagieren
kann. Daher ist es notwendig Verzweigungen in das Programm einzubauen. „Wenn
der Benutzer hier klickt, dann mache dies. Wenn er dort klickt, dann mache
das.“ Und auch Wiederholungen, Schleifen genannt, sind notwendig. Schließlich
soll der Benutzer auch mehrmals klicken dürfen. Da man vorher nicht weiß, wie der
Benutzer genau mit dem Programm interagiert, muss man sich vorher genau
Gedanken machen, was das Programm alles ermöglichen, erlauben, und verbieten
soll. Das kann manchmal eine ganze Menge sein. Allein wenn man sich die
Iconleisten von gängigen Schreibprogrammen ansieht, dann kann der Benutzer zu
jedem beliebigen Zeitpunkt alles Mögliche anstellen. Und die Software muss in
jedem Fall damit umgehen können.
Komplexität
In eingebetteten Systemen wie Autos wird das Ganze noch
komplizierter: Die Klimaanlage muss geregelt werden, das Navigationssystem muss
ständig überprüfen, ob der Fahrer sich auf der geplanten Route befindet, das
Entertainmentsystem läuft nebenbei und dann kommt plötzlich eine Vollbremsung!
In so einem Moment möchte niemand, dass der Airbag zu spät aufgeht, weil das
Navigationssystem vorher noch eine neue Route berechnen musste. Diese ganzen
Vorgänge müssen also aufeinander abgestimmt sein. Und das ohne das man vorher
weiß, welche Situationen genau auftreten werden.
Größe
Ein kompliziertes Kochrezept erstreckt sich über ein bis zwei Seiten im
Kochbuch und besteht damit aus 50 bis 100 Zeilen Text. Komplexe Software kommt
allerdings schnell auf mehrere Millionen Zeilen Programmcode. Das entspricht
eher einer Zahl von 100000 Seiten Text. Bei diesen Zahlen wird schnell klar,
dass niemand sich ein Programm einfach komplett durchlesen kann um zu
überprüfen was es tut oder ob es fehlerfrei ist. (Abgesehen davon ist
Programmcode kein Prosatext, denn man einfach „runterlesen“ kann.) Dazu kommt
noch das Problem, dass so ein ausgedrucktes Programm linear ist. Es fängt auf
Seite 1 oben an und endet unten auf Seite 1000000. Das kann man (mit viel Zeit)
zwar durchlesen, wird damit dem Ablauf der Software aber nicht gerecht. Die
oben erwähnten Schleifen müsste man mehrmals lesen, bei Verzweigungen („Wenn
dies passiert, dann tue das, sonst mach etwas anderes.“) müsste man wild im
Dokument hin und her springen. Und dadurch würde man blitzschnell die Übersicht
verlieren, was man schon gelesen hat, und was nicht.
Was kann man dagegen tun?
Es ist also nicht so leicht eine funktionierende,
komplexe Software zu entwickeln. Deswegen versucht die Softwaretechnikforschung
Werkzeuge und Methoden zu finden, die die Entwicklung von Software erleichtern.
Die Ansätze dazu kann man grob in konstruktive und analytische Verfahren
unterteilen. Konstruktive Ansätze beschäftigen sich damit, wie man Software
leichter entwickeln kann, so dass sie von Anfang an möglichst korrekt
funktioniert. Dabei geht es darum Mittel und Wege zu finden, die die oben
angesprochenen Probleme wie Größe, Komplexität und Interaktivität abschwächen
und sie damit möglichst gar nicht erst zu Problemen werden lassen. Analytische
Verfahren hingegen konzentrieren sich darauf, Fehler und Probleme in bereits entwickelter
Software zu entdecken.
Konstruktive Verfahren
Wenn der Mensch vor einer schwierigen Aufgabe steht, dann
tendiert er, sich Werkzeuge zu schaffen, die die Aufgabe erleichtern. Das ist
in der Softwaretechnik nicht anders. Software wird nicht in einem einfachen
Texteditor oder in einem Textverarbeitungsprogramm geschrieben, sondern
mithilfe einer Entwicklungsumgebung. Die enthält zwar auch einen Editor, aber
zusätzlich jede Menge Hilfsmittel. Sie prüft den Programmcode auf
offensichtliche Fehler (z.B. falsch geschriebene Wörter), bietet eine Übersicht
über die Struktur des kompletten Programms und hat Funktionen zur
nachträglichen Anpassung und Veränderung der Software. Die Konzipierung,
Entwicklung und Erweiterung solcher Entwicklungsumgebungen ist ein Teil der
konstruktiven Softwaretechnik.
Es gibt auch Werkzeuge, mit denen man erst einmal die
grobe Struktur oder das Verhalten seiner Software in einem Diagramm modellieren
kann. Dadurch behält man einen besseren Überblick und muss nicht zunächst nicht
um die Details kümmern. Es gibt auch Standards, die vorschreiben, wie so ein
Diagramm auszusehen hat. Dadurch haben Softwaretechniker eine gemeinsame
„Sprache“ zur Verfügung mit der sie sich über Ideen und Konzepte für eine
Software austauschen können. Und im Idealfall kann man den Programmcode aus
diesen Diagrammen zumindest teilweise generieren lassen. Das erspart einerseits
viel Arbeit und vermeidet andererseits auch viele Fehler, die man sonst beim
Selberschreiben machen würde.
Analytische Verfahren
Die einfachste Möglichkeit zur Überprüfung einer Software
ist das Testen. Man startet einfach das Programm und probiert aus, ob es das
tut, was man erwartet. Allerdings kann man sich leicht klarmachen, dass man
niemals ein Programm vollständig testen kann. Wenn ich beispielsweise eine
einfaches Taschenrechnerprogramm schreibe, wie es bei vielen Betriebssystemen
mitgeliefert wird, dann kann ich nicht alle möglichen Rechnungen
durchprobieren, um zu überprüfen, dass die Ergebnisse immer stimmen. Dazu gibt
es einfach zu viele Möglichkeiten. (Im streng mathematischen Sinne sind es
sogar unendlich viele. Warum das hier nicht ganz zutrifft, ist ein anderes
Thema) Ich könnte aber jede Funktion (Addition, Subtraktion, Multiplikation,
Division, Potenz, Wurzel, usw.) jeweils einmal ausprobieren und zumindest dafür
sicherstellen, dass alle Ergebnisse stimmen. Über die Entwicklung und Umsetzung
von solchen Teststrategien gibt es ganze Tagungsreihen.
Man kann an das Problem auch etwas mathematischer
herangehen. Zu jedem beliebigen Zeitpunkt seiner Ausführung hat ein Programm
einen „Zustand“. Der ist charakterisiert durch die aktuell gespeicherten Werte
(beim Taschenrechner z.B. die eingegebenen Zahlen und die ausgewählte
Operation) und den Punkt an dem das Programm gerade angekommen ist (z.B. kurz
bevor der Benutzer auf die „=“-Taste drückt. Jetzt kann man versuchen sich alle
diese Zustände zu überlegen und für jeden Zustand zu prüfen, was als nächstes
passieren kann. Wenn z.B. die gewählte Operation die Division ist und die zweite
Zahl eine Null, dann sollte das Programm danach den Teil ausführen wollen, der
dem Benutzer einen Fehler anzeigt. Wenn es das nicht tut, dann erreicht das
Programm einen unerwünschten Zustand und man hat ein Problem gefunden. Diese
theoretische Betrachtungsweise wird Verifikation genannt. Im Vergleich zum
Testen kann man mit ihr beweisen, dass ein Programm fehlerfrei ist (das es also
nicht in einen unerwünschten Zustand gerät). Aber dafür ist das Verfahren auch
so kompliziert, dass man es nicht für komplette, komplexe Programme durchführen
kann, sondern allenfalls für kleinere Teile.
Und weiter?
Das ist er also, mein erster Blogeintrag. Ich habe versucht
einen kleinen Einblick in die weite Welt der Softwaretechnik zu geben. Mir ist
bewusst, dass ich viele Themen nur sehr oberflächlich gestreift habe und vieles
ausgelassen oder sehr vereinfacht dargestellt habe. Ich habe keine Ahnung, ob das Thema von
Interesse ist, ob ich einen guten Abstraktionsgrad erwischt habe und ob
irgendjemand bis zu diesem Punkt lesen wird. Daher brauche ich euer Feedback: Was
hat euch gefallen und was nicht? Würdet ihr gerne mehr lesen? Zu welchen
Themen? Ich bin sehr gespannt auf eure Kommentare, Anregungen und Fragen.
Kommentare (58)