Hallo, herzlich willkommen zur zweiten Vorlesung, Softwareentwicklung 2,
SE2 in diesem Semester. Ich begrüße Sie wieder von
zu Hause. Wir haben im Internet gesehen,
es gibt im Homeoffice durchaus die Möglichkeit, den Hintergrund zu bewerten.
Also bei mir sehen Sie Ikea, ganz Standard, insofern nichts Besonderes.
Wir bleiben doch, weil wir bewerten lieber die Hintergründe der Promis.
Heute geht es bei uns um Fehler und dabei vor
allen Dingen natürlich gute Software zu machen, um Korrektheit,
Fehler zu vermeiden
Dabei starten wir so, dass wir über Fehlerwürkungen sprechen, wie können wir die verringern?
Das wäre der defensive Programmierstil, wie wir Fehler vermeiden.
Das wäre das Vertragsmodell mit Vor- und Nachbedingungen und wie
wir Fehler finden im zweiten Teil mit Testen und Reviews.
Das Ganze wieder in kleinen Häppchen für diese drei Sachen,
aber für diese Abschnitte und jetzt dabei werden wir immer diese Fragen behandeln,
die ihnen hoffentlich helfen, vorbereitet zu bleiben,
zu folgend sicher zu sein, dass sie alles gut verstanden haben.
Und natürlich haben sie nach der Vorlesung,
also betroffen bezogen auf die real geplante Zeit,
die Möglichkeit live mit uns im Austauschforum im Fragen- und Antwortspiel,
uns diese Fragen bei uns mit uns nochmal zu diskutieren,
beziehungsweise jede andere Frage wieder.
So, wir starten mit dem Vertragsmodell und zwar mit der
Frage Korrektheit. Korrektheit bedeutet zunächst erstmal, dass wir,
nein, hier möchte ich gerne einen Laserpoint haben,
Moment,
den kriegen wir auch hin
Ähm, das bleibt blopp, ein mysteriöser Pointer.
Genau. Also bei Korrektheit geht es darum, dass wir das tun,
was die Software möchte, was sie dort vertun soll.
Ja, und Korrektheit, einerseits wollen wir am liebsten
ganz sicher sein, das wäre der Beweis.
Und zum anderen bezieht sich das immer auf das, was sie Software tun soll.
Das heißt, es kommt darauf an, dass exakt zu beschreiben,
das ist die Herausforderung. Das ist ein wichtiges Ziel,
ein wichtiges, eine wichtige Produkteigenschaft von dieser Software,
bezogen auf den Auftraggeber, den Anwender, den Kunden,
ja, und ich habe hier zwei Beispiele, ja,
eine Maschine hat eine Steuerung, diese Maschine kann zum Beispiel eine sein,
Bleche zu Kotflügeln verarbeitet.
Und die sollen nicht nur verhindern,
dass es da einen Unfall gibt,
dass also so ein Mensch seine der Bearbeiter irgendwie da zu Schaden kommt,
durch ein umherfliegendes Blechteil oder gar der Armes ab oder so etwas.
Auch, dass die Maschine oder das Blechteil geschädigt wird.
Auch das soll durch die Steuerung der Maschine verhindert werden.
Ein anderes Beispiel, eine Bank gibt Kredite oder einen Händler,
erlaubt Zahlung erst nach der Lieferung.
Damit geht man ein Risiko ein und dieses Risiko versucht man
durch Regeln relativ besteuert zu machen.
Nicht heute mache ich das mal so, um Wochen machen
wir.
So ist man wieder
Produzierbar, da kann man Erfahrungen ganz gut reinbringen, da kann man optimieren.
Und diese Regeln hat sich jemand ausgedacht von der Bank oder
von dem Händler und die Software soll natürlich entsprechend genau das
machen und nicht mal aufgrund irgendwelcher Sachen jemandem einen Kredit geben,
der den gar nicht möchte oder jemanden oder einen guten Kunden plötzlich den Kredit versagen,
das wäre beides nicht richtig.
Also Korrektheit bezüglich der Sachen, die die Anforderungen entsprechen. Und es gibt,
also dafür, dass die Korrektheit den Anforderungen entspricht,
da gibt es den Begriff Spezifikation to Specify,
etwas genau beschreiben, das ist ein anderes Wort für Anforderungsbeschreibung
Und das soll am Ende so sein,
dass wir für jede mögliche Eingabe, soll die Software in einer Form reagieren,
wie wir das erwarten, wie wir das fordern.
Und deswegen diese Frage mit dem Beweis ist das korrekt beschrieben überhaupt.
Und wenn wir es prüfen wollen, brauchen wir den Beweis.
Und die Begriffe, die ich hier unten aufgelistet habe,
das sind Begriffe, wie sie in der theoretischen Informatik gebraucht werden.
Tatsächlich gibt es Bereiche von Softwareentwicklung, wo man wirklich es korrekt halt nachweisen muss.
Als Beispiel möchte ich ihn einführen, Transport bei der Eisenbahn. Da ist es so,
dass die Stellwerksteuerung, also dort, wo die Weichen gestellt werden,
dass man immer den Zustand vermeiden muss,
der uns sicher beweisen muss, dass er nicht eintritt,
dass zwei Züge auf eine weiche Zufahren und dann seitlich aneinanderstoßen können,
Flankenfahrt oder das Zweizüge, frontal zueinander fahren,
auf eine Strecke geschickt werden.
Sowas darf es nicht geben, die Software muss das verhindern und dieser fehlerhafte Zustand,
und das muss die Software auch beweisen,
sonst wird so eine Software für ein Schnellwerk nicht freigebieten.
Und wenn Sie sich an die letzten Unfälle erinnern,
die so waren,
dann war das eigentlich immer ein Fehlverhalten eines Menschen,
der dann alle die Sicherungen alle ausgeschaltet hat und dann im Notfallmodus dann trotzdem im Zug hat fahren lassen,
das waren also Fehler in der Bedienung,
nicht ein Fehler in der Softwarefehler,
der Software muss
immer korrekt sein
Dieser Korrektheitsbeweis ist sehr aufwendig. Er wird nur ganz selten gemacht,
in wenigen Fällen. Wir beschäftigen uns mit der normalen Software.
Und in normaler Software sieht es so aus, dass Fehler natürlich vorkommen.
Aber wir wollen versuchen, die Fehler zu vermeiden, zu verringen.
Damit wir das gut tun können, ist es wichtig, sie zu unterscheiden.
Ich habe hier mal Begriffe aufgeführt, die uns zeigen,
dass es im Englischen sehr viel präziser beschrieben werden kann,
worum es geht.
In Deutschland haben wir nur den Wort Fehler. Und Fehler ist jetzt
zum Beispiel das Wort Miss Take steht für einen Fehler.
Und zwar ist das ein Fehler, der ein Mensch macht.
Also wenn ich etwas falsch mache,
ist das
ein Miss Take
Fruit ist ein Fehler, der zum Beispiel in einem System steckt.
Zum Beispiel in der Quelltext einer Software. Natürlich ist die Ursache,
dass ein Mensch etwas falsch gemacht hat, dass der Fehler da reinkommt.
Man könnte auch sagen, weil es ein Programm ist,
ein Programmcode, ist ein Kurierungsfehler, also beim Codieren ist er Fehler entstanden.
Es gibt umgangssprachlich bei den Entwicklern den Begriff Bug.
Vielleicht weiß der eine oder andere von ihm,
wo dieser Begriff Bug herkommt, Bug heißt Motte, Käfer.
Und in der Zeit, bevor die Computer wirklich mit Elektronik arbeiteten,
sondern noch mit Relais, also Kontakt auf,
Kontakt zu, da hat man dann gesagt, ja,
die falsche Rewe-Rechnungsergebnisse oder plötzlich der Abbruch, das ist passiert,
weil da ein Käfer drin war, eine Motte.
Und ich persönlich denke eher, dass auch damals schon
die Menschen, die Ingenieure einen Fehler gemacht haben.
Und dass es dann so war, dass da nicht wirklich,
sie haben da nur gesagt, ja, da war ein Käfer drin.
Also Bug ist irgendetwas, was falsch ist. Und ich denke,
das ist ein Fehler des Menschen, ist die Ursache davon.
Wenn wir also so eine Software haben,
die fehlerhaft arbeitet, dann kommt es dazu,
dass ein System auch tatsächlich versagen kann.
Also die Presse macht dann das Bechtteil kaputt oder irgendwas anderes oder sich selbst kaputt.
Und das wäre dann ein Fehler. Mir Fehler resultiert dann
wieder aus diesen Fouls,
die wir hier oben haben
Es gibt auch noch den Begriff Error,
der sich bezieht auf das Gegenüberstellung zwischen Anforderungen und Realisierung.
Ja, also die Realisierung entspricht nicht der Forderung oder der Anforderung.
Da müssen wir aber besonders darauf hinweisen. Deswegen habe ich sie
unten nochmal im Kasten. Es gibt auch eine Java-Klasse,
Error, die hat damit erstmal nichts zu tun.
Java-Klasse, Error, beschreibt, beschreibt Fehler,
die man als Programmierer quasi nicht behandeln kann,
die also auch nicht für defensiven Programmierstil geeignet sind.
Unser nächstes, unser nächster Begriff. Diese Fehler sind im
realen Leben sehr präsent. Man kann so sagen,
dass Menschen immer Fehler machen. Das ist ein Naturgesetz,
das hat damit zu tun, wie unser Gehirn arbeitet,
dass wir eben keine Maschine sind, die alles rekommunizieren kann.
Und man sagt, aus Beobachtung über lange Zeit,
Menschen machen durchschnittlich drei Prozent Fehler. Ja,
es sind auch ein Prozent, man kann es reduzieren,
bis auf ein Prozent Fehler, wenn man besonders motiviert ist,
das muss man uns gut zu machen oder besonders qualifiziert ist.
Ja, wenn man für bestimmte Berufssachen, also irgendwas Elektrotechnisches,
wo man Stromschlag kriegen kann oder was Medizinisches,
der erfordert, ist eine formale Qualifikation,
die man bis nachgelesen haben, dass das gut kann,
unter anderem mit dem Ziel,
dass wir hier
weniger Fehler haben
Wenn wir ein bisschen genauer das sehen und das mal umsetzen
auf eine Software, dann müssen wir sagen, okay,
wenn wir tausend Anweisungen haben, dann haben wir vermutlich zehn Fehler.
Ja, und vielleicht auch 30 Fehler in der Programmierung
nicht so besonders motiviert oder qualifiziert war.
Und tausend Fehler, tausend Anweisungen sind noch kein wirkliches Programm.
Ja, also wir haben häufig eine Million Zeilencode
und bei einer Million Zeilen sind durchaus beim 10.000 Fehler.
Das sind während dieser einen Prozent. Und das ist natürlich
viel mehr, als wir erwarten wollen. Das heißt,
wir müssen versuchen, irgendwie mit dieser Situation umzugehen.
Wir können es nicht ganz verhindern
Zitiere ich einen Kollegens Bilder von vor 15 Jahren, der sagt,
das ist federfreie Software derzeit nicht gibt und in naher Zukunft vermutlich auch nicht,
weil wenn das Programm eine reale Größenordnung hat.
Ja, wir hatten im Vorgehen, hatten wir gesehen,
diese Beweisfragen, auch bei Beweis,
wobei Mönchen einem Korrektheit beweisen kann, bedeutet das ja noch nicht,
dass die Spezifikation richtig ist und gut verstanden ist.
Zum realen Leben zurück. Das reale Leben sagt, es
gibt Fehler. Anwesenheit von Fehlern müssen wir immer erwarten,
es sind immer welche da.
Und deswegen versuchen wir,
risikoarm zu arbeiten
Begriff defensiver Programmierstücks, klingt so ein kleines bisschen langweilig,
wenn man sagt offensiv. Ja, wir wollen offensiv und wir wollen
den Markt überwinden und wir wollen den Sportsiegel und so weiter.
Diese Offensivität wird ja manchmal gepredigt. In manchen Fällen klingt das
auch cool, ja. Und wir haben ja noch jemanden,
wo das cool ist, ja, irgendwas besonders Tolles zu machen.
Aber der Mensch hat nun ganz schön viel Risiko,
stellen Sie sich vor, da fällt jetzt hier runter,
plötzlich kommt eine Windbühne oder was auch immer.
Er hat keine Sicherung sein. Und es sieht ja so
ein bisschen so aus, als ist ja hier über dem Baumwickel,
vielleicht nicht über dem Ort,
aber über dem Baumwipfel ist er schon
Das würde man nicht machen, wenn wir risikoarm arbeiten wollen.
Und wir wollen versuchen, dass unsere Software risikoarm arbeitet. Das heißt,
wenn wir Fehler haben, dann wollen wir möglichst wenig Auswirkungen haben oder diese Auswirkungen verringern.
Es gibt noch ähnliche Begriffe, Robustheit, die Unempfindlichkeit gegen Fehler. Ja,
also wenn jemand einen Programmierer und sagt, oh,
funktioniert schon, ich habe das ja mal getestet,
dann hat er das möglicherweise nur mit seinen eigenen Daten getestet,
das sind nicht die wirklichen Fehler,
die auftreten können und auch nur für Situationen, wie alles klappt.
Also im Survival mag das vielleicht oder im Straßenverkehr wollen wir solche Fehler nicht,
immer deinen Menschen beschädigt sind, wenn sie Survival machen,
also Überlebenstor in Alaska, drei Wochen weit weg,
drei Wochen Fußballspekt von der nächsten menschlichen Behausung.
Da würden sie vielleicht das auch nicht ohne Besicherung machen,
weil die Hilfe einfach weit weg ist.
Und die Gefahr ist, dass sie es nicht überleben,
doch relativ groß. Okay, defensiver Programmierspiel mit Beispielen,
wie machen wir das? Links nochmal das,
was die Grundsätze sind, Risiken vermeiden,
indem wir die Tests zuerst entwickeln und nicht erstmal Programm laufen lassen,
sondern wir entwickeln zuerst die Tests,
überlegen uns,
was sind die Fehler,
die passieren können und wie gehen wir damit um
Wir prüfen Vorbedingungen, also wenn Software,
wenn ein Parameter in ein Programm reinkommt, die Voraussetzungen,
bevor eine Funktion überhaupt arbeitet,
bevor ein Modul seine Arbeit aufnimmt, die werden geprüft.
Wir nehmen Assert, das werden wir gleich noch behandeln.
Oder wir versuchen dort weiterzuarbeiten, wo ein Fehler armer Zustand ist.
Wir versuchen Tests für Vor- und Nachbedingungen zu machen,
also vorher Bedingungen war das, mit dem es hört,
und für Nachbedingungen versuchen wir das zuzumachen,
dass Fehler möglicherweise nicht sich fortpflanzen können.
Diese Fehlerfortpflanzung bedeutet ja,
dass ein Fehler auftritt an einer Stelle,
für die
wir es nicht erwarten
Diese Auswirkungen auf Fehler, auf minimale Auswirkungen richten,
bedeutet tatsächlich, dass man einiges an Gehirnschmalz braucht,
dass man einiges an gute Überlegungen braucht, wie reagiert denn so eine Software.
Und ich möchte das so sagen, dass sie sich bitte vorstellen,
was passiert denn, wenn wir das nicht tun.
Nur Programm beenden bei einem Fehler, ist keine gute Idee in vielen Fällen. Ja,
also wenn wir eine Software haben,
die zum Beispiel an Bankschalter eingesetzt wird,
der bei meiner gute epolitischen Situation, Oma geht zur Bank,
weil ihre Karte gesperrt ist oder weil sie irgendwas will,
dann wäre das doch doof,
wenn die Software dann auf dem Bildschirm der Bankberaterin sagte,
Internal Airbord 2025 und das Programm einfach beendet.
Nur weil der internen Fehler ist, dann sollten wir doch irgendeinen Fehlerabend fortpflanzen.
Für diesen defensiven Programmierstil, also immer prüfen,
ob Fehler da sind und weitergehen, hier erstmal was zu dem Fehler.
Prüfungen, ja, also zum Beispiel, dass sich MTCs,
Pointer und so weiter immer geprüft habe, ob sie innerhalb einer Grenze sind,
importierte Daten, sind sie gültig, sind die Ausgabevarianten überhaupt zugewiesen.
Hier hat jede Anwendung korrekte Daten, gibt es Speicher,
ja, benutzt worden ist, sage ich mal,
wieder freigegeben für das Betriebssystem,
dass wir nicht diese Speichersammler haben, Speicher und Next,
sagen wir dazu, gibt es, sind Teilouts geprüft worden,
sind, prüft man eine Datei auf Existenz,
bevor man darauf zugreift oder macht man, sorgt man dafür,
dass Geräte in Dateien wieder ordentlich geschlossen sind,
mit denen man im Programm beendet.
Also das alles ist defensiver, Programmierstil. Wir gehen,
wir machen dann weiter mit dem Vertragsmodell,
doch das ist dann die nächste,
der nächste