Okay. Ja, freue ich mich,
dass Sie zur zweiten Vorlesung zur SE2 gekommen sind.
Also heute bin ich in der ersten Hälfte dran.
Zweite Hälfte wird Fred Winkler gestalten, den die meisten von Ihnen
ja auch schon aus SE1, als herausragender Tutor und Übungsgruppenbetreuer kennen.
Wir werden nämlich heute mit Ihnen zwei Themen besprechen.
Und die Themen sind beide so ein bisschen trockener Art,
einmal testen und dann über Zusicherung Vertragsmodell.
Aber beide Themen sind so wichtig, dass wir Ihnen das
doch hier vorstellen möchten, auch in der Vorlesung, nicht nur Fanson.
Wofür das zweite Thema Haben wir uns überlegt,
so Vertragsmodellen mit Zusicherung,
wenn man das komplett hier vorne nur Folien macht,
dann ist es staubtrocken und Fred als einer der begnadeten Hacker am Gerät,
wird ihnen das auch ein bisschen live demonstrieren.
Das traue ich mir selbst nicht so zu, so live hier vortragen unterm Rechner.
Ich habe da immer so irgendwas an den Fingern,
wenn ich einen Rechner anpacke, ist ja an sich schon kaputt.
Okay, also ich würde ihn im ersten Teil etwas über Testen erzählen.
Sie haben ja schon in SE1 ein bisschen etwas über Testen
gehört und hoffentlich auch ein bisschen getestet.
Aber damit ist die Welt des Testens natürlich noch nicht erschlossen.
Und wir wollten zumindest eine halbe Vorlesung für NSE 2 machen.
An sich ist es viel zu wenig und ich möchte so
Am Anfang motivieren, weshalb testen heute in der Wahrnehmung.
Das Software-Engineering, der Software-Technik vielmehr an Bedeutung gewonnen hat und
das jetzt nicht nur universitär, sondern auch in der Berufspraxis.
Damit wollte ich anfangen, dann kommen so ein paar Grundbegriffe,
Grundkonzepte, wenn so ein wenig Frage- und Antwortspiel machen.
Schauen wir mal, dass wir das Thema so in der Dreiviertelstunde durchkriegen.
Miteraturhinweise, diesmal ganz explizit wollte ich drauf eingehen. Das eine ist,
ich werde was erzählen über zertifiziertes Testen, die Leute im deutschsprachigen Bereich,
die das ganz weit nach vorne gebracht haben, haben auch darüber geschrieben.
Andreas Spilner, Kollege aus Bremen und Thilo Linz,
das ist das Buch zum Film zertifiziertes Testen und Testen überhaupt.
Klar, sage ich gleich noch was zu zu diesem Zertifikat.
Das zweite Robert Binder haben das ganze Thema Testing Object Oriented Systems.
Wenn wir hier nicht kompakt zusammenhängend machen,
sondern werden das nur an einzelnen Stellen beispielsweise bei Vererbung ansprechen.
Es ist aber ein sehr, sehr großes Thema.
Also wer sich ernsthafter mit Testen beschäftigt und dann nicht im Objektorientierten naiv rangeht,
sondern sagt, wie teste ich vernünftig objektorientierte Programme,
kommt an sich an so einem Standardbuch nicht vorbei.
Deshalb empfehlen wir das und das dritte.
Testen ist ja heute auch dadurch etwas populärer geworden,
dass agile Methoden allgemein als testgetrieben bezeichnet werden
Wer sich darüber ein bisschen tiefergehend informieren will,
was ist mit testgetriebenen oder Test-First auf sich hat,
das Buch der drei Autoren ist da sicherlich ein guter Einstieg.
Okay, Motivation für das Testen. Einmal in der Sache selbst,
wir haben es mit Software zu tun, wir haben es meistens mit interaktiver Software zu tun.
Ich hatte beim letzten Mal schon gesagt,
wir haben es meistens mit großer interaktiver Software zu tun und
damit betreten wir einen Bereich und haben einen Gegenstand vor uns,
der so komplex ist, dass man oder dass wir,
ich, wer auch immer, der sich damit beschäftigt,
diesen Satz von Spinner und Linz unterschreibt,
das wird keine fehlerfreie Software geben.
Die Zeiten sind vorbei, wenn es sie überhaupt jemals gegeben hat.
Das heißt, wir müssen uns mit unserer fehlerhaften Software oder
noch schlimmer oder noch alltäglicher mit der fehlerhaften Software,
die andere Leute geschrieben haben, auseinandersetzen.
Und eine Möglichkeit, sich damit auseinanderzusetzen, ist das Testen.
Es ist ja viel weitere Möglichkeiten, einfache Möglichkeiten haben wir nicht.
Also müssen wir testen. Da kommen wir nicht dran vorbei. Das Zweite ist,
wenn wir testen, können wir ein paar Dinge mehr machen,
die unsere Software und uns zugutekommt.
Und zwar wir beruhigter über unsere Software nachdenken können.
Wir können mehr durchtesten über die Qualität der Software sagen,
die wir vor uns haben.
Wir können durch eine andere Art es testen,
so durch spezielle Varianten des Testens sehr viel mehr über
die Funktionalität unserer Software sagen
Und was für uns im Entwicklungsprozess, oder wenn wir Software überarbeiten,
verändern, extrem wichtig ist, testen ist ein herausragendes Mittel,
um zu verstehen, was Software macht.
Ja, das ist die Motivation vom Gegenstand her. Ein zweiter Aspekt,
der in den letzten Jahren dazugekommen ist, und wo ich sagen muss,
okay, solange wie ich beruflich mit Softwareentwicklung zu tun habe,
hat sich sehr viel getan im Bereich testen.
Als ich so die ersten Projekte gemacht habe,
bei Bankenversicherung war das so, es gab so eine Zweiklassengesellschaft.
Man könnte sagen, es gab so zwei Kasten.
Die einen waren die Entwicklung, Entwickler und Entwicklerinnen,
die durften die neue Software entwickeln. Und dann gab es die anderen,
davon hießen die Besseren, das waren die Wartungsprogrammierer,
die durften auftretende Fehler beseitigen und die,
die es ganz verzockt hatten, das waren die Tester.
Die saßen dann meistens im Keller. Das waren so
die Parias. Die mussten das Zeug halt testen,
bevor sie auf die Großrechner dann in der Produktion oder für die Produktion freigegeben waren.
Die Zeiten sind zum Glück, ich will nicht sagen vorbei,
aber diese Einteilung hat sich als mehr und mehr unsinnig erwiesen,
was man Iran sieht, seit einigen Jahren ist testen nicht nur etwas,
was man als Entwickler und Entwicklerin, wie selbstverständlich können sollte,
sondern hat sich als eigenes Berufsbild herausgeprägt.
Es gibt nicht nur den Tester und die Testerin,
als mit Qualität von Software sehr eng verbunden, sondern es gibt die Zertifikate dazu.
Zertifikate, wo sie das Basislevel während des Studiums erwerben können,
aber dann gibt es auch höhere Zertifikate.
Und das ist so die eine Seite, es gibt,
wenn Sie mal so in die Stellenausschreibung reinschauen und wenn wir so auf der Firmenseite schauen,
was wir an Projektnachfragen bekommen, sehen wir immer wieder,
wir brauchen auch Leute, die testen können, aber bitte zertifiziert.
Denn die Leute sollen nicht einfach nur einen Test schreiben können,
die sollen wissen, was sie tun, wenn sie testen.
Also insofern gibt es jetzt dieses neue Berufsbild und Das ist für mich ja,
oder ist für uns auch die Motivation zu sagen,
okay, für SE2 machen wir hier eine halbe Vorlesung,
aber es soll zumindest hängen bleiben.
Das ist sehr, sehr spannend und beschäftigen Sie sich damit.
Es gibt ein internationales Software-Testing, Qualification Board.
Mit Ablegern in Deutschland und wenn Sie ein Zertifikat erwerben,
was hiermit verbunden ist, dann wissen Sie,
das ist im Moment international die Organisation, die die anerkanntesten Testzertifikate ausfüllen.
Es gibt noch andere, jede Menge Schulungsunternehmen,
die aussagen, dann bekommen Sie ein Zertifikat oder so,
aber wir können mit gutem Gewissen sagen,
das hier ist schon okay.
Okay, das als Motivation am Anfang.
Jetzt wieder zurück zu unserem Gegenstand
In der theoretischen Informatik hat man sich über viele Jahre,
Jahrzehnte damit auseinandergesetzt, die Frage zu beantworten, wann ist Software korrekt?
Korrekt in einem formalen Sinn, sprich die Implementation der Software
tut das, was die Bauvorschrift vorgeschrieben hat.
Und es gibt in der theoretischen Informatik oder in einer
bestimmten Form zwischen Theorie und Angewandter halt sehr viele Ansätze,
wie ich mit formalen, mathematischen Modellen und Verfarben nachweisen kann,
dass eine schriftliche Spezifikation der Software in der Implementation korrekt umgesetzt worden ist.
Das war oder das ist der klassische Korrektheitsbegriff. Das Problem ist,
dieser Korrektheitsbegriff lässt sich nur für sehr kleine Programme,
oder für Ausschnitte, sehr kleine Ausschnitte, größere Programme,
lässt sich dieser Ansatz aufrechterhalten.
Denn es gibt weder ausreichend Leute mit ausreichend viel Zeit,
um diese Spezifikationen zu schreiben. Noch gibt es Leute und Zeit genug,
um hinterher anhand einer Implementation nachzuweisen, dass diese Implementation mit der Spezifikation übereinstimmt.
Überhaupt nicht beantwortet, ist die Frage, ob das,
was in der Spezifikation steht, korrekt und sinnvoll ist.
Das ist genauso, als wenn sie in der Mathematik
eine Hypothese beweisen sollen und haben das mühevoll geschafft.
Und dann stellt jemand die Frage, aber was ist das denn überhaupt für eine Hypothese?
Gut, in der Mathematik kann man sagen,
das ist irgendwie ein Ausdruck irgendeiner Theorie,
aber das ist natürlich nicht die Antwort, die wir in der Softwareentwicklung haben wollen.
Es nützt ihnen ja nur relativ wenig, wenn sie sagen,
ich habe genau das implementiert und das kann ich auch nachweisen,
was hier auf diesem Zettel jemand hingeschrieben hat.
Weil als nächstes wird sofort hoffentlich jemand fragen, ja,
und was tut das Ding eigentlich?
Ist das sinnvoll? Und diese Frage können Sie anhand der Spezifikation überhaupt nicht beantworten. Okay,
also das heißt, zu dieser ganz klassische Korrektheitsbegriff,
der ganz lange im Mittelpunkt der theoretischen Informatik gestanden hat,
ist, wenn wir in die Softwareentwicklung gehen, nicht unsinnig,
aber muss spätestens dann ersetzt werden durch die Frage,
wie kann ich Sicherheit darüber bekommen, mehr Sicherheit darüber gekommen,
ob ein Programm Sinnvolles, Unnützliches tut,
ob es valide ist.
Und das ist also die Weitergehende Frage, die uns bewegt. So,
an sich wollte ich jetzt,
und damit haben wir wieder ein schönes Beispiel für Testen und Nicht-Testen,
Sie kennen ja aus SE1 das, was Axel immer gemacht hat,
so mit den Klickern und QR-Code.
Und ja, hatte ich alles bis gestern vorbereitet und mir
solche Fragen schön für das Jurési aufbereitet.
Und dann kam der Wolf und ich wollte das mit ihm live ausprobieren.
Dann sagt er, was hast du denn da für eine Client-Version laufen?
Ich sage, die neueste, die ich mir runtergeladen habe.
Klar, läuft da wunderbar. Ja, sagt er,
hm, hast du nicht mitgekriegt, der Server dazu,
der läuft erst ab diesem Freitag. Ich sage,
okay, dann setze ich mich hin und schreibe die,
nehme die ganzen Fragen und portiere die wieder auf die alte Version.
Ja, sagt er, mach das und rufst du nicht an,
wenn das läuft, dann gucken wir uns das an.
Das war die zweite falsche Annahme. Ich habe nämlich festgestellt,
man kann die Fragen aus der neuesten Version nicht exportieren,
um sie zu bearbeiten und in die alte Version wieder zu importieren.
Also machen wir jetzt heute den Papiertest. Demnächst dann wieder
mit Klicker und Mobile Phones. Ist auch auch ganz nett,
meine gute alte Handarbeit. Was kann Testen nicht leisten?
Fälle A bis F. Was kann Testen nicht? Überlegen Sie
. Äußere Qualität prüfen, innere Qualität prüfen. Benutzbarkeit garantieren,
Programmverständnis verbessern, Fehlerfreiheit eines Programms garantieren und Funktionalität verbessern.
Also ich will jetzt nicht so durch Aussehen.
Wissen Sie wo, was haben wir für sich schon notiert,
was Software testen, nicht leisten können.
Haben wir schon ein Bild davon? Das ist eine Antwort.
Hans-Hot mal viele. Ja, jeder überlegt sich das mal,
macht sich vielleicht eine kleine Notiz, welche Kandidaten sie hätten.
Gleich kommt die Auflösung. Alles hier zu Fuß getrieben.
Harquette. Machen wir. A, äußere Qualität prüfen.
B, innere Qualität prüfen. Was war das nochmal mit
der Äußerung der inneren Qualität? Benutzbarkeit garantieren. Ja,
Programmverständnis verbessern. Fehlerfreiheit eines Programms garantieren und Funktionalität verbessern.
Okay, das ist die Lösung. Ja,
ich kann natürlich testen, ob irgendwas ganz gut benutzbar ist
Ich kann auch testen, ob es bestimmte Laufzeiteigenschaften hat.
Bestimmte andere Dinge. Also innere Qualität. Ich kann nicht garantieren,
wenn ich selbst teste, garantieren kann ich sowieso nicht.
Ich kann dir Hinweise geben lassen, wie benutzbar.
Software ist, weil Benutzbarkeit kann man leider nur durch benutzen.
Letztlich feststellen, wenn ich teste,
mache ich mir ein anderes Bild von meinem Programm,
als wenn ich es selbst entwickle.
Also bekomme ich ein besseres Verständnis.
Ja, E ist die große Krux des Testens.
Ich kann durchtesten einfach keine Fehlerfreiheit garantieren. Und Funktionalität verbessern
, ja. Hätte ich vernünftig meinen Client-Server-Modell getestet,
hätte ich ein bisschen mehr über Benutzbarkeit gewusst und auch
die Funktionalität verbessern können im Zusammenspiel.
Okay, ja
Nochmal, weil das ganz wichtig ist. Wann ist ein
Programm korrekt? Man ist ein Programm korrekt, auch.
Ganz wichtig, dass man das im Kopf klar hat.
Wenn es das tut, was seine Anwender von ihm erwarten?
Wenn es das tut, was seine Entwickler von ihm erwarten?
Wenn es das tut, was seine Auftraggeber von ihm erwarten?
Wenn es das tut, was seine explizite Spezifikation definiert,
oder wenn alle Tests fehlerfrei durchlaufen
Ich bin ein Kritiker. Ich bin ein Kritiker. Ich bin
ein Kritiker. Keine Ahnung. Naja, haben Sie ja eine,
sich eine Meinung dazu gebildet, wie Sie das sehen?
Erinnern Sie sich, was ich vorhin erzählt habe?
Okay. Also, unter dem Korrektheitsbegriff und nochmal zur Wiederholung.
Unter praktisch allen formalen Verfahren, die wir in der Informatik haben,
kann ich nur nachweisen, dass wenn es gut geht,
ein Programm das tut, was seine explizit aufgeschriebene Spezifikation beschreibt, definiert.
Alles andere, alle anderen wichtigen Anforderungen,
kann ich über formale Verfahren
direkt nicht nachweisen
So. Und damit sind wir schon in großen Teilen bei dem,
was man heute unter Testen versteht und was man mit Testen machen kann.
Und wenn Sie sich an Ihr erstes Semestern,
SE1 erinnern, wenn Sie sich erinnern,
dass Sie im Wesentlichen so Unitests geschrieben haben,
wenn Sie sie geschrieben haben, wo Sie sich als Entwickler,
als Entwicklerin, so ein Verständnis darüber oder eine gewisse Sicherheit darüber verschafft haben,
ob das, was Sie implementiert haben, noch einigermaßen vernünftig ist.
Die anderen Fragen haben Sie durch Unitests ja noch gar nicht angepackt.
Und was man in diesen Bereichen noch tun kann,
so von der Idee her, darüber werden wir jetzt im Weiteren ein bisschen reden.
Damit wir ein paar Begriffe zur Verfügung haben, wenn wir über Testen reden,
hier erst einmal die grundsätzliche Unterscheidung gehst in der Literatur,
wird hier immer wieder gemacht zwischen Staatlichen und dynamischen Tests.
Ich bin da vielleicht nur oldschool. Ich bin mit dieser Unterscheidung in statisch und dynamische Tests,
bin ich nicht so ganz glücklich, weil statische Tests heißt,
ich schaue mir im Wesentlichen Programmtests, Programm, sorry,
Programmtext und Programmdokumente an.
Oder ich setze ein Werkzeug auf diese Dokumente an.
Dynamischer Test heißt immer, ich lasse die Software ablaufen.
In der Testumgebung, in der speziellen Entwicklungsumgebung, in der Umgebung im Einsatzbereich.
Das ist ein dynamischer Test. Ich würde viel lieber mit
anderen Autoren in dem einen Fall über statische Analyse reden.
Weil sonst weicht so Der Testbegriff so ein bisschen auf.
Denn wenn ich ein Team frage, Leute, habt ihr die Software getestet?
Und die sagen, ja, haben wir,
dann meine ich normalerweise nicht, habt ihr euch zusammen mal den Programmcode angesehen.
Sondern dann meine ich wirklich, ist das Ding gelaufen,
ohne dass es gekracht hat? Oder habt ihr es so ausgetestet,
dass nicht nur die drei Fälle, die ihr euch überlegt habt,
sondern auch so Grenzbereiche, dass die funktionieren, ohne dass es kracht? Also das,
was ich hätte machen sollen, hat dieses Sturesi-System,
was ich habe, nicht nur hier alleine,
eigenständig auf meinem Rechner, mir Fragen und Antworten vorgespielt,
sondern habe ich das auch über das Web-Interface mir ansehen können,
sonst hätte ich, wenn ich das am Wochenende gemacht hätte,
hätte ich mir viel Arbeit erspart, dann hätte ich nämlich gesehen,
ich kriege das gar nicht aufs Web-Interface.
Okay, also trotz trotzdem diese Unterscheidung,
starte ich ja Test, ich schaue mir die Dokumente an,
die ich habe und dynamischer Test, ich führe es aus.
Damit sage ich nicht, dass diese staatlichen Tests oder staatliche
Analyse sinnlos ist, ganz im Gegenteil.
Nur ich habe andere Dinge im Auge. Also das,
was ja auch aus SE1 kennen, wenn sie mit ihrem Betreuer,
ihrer Betreueren sich zusammen Programmtext ansehen,
dann kommen dann natürlich Themen zur Diskussion, die,
wenn sie das Programm ausführen, gar nicht zur Diskussion kommen und umgekehrt.
Über Konventionen, über Bezeichner redet man anhand des Programmtests,
aber nicht anhand eines Laufenden ausgeführten Programms. Und was sie hier in SE1,
SE2 noch überhaupt nicht machen, aber was hinterher,
wenn sie in dem Bereich, beispielsweise Software-Architekt, Software-Architekt hinzugange sind,
was für sie dann ein ganz wichtiges Handwerkszeug ist.
Sie bekommen Analyse-Tools, die sind sehr mächtig, die kann
man nicht einfach bald starten und loslegen. Da brauchen sie selbst einige Tage,
vielleicht Wochen, um sich in so ein Analyse-Tool einzuarbeiten,
mit dem sie dann hinterher auf Programmtexte losgehen,
um beispielsweise zu überprüfen, wie stimmt die Architektur des Gesamtsystems,
die vielleicht in den Köpfen des Teams war.
Wie stimmt die Architektur mit dem zusammen, was implementiert worden ist?
Haben sie tolle OML-Diakramme und Schichten, Architekturen entworfen,
aber implementiert haben sie Spaghetti-Code, wo alles mit allem interagiert.
Ganz, ganz wichtige, heute Hilfsmittel, diese Werkzeuggestützte,
staatliche Analyse
Ist nur ein ganz anderer Bereich, das ist ein ganz wichtiger Bereich der Softwareentwicklung.
Heute im Testteil reden wir über ein paar andere Dinge.
Und dazu jetzt bezogen auf Testen, auf dynamisches Testen, auch im Schwerpunkt.
Was ist das Wichtige daran? Also das Objekt,
die Software, die ich teste, wird immer stichprobenartig ausgeführt.
Das heißt, ich muss mir Gedanken machen,
für welche Fälle lasse ich meine Software laufen?
Es ist natürlich immer schon mal Ebene null. Ich habe mir vorgestellt,
die Operation, die ich implementiere, für was sie gut sein soll,
dann gebe ich genau diese Parameter als Eingabe,
Parameter und wusch,
das Ergebnis kommt zu äuß,
wie ich
mir das vorgestellt habe
Es gibt natürlich hunderte, tausende von anderen Eingabemöglichkeiten.
Welche nehme ich mir vor? Was gehört in meine Stichprobe?
Schon das ist eine ganz, ganz wichtige Frage beim Testen.
Die Ausbildung zu diesem Zertifikat enthält auch wesentliche Hinweise und Vorgehensweisen,
wenn ich ein Programm vor mir habe,
wie komme ich zu einer sinnvollen Stichprobe,
sodass ich in meiner verfügbaren Zeit ein möglichst optimales Ergebnis bekomme.
Das ist also die eine Seite, mit was,
mit welchen Parametern oder mit welcher Interaktion,
mit welchen Klicks an Bildschirmen, führe ich mein Programm im Test aus.
Das ist das eine. Und jetzt kommt die andere Seite,
weil das ist ja nur die erste Hälfte.
Test besteht immer aus zwei Teilen. Der erste Teil ist,
ich Ich starte mein Programm, ich rufe mein Programm mit bestimmten Eingangswerten oder Eingangsinteraktionen auf.
Das ist das eine. Das Zweite,
was immer zum Test dazugehört, der Test produziert ein Ergebnis.
Früher produziert ein Ausgabewert im Sinne von, ich rufe eine Funktion auf,
mit allen Gangswerten und bekomme ein Ergebnis, Ausgabewert, Ergebniswert.
Heute, ich knicke drei Menüs, zwei Knöpfe auf dem
Bildschirm an und es passiert irgendwas.
Es scheint ein Bild oder das Bild, was ich sehe,
rotiert oder irgendwas. So, das ist das Ergebnis meiner Interaktion.
Die zentrale und oft extrem schwer zu beantwortende Frage ist,
ist das, was als Ergebnis produziert wird, das erwartete Ergebnis.
Gut, wenn Sie Dinge aus ihrem eigenen Alltagswissen haben.
Also ein Bildbearbeitungsprogramm, wo oben auch so ein Knopf,
so ein Pfeil nach rechts ist, wo sie erwarten,
okay, wenn ich ein Bild markiere und drücke auf diesen Knopf,
dann wird das Bild in der Darstellung hinterher rotiert sein.
Da haben sie hinterher ein Gefühl, wenn dieses Bild auch
noch in die richtige Richtung rotiert.
Das Ergebnis ist richtig. Okay. Wenn es eine mathematische
Funktion aufrufen und 47,11 mit drei Nachkommastellen angeben und es kommt
irgendein Reelwert zurück, müssen sich schon mal etwas genauer hinsehen.
Das heißt, da müssen sie zumindest die Funktion verstehen,
die berechnet werden soll. Sonst steht da was und sie sagen,
okay, also eine Ausgabe wird produziert, aber ist die Ausgabe richtig?
Das ist noch so der Bereich, da kann man sich
noch so ein bisschen reindenken
Es gibt Bereiche, da wird das Reindenken sehr schwierig.
Nehmen wir mal an, ein sehr schönes Beispiel. Sie arbeiten für eine Firma,
die Baumaschinen nicht verkauft, sondern vermietet in einem Leasing-Konzept.
Das heißt, die Kunden dieser Firma kaufen nicht Bugger,
sondern Laien-Bugger. Und es gibt ein bestimmtes betriebswirtschaftliches Verfahren,
wie berechnend auf den Preis des Buggers und der Mietzeit berechnend,
was die Firma daran verdienen will,
berechnet wird, was das den Kunden kostet.
Wenn sie so eine Software testen wollen, dann ist das
überhaupt nicht mehr einfach. Dann wird das teilweise so sein,
dass sie zwar Eingabewerte da reintun können,
aber wenn die Fachabteilung ihnen zu den Eingabewerten keine Ergebniswerte liefert,
Können Sie beim Test nur sagen, okay,
da kommt ein Euro-Betrag raus, aber ob der zehnfach zu hoch ist?
Keine Ahnung. Also das Thema Testen gewinnen da andere Dimensionen und
wir arbeiten nun im Moment zusammen hier mit unserem klimareichen Zentrum.
Da haben wir ein aus unserem Team, der soll dann eine Dissertation schreiben.
Da wird das noch schwieriger. Es geht,
er schreibt so eine Dissertation über das Testen von Klimamodellen.
Und das ist eine ganz heiße Sache, weil selbst die Wissenschaftler,
die da sind, wissen für ein neues Klimamodell nicht,
für bestimmte Eingaben, ob die ausgaberechtig ist.
Also wenn das Klimamodell berechnen soll, wie entwickelt sich
das Klima in Hamburg in 50 Jahren?
Und da kommt raus, durchschnittlicher Anstieg der Jahrestemperatur um 4 Grad.
Was sagt dieser Test
Hat das Modell richtig gerechnet? Dass wir das allen.
Oder kommt ein Ergebnis raus, aber das Modell ist falsch.
Die Software ist zwar richtig, aber das Modell,
was dahinter steht, ist falsch. Also,
wie passt das, was ich heimgebe, mit dem,
was rauskommt, zusammen und wie kann ich demnach bewerten,
feststellen, ob mein Test richtig gelaufen ist?
Sollte ich ihn so ein bisschen nahe bringen,
dass das nicht so trivial ist?
Zwischendurch wieder, damit sie wieder vom reinen Dasitz und Rezeptionsmodus
umschalten. Welche Aussagen zum Testen stimmen ihrer Meinung nach?
Ein Test zeigt, ob das Programm korrekt ist.
B, das Testprinzip ist für eine bestimmte Eingabe produziert
das Programm eine erwartete Ausgabe
Ja. C, wenn das Programm fehlerfrei durchläuft, ist es korrekt?
D, wenn der Test keine Acception produziert, ist das Programm korrekt?
B. Für Entwickler ist es oft schwierig festzustellen,
ob die Ausgabe eines Tests zur Eingabe passt.
Stell dir vor, sie saßen jetzt in der SE2-Klausur
und dürften ankreuzen, welche Aussagenstimmung.
Das ist schon ganz nett. Also sie brauchen jetzt nicht
Angstschweiß zu entwickeln, aber...
Welche Aussagen stimmen dir Meinungen
Ja. Die beiden Grünen, Stimmen,
das Testprinzip ist, wollte ich Ihnen einhämmern,
für eine bestimmte Eingabe produziert das Programm, die erwartete Ausgabe,
dann ist der Test grün durchgelaufen und für Entwickler ist es oft schwierig festzustellen,
ob die Ausgabe eines Tests zur Eingabe passt.
Das ist die Story, die ich Ihnen gerade erzählt habe.
Der Rest stimmt in der Form nicht. Wir können
weder Korrektheit, hatten wir schon, wir können nicht,
wenn ein Test fehlerfrei durchgelaufen ist, sagen.
Das ist es. Und Exceptions und nicht Exceptions sagen auch
nichts darüber, ob ein Programm korrekt ist.
Es ist teilweise sogar so, dass sie testen,
ob für bestimmte Eingabewerte eine Acception auftritt.
Auch das ist eine Teststrategie
Okay. Was ist überhaupt das, was der Test feststellt?
Auch das ist nicht so ganz trivial.
Auch da muss man sich ein bisschen mit den Begriffen auskennen,
sonst wenn man in die Literatur reinschaut oder man redet über Tests,
sondern man macht sich Gedanken, was passiert denn in einem Test?
Muss man verstehen, worum man drunten ist?
Burtron Meier hat ganz gut eine Einteilung hier vorgestellt.
Andere Leute haben anderes vorgestellt. Ich will Ihnen nur mal
die, quasi uns ganz griffig erscheint, hier vorstellen.
Ich programmiere an irgendeiner Stelle, schreibe ich etwas hin,
was ich so nicht hätte hinschreiben sollen.
Ich wollte an sich was anderes hinschreiben,
aber da steht nun irgendetwas Falsches,
schon aus meiner eigentlichen Wahrnehmung,
aus meiner Intention heraus,
steht da
was Falsches
Jetzt läuft das Programm ab, sind als Folge dessen,
was sich da fehlerhaft reinprogrammiert habe, passiert bei der Ausführung etwas,
dass sich die Software nicht so verhält, wie das gedacht war.
Das heißt, die Software macht irgendetwas, was sie nicht machen sollte.
Das Problem ist, dass die Software oft das nicht an
der Stelle macht, wo ich meinen Programmierfehler gemacht habe.
Also wenn ich eine Variable falsch initiiert habe mit dem falschen Wert,
kann der Effekt der eigentliche Programmfehler,
der ist an einer ganz anderen Stelle auftreten bei irgendeiner IF-Abfrage beispielsweise.
IFX größer 15. Sollte an sich sein, aber ich habe
nicht mit 15, sondern aus Versehen mit 1,5 initiiert.
Das heißt, der Effekt tritt an einer anderen Stelle auf,
als mein Programmierfehler, wo er im Code steht.
Ich habe einen Programmfehler. So, und dann im Ablauf
kann daraus etwas entstehen, was man als Laufzeitfehler bezeichnet.
Das heißt, das Programm zeigt ein Laufzeitverhalten,
was allgemein als fehlerhaft akzeptiert wird.
Es gibt eine Fehlermeldung. Es gibt ein Programmabbruch.
Es kommt ein Ergebnis raus, was nicht rauskommen sollte.
Und das sehe ich. Und dann stelle ich fest,
aha, hier ist zur Laufzeit ein Fehler passiert.
Da muss es also einen Programmfehler geben.
Und irgendjemand hat den verursacht an irgendeiner Stelle im Code.
Diese Stelle suche ich dann. Okay. Ich habe nochmal
ein schönes Bildchen
Bezogen auf den Zustand. Ich habe Variablen in meinem Speicher.
Und da ist alles okay. Auf einmal gibt es irgendeine Stelle,
da hat mein Speicherwerte, die nicht da stehen sollten.
Etwas später hin der Zeit füllt das dann auf.
So, und dann sehe ich das von außen.
Und hier sieht man also nochmal das, was ich also gemeint habe.
Sehr oft kann der Abstand zwischen der fehlerhaften,
dem Fehlerprogrammzustand und der beobachtbaren Wirkung sehr weit auseinanderlegen.
Und dann wird es schwierig für mich überhaupt festzustellen, wo liegt die Ursache.
Okay, hier nochmal das andere mit einem anderen Bild,
so von innen nach außen. Und was ich dagegen tun kann,
naja, ich kann im Inneren,
wenn ich Programme Kamera kann ich halt Konventionen, Muster,
was auch immer vorgeben, um den Leuten Anleitungen zu geben,
dass sie nicht falsch implementieren.
Ich kann Debugger sehen, während der Laufzeit,
wie ist der Zustand meines Programms im Ablauf und wenn ich einen nicht korrekten Zustand entdecke,
kann ich sagen, hier ist irgendwas schiefgelaufen und ganz außen,
wenn ich die Fehlerwirkung schon merke,
dann ist das schon sehr spät.
Das kann ich durchtesten. Also wenn man einen Test fehlschlägt
und ich sehe, aha, der Programmablauf war fehlerhaft,
dann bin ich halt ganz außen bei den Effekten.
Okay. So, nochmal,
damit sie die Begriffe so ein bisschen im Kopf sortieren,
ob sie das jetzt schon mitgekriegt haben,
was ich hier vorne erzählt habe.
Ein Programmierfehler führt immer zu einem Laufzeitfehler.
Ein Laufzeitfehler brut immer auf einem Programmierfehler
Ein Programmfehler führt immer zu einem Programmierfehler.
Und ein Programmfehler ist meist Folge eines Programmierfehlers.
Welche Aussagen sind es richtig? Versuchen Sie mal,
ob Sie schon so viel jetzt behalten haben,
dass Sie aus diesem kleinen Satz drehen, irgendetwas Sinnvolles für sich rauskriegen.
Ein Programmierfehler führt immer zu einem Laufzeitfehler. Ein Laufzeitfehler beruht immer auf
einem Programmfehler. Ein Programmfehler führt immer zu einem Programmierfehler.
Wurde ein Programmfehler ist Das heißt, Folge eines Programmierfilms.
Das sind alles so ein bisschen viel Begriff auf einmal.
Eine Aussage ist also garantiert richtig. In den meisten Fällen,
höhen Programmfehler darauf, dass irgendjemand beim Programmieren einen Fehler gemacht hat.
Und auf der anderen Seite, es können Laufzeitfehler auftreten,
die ich nicht direkt auf ein Programmierfehler zurückführen kann.
Also wenn irgendwo durch Benutzung,
durch zu viel Benutzung kein Speicher mehr vorhanden ist,
kriege ich im Regelfall einen Laufzeitfehler,
ohne dass das jetzt an einer Stelle im Codefall sein könnte.
Also so vielleicht auch nochmal für das Nachlesen,
dass sie das auf die Reihe kriegen
Ich will jetzt abschließen zu den letzten fünf Minuten,
will ich so ein paar Weisheiten, die Kollegen,
die sich schon lange damit befassen mit testen,
die die zusammengetragen haben,
will ich so zum Abschluss noch so ein paar Kernsätze hier vorstellen,
dass sie sie zumindest einmal gehört haben und vielleicht noch mal nachlesen und so.
Was wir schon hatten, testen garantiert nicht Fehlerfreiheit.
Okay, sollten wir jetzt verstanden haben? Vollständiges Testen ist nicht möglich,
zeige ich Ihnen zum Abschluss auch noch ein kleines Bötchen zu.
Nicht wie früher, wenn alles getan scheint,
dann das Programm in den Keller geben und sagen,
Leute testet mal, sondern ganz anders heute.
Bei agilen Methoden beleichtigt leichtgewichtigen Methoden, so früh es geht,
mit dem Testen beginnen, eigentlich schon parallel zum Entwickeln.
Eine ganz interessante Aussage ist, wenn ich irgendwo in einem Programmteil,
in einer Klasse oder in einem Package, finde ich,
zwei oder drei Fehler finde, dann ist die Wahrscheinlichkeit sehr hoch,
dass ich in diesem Package noch mehr Fehler finde.
Also Fehler sind in größerem Programm nie gleich verteilt,
nie über das ganze System in gleicher Dichte gestreut.
Also wer schon zwei in irgendeiner Ecke gefunden hat,
hat gute Chancen, einen dritten zu tun.
Tests veralten, veraltern. Wenn Programme weiterentwickelt werden,
aber die Tests nicht, sind die Tests irgendwann nichts mehr wert.
Das heißt, die ganze liebe Mühe,
die sie sich gemacht haben,
ist umsonst
Tests sind sehr abhängig von ihrem Umfeld. Auch eine ganz
wichtige Einsicht. Was bei Ihnen am Arbeitsplatz in ihrer Entwicklungsumgebung
fehlerfrei läuft, muss in der Einsatzumgebung überhaupt nicht laufen.
Das sind leider, leider, leider die unangenehmsten Fehler,
weil es sie teilweise in meiner Entwicklungsumgebung nicht reproduzieren können.
Also ein simples Beispiel, Benutzer von Mobile Phones werden das
in Teilen von Hamburg für einen bestimmten Provider schmerzhaft feststellen.
Ich weiß nicht, ob Sie das kennen,
man ist in irgendeiner Gegend von Hamburg und dauernd brechen die Gespräche ab.
Oder jemand versucht sie anzurufen, der kann sie aber nicht
erreichen und nach irgendeiner Zeit sagt Ihnen das Handy Anruf in Abwesenheit
Ja. Das ist ein ganz unangenehmer Fehler,
weil mittlerweile ist relativ klar, worin der beruht.
Die Server, die irgendwo stehen, haben ein Zeitverhalten und
die neuen Mobile-Phones, die schicken ihre Befehle zu schnell.
Und die Server verstehen die Befehle nicht.
Die verstehen die Anmeldebefehle nicht, weil die zu schnell kommen.
Die können die nicht schnell genug verarbeiten. Deshalb haben sie
in bestimmten Bezirken, haben sie diesen Effekt,
dass ihnen die Gespräche abbrechen oder sind nicht erreichbar sind,
in anderen Teilen von Hamburg haben sie nicht.
Und das ist in der Entwicklungsumgebung natürlich so gut wie nicht reproduzierbar,
der Fehler. So, also sie können viel testen,
aber damit ist das noch nicht benutzbar.
Nur Benutzer und Innen können was über Benutzbarkeit sagen,
sie nur sehr eingeschränkt.
Tja. Wollte zum Abschluss etwas
zum Austesten sagen
Ja, man könnte ja sagen, okay,
rein theoretisch formal kann ich sagen,
wenn ich alle Eingabemöglichkeiten eines Programms ausprobiert habe und alle Ergebnisse,
die ich bekomme, sind korrekt, sind richtig,
dann kann ja mit meinem Programm nichts mehr passieren.
Und das muss ich vielleicht nicht zu Fuß machen,
sondern ich habe einen Generator dafür, der generiert mir alle Testfälle.
Das macht er irgendwo so im Hintergrund,
das muss ich gar nicht tun,
weil der kann ja einfach blöde sein,
der muss nur einfach die Eingabewerte variieren,
sodass alle Kombinationen mal als Eingabewerte zur Verfügung stehen und dann rauscht das Ding so durch.
Lass ich nachts überlaufen am nächsten Tag, weiß ich,
alle Eingabemöglichkeiten sind erschöpft, alle Tests sind durchgelaufen, prima.
Das ist ein Ansatz, den man,
wenn man ein bisschen so sich theoretisch Gedanken macht,
kann man schon sagen, hey, etwas Kombinatorik,
das wird nicht so gut funktionieren.
Sie sehen hier dieses kleine Beispiel, einfaches Programm,
mit einer Schleife und ein paar Verzweigungen.
Vier Verzweigungen, was nicht vieles für ein Programm,
eine Schleife und die Schleife soll auch nur maximal 20 mal durchlaufen werden.
Wie lange dauert das, bis ich alle Testbahnfälle ausgetestet habe,
wenn ich automatisiert 100.000 Tests pro Sekunde ausführen kann?
Ein kleines Programm, 10, 15 Zahlen,
ein paar vier IF-Abfragen, eine Schleife, 20 Durchläufe.
Und dahinter ein Riesentestgenerator mit 100.000 Tests pro Sekunde.
Wie lange dauert der Test? Eine Stunde, zwei Tage,
dreimal vier Jahre, fünf Jahrzehnte, so ungefähr, die Zahlenseeklasse.
Jetzt machen wir mal ein kleines, kleine Aufwärmenübung.
Wer ist für A, eine Stunde? Okay, einzelne.
Wer ist für zwei Tage? Ja, schon ein paar mehr.
Wer ist für drei Monate? Ja, noch mehr.
Wer ist für vier Jahre? Das sind schon ganz schön
viele. Und wer ist für fünf Jahrzehnte? Okay.
38 Jahre. Ganz schön fehlen für ein kleines Programm.
Also das zu der Idee, wir testen das Ding mal aus.
Gut, bitte für die Klausur
Schauen Sie sich wenigstens mal an, was es noch so
an Testmöglichkeiten an unterschiedlichen Testarten gibt, lesen können Sie selbst.
Dass Sie mal so einmal gesehen haben, was es noch so gibt.
Einen Test wollte ich Ihnen noch vorstellen. Ganz wichtig,
wenn Sie in Zyklen, in kurzen Zyklen entwickeln,
auch so mit J. Unit beispielsweise, ganz wichtig,
sind die sogenannten Regressionstests, wenn Sie die nicht haben,
ist das mit in kurzen Zyklen entwickeln ein ziemlicher Mist,
weil sie nämlich mit Regressionstests prüfen,
ob das Programm nach einer kleinen Veränderung noch das tut,
was es vorher getan hat.
Zumindest das tut, was es vorher getan hat. Okay, Regressionstests. So,
Testenobjektorientierte Software ist nicht einfach, habe ich gesagt,
testgetriebene Entwicklung lassen wir mal heute weg, denke ich,
werden wir auf jeden Fall noch mal drüber sprechen, über agiles Vorgehen.
Ich werde da noch ein bisschen was hier im Rahmen
der Vorlesung zu Vorgehensmodellen sagen, kommt das?
Weitere Testdaten, schauen Sie auch hinterher drauf. Okay,
das zum ersten Teil, fünf Minuten Pause, hier vorne kleiner Szenenwechsel,
Fred wird die zweite Hälfte dann über Zusicherung machen.
Erstmal vielen Dank. Klassisch ist es immer so,
dass der Dozent sich an der ersten Vorlesung vorstellt und jetzt ist ja schon
die zweite Vorlesung und ihr werdet auch nicht so viel von mir haben.
Ich bin nur heute 45 Minuten da. Ich wollte keine Folie
über mich machen, das finde ich immer so ein bisschen langweilig.
Was habe ich so in der Vergangenheit gemacht? Ich wollte
euch mal zeigen, wie ich eigentlich so zur Informatik kam.
Ganz schnell, fünf Minuten und dann kommen wir zum eigentlichen Thema.
Es ist also schon ungefähr 26 Jahre her,
da hat meine Familie den ersten Computer bekommen,
also nicht ich
Damals hatte man einen Computer pro Familie. Und
der Computer kam mit einer Textverarbeitung, so auf Diskette.
Und das war es. Mehr gab es nicht. Also
es gab keine Spiele, es gab keine weiteren Anwendungen.
Also die gab es natürlich, aber ich hatte sie nicht.
Und man konnte sie auch nicht aus dem Internet runterladen,
weil, naja, Internet gab es in der Form noch nicht.
Und selbst wenn man hätte wahrscheinlich, ich glaube,
in der ISDN-Leitung in ungefähr vier bis fünf Sekunden in Speicherfolge geschrieben.
Okay, man musste sich also irgendwie seine eigenen Programme schreiben,
also einen Computer besitzen und Programme schreiben müssen, war irgendwie dasselbe damals.
Das heißt, ich programmiere auch seit ungefähr 26 Jahren.
Und so die ersten Programme, die man damals so geschrieben
hat, die gingen dann so los.
Wie heißen sie? Naja gut, als Achtjäger wurde man
vielleicht nicht unbedingt gesiezt, aber gut.
So, dann wurde das irgendwie eingelesen in eine Variable,
so in Variablen gab es da auch schon damals.
Und dann konnte man also ausgeben, herzlich willkommen, herzlich.
Herzlich willkommen
Tschau, das ist jetzt mein Programm. Das konnte ich einfach so schreiben,
der Computer aber an und man konnte loslegen, sein Programm zu schreiben.
Und dann kann man das auch ausführen. Wie heißen Sie
? Fremd? Toll. Ah, noch nicht ganz perfekt
, das Programm. Wie bearbeite ich jetzt mein Programm?
Ich gehe einfach wieder mit den Cross-Tasten hier hoch.
Ja. Hier will ich jetzt eine Leerfaste haben.
Leertaste jetzt durch Enter und ich führe das Programm nochmal aus.
Guckst. Ja, manche sehen es vielleicht schon.
Was ist hier passiert? Es ist ein Sonntagsfehler in dem Programm,
aber er ist erst entdeckt worden, als ich das Programm ausgeführt habe.
Nicht so schön. Ja, man würde normalerweise erwarten,
dass hier irgendwo ein Knopf ist, wo draufstehen, übersetzen.
Und dann würde der Compiler einem sagen, den es damals
auch nicht gab. Hey, Finn 230 ist ein Fehler.
Den müssen wir jetzt also beheben, eine Empfehlung.
Helden wir denn mal?
Bitte einmal hin der Leertaste
Zack. So, jetzt will ich nochmal eine Ausführung.
Super. Also ich war süchtig. Das war mein
erstes Programm und ab da. Und dann, gut,
wie lernt man jetzt programmieren? Meine Mutter erkannte jemanden,
der jemanden kannte, der jemanden kannte, der Informatik studiert.
Das habe ich noch nie gehört. Informatik klingt interessant.
Scheint was mit den Informationen zu tun haben.
Flottow mit Martinatik. Und der kam mit einem Listing ausgedruckt,
so über mehrere Seiten, auf so Endlospapier.
Ich weiß nicht, ob das noch jemand von euch kennt.
Das heißt, der Drucker spuckt nicht einzelne DIN-A4-Seiten aus,
sondern das ist ein endloses Band sozusagen.
Und da war dann ein riesiges Programm darauf abgedruckt.
Und das mit dem kam er dann zu uns und hat
das dann eingetippt in den Computer.
Dann hatte ich einen Vokabeltrainer. Nicht,
dass man den Noten sich dadurch merklich verbessert hätten in Englisch,
aber ich konnte Vokabeln lernen auf meinem Rechner.
Wahnsinn, dann machen wir sie ausdrucken und alles.
Und dann dachte ich, also was der kann,
will ich auch können, ich muss Informatik studieren.
So, so ging das bei mir los.
26 Jahre
Das heißt, wenn ich damals einen dieser Testfälle
auf diesem Rechner geschrieben hätte, der 38 Jahre läuft,
dann würde der Computer immer noch laufen.
Ziemlich beenzigend. Ich fürchte, dass heutzutage keiner dieser Computer
mehr läuft. Also ein Test, der 38 Jahre läuft,
der versagt ja vorher jede Hardware.
Exit oder sowas gibt es hier gar nicht. Okay,
ich schließe das mal wieder. So ging das also damals
bei mir los. Gut. Okay. Jetzt fangen wir
bei Folio 1 an. Vertragsmodell. Wir gehen ja davon aus,
dass ihr SE1 besucht habt oder wenn ihr SE1 nicht besucht habt,
vielleicht zumindest euch mal die Folien angeschaut habt und die Übungsblätter.
Wir haben uns ja auf dem letzten Level von SE1 mit Sammlung beschäftigt.
Listen, Mengen, Choose, Stacks und so weiter.
Und wir haben die auch implementiert. Wir haben uns also überlegt,
um so ein Stack zu implementieren, braucht man vielleicht so
Knoten und dann verweist der neue Knoten auf den alten und so weiter.
Und ganz interessant ist, es gibt einen Teilbereich der Informatik,
die beschäftigt sich damit. Wie kann ich formal von was
zum Beispiel ein Stack tut, ohne ihn zu implementieren.
Wie kann ich also zum Beispiel sagen, dass man immer
nur auf das oberste Elevent zugreifen kann und so weiter.
Und ich habe mal so ein kleines Beispiel hier reingemacht,
dass es nicht zu abstrakt ist.
Wir werden uns da später noch in SC2 mit beschäftigen.
Was ihr also seht, ist, ja, eine mathematische Gleichung sozusagen.
Wir haben hier einen Stack, den habe ich mal S genannt.
Und ein Element, das habe ich X genannt.
Und dann rufe ich da eine mathematische Funktion auf,
die heißt also Push, übergebe diesen Stack.
Und dieses X, und dann kommt zurück ein neuer Stack,
wo eben dieses X obendrauf liegt. Das bedeutet also,
dieser Ausdruck hier, der hier losgeht und hier aufhört,
ist also ein neuer Stack,
wo das X jetzt obendrauf liegt und den ich den jetzt in eine mathematische Funktion top reinstecke,
kommt das X wieder raus.
Und so kann ich also recht formal fassen. Das Element,
was ich mit Push drauf tue, ist dann auch obendrauf.
Toll. Muss ich es nicht mehr auf Deutsch schreiben,
aber man kann es auch auf Deutsch schreiben.
Ich habe es immer versucht auf Deutsch. Damit werden wir
uns also später noch beschäftigen, das nur als,
damit das Wort abstrakter Datentyp nicht ganz so abstrakt ist als
kleines Beispiel
Okay, aus dieser ganzen Theorie der abstrakten Datentypen ist etwas rausgekommen,
was in der Praxis relevant ist oder zumindest teilweise Relevanz hat,
je nachdem, mit wem man sich gerade unterhält.
Es gibt also Leute, die starke Befürworter für das Vertragsmodell sind und viele,
die nicht so richtig verstanden haben, was es eigentlich soll, nicht so wirklich den Sinn daran sehen. Okay,
und das Vertragsmodell hilft uns, wir haben ja in SE1 schon oft geredet,
bei Klient und Dienstleister, ein Klient ruft Methoden bei einem Dienstleister,
auch was bedeutet das eigentlich, was kann er da erwarten,
was da passiert, welche Regeln gibt es da,
das soll durch das Vertragsmodell so ein bisschen klarer gefasst werden, also über etwas, was über Kommentare hinausgeht.
Okay, das ist ein Vertrag, man kann sich vorstellen,
ich will vielleicht ein Haus bauen und wenn ich dafür ein Grundstück kaufen muss,
dann gibt es sicherlich einen Vertrag, wo genau geregelt ist,
was da von mir verlangt wird,
also möglicherweise muss ich schuldenfrei sein oder darf ich zu viele Schulden haben,
ich brauche vielleicht irgendjemand, der für mich birgt,
falls ich arbeitslos werden sollte,
vielleicht braucht man demnächst keinen Informatiker mehr und so weiter,
Dafür kann ich auch, wenn ich diese ganzen Voraussetzungen erfülle,
auch erwarten, dass ich eine gewisse Leistung dann bekomme.
Dass das also dann irgendwie funktioniert. Oder wenn ein Auto
mietet oder wenn ihr eine Nacht im Hotel übernachtet und so weiter.
Da gibt es also immer jemanden, den Dienstleister, der euch eine Dienstleistung anbietet.
Und es gibt ein oder auch ganz viele Klienten,
die diese Dienstleistung in Anspruch nehmen wollen.
Gut. Und jetzt gibt es ein paar wichtige Begriffe in
diesem Vertragsmittelklärt und Dienstleister kennen wir ja schon aus ST1.
Das ist also nichts Neues. Neu ist jetzt der Begriff
der Vorbedingungen. Das ist also eine Ansammlung von Bedingungen,
die der Klient erfüllen muss, bevor ihr den Vertrag irgendwie in Anspruch nehmen kann.
Dann rattert also der Dienstleister los und erledigt seine Dienstleistung,
berechnet vielleicht irgendwas oder erzeugt irgendwelche Objekte und liefert sie dann zurück.
Und der Dienstleister garantiert dann auch, dass gewisse Nachbedingungen gelten.
Also dass das Objekt in einem gewissen Zustand sich befindet,
was da zurückgeliefert wird oder ähnliches.
Es gibt tatsächlich Sprachen, wo das Vertrag Modell Teil der Sprache ist.
Wo also die Sprachdesigner sich überlegt haben,
das finden wir sinnvoll, dass man formaler fasst,
wie Aufrufe von operationellen Objekten so stattfinden sollen,
was man da erwarten kann und was man garantieren kann im Gegenzug
und haben das dann in die Sprache eingebaut.
Und einer der ersten war Bert Hormelier, der Sony programmierte Sprache Eifel eingebaut hat.
Und Eifel ist dafür eben auch hauptsächlich bekannt geworden.
Jedenfalls noch mal im Eindruck. Und ich habe mir überlegt,
schaue ich doch einfach mal, was ist denn so das
Standardbeispiel von Eifel oder das erste Beispiel in Eifel für das Vertragsmodell?
Ich habe extra einen Screenshot gemacht, damit ihr nicht denkt,
ich beschönige hier irgendwas oder baue hier absichtlich irgendwelche Fehler ein oder so.
Das ist also das erste Beispiel, was man findet.
Und wir bleiben erst mal bei dem ersten Satz. Ja,
das Beispiel geht also davon aus, man möchte ein Element
in ein Wörterbuch einfügen und dieses Wörterbuch hat eine beschränkte Kapazität.
Jetzt tauchen ja schon so ein paar Begriffe auf,
die ihr kennt, Kapazität und Begriffe,
die ihr vielleicht nicht, kein Wörterbuch.
Ich dachte, Ich zeige euch das einmal ganz kurz an
einem Beispiel in Java, was damit eigentlich gemeint ist.
Denn ihr kennt das eigentlich schon. Also wechsle ich mir
ganz schnell zu Equips. Alles schon vorbereitet.
Ein Wörterbuch ist einfach nur ein Synonym für eine Map.
Wer von euch erinnert sich noch, dass wir in SE1
mal Maps verwendet hatten? Aber bitte ganz deutlich handhoch.
Haben wir mal Maps verwendet in SE1? Ja,
das habe ich befürchtet. Die meisten erinnern sich nicht mehr
dran. Es war nämlich in Woche 14,
wo wir die Grafen gebaut haben und uns überlegt haben,
jeder Knoten soll eine Liste seiner Nachbarknoten haben.
Also brauchen wir irgendeine Datenstruktur, wo eben für jeden Knoten
die Liste seiner Nachbarknoten abgelegt ist.
Und solche Datenstruktur ist eben eine Map oder ein Dictionary.
Wie benutzt man sowas in Java? Ich habe jetzt also
hier erstmal so eine Map deklariert. Das Interessante ist,
jetzt hier bei der Variablendeklaration, dass sich zwei Typ-Argumente angeben muss.
Wenn die Allisten deklariert oder Mengen,
braucht ihr immer nur einen Typ-Argument, nämlich,
was ist der Element-Typ des Containers oder der Sendung?
Hier braucht man zwei
Der Linke sagt, das nimmt man auch gerne den Schlüsseeltyp.
Das ist also das, wonach dieses Wörterbuch organisiert ist.
Stellt euch vor, es wäre ein Wörterbuch,
was von Deutsch nach Englisch abbildet. Dann wäre das erste,
also hier das deutsche Wort und das zweite wäre das englische Wort.
Okay, das ist jetzt aber nur die Referenzvariable und hier
erzeuge ich dann ein Exemplar in der Klasse,
die das Interface Map implementiert, zum Beispiel Hashmap.
Hashing erinnert sich da noch jemand als ernst, dass das Wort ankam?
Hashing hat ja sogar selbst implementiert, sehr gut. Okay,
das geht also nicht nur für Sets, sondern auch für Maps.
Okay, und man kann dann, im Moment ist noch nichts
so in diesem Wörterbuch, man kann das jetzt befüllen.
Ich habe zum Beispiel überlegt, vielleicht interessiert man sich dafür,
welche unserer Mitarbeiter wo, in welchem Raum sitzen.
Außer habe ich zum Beispiel immer gesagt,
Christian befindet sich im Raum D214, das ist also Christian Spee,
Till, auch ein D214 Reinhardt, zu dem müsst ihr immer hingehen,
wenn ihr Probleme mit euren Accounts habt.
Ich habe mein Passwort vergessen oder ich habe es zu Hause
liegen lassen oder so. Schnell zu Reinhardt gehen.
Ich benutze immer die 215 und Christian Zoller ist im Zimmer
Puh. Frage an euch, was glaubt ihr,
wie viele Einträge in der Map sind,
nachdem ich jetzt also hier fünfmal diese Put-Operation aufgerufen habe?
Wer glaubt, es zu wissen, einfach mal Hand hoch?
Ja. Vier. Wie kommst du auf vier?
Warum nicht fünf? Weil die Schlüssel eindeutig sein müssen.
Richtig, genau. Und wir haben zwei Christians.
Das heißt, dieser Christian wird spätestens hier überschrieben.
Und da geht die Information verloren, wo der Christians Follower.
Genau. Okay. Und wie greifen wir uns auf so
eine Map zu? Ich zeige es auch deswegen so ausführlich,
weil das in unseren Projekten in SE2 auch eine Rolle spielen wird.
Man kann also sagen, ich möchte das Büro wissen,
in dem Christian sitzt. Okay,
ich stelle also eine Anfrage an diese Map,
übergebe den Schlüssel und bekomme dann dieses Ding hier zurück,
den Zugeordneten strengen.
Das können wir einmal ausführen. Ich hoffe, dass das funktioniert.
Ja, ich meine, Bildschirm ist nicht besonders groß,
es funktioniert.
Sehr schön
Gut, jetzt haben wir ungefähr ein Verständnis,
was so eine Map ist, welchen Sinn die hat,
was man damit so machen kann.
Jetzt wechsle ich wieder zurück. Hier ist jetzt also ein Beispiel,
wie das Einfügen in eine Map vertraglich geregelt sein könnte.
Okay, was darf ich da übergeben,
wenn ich was in einer Map reintun will? Ja,
nur die Operation heißt sogar genauso in Eife, die heißt auch Putt.
Nur sind hier die Argumente vertauscht. Also wir hatten bei uns
den Schlüssel als erstes übergeben und dann das zugeordnete Element als zweites.
Das ist ja genau andersrum, aber das ist jetzt,
darüber sollten wir jetzt nicht zu sehr stolch halten.
Die Reihenfolge, da ist ja völlig beliebig. Okay,
dann sieht man offenbar, dass Kommentare in Eife,
wenn wir zwei Minuszeichen anfangen, gibt es ein paar Sprachen, die das machen?
Und jetzt wird es spannend, jetzt kommt das Vertragsmodell.
Hier wird jetzt geregelt, nach diesem Require-Schlüsselwort,
was die Operation Putt von dem Klienten verlangt.
Sie verlangt also, dass die Kapazität noch nicht ausgeschafft ist
und der Schlüssel soll auch nicht leer sein.
Ich kenne jetzt nicht Eife, gut genug um zu beurteilen,
ob das jetzt hier zum Beispiel sowas heißt,
wie darf nicht Nall sein, wie in Java?
Also sind Strings auch sogar Referenzen, das weiß ich nicht.
Oder heißt es tatsächlich, das muss mindestens ein Zeichen sein?
Eins von den beiden wird es sein, aber so wird es formal hingeschrieben.
Dann kommt der eigentliche Funktionsrumpf und dann kommen die Nachbedingungen nach diesem Entschuh.
Was sind das für Nachbedingungen? Also nachdem die Pot-Operation durchgelaufen ist,
kann man davon ausgehen, dass X in der Map eingetragen ist.
Das Häs ist also auch eine Operation bei dieser Map.
Dann das, was in Java Gett hieß,
das heißt hier Item, also wenn ich eintrage,
dass Christian ins Zimmer D215 sitzt und ich frage anschließend,
wo sitzt denn Christian?
Dann wird das Zimmer D215 rauskommen. Das bedeutet diese Nachbedingung.
Und jetzt kommt auf was ganz Spannendes. Die dritte Nachbedingung sagt,
dass die Anzahl der Elemente sich um einen erhöht, wenn ich einführe.
Und hier sieht man etwas, was das in Java so nicht gibt.
Ich kann also sozusagen auf das alte Ergebnis von kaum
zugreifen sozusagen bevor froh die Operation ausgeführt wurde.
Und wenn ich mir da einen gedanklich raufrechne, dann kommt der neue Account draus.
Das ist ziemlich nett. Spätestens hier bei solchen Arten von Nachbedingungen,
die sich auf Zustand vorher im Zustand anschließend beziehen,
versagen alle Programmiersprachen, die das Vertragsmodell nicht eingebaut haben.
Weil sowas wie Old macht außer dem Vertragsmodell nicht wirklich Sinn,
in eine Sprache einzubauen.
Das heißt, sowas könnte man in Java gar nicht ausdrücken.
Gut. Okay, und dann, ja,
wie gesagt, ich habe extra einen Screenshot gemacht.
Ich bin der Meinung, dass die erste Vorbedingung einen Flüchtigkeitsfehler enthält.
Ich nehme das mal vorsichtig flüchtig als Fehler, wenn das
nicht zu böse klingt. Vielleicht erinnert ihr euch noch,
in der SE1 hatten wir immer gesagt,
die Kardinalität muss in einem bestimmten Zusammenhang zur Kapazität stehen.
Grundsätzlich. Sieht jemand hier einen Fehler?
Also hier wird behaupten
Wäre die Arztzeit der Elemente gleich die Kremparität,
ihre Erinnerung, dass wir immer noch übel sind.
Richtig, genau. Also der Student hat gerade gesagt,
diese Vorbedingung erlaubt ja auch, dass die Anzahl der Elemente
gleich der Kapazität ist durch dieses gleiche Zeichen.
Und man ist aber kein Platz mehr für ein neues Element da.
Ja, das ist also tatsächlich ein Fehler an der Vorbedingung.
Hier müsste stehen, Count, kleiner, Kapazität.
Finde ich ganz witzig, dass das erste Beispiel gleich falsch ist.
Okay, wenn jemand der Meinung ist,
dass ich mich irre, könnt ihr mich gerne korrigieren.
Okay, das ist als erstes Beispiel. Dann,
was wir eben auch gesehen haben, ich gehe nochmal kurz in Folie zurück.
Alles, was in diesen Vor- und Nachbedingungen steht, ja,
sind bulische Ausdrücke. Also hier kommt entweder Show oder False House,
hier kommt entweder Show oder False House,
hier genauso hier auch und hier auch.
Das heißt also, entweder ist es ein Methodenaufruf,
der sowieso schon Bullien zurückliefert, so wie Hass.
Oder es ist irgendeine Gleichung oder Ungleichung,
wo dann auch eben ein bullischer Wert da rauskommt.
Und wichtig ist, dass das alles Ja,
Dinge sein müssen, die für den Klienten verständlich sind.
Also er muss verstehen, was dieses Count bedeutet, was dieses Capacity bedeutet.
Das sind einfach weitere Operationen an der Map. Was ich
jetzt nicht machen dürfte, wäre da irgendwelche Exemplarvariablen zu erwähnen.
Sowas wird gerne von Programmieren am Anfang gemacht. Das heißt,
sämtliche Prädikate, die da so auftreten, müssen irgendwie aus Operationen zusammengebaut sein,
sondierenden Operationen, die die Klasse ebenfalls anbietet.
Sonst hat der Queen keine Chance, den Vertrag zu überprüfen.
Man muss den Vertrag verstehen können und sinnvoll überprüfen können.
Okay, und bitte keine privaten Exemplare arbeiten. Okay,
dann neben den Vor- und Nachbedingungen gibt es noch etwas,
das nennt sich Klassen in Varianten.
Und das ist immer so ein bisschen blödes,
es ist immer so ein bisschen schwierig, da gute Beispiele zu finden.
Und ich dachte, ich schaue mal in SE1 in den Projekten,
ob es da irgendwo gute Beispiele für Klassen in Varianten gibt.
Und ich habe auch mal ein bisschen recherchiert im Internet,
was da sogar Klassen in Varianten gesagt wird.
Und da ist es tatsächlich so, dass da Diese Anforderung,
es muss sich alles auf die Schnittstelle beziehen.
Oft pragmatisch einfach aufgeweicht wird, weil man viele sinnvolle Klassenvarianten,
Klasseninnenvarianten definieren kann, die sie eben auf Interne beziehen.
In der Hoffnung, damit die Klasse robust gegen Änderungen zu machen.
Wenn wir so nach dem Motto,
ich als Auto der Klasse habe mir vorgestellt,
dass diese drei Exemplare, ich habe einen folgenden Zusammenhang immer haben müssen.
Und wenn das später irgendwann mal verletzt wird,
dann hat sicherlich ein Programmierer einen Fehler in diese Klassik eingebaut.
Ich habe noch gar nicht definiert, was eine Klasseninnenvariante ist.
Ich bin hier ein bisschen runtergesprungen. Also was ist eine Klasseninnenvariante?
Eine Klasseninnenvariante muss immer dann gelten, wenn der Kontrollfluss nicht
gerade in einer öffentlichen Operation der Klasse drin ist.
Also ihr habt das Objekt zum Beispiel erzeugt,
dann sitzt es da irgendwie, dann gelten die Klasseninnenvarianten.
Dann ruft ihr eine Methode auf, die Methode rattert durch,
es wird irgendwas geändert und bin die Methode,
dann wieder durchgelaufen ist und der Kontrollfluss kehrt zum Klienten zurück,
dann müssen die Klasseninveramenten auch wieder gelten.
Okay. So, dann habe ich mich erinnert,
es gab dieses Projekt RAI Titelliste
Vielleicht erinnert euch noch daran, ich glaube, es war
Woche elf oder so. Ich habe dazu mal die Lösungen,
die wohnen ja irgendwann mal im Komsi veröffentlicht,
angeschaut und da gibt es so eine schöne Grafik.
Wo ist die Grafik? Da ist die das völlig größer haben.
Hier ist die Grafik, ja, die solltet ihr irgendwann mal selber zeichnen.
Was sieht man in dieser Grafik? Man sieht also ein Array,
das hattet ihr selber erzeugt, das hieß Titel Array.
Wie groß ist dieses Array? Ja, wie groß ist es?
Hat das jemand nachgezählt? Man will sich ja nicht blamieren,
dass er eins, zwei, drei, vier,
fünf, sechs, sieben, acht, neun, zehn.
Okay, ist halt, es bietet also Platz für zehn Referenzen auf Titelobjekte.
Momentan sind aber nur die ersten vier belegt. Das heißt,
man würde davon ausgehen, dass die zweite Exoplar variable Anzahltitel,
den Wert vier hat.
Okay, das sind vier Titel abgespeichert, Pardinalität,
Kapazität ist aber zehn. Und jetzt kann man die erste Invariante,
ich gehe ganz kurz auf die Folie, danach wechsel ich wieder zurück.
Die erste Innenvariante, die hatten wir schon, die kamen,
glaube ich, sogar in der Klausur vor,
die auf Deutsch eben ausdrückt, dass die Kardinalität immer kleiner gleich ist als die Kapazität.
Das könnte man tatsächlich, wenn Java das unterstützen würde,
dass man invariant formulieren kann, würde ich als Innenvariante hinschreiben, diesen Ausdruck.
Okay, man würde das immer für mich überprüft werden und
wenn irgendwann mal ein Programmierer einen blöden Fehler macht und vergisst irgendwie die Variable zu ändern,
dann wird das möglicherweise aufgefangen.
Gut, jetzt zu den anderen beiden muss ich ein bisschen
was sagen, wechseln wir wieder zurück.
Nein, hier bin ich genommen. Was ganz Spannendes ist,
dass die Variable Anzahl Titel quasi so eine Art Partitionierungspunkt darstellt.
Also hier ist eine Art Grenze und alle Elemente links von der Grenze
sind Referenzen auf Titelobjekte und alle Elemente rechts von der Grenze
sind Neilreferenzen
Das ist eine wunderbare Invariante, die man formulieren könnte.
Schauen wir uns doch mal an, wie ich versucht habe,
das zu formulieren. Nee, falsches. Auch falsch.
Hier bin ich. Was habe ich versucht, hier zu formulieren?
Also Kittle Array ist mein ganzes Array. Dann sage ich,
ich möchte dieses Array als Liste ansehen. Das ist einfach nett,
weil man dann gewisse nette Operationen daran aufrufen kann.
Array Saber haben wir nicht wirklich schöne Operationen, wie ich finde,
mir mal irgendwas oder mach das mal kleiner oder so.
Also ich will mir das Array als Liste anschauen. Und dann sage ich,
ich möchte mir nur einen Teil dieser Liste anschauen,
nämlich von dem Index 0 bis exklusive Anzahltitel.
Das heißt, ich bekomme jetzt eine Sicht auf das Array,
wo genau die Referenzen liegen, die nicht nall sind.
Okay. Und dann frage ich,
ob es in dieser Sicht eine Neilreferenz gibt und erwarte,
dass das nicht der Fall ist. Okay. Ja,
also in einem normalen Programm würde man wahrscheinlich stattdessen eine Methode schreiben,
die heißt, sind alle nicht ny,
wo man dann das Ere und zwar Indizes übergibt,
damit es das Ganze ein bisschen lesbarer wird.
Okay. Gut. Vielleicht mal Frage an euch. Wer sieht
den Sinn in dieser dritten Invariante, die ich da aufgeschrieben habe?
Was soll die denn aussagen? Also wir hatten uns eben darum gekümmert,
in der zweiten Invariante, links von dieser Grenze,
sind überall keine Laireferenzen und was prüft jetzt die andere in Variante?
Also wenn das Ereignis nicht ganz voll ist,
ob der erste Einfach hinter dem Titel einen da ist.
Schön. Du hast es mit Van formuliert, das finde ich ganz interessant.
Sehr gut. Genau. Es gibt also zwei Fälle,
die wir berücksichtigen müssen. Wenn das Ere schon komplett voll ist,
dann gibt es ja rechts von dieser Grenze gar keine Elemente.
Da muss ich dann also vorsichtig sein. Aber angenommen ist es
noch nicht voll. Dann schaue ich, ob an der Position,
wo dann ja sozusagen die nächste Referenz eingespeichert werden sollte,
wenn ich mal wieder eine einfügen möchte,
Man muss auf jeden Fall Neil stehen.
Sonst haben wir dieses Problem, was auch im Übungsbetrieb auftragt.
Eigentlich brauchen wir das Element gar nicht mehr,
aber der Garbage Collector hat keine Chance, es wegzuräumen,
weil es steht ja noch im AR in der Referenz darauf drin.
Ja. Ich habe leider keine gute Invariante gefunden,
um zu sagen, alle Elemente dahinter Signal.
Vielleicht findet von euch ja eine Möglichkeit, dass in einer Zeile Java auszudrücken.
Okay. Ja, dann wird hier noch mal ein bisschen
formal das gesagt, was ich eben eigentlich schon erzählt hatte.
Wie ist der Lebenszyklus so eines Objekts? Es wird durch einen Konstruktor erzeugt,
ein Konstruktor kann natürlich auch Vorbedienung haben, aber angenommen, die sind erfüllt.
Der Konstruktor sorgt dann dafür, dass die Invarianten zum ersten Mal gelten.
Dann gelten sie eine Zeit lang, dann wird irgendeine öffentliche Operation aufgerufen,
dann dürfen sie mal nicht gelten, aber so lange,
Entschuldigung, sobald aus dieser öffentlichen Operation rausgesprungen wird,
gelten die in Varianten fitter.
Gut, dann vorbedingungen nachhaltig wird ja auch auch noch alles formal gefasst.
Gut. Und wichtig ist ja auch jetzt,
Wie wir das Ganze in Java jetzt einbauen.
Ihr sollt das ja im Übungsbetrieb benutzen, dieses Vertragsmodell.
Ja, und leider ist es eben so,
Vertragsmodell ist in Java nicht eingebaut.
Es gibt ein ganz interessantes Interview. Ich habe mir das
schon mehrfach durchgelesen. Da werden also drei große Programmiersprachendesigner interviewt.
Schauen wir mal ganz kurz, welche Leute das sind.
Dennis Richie, der ist Ende 2011 gestorben.
Der hat C mitgedesigned. Dann haben wir Bjarnes Großdruck,
der hat Circus. Plus Design lebt noch und wird auch
immer noch weiterentwickelt. Dieses Jahr kam gerade der neue Standard.
Und James Gosling, der Java entwickelt hat.
Und das ist dieses Interviews entstanden. Ja, schon vor 14 Jahren,
wo Java zum Beispiel auch noch gar keine Generics hatte.
Also wo man nicht sagen konnte, List von Tee oder so.
Ganz interessantes Interview. Und da sagt eben James Gosling,
er hätte gerne das Vertragsmodell eingebaut im Java.
Aber die Leute, denen er das so gezeigt hat.
Java hat ja auch ein großes Publikum. Und das,
was man da einbaut, muss ja auch akzeptiert werden.
Die haben alle gesagt, den Sinn verstehe ich nicht,
das braucht auch keiner.
Ja, und dann konnte er es leider nicht einbauen.
Und das findet er selber
sehr schade.
Müssen uns also Gedanken darüber machen, wie können wir das manuell irgendwie reinkriegen?
Schreiben wir da irgendwelche IFs oder so? Mal schauen.
Was sind die Gedanken, die wir uns machen müssen?
Ich gehe noch mal ganz kurz zu der Eifelfolie zurück,
damit euch klar ist, was in iPhone eigentlich geleistet wird.
In Eifel werden hier zwei Dinge geleistet. Wenn ich diese
Vorbedingungen mit dem Require-Schlüsselwort hinschreibe, dann ist das Erste,
was passiert, diese Vorbedingungen tauchen in der Dokumentation auf.
Wenn ich mir also die Dokumentation, die Schnittstellen an sich
der Klasse anschaue und mir angucke, wie funktioniert diese Pot-Operation?
Dann stehen da die Vorbedingungen. Ein Klinik kann sie sich also angucken,
kann sie sich ausdrucken und abends im Bett durchlesen.
Okay, bei den Nachbedingungen genau das Gleiche. Okay,
das ist also der erste Punkt. Und der zweite Punkt ist,
sie werden, wenn das Programm ausgeführt wird, auch überprüft.
Das heißt also, wenn jetzt jemand hier einen Schlüssel übergeben würde,
der leer ist, dann hält das Programm an,
gib irgendeine Fehlermeldung aus und sagt, hier,
da hast du dich wo irgendwo vertan,
ich beende mal das Programm, Programmierfehler.
Das sind also zwei Aspekte.
Einmal der Klient muss das in der Dokumentation sehen
Es sollte auch nach Möglichkeit überprüft werden. Jetzt gehe ich
wieder zurück hier. Und diese beiden Fälle müssen uns jetzt
jeweils überlegen, wie wir das in Java sinnvoll machen.
Okay, Dokumentation klingt jetzt erstmal nicht so schwer,
wir schreiben es einfach in den Schnittstellen-Kommentar rein. Slash,
Stern, Stern, dann wird der Kommentar schön in blau und alles,
was ich da reinschreibe, taucht dann ja an der Schnittstelle als Kommentar auf.
Gut, könnte man da also vielleicht auf Deutsch einschreiben oder
vielleicht denken wir uns eigene Tags aus.
Schauen wir gleich mal. Überprüfung ist schon ein bisschen schwieriger
. Da reden wir gleich noch ein bisschen drüber.
In Eifel ist es so, bevor in den eigentlichen Funktionsraum
reingesprungen wird oder Methoden rumf, werden die Vorbedingungen überprüft.
Zu einem anderen Zeitpunkt macht das nicht wirklich Sinn.
Also bevor der eigentliche Code losgeht, einmal kurz die Vorbedingungen überprüfen.
Wir müssen dann also zu Beginn der Methode die Vorbedingungen umprüfen,
das heißt, wir müssen Code reinschreiben,
ganz oben in den Rumpf rein, der die Vorbedingungen prüft.
Da müssen wir von Hand da reinschreiben, das passiert nicht automatisch.
Okay, dann bei den Nachbedingungen
Wenn man sie prüft, müssen sie geprüft werden am Ende
des Umfelds, kurz bevor ich zurückspringe.
Also ihr könnt nicht nach einer Return-Anweisung noch Nachbedienung prüfen,
sondern kurz vor der Return-Anweise. Wir haben uns aber in SE2
aus verschiedenen Gründen entschlossen, diese Prüfung nicht zu machen.
Das werde ich gleich noch diskutieren, warum wir uns dazu entschlossen haben.
Gut, in Varianten werden in SE2 keine große Rolle spielen.
Also ich habe bis jetzt keine Übungsaufgabe gesehen,
wo irgendwie in Varianten von euch verlangt werden.
Aber man kann die in den Klassenkommentar reinschreiben,
wo man das möchte. Gut. Wenn man jetzt wollte,
dass die auch noch überprüft werden,
müsste man ja in jeden Methoden auf einmal am Anfang diese Innenvariantenmethode aufwenden und einmal am Ende.
Dann werden die Methoden auf einmal sehr viel länger.
Gut, was wir gleich auch noch sehen werden,
wir müssen jetzt also die Vorbedingungen an zwei verschiedenen Stellen formulieren.
Einmal im Kommentar, einmal im Code. Und sobald man
eins von beiden ändert, kann das zu Wartungsproblemen führen.
Gut, nun machen wir jetzt die Überprüfung.
Man könnte das zum Beispiel einfach mit dem IF machen
Wenn diese Bedingung nicht gilt, dann wird folgende Acception,
kann man machen. Dann gibt es in vielen Frameworks-Methoden,
die heißen dann irgendwas mit dem Require oder so,
zum Beispiel ein Framework-Jump, was man, Jay-Wamm,
was man hier in der Uni Hamburg entwickelt wurde.
Da gibt es ja so eine Methode Require. Da kann ich
eine Bedingung übergeben. Ja, hier kann ich den Dienstleister angeben.
Wahrscheinlich wird er dann als Fehlermeldung auch irgendwo gelockt oder so.
Und eine Beschreibung der Vorbedingungen. Und falls diese neue Vorbedingung
verletzt wird, dann macht diese Spray immer irgendwas sinnvolles.
Hauptsache das Programm wird angehalten. Gut. Okay,
dann gibt es auch noch Leute, die sagen,
eigentlich muss man doch diese Vorbedingungen nur prüfen,
solange das Programm in der Entwicklungsphase ist.
Und irgendwann sind wir der Meinung, das ist jetzt fertig,
wir liefern es an den Kunden aus.
Wir sind der Meinung, dass da keine Programmierfelder mehr drin sind.
Dann brauchen wir doch eigentlich die Vorbedingungen gar nicht mehr zu prüfen.
Wir würden die gerne auf eine einfache Art und Weise ausschalten können.
Ja, und das geht bei manchen Framework-Lösungen geht das,
bei manchen geht es nicht.
Meistens geht es nicht
Und was ganz witzig ist, es gibt in Java
seit Java 1.4 eine spezielle Anweisung, die heißt DS-Shirt-Anweisung.
Also ein eigenes Schlüssel wird Assort. Und diese,
schaut an, was kann man ein- und ausschalten.
Das ist also, wenn man der Meinung ist,
ich möchte die Option mir offenhalten, das irgendwann mal auszuschalten,
ganz nett, dann ist das Shirt dafür zu verwenden.
Okay. Hier sieht man mal die allgemeine Sonntags von dem Assort.
Hier die einfachste Variante. Ich schreibe einfach nur das Schlüsselwort
Assort, gefolgt von einer Bedingung. Wenn was schiefgeht,
kommt ein Assertion-Arror und ich weiß nicht wirklich, was schiefgegangen ist.
Oder ich kann hinter einem Doppelpunkt noch schreiben,
irgendeinen Text, der dann sinnvoll irgendwo ausgegeben wird,
dass man weiß, was jetzt wirklich schiefgegangen ist.
Und der Klassiker ist natürlich hier unsere Quantoklasse.
Wir haben in unserer Kontoklasse eine Operationszahle ein, der man
einen Betrag übergibt. Und beim Einzahlen ist es sicherlich sinnvoll,
es kann eine negative Zahl übergeben wird.
Ich kann nicht minus 10 Euro auf ein Konto einzahlen,
das geht nicht. Okay, also,
hier sieht man jetzt den ersten Punkt,
wie dokumentiere ich an solche Vorbedingungen nach unserer Konvention
Ich schreibe also hier ein Adge-Zeichen, gefolgt von Require.
Und dann schreibe ich eben die Bedingungen so hin,
so wie man sie auch in Jada schreiben würde,
als normalen bulischen Ausdruckbetrag, was größer gleich neu sein.
Man kann also der Klient diesen Vertrag sehen.
Gut. Dann überprüfe ich das Ganze mit dieser Short-Antwort.
Also ich sage also, bitte überprüfe das Liebes Java.
Und falls das nicht der Fall sein sollte,
dann soll hier eine sinnvolle Fehlermeldung ausgegeben werden.
Das können wir uns doch mal live angucken.
Das ist immer spannender als eine Freude. Wir schauen es
uns live an. Dann mache ich mir hier die Mitarbeiter
wieder zu. Machen wir mal hier die Konten auf.
Hier habe ich mal eine Methode zum einen Song.
Und dann schreiben wir das doch einfach mal hin.
Wie sah das aus? Erst, dass du Surfschlüssel baut?
Seht ihr es schön rot, weil es ein Schlüsselwort ist?
Oh, ich habe das noch gar nicht dokumentiert.
Vielleicht sollte ich das mal als erstes machen.
Also, warum ist das so komisch eingerückt?
Require, Betrag,
größer gleich
Skopiere ich mir mal mal. Natürlich nicht hier aus Versehen was falsche Schraube.
Und dann schreibe ich sowas wie auf den Folien.
Vorbelegung verletzt. Betrag aus Vergleich noch. Gut. Okay,
haben wir hier irgendwo mal einen Klienten von diesem Sparkonto?
Nehmen wir mal hier dieses Start-up. Was passiert da? Nee,
da wird schon der Überweisungsservice benutzt, das will ich gar nicht.
Machen wir uns ganz kurz einen eigenen Klienten.
So, also machen wir mal ein neues Konto.
Uh, schade, das kann automatisch.
Konto, Karte, nicht New Konto. Sparkonto deswegen,
ich wollte noch mal einen kleinen Trick sagen.
Also ich sage New Sparkonto.
Dann kann ich nur sagen
A science steckment to new local variable. Toll. Alles
direkt hingeschrieben. Muss ich nicht dreimal sparen unterschreiben.
Super. Okay, und dann will ich mal was einzahlen.
Sparkonto, schau mal ein. Sagen wir mal, minus zehn.
Okay. Ich habe nämlich gerade eine neue Maus gekauft,
die hat zehn Euro gekostet.
Bobs. Das Geld will ich jetzt wieder haben.
So, dann führen wir das auch mal aus.
Und wir würden jetzt eigentlich erwarten, dass da irgendein Fehler kommt.
Kommt aber gar nicht. Das ist ja merkwürdig.
Schauen wir mal ganz kurz. Sparkonto, Gibsaldo.
Das heißt nicht Gibsaldo, wie heißt das?
Die Konterstand. Und dann kann ich das hier wieder zu
einer Wahlablehnung
zur Verfügung
Toll. Waren wir das richtig? Und den gebe ich einfach mal aus.
Wenn ihr System out Printline nicht von Hand schreiben wollt,
sagt ihr Süßo, Steuerungiltaste und es kommt automatisch.
Super. So. Okay. Schauen wir noch mal
ganz kurz, was da schief gelaufen ist.
Tatsache, es war möglich, minus 10 Euro einzuzahlen.
Aber ich habe auch eben diese schöne Vorbedingung formuliert.
Was ist das denn? Ganz kurz zu den Folien zurückgehen.
Die Assursions, die man, ich habe ja gesagt,
man kann sie ausschalten. Das klingt so,
als würden sie standardmäßig eingeschaltet sein, sind sie aber nicht.
Sie sind standardmäßig ausgeschaltet und wir müssen sie explizit einschalten,
wenn wir sie, wenn wir sie zur Laufzeit ausführen sollen.
Und auf dieser Folie steht, wie man das macht.
Das ist ganz gut, weil ich das in den Clips
nicht auswendig weiß. Window Preferences, Java, Instagram,
East, Boah. Hoffentlich finde ich das gleich noch.
No, Speferences, Java, ins deutsche AEs.
Hier haben wir es,
einmal editieren
Minus EA. Das heißt, das E steht für Enable
und das A steht für Assursions.
Ich möchte also, dass die Assursions aktiviert sind.
Und wenn ich das jetzt noch mal ausführe? Ja,
toll. So kommt also jetzt hier direkt die Fehlermeinung,
der mir also sagt, an dieser Stelle in Maine hast du etwas getan,
was du nicht tun durftest.
Du hast gegen den Vertrag verstoßen. Ja, und wenn
ich auch wissen will, wie das beim Dienstleister aussah,
dann ist das genau hier passiert.
Genau hier hat er gemerkt, Betrag ist ja gleich null
, wurde nicht erfüllt. Okay. Gut. So,
dann kann man eben diskutieren, ist das jetzt so sinnvoll
mit dem SHL ja oder nein?
Da gibt es verschiedene Positionen. Sun selber,
beziehungsweise mittlerweile sind es ja Oracle, sagen, das ist nicht so sinnvoll.
Die stellen euch also Bibliotheken zur Verfügung,
wie das Collection Strambock und so weiter.
Und sie haben einfach Angst,
dass jemand da diese ganzen Prüfungen ausstellen kann und sich dann
später über Fehler wundert,
die die Schuld des Entwicklers sind
Oder derjenige, der dieses Framework benutzt hat. Also die sagen,
wir wollen nicht, dass das ausgeschaltet werden kann.
Deswegen benutzen wir es nicht. Wir sind eher der Meinung,
wir benutzen das für unser eigenes Projekt. Wir werden das
niemals irgendwo als Library zur Verfügung stellen und Angst haben,
dass wir falsch benutzt werden, sondern solange wir das Projekt entwickeln,
sind die Sessions an.
Und möglicherweise, wenn wir es an den Kundenausliefern machen,
machen wir sie wieder aus.
Man kann da so geteilter Meinung sein. Wir sind der Meinung,
es ist sinnvoll, dass wir das hören zu machen.
Gut. Jetzt kommen wir zu der Frage, warum überprüfen wir keine Nachbedingungen?
Ein Problem ist, dass es in Java dieses Old nicht gibt.
Wir könnten jetzt zum Beispiel mal versuchen, eine Nachbedingung zu formulieren,
die aussagt, wenn ich etwas einzahle auf ein Konto,
einen bestimmten Betrag, dann ist anschließend der Kontostand,
um diesen Betrag höher.
Ihr werdet keinen Java-Ausdruck finden, der das aussagt. Das heißt,
ihr könnt das höchstens irgendwie so auf Deutsch sagen oder irgendeine Pseudonotation.
Okay. Und wenn man das nicht formulieren kann,
heißt das nicht unbedingt, dass man es nicht prüfen kann,
aber es wird meistens
sehr umständlich
Okay, dann ist es oft so, dass Überprüfung relativ trivial sind.
Also stellt euch vor, ihr habt folgende Anweisungen in einer Methode.
Ich erzeuge ein neues Exemplar auf der Klasse X und möchte eine Referenz darauf zurückgeben.
Und ich sage als Nachbedingung, hier kommt keine Neureferenz zurück.
Dann ist das eigentlich offensichtlich, dass da keine Neureferenz zurückkommen kann.
Wenn ich also ein neues Objekt erzeuge,
dann kriege ich eine Referenz auf das Objekt.
Er kann niemals nahe. Ein New-Aufruf kann niemals nahe zurückkommen.
Deswegen erscheint es unsinnig, das überprüfen zu wollen. Sonst müsstet ihr erstmal sagen,
meine Variable gleich in New X, Assert Variable ungleich nahe,
Return Variable und schon ist der Quertext dreimal länger.
Kim? Ja, und solche nicht trivialen Abregungen,
wie ich sie gerade als Beispiel gemacht hatte,
wo man dann also mehrere Zeilen pro Nachbedingungen braucht,
da fragt man sich, irgendwann lohnt sich der ganze Aufwand noch.
Kann es nicht irgendwann passieren,
wenn ich für eine Nachbedingung zehn Zeilen Code brauche,
dass ich da auf einmal neue Fehler einbaue in meinen Code,
weil der auf einmal durch die Prüfung der Nachbedingungen
so kompliziert geworden ist
Können. Während zum Beispiel bei den Vorbedingungen, das ist immer eine Zeile.
A Shirt, Bedingungen und dieser Strength. Mehr nicht.
Wir müssen niemals irgendwelche komplizierten Dinge machen, um Vorbedingungen prüfen zu können.
Okay. Und auch noch mal so ein bisschen als Motivation.
Also wir wollen ja Fehler entdecken in unserer Software mit diesem Vertragsmodell,
so früh wie möglich. Und viele Fehler sind nicht,
wie soll ich sagen, innerhalb einer Methode,
dass ich irgendwie hier das Richtige gemacht habe und zwei,
drei später das Falsche und dann ärgere ich mich.
Sondern oft ist es so, es gibt irgendeinen Dienstleister,
da gibt es eine API-Dokumentation, ich lese die mir durch,
vielleicht nicht ganz so aufmerksam, der Tau ist schon lang gewesen.
Und ich verstehe das einfach falsch. Ich verstehe einfach falsch
, was da dokumentiert ist. Ich denke, ich darf
dich und jenes übergeben, darf es aber in echt gar nicht.
Also viele Fehler oder viele interessante oder viele nicht triviale Fehler
sind einfach Missverständnisse von solchen Schnittstellen.
Wenn jetzt also ein Klient die Vorbedingungen falsch versteht,
dann kann dieses Missverständnis sofort aufgedeckt werden dadurch
Dass ich die Vorbildung umprüfe. Das ist bei den Nachbedingungen
nicht so. Die Nachbedingung prüft ja, ob ich als Dienstleister,
das, was ich hier oben implementiert habe, hier unten,
oder beziehungsweise das, was ich hier oben implementiert habe,
prüfe ich hier unten.
Das ist also im selben Methodenrumpf drin. Es ist also
nicht so, dass der Fehler möglicherweise ganz woanders liegt.
Ich könnte mir also diesen Methodenrum ausdrucken,
eine Stunde gemütlich in die Badewanne gehen.
Und wenn dann ein Fehler drin ist, finde ich ihn hoffentlich.
Während den Fehler im Klientencode zu finden, ist manchmal gar nicht möglich.
Wieder gibt es den Klientencode noch gar nicht.
Ihr könnt ja beliebig viele Klienten haben. Manche werden vielleicht
erst nächste Woche geschrieben, manche erst in zwei Jahren.
Ihr könnt diese Sicherheit nicht haben, nur durch Anschauen aus eigenen Codes.
Okay, also wir haben uns lange überlegt, was machen wir jetzt?
Sollen wir irgendwie eine ganz komplizierte Richtlinie rausgeben,
unter welchen Umständen man Nachbedingungen prüft und unter welchen nicht?
Und wir haben uns irgendwann dagegen entschieden und gesagt,
ihr könnt solche komplizierten Sachverhalte noch nicht entscheidend selber.
Also machen wir eine ganz einfache Grundregel.
Wir prüfen die Nachbedingungen nicht. Wir formulieren sie zwar,
aber wir prüfen sie nicht
Sie tauchen also in der Schnittstelle auf als Kommentar. Wir prüfen sie nicht.
Gut. Was es aber ganz nett ist an diesen Nachbedingungen,
diese Nachbedingungen sagen uns ja eigentlich viel über diese Mantik eine Operation.
Was passiert da eigentlich? Warum sollte ich diese Operation aufrufen? Weil ich erwarte,
dass Folgendes passiert, dass ich mit folgendem Ergebnis rechnen kann,
dass ich mit folgendem Nebenwirkungen retteln kann.
Und wenn man sich solche Nachbedingungen anschaut, zum Beispiel dieses Beispiel,
der neue Kontostand ist der alte Korn, stand bloß der eingestrahlte Betrag.
Das klingt ja wie ein Testfall. Das klingt wie ein Testfall,
erzeuge dir ein Konto mit einem bestimmten Betrag,
zahle was ein und prüfe anschließend, ob der Neubetrag auch völlig drauf ist.
Und solche Testfälle habt ihr auch schon geschrieben.
Das heißt also, wir einigen uns auf folgende Konventionen.
Vorbedingungen werden vom Dienstleister überprüft mit der Shirt-Anweisung, und zwar ausnahmslos,
wenn ihr das nicht macht, kriegt ihr den Haken nicht.
Und Nachbedingungen werden nicht überprüft, sondern sie dienen als Inspiration für Testfälle.
Okay. Gut, das ist auch schon die Zusammenfassungshole.
Ich wollte eigentlich noch ein bisschen mehr programmieren. Wir haben ja,
glaube ich, noch ein paar Minuten durch die Pause.
Klar, es geht, ich denke mal, ein paar Minuten habe ich noch.
Ich will das ausnutzen, dass ich auch mal hier stehen darf.
Okay, wir haben also hier eine Vorbedingung formuliert,
die sich ausschließlich auf einen Parameter bezieht.
Ja, das, was du mir übergibst, lieber Klient,
muss folgende Eigenschaften haben. Man kann aber auch Vorbedingungen formulieren,
die sich nicht nur auf Parameter beziehen,
sondern auch zum Beispiel auf den aktuellen Objektzustand.
Würde euch da bei einem Sparkonto, wenn ich etwas abheben will,
eine sinnvolle Vorbedingung einfallen. Also ich habe auf dem Sparkonto
irgendwie 100 Euro drauf und jemand will irgendwie 1000 Euro abheben.
Was haltet ihr davon, ja? Ja, das geht drauf,
lass uns das machen. Es muss genug Geld raus sein,
weil Sparbücher oder Sparkonto darf man normalerweise nicht überziehen.
Wie könnte ich denn formulieren? Das genug Geld drauf sein muss
als eine, ja, als einen bulischen Ausdruck Recryer.
Ja, und jetzt muss irgendein Ausdruck da stehen,
der irgendwas mit dem Betrag, ja.
Das ist eine kleine Frage. Okay, du sagst also,
ich muss mal ganz kurz gucken, Saudo, größer,
gleich Betrag. Und jetzt frage ich sofort ins Publikum,
wer hat aufgepasst während der Vorlesung und sieht,
was das Problem dieses Vertrags ist,
der ja für den Klienten Sinn ergeben soll.
Der Klient guckt sich die Schnittstelle an,
was kann so ein Sparuch, ja?
Jenten haben Salber bekommen. Richtig, der Klient sieht also hier
dieses Unterstrich-Saldo und sucht sich völlig verzweifelt in der Dokumentation.
Wo ist denn dieses Unterstrich-Saldo und findet es nicht?
Wir müssen also stattdessen, wie heißt es bei uns,
gibt Kontostand hier hinschreiben. Okay. Gib Kontostand,
kürzer Gleichbetrag. Und jetzt muss ich diese Überprüfung machen,
dann würde ich wahrscheinlich jetzt das hier runterkopieren, würde irgendwas wieder vergessen.
Das ist irgendwie blöd. Kann man nicht irgendwie dieses Schreiben
des Assorts vereinfachen? Und das kann man tatsächlich.
Wenn ihr irgendwas sucht in den Clips, diese Menüs,
da sind ja umfangreich, machen ja oben solche Schlüsselwörter eingeben.
Und ich will, glaube ich, das hier haben.
Ja, genau, das will ich haben.
Wir zeigen euch eine Übung, wie es geht,
aber ich wollte es euch auch schon mal zeigen.
Ihr könnt also hier so was sagen wie,
ich nenne das Ganze mal pre,
wie Pre-Condition,
Vorbedingungen. So, und jetzt kann ich einen Code pattern hier eingeben,
was immer erzeugt werden soll, wenn ich dieses Pre-Inneclipse eingehe.
Also ich will zum Beispiel sagen, Asshirt,
dann will ich hier irgendeinen Platz heute haben,
dann müssen wir nicht mal Condition.
Dann soll ein Doppelpunkt kommen und dann soll ein Stream kommen.
Vor Bedingungen, verletzt, Doppelpunkt. Und dann soll wieder
diese Condition auftauchen. So. Okay. Okay, okay.
Und wenn ich jetzt dieses Pre hier eingebe und Steuerung
Leertaste mache, steht ja mir dieses Vorbedingung vor,
das will ich haben, habe ich einen Tom.
Und jetzt kann ich das Condition hier eintragen. Also,
gib, und jetzt achtet mal darauf, dass das hier gleichzeitig mitgepflegt wird.
Toll. Gib Kontostand, größer Gleichbetrag. Zack. Okay.
So. Okay, ich glaube, meine Zeit ist schon um,
das ist schade. Ich hatte noch ganz viel vorbereitet.
Ich wollte mit euch noch weiter Coppodore 80,
32 programmieren und grün und schwarz. Aber gut,
dann lege ich einmal die Zusammenfassungsfolie auf und bedanke mich bei
euch für eurer Auflösung