Einen schönen guten Morgen.
Herzlich willkommen zur Vorlesung Softwaretechnik 1.
Ich wollte gerne darauf verzichten, aber ich muss jetzt doch noch mal
die Keule rausholen.
Bitte gewöhnen Sie sich an, pünktlich da zu sein.
Wir haben es jetzt 9.46 Uhr, wir sind schon eine Minute drüber, wir
haben heute viel vor.
Es wäre einfach schön, wenn wir uns darauf einigen könnten, dass die
Vorlesung anfängt, wenn sie anfängt.
Und das ist nun mal 9.45 Uhr.
Gut.
Zur Entschädigung für diese unfreundliche Ansprache gibt es jetzt was
Schönes.
Nämlich ein kleines Quiz, das werden wir ab und zu mal zu Beginn
machen.
Und zwar gibt es so eine Sammlung von sogenannten Java-Puzzlers, die
tatsächlich aus echten Problemen herauskommen, wo mal jemand ein
Problem mit Java gehabt hat, irgendeinen komischen Fehler, der
aufgetreten ist, und dann hat das jemand zu einem kleinen Quiz
zusammenkondensiert, in dem man den Fehler gut sieht.
Und dann, naja, im Grunde so ein bisschen eine Besprechung drüber
gemacht, was denn jetzt hier eigentlich das Problem ist.
Und das möchten wir mit Ihnen ganz gerne machen.
Zum einen, damit Sie ein bisschen wach werden, ein bisschen mitdenken,
und zum anderen, damit Sie so die kleinen Feinheiten von Java und von
Programmieren im Allgemeinen lernen, sehen, wie auch immer.
Und heute fangen wir mit was ganz Einfachen an.
Der Puzzler hat den schönen Namen Diddl-Dumm.
Warum, weiß ich immer noch nicht, aber er hat ihn.
Sag mal, ist das angeschlossen?
Jetzt geht's.
Wunderbar.
Normalerweise...
Ja, gehen wir heute schon mal von dem Schirm weg.
Normalerweise sehen Sie auf der ersten Folie immer ein Stück Code und
dürfen sich überlegen, was ist denn hier eigentlich gerade kaputt.
Heute fangen wir mal andersrum an.
Sie dürfen sich ein Stück Code überlegen, der etwas kaputt macht.
Und zwar das, was da steht.
Die zwei Zuweisungen x plus gleich i und x ist gleich x plus i.
Ich weiß nicht, wie es Ihnen geht, aber ich habe lange Zeit gedacht,
das ist das Gleiche.
Als ich angefangen habe zu programmieren, wird einem auch häufiger so
gesagt, wenn man auf Stack Overflow unterwegs ist oder sonstigen
einschlägigen Seiten, die gerne auch mal Quatsch verbreiten.
Der denkt vielleicht, naja, das ist doch das Gleiche.
Ich mache da oben ja nur die Kurzschreibweise.
Das erste ist ja nur die Kurzschreibweise von dem zweiten.
Ist aber nicht ganz wahr.
Und Sie dürfen sich jetzt mal überlegen, wo das kaputt gehen könnte.
Und vielleicht hat ja der eine oder andere eine Idee.
Ich gebe Ihnen mal, sagen wir mal, eine Minute Zeit, mal darüber
nachzudenken, was denn da kaputt gehen könnte.
Warum ist das nicht ganz das Gleiche?
Vielleicht weiß es ja jemand.
Das ist übrigens der einzige Moment in der Vorlesung, wo Sie auch mal
mit dem Nachbarn quatschen dürfen.
Offiziell, genau.
So, guten Morgen die Herren da oben in der linken Ecke.
Ich habe gerade eben schon eine Ansprache gehalten zum Thema
Pünktlichkeit.
Das betrifft dann auch Sie.
Wir fangen gerade an, uns über ein Problem in Java Gedanken zu machen
und es wäre schön, wenn Sie da auch noch mitmachen würden und in
Zukunft einfach pünktlich kommen würden.
Das erleichtert uns allen die Arbeit.
So, ich glaube, die Minute ist dann auch so langsam mal rum.
Hat jemand eine Idee, was da kaputt gehen könnte?
Warum das nicht ganz das Gleiche ist?
Keiner eine Idee?
Ruhig mal trauen.
Hier vorne.
Ah, da ist einer.
Ja, bitte.
Ich muss mich gerade mal überlegen, was Ihr Kommilitonen überhaupt
gesagt hat.
Ich muss das gerade mal in meinem Kopf sortieren, das liegt nicht an
Ihnen.
Sie haben, glaube ich, gesagt, bitte korrigieren Sie mich, dass bei
der ersten Variante das I erhöht wird und dann zugewiesen.
X wird erhöht und dann zugewiesen.
Das geht in die richtige Richtung tatsächlich.
Das trifft es noch nicht ganz genau.
Es gibt tatsächlich ein konkretes Problem.
Ja, Sie in dem karierten Hemd.
Ah, der Kommilitone sagt das richtige Stichwort.
Es wird irgendwie was komisch gecastet.
Das ist genau das Problem.
Kann sich jemand vorstellen, was da genau passiert?
Da ist noch eine Wortmeldung.
Ja.
Wunderbar, danke.
Das ist die Lösung und deshalb wiederhole ich auch Ihre Antwort nicht,
sondern zeige es jetzt einfach auf den Folien.
Also, nochmal zur Rekapitulation.
Viele denken, das ist das Gleiche.
Ist es aber nicht.
Und jetzt müssen wir uns mal überlegen, was denn da tatsächlich
passiert.
Der zweite Ausdruck ist einfach eine einfache Zuweisung.
So, wie wir das kennen.
Der erste Ausdruck hingegen ist eine zusammengesetzte Zuweisung.
Mit einem Operator dazu.
Und was jetzt Java intern macht, ist tatsächlich genau das, was Ihr
Kommilitone in dem schönen karierten Hemd gesagt hat.
Da gibt es irgendeinen komischen Cast.
Und das Problem, was dabei auftritt, ist genau das, was dann wiederum
der nächste Kommilitone gesagt hat.
Wenn wir da jetzt unterschiedliche Datentypen haben, da können wir in
Probleme kommen.
Was nämlich passiert, wenn ich zum Beispiel sage, dass mein x ein
Short ist und mein i ein Int, dann habe ich an dieser Stelle, wenn ich
diesen Zuweisungsoperator verwende, einen versteckten Cast.
Was dann nämlich eigentlich passiert ist, dass ich rechne x plus i und
davor schreibe ich noch ein Cast und zwar auf den Typ von x und der
ist Short.
Und dann habe ich an der Stelle natürlich das Ganze kaputt gemacht.
Da kommt nicht mehr das raus, was ich haben will.
Und wenn ich jetzt dieses Programm schreibe und die normale Zuweisung
benutze, dann sehe ich auch, dass das Ganze gar nicht mehr übersetzt,
weil ich hier den Hinweis bekomme vom Compiler, naja, x plus i kann
ich nicht rechnen, weil da muss ich von Int zu Short konvertieren.
Das heißt, an der Stelle würde man es merken, wenn man nicht die
Kurzform verwendet, sondern die Langform.
Gut.
Da gibt es eine Wortmeldung.
Wenn x gleich Null ist, gut, das haben wir jetzt in dem Fall natürlich
fairlich möglich.
Das Problem habe ich ja dann grundsätzlich, oder?
Ich meine, dann habe ich halt Null-Pointe.
Oder worauf wollen Sie hinaus?
Warum würde es bei dem einen gehen und beim anderen nicht?
Also, Ihre Kommilitone sagt, wenn ich x als Objekt hätte und das Null
wäre, dann funktioniert das auch nicht.
Funktioniert in beiden Fällen doch damit.
Oder wie sehe ich gerade aus?
Also Null plus i ist auch ein Null-Pointer.
Ja, also Null plus i ist genauso blöd.
Mal abgesehen davon, dass ich das ja dann erstmal definieren müsste
für meinen...
Genau, man müsste auch diesen Plus-Gleich-Operator erstmal überhaupt
definieren für das Objekt, was man da hat.
Genau.
Was ist jetzt die Moral von dem Ganzen?
Man sollte vorsichtig sein mit diesen Abkürzungen.
Also wenn man die benutzt, dann sollte man die wirklich nur dann
benutzen, wenn man sich sicher ist, was sie denn da eigentlich tun.
Insbesondere wenn man natürlich solche Datentypen wie Byte, Short und
Character benutzt.
Dann kann es halt schnell mal passieren, dass man da in irgendwelche
Fallen läuft.
Also da bitte aufpassen.
Das gleiche gilt natürlich, wenn man Int benutzt und plötzlich Long
dazu addieren möchte.
Auch da kommt natürlich das gleiche Problem.
Das heißt, wenn Sie solche Abkürzungen benutzen, seien Sie gewahr, was
da passiert.
Nicht einfach denken, das ist das gleiche wie die normale Zuweisung.
Denn das stimmt einfach nicht.
Gut.
Wunderbar.
Das war die Lehre zum Morgen.
Jetzt geht es an der Stelle weiter, an der wir am Montag aufgehört
haben.
Wir rekapitulieren nochmal ganz kurz.
Wir wollten Sie so ein bisschen motivieren, Werkzeuge zu benutzen für
Softwareentwicklung.
Und dafür haben wir Ihnen so ein bisschen gezeigt, was denn alles
schieflaufen kann in einem kleinen, szenischen Stück.
Und dann haben wir begonnen, über Versionsverwaltung zu sprechen.
Und wir waren ungefähr bis dahin gekommen, ein bisschen weiter, aber
ich fange jetzt hier nochmal an, damit der Einstieg leichter ist.
Wir hatten darüber gesprochen, wie man denn jetzt eigentlich mit so
einem entfernten Depot arbeiten kann, indem man Versionen ablegt und
gesagt, naja, man kann ein Checkout machen und sich die Version holen.
Stellen Sie sich das ungefähr so vor, wie Sie gehen in die Bibliothek
und holen sich halt das Buch von Balzert, weil Sie der Meinung sind,
das müsste mal überarbeitet werden.
Das heißt, Kollege Hai geht in die Bibliothek und sagt, hier, ich
möchte das jetzt gerne holen, möchte das überarbeiten.
Dann bekommt er da die Kopie von der Bibliothek und dann darf er das
bearbeiten, ändert Kapitel 3, Überschrift 1, gibt es zurück und dann
ist es wieder bei ihm, dann ändert er es und dann gibt er es wieder
zurück und dann ist es wieder im Depot.
Während er die Kopie von dem Balzert hat, darf kein anderer etwas tun
daran.
Also die Bibliothek merkt sich dann, okay, der Herr Hai, der war der
Erste, der sich das ausgeliehen hat, alle anderen dürfen sich das
jetzt auch immer noch ausleihen, aber nur angucken, nicht schreiben.
So funktioniert das normalerweise, wenn man mit einem entfernten Depot
arbeitet.
Das heißt, alle, die dann irgendwie was ändern wollen, die müssen
warten, bis mein Kollege das wieder in der Bibliothek abgelegt hat und
das kann dauern.
Und genau deshalb, und darüber hatten wir auch schon gesprochen, gibt
es eine Alternative zu dieser strikten Variante.
Es gibt auch die Variante, man kann das optimistisch machen, wenn er
sich jetzt ein Buch ausleiht und nur in Kapitel 3 die Überschrift
ändern will, wie wahrscheinlich ist es denn, dass, wenn ich mir das
gleiche Buch ausleihe, an derselben Stelle auch was ändern möchte.
Eigentlich relativ gering.
Ich möchte vielleicht Kapitel 4 Überschrift ändern.
Und deshalb gibt es auch das optimistische Ausbuchen, da dürfen dann
alle, die sich das Buch ausleihen, Änderungen tatsächlich machen und
dann wieder in das entfernte Depot wieder einchecken.
Das heißt, in die Bibliothek zurückgeben und die Bibliothek kümmert
sich dann darum, dass eben beide Änderungen oder alle fünf Änderungen,
wenn sie zu fünft dran arbeiten, alle in das Buch reinkommen.
Wenn man allerdings es doch schafft, an der gleichen Stelle was zu
ändern, dann muss man sich natürlich überlegen, was man in solchen
Fällen macht.
Wir hatten auch dazu gesprochen, wir hatten ja ein Beispiel, ein
Miniprogramm, unser Hello World Programm, was wir ja auch schon im
Schauspiel hatten mit dem Hello World.
Und wir hatten gesagt, naja, wir wollen vielleicht nicht nur die Uni
grüßen, weil die gibt es irgendwie schon länger nicht mehr, wir wollen
jetzt das KIT grüßen.
Und Kollege Haik, ganz pragmatisch, hat einfach aus dem Uni fit
gemacht, so ist er halt, da geht es ganz schnell und dann ist man
fertig.
Und ich habe aber gedacht, naja, wer weiß, so Kompatibilität,
vielleicht brauchen wir doch nochmal die Uni, wer weiß, vielleicht
kommt die mal wieder.
Und deshalb habe ich einfach eine neue Methode geschrieben.
Und jetzt kommen wir hier zu Problemen.
Wir haben jetzt zwei unterschiedliche Varianten für die gleiche Lösung
und die überschneiden sich teilweise.
Hier sehen wir natürlich diese Änderung, die es bei mir nicht gibt,
bei Tobias aber vielleicht schon.
Das heißt, wir müssen uns dann hier selber entscheiden, welche Version
wollen wir denn haben.
Hier unten ist es einfach, die Methode kann man einfach hinzufügen,
deshalb ist es auch die grünen dargestellt, die kann man einfach
problemlos hier unten dran anfügen.
Hier oben haben wir wieder das Problem, dass ich halt gesagt habe,
naja, ich möchte New Hello aufrufen, weil das ist ja was Neues, was
ich implementiert habe.
Und bei Tobias sieht es halt so aus, dass immer noch die alte Methode
aufgerufen wird.
Und da sehen wir auch schon, man muss da selber ein bisschen drüber
nachdenken, was man denn da jetzt eigentlich semantisch haben will.
Also ich kann natürlich jetzt mich auf den Standpunkt stellen, na gut,
dann behalten wir halt hier meine Variante mit dem Get Uni, aber rufen
das Hello Kit auf von Tobias und das hier unten können wir eh
hinzufügen.
Ja, das wäre eine mögliche Lösung tatsächlich dafür, die man machen
könnte.
Relativ problemlos.
Aber dann haben wir das Problem, dass wir dann zweimal das gleiche
machen.
Also dann haben wir hier das Get Hello mit dem Kit und hier unten das
Get New Hello macht dann auch das gleiche.
Und das ist genau der Grund, warum der Merchant-Kunde nicht
automatisch funktioniert, sondern warum sie sich dann Gedanken drüber
macht.
Genau, das ist glaube ich ungefähr die Stelle, an der wir stehen
geblieben waren und da machen wir jetzt weiter.
Was kann denn da überhaupt alles so rein in so eine Konfiguration, die
wir als Version speichern wollen für unsere Software?
Naja, offensichtlich der Programmtext, möglicherweise verwendete
Bibliotheken, Initialisierungsdaten, natürlich Dokumentation,
vielleicht Konfigurationsdaten.
Das ist alles, was sie irgendwie selber schreiben oder benutzen.
Aber man kann auch sagen, man kann sich auf den Standpunkt stellen,
naja, abgeleitete Elemente möchte man auch haben.
Man möchte vielleicht auch das Kompilat haben, damit man weiß, okay,
das war zu dem Zeitpunkt so lauffähig.
Genauso kann man sich auf den Standpunkt stellen, naja, ich möchte
vielleicht das Werkzeug haben, was ich benutzt habe, zum Übersetzen
zum Beispiel.
Vielleicht brauche ich den Compiler, damit ich sicherstellen kann,
wenn ich den Programmtext in der Version nochmal benutzen möchte, dann
weiß ich, mit dem Compiler ging es auf jeden Fall.
Und das ist tatsächlich etwas, was kritisch sein kann.
Stellen Sie sich vor, Sie haben in den 60er Jahren in der Bank
gearbeitet und haben diese neue fancy Programmiersprache COBOL
ausprobiert.
Dann wäre es schon geschickt gewesen, wenn Sie eine Version eingelegt
hätten mit dem damals verwendeten COBOL-Compiler dazu, weil jetzt
irgendwie 50 Jahre später muss das wieder jemand rauskramen und muss
da vielleicht einen Fehler fixen, den er jetzt erst gefunden hat.
Und wer das jetzt für unrealistisch hält, dem kann ich gleich aus
seinen Träumen reißen, sowas kommt tatsächlich vor.
Also kann gut passieren, dass Leute heute Code aus den 60er Jahren
anfassen müssen in Programmiersprachen, die sie vielleicht nie gelernt
haben.
Und Leute, die das können, die werden dann auch entsprechend gut
bezahlt.
Das heißt, das sind echte Probleme, die es gibt.
Das heißt, denken Sie immer vielleicht auch so ein bisschen an den,
der später mal an Ihren Code ran muss.
Gut.
Was haben wir hier noch?
Was möchte man vielleicht auch noch bedenken?
Naja, man möchte vielleicht diese Konfiguration auch so ein bisschen
an den Entwicklungsprozess angleichen.
Das heißt, wenn ich so gewisse Entwicklungsphasen habe, damit werden
wir uns in der Vorlesung noch beschäftigen, Anforderungsanalyse,
Entwurf, dann möchte ich vielleicht genau für diese Zwischenschritte
jeweils eine Version erstellen.
Damit kann ich dann eben besser die Änderungen über die einzelnen
Phasen zurückholen.
So.
Jetzt müssen wir uns mal überlegen, wie wir das denn jetzt eigentlich
machen wollen mit diesen Versionen.
Wie wollen wir die denn eigentlich abspeichern?
Ich glaube, jedem dürfte klar sein, dass es eine blöde Idee ist, wenn
wir immer die komplette Version abspeichern.
Das ist so das, was man macht, wenn man keine Ahnung hat.
Dann legt man sich auf dem Desktop nochmal einen Ordner an und da
steht dann Programm XY-Neu.
Das machen wir nochmal.
Wenn man irgendwas ändert, Programm XY-Neu 2.
Jeder schon gesehen.
Und dann kopiere ich das halt darüber und mache dann meine Änderung.
Ist aber blöd, weil dann verschwende ich einen Haufen Platz.
Das heißt, das will ich nicht haben.
Ich will mir eigentlich nur die Änderung speichern.
Das heißt, wenn wir bei dem Buch-Beispiel bleiben, dann ist das
ungefähr so, als würde ich in das Buch einfach mal so einen gelben
Klebezettel reinschreiben.
Ändere doch bitte mal die Überschrift in Kapitel 3 auf was auch immer.
Das sind die Deltas und die sind sinnvoll, weil man feststellen kann,
dass so Änderungen an Softwaren normalerweise nur ein bis zwei
Prozent, und das halte ich schon für hochgegriffen, des Umfangs der
Vollversion haben.
Die Änderungen sind normalerweise relativ klein.
Und deshalb speichern wir uns einfach so einen Änderungsskript.
In dem steht im Wesentlichen genau das drin, was ich gerade erklärt
habe.
Nimm Überschrift 1, Kapitel 3 und ändere die von XY in Z.
So sieht so ein Delta aus.
Und die einfache, intuitive Variante ist natürlich so ein Vorwärts
-Delta.
Ich fange an, habe eine Grundversion und merke mir jetzt alle
Änderungen in diesen Deltas.
Und so kann ich dann die aktuelle Version, zum Beispiel 2.0, einfach
ausrechnen, indem ich alle Änderungsskripte aufeinanderrechne.
Dann bin ich fertig.
Wer hält das für eine blöde Idee?
Ein paar Leute.
Leute ganz hinten, die gefragt haben, warum ist das eine blöde Idee.
Sie haben sich relativ schnell gemeldet.
Also ich habe es nicht nur so halb verstanden, aber ich rekonstruiere
das mal.
Sie haben, glaube ich, gesagt, die Änderungen können sehr groß werden,
es können sehr viele sein, es können sehr viele Deltas geben.
Und dann jedes Mal, wenn ich die aktuelle Version haben will, erst mal
von der Grundversion wieder auszurechnen, was denn jetzt eigentlich
gerade das Aktuelle ist.
Das ist irgendwie blöd.
Vielleicht Rechenaufwendig, vielleicht Zeitaufwendig, wie auch immer.
Das heißt, man möchte eigentlich die aktuelle Version haben.
Und dann, wenn man was anderes braucht, gegebenenfalls zurückrechnen.
Das ist nur für den Ausdruck.
Und das ist genau der Punkt.
Die Vorwärts-Deltas haben eben genau den Vorteil, dass ich zwar auf
die erste Version gut komme, aber auf die späteren Versionen eher
nicht so gut.
Und, naja, der Punkt ist genau richtig.
Die aktuelle Version ist halt das, was ich normalerweise brauche, wenn
ich irgendwie weiterarbeiten will.
Und deshalb gibt es analog die Rückwärts-Deltas.
Ich glaube, das ist intuitiv, wie das funktioniert.
Genauso bloß rückwärts.
Da kann ich halt von meiner aktuellen Version 2.0 mir gegebenenfalls
die alten Versionen ausrechnen.
Genau.
So kann das funktionieren.
So funktionieren eigentlich fast alle Versions-Kontrollsysteme in der
einen oder anderen Weise.
Und jetzt schauen wir uns mal an, welche es denn da eigentlich so
gibt.
Und da Sie alle so schön wach gewesen sind, will ich dafür sorgen,
dass Sie wach bleiben und Ihnen eine kleine Chats-Frage stellen.
Und ich bitte jetzt explizit die Leute, die letztes Jahr schon in der
Vorlesung waren, da mal einfach mal nichts zu zu sagen, weil die
wissen es gegebenenfalls schon oder haben es wieder vergessen.
Es geht darum, wer hat denn eigentlich das erste Versions
-Kontrollsystem entwickelt.
Das hieß Revision-Control-System, also eingängig, so wie das, was es
auch tut.
Jetzt muss ich mir überlegen, wer könnte das gewesen sein.
Wir haben Kandidat A, Bill Gates, der hat es vielleicht erfunden, weil
er naja, während er Microsoft hochgezogen hat, sich ein paar Versionen
merken wollte.
Ist auch irgendwie naheliegend.
Ich meine, jeder kennt Windows 3.0, Windows 3.1.
Das klingt schon sehr nach Version.
Vielleicht ist es das.
Oder war es doch eher Larry Page?
Das wäre dann ein bisschen später.
Also Sie müssen auch so ein bisschen sich jetzt zeitlich orientieren.
Übrigens, ich habe das dieses Jahr in Klammern dahinter geschrieben,
weil letztes Jahr tatsächlich Leute dabei waren, die einzelne Personen
hier nicht kannten.
Deshalb bin ich dieses Jahr auch nochmal sicher gegangen.
Also Larry Page, einer der Google-Gründer.
Vielleicht wäre es auch da sinnvoll gewesen, irgendwie eine Version zu
haben, während man sich da über einen sinnvollen Suchalgorithmus
Gedanken macht.
Oder war es doch Tim Berners-Lee, einer der Begründer des Internets.
Ohne den könnten Sie heutzutage nicht den ganzen Tag mit Surfen auf
Ihrem Smartphone verbringen.
Vielleicht war es auch der.
Oder war es Kandidat B, der Herr Tichy?
Jetzt eine Frage, wer von Ihnen weiß...
Da müsste jetzt in Klammern stehen, übrigens Ihr Prof, der ihn noch
nicht gesehen hat.
Hätte ich Sie auch noch fragen können, ob Sie wissen, wer das ist.
Ja, ja, genau.
Erste Frage, wer weiß nicht, wer die vierte Person ist?
In den letzten Reihen trauen Sie sich dann doch mal so einen Arm
zumindest mal kurz zu heben.
Gut, jetzt die Schätzfrage, wer glaubt denn, dass es Bill Gates war?
Einer, zwei, ein paar, drei, vier.
Ja, es sind schon so sieben, acht Leute gewesen.
Okay, zweiter Versuch, Larry Page.
Ja, er ist schon ein schlauer Junge.
Vielleicht war es der.
Auch noch zwei, drei.
Okay, Tim Berners-Lee.
Mein Liebling, der Außenseiter auf der Folie.
Den kennen die wenigsten.
Vielleicht war es der.
20, vielleicht 25.
Und wer meint, dass es ihr Prof war, weil der meint, das wusste er
mal.
Wir sollten irgendwie diese Frage anders stellen.
Letztes Jahr hat das besser funktioniert.
Suggestivfrage.
Letztes Jahr meinten alle Larry Page.
Aber da kannten Sie den noch nicht.
Ja, vielleicht war es der.
Gut, also die meisten haben sich jetzt tatsächlich bei Professor Tichy
gemeldet.
Und das ist tatsächlich auch die richtige Antwort.
Das heißt, Professor Tichy ist derjenige, der sich das erste
Versionskontrollsystem überlegt hat.
Und das stelle ich Ihnen jetzt mal ganz kurz vor.
Weil darauf hat sich tatsächlich einiges aufgebaut.
Das Revisionskontrollsystem von 1983 macht im Grunde genau das, was
wir gerade besprochen haben.
Man kann Dateien aufbewahren.
Man kann Dateien wiederherstellen.
Man kann Logbuch führen über die Änderungen.
Man kann Software-Elemente identifizieren über Identifikatoren
offensichtlich.
Und man kann Versionen verschmelzen.
Also auch dieses Merging, das funktioniert.
Hatte aber, und das ist vielleicht auch der Zeit geschuldet, so ein
paar kleine Probleme noch.
1983 war es erstmal noch nicht netzwerkfähig.
Okay, da hat man damals einfach noch nicht so ein Problem mitgehabt.
Da hat man das halt für sich selber gemacht im Keller.
Hat man für sich selber die Versionen weiterentwickelt.
Und man konnte keine Verzeichnisse unterstützen.
Aber ansonsten, alles, was wir bisher gesehen haben in den
Versionsverwaltungen, ging da auch schon.
1983, wie gesagt, und darauf aufgesetzt CVS.
Kennt jemand CVS vielleicht?
Ja, ein, zwei Leute melden sich tatsächlich schon mal mit CVS
gearbeitet.
Oder nur vom Namen her.
Wer hat schon mal damit gearbeitet?
Ah, tatsächlich.
Sehr schön.
CVS benutzt tatsächlich intern RCS.
Und grundsätzlich gilt auch, es wird tatsächlich noch RCS eingesetzt.
1983, nicht netzwerkfähig und kann keine Verzeichnisse versionieren.
Wird aber trotzdem nur noch eingesetzt.
Also, das ist nicht jetzt irgendwie aus der Luft gegriffen.
Die können das sogar heutzutage noch in den meisten Linux
-Distributionen noch runterladen.
Also, das ist kein Problem.
Können sie noch benutzen, wenn sie das möchten.
Wenn sie mal einen echten Fichie-Code ranwollen.
Da können sie sich RCS runterladen.
Ist auch Quell-offen, also da kann man nochmal reinschauen, wie es
funktioniert.
Wie gesagt, CVS benutzt intern RCS und fügt im Wesentlichen
Netzwerkfähigkeit und die Verzeichnisräume hinzu, dass man die auch
versionieren kann.
Das ist aber auch schon alles.
Dann der nächste große Schritt ist dann SVN.
Und wenn ich jetzt frage, wer hat das schon mal verwendet, dann sehe
ich hoffentlich ein paar mehr Hände.
Wer hat schon mal SVN verwendet?
Und ein paar mehr.
Sehr schön.
Naja, offensichtlich braucht man irgendwann mal was, was internetfähig
ist.
Und was außerdem noch so ein paar andere Randfälle mit abdeckt.
Wenn ich bei CVS nämlich eine Datei umbenannt habe, dann war die
komplette Historie weg.
Also ich hatte Datei A, mach 100 Änderungen, nenne die um in Datei B,
dann ist plötzlich die ganze Historie weg.
Das ist irgendwie blöd.
Nur weil ich sie umbenannt habe.
Das geht jetzt in SVN.
Man kann über das Internet arbeiten.
Man kann außerdem optimistisches Ausbuchen machen.
Man kann beim Einbuchen sicherstellen, dass die Änderungen atomar
übertragen werden.
Bei CVS war es so, sie machen fünf Änderungen an fünf Dateien, buchen
das wieder in das entfernte Depot ein.
Vier davon gehen ohne Probleme durch.
Und beim fünften sagt dann plötzlich das Remote Depot, ja blöd, da hat
jetzt jemand anders was dran geändert.
Und schon haben sie einen konsistenten Zustand.
Das ist einfach blöd.
SVN stellt sicher, dass das nicht passiert.
Da wird dann die komplette Einbuchung abgelehnt.
Genau, optimistisches Ausbuchen hatte ich schon gesagt.
Nichtsdestotrotz ist das irgendwie noch nicht so ganz das Ende der
Fahnenstange.
Sonst würden wir das vielleicht auch in der Vorlesung einsetzen.
Sie haben ja schon gesehen, dass wir das nicht tun.
All das, was Sie jetzt gesehen haben, RCS, CVS, SVN, das ist irgendwie
so eine lineare Kette von Weiterentwicklung von derselben Idee.
Nicht im Wesentlichen das, was ich Ihnen davor über Versionsverwaltung
so ein bisschen gezeigt habe.
Und dann hat man irgendwie mal so gedacht, ist ja alles gut und schön,
aber irgendwie ist es noch nicht so richtig, was man wirklich haben
will.
Und weil man keine Ahnung davon hatte, wie man das jetzt richtig
macht, hat man gesagt, na gut, dann machen wir es doch einfach mal
anders.
Und hoffen, dass es richtig ist.
Und was dabei rausgekommen ist, ist Git.
Und Git werde ich Ihnen jetzt ein bisschen ausführlicher erklären.
Es liegt daran, dass wir das auch in der Vorlesung einsetzen.
So, was ist jetzt Git?
Das Wichtigste an Git ist, Git denkt nicht mehr über Dateien nach.
Bisher war es ja immer so, wir haben gesagt, okay, wir haben irgendwie
Dateien, wir machen da Änderungen dran, wir buchen das ein.
Wir sagen, okay, wir ändern hier eine Teile XY folgendes und dann wird
das wieder eingebucht.
Kann man machen, aber man kann es auch mal anders sehen.
Man kann nämlich sagen, okay, alles ist erstmal ein Objekt.
Ob das jetzt Dateiinhalte, Verzeichnisse, Konfigurationen, was auch
immer sind, Varianten.
Völlig egal.
Alles ist ein Objekt.
So denkt Git.
Wir werden nachher sehen, wie das funktioniert.
Außerdem kann Git wunderbar mit Varianten umgehen.
Wer sich noch an die letzte Vorlesung erinnert, da haben wir über
Versionsnummern gesprochen, wie man das SimCode anlegt.
Und da haben wir auch darüber gesprochen, dass es ja Varianten geben
kann.
Wie wir die benennen, haben wir hauptsächlich darüber gesprochen.
Aber Varianten, wer schon mal selber was entwickelt hat, wer auch mal
mit anderen Leuten entwickelt hat, der weiß, dass Variantenbildung
ziemlich wichtig und ziemlich integral eigentlich ist.
Und alle anderen Versionsverwaltungssysteme haben das immer sehr
stiefmütterlich behandelt.
In SVN ist es zum Beispiel so, da gibt es dann einfach gewisse
Ordnerstrukturen, die man benutzt per Konvention, um sicherzustellen,
dass da irgendwie Varianten drin liegen.
Das ist aber irgendwie blöd, weil da müssen sich alle dran halten.
In Git wird das sichergestellt, dass man immer irgendwie
Variantenbildung macht.
Wie das genau passiert, sehen wir gleich.
Außerdem wird die Historie kryptographisch gesichert.
Wer da so ein bisschen paranoid veranlagt ist, für den ist das super.
Ansonsten ist das auch super, weil, worüber wir uns noch keine
Gedanken gemacht haben, ist, was ist denn eigentlich, wenn ich so eine
Änderung, die ich irgendwann mal gemacht habe, in so einem Delta
später nochmal anfasse, weil Ausbewussthaftigkeit oder weil ich
verschleiern will, dass ich da einen Fehler gemacht habe, vielleicht
möchte ich den nochmal ändern.
Ist das wirklich eine gute Idee, weil damit mache ich ja irgendwie so
die Historie kaputt.
Und das stellt Git sicher, dass das nicht passieren kann.
Die sehen wir dann auch später.
Und was auch noch super ist, bei Git ist das gesamte Depot erstmal für
jeden Benutzer lokal.
Das heißt, wir verabschieden uns so ein bisschen von der Idee von
diesem entfernten Depot, was super ist.
Weil ich komme aus einer Zeit, da gab es im ICE kein Internet.
Und wenn ich dann im Zug gearbeitet habe, dann wollte ich nicht
warten, bis ich irgendwo ankomme, bevor ich meine ganzen Sachen ins
Depot einbuchen kann, sondern ich wollte das auch zwischendrin schon
machen.
Und das kann eben Git.
Das heißt, man kann erstmal selber lokal sich ausproben, hat da selber
ein Depot, auf dem man arbeiten kann.
Und wenn man noch ein entferntes benutzen möchte, dann geht das auch.
Dafür braucht man Push, Pull und Fetch.
Da werden wir ein bisschen schneller drüber gehen, weil Sie brauchen
das in der Übung nicht, aber ich werde Ihnen trotzdem mal zeigen, wie
das funktioniert.
Was man außerdem wunderbar noch über diese Variantenbildung machen
kann, man kann wunderbar Arbeitsprozesse oder Befehlshierarchien
abbilden.
Man kann zum Beispiel sagen, Sie erinnern sich, bei den Varianten hat
man gesagt, es gibt eine Hauptvariante, einen Hauptzweig, auf dem wir
arbeiten.
Und dann kann man sagen, da dürfen nur befugte Personen, zum Beispiel
ich als Chef, der Hai hier als kleines Licht, darf da nicht was drauf
einbuchen, sondern ich muss entscheiden, wenn er was einbucht in einer
anderen Variante, kann ich mich dann entscheiden, möchte ich das auch
im Hauptzweig haben oder nicht.
Sowas kann man auch machen, werden wir uns aber auch nur mal kurz
anschauen.
So, wie funktioniert jetzt Git, wenn Sie damit arbeiten wollen?
Angenommen, wir haben es schon mal in GiptyPro, wie wir eins anlegen,
sehen wir auch gleich, aber angenommen, wir hätten schon mal so eins
lokal.
Wenn ich da Dateien drin liegen habe, zum Beispiel das, was Sie hier
in der Übung bei uns programmieren dürfen, dann ist das Git erstmal
völlig egal.
Lassen Sie die Dateien doch da rumliegen, interessieren mich nicht.
Sie müssen erst explizit sagen, dass Git sich doch bitte um die
Versionierung dieser Dateien kümmern soll.
Und das machen Sie mit diesem git add-Befehl.
Damit können Sie sagen, Datei X, Datei Y, Datei Z, bitte unter
Versionskontrolle stellen.
Und wenn Sie das gemacht haben, dann können Sie über einen sogenannten
commit, das ist das Einbuchen, können Sie sagen, okay, das ist jetzt
eine fertige Änderung, die ich habe, da habe ich jetzt Fehler XY
geändert und dann liegt es hier fertig in Ihrem lokalen Depot.
Und Sie sagen, okay, das ist jetzt Version 1.1 oder was auch immer.
Von dort aus können Sie dann aber auch noch in ein entferntes Depot
tatsächlich kommen und das machen Sie mit einem push-Befehl, das
heißt, damit kommen Sie dann tatsächlich in das entfernte Depot.
Das gibt es auch noch bei Git, aber wie gesagt, eigentlich bis hierher
ist die eigentliche Denkweise von Git mit Ihrem lokalen Depot.
Wenn Sie wiederum Änderungen von einem entfernten Depot holen wollen,
dann können Sie das machen mit diesem git fetch-Befehl.
Dann bekommen Sie alle Änderungen, die jemand anders vielleicht
gemacht hat und eingebucht hat, bekommen Sie dann bei sich lokal,
können da reinschauen und dann können Sie sich überlegen, möchte ich
die haben mit einem Merge, dann kann ich die in meine Änderungen oder
meine Version einfliegen.
Das Checkout macht schauen wir uns dann gleich auf der überwiegenden
Folie an.
Gibt es soweit Fragen?
Alles klar.
Vielleicht jetzt nochmal von mir die Frage, wer hat denn schon mal mit
Git gearbeitet?
Jetzt mal unabhängig vom Übungsbetrieb hier, sondern davor vielleicht
schon mal oder privat, weil er Lust hat daran.
Knappes Drittel, würde ich mal schätzen.
Danke.
Das heißt für Sie ist das jetzt alles irgendwie nichts Neues, ich
mache trotzdem mal weiter.
Was gibt es für Befehle für Git, die für Sie wichtig sind?
Naja, so ein Hilfebefehl ist klar.
Git init ist genau das, was Sie in einem Depot anlegt.
Das heißt, Sie haben einfach irgendeinen Ort in Ihrem Dateisystem und
an dem sagen Sie, okay, jetzt machen wir hier bitte ein Git-Depot auf.
Sie können aber auch eins bekommen, indem Sie ein Depot holen von
einem entfernten Server.
Das machen Sie über den Git-Clone-Befehl und das Schöne bei Git ist,
Sie bekommen nicht nur die aktuelle Variante, so wäre das bei SVN
gewesen, sondern Sie bekommen die komplette Historie mit und das liegt
einfach an der Denkweise von Git.
Diese verteilte Denkweise, dass jeder, der das Depot hat, auch das
gesamte Depot haben sollte und darauf arbeiten kann.
Genau.
Add haben wir schon gesagt.
Fügt eine neue Datei hinzu.
Oder aber, wenn Sie etwas an einer Datei, die schon hinzugefügt war,
dann geändert haben, das heißt, Sie machen irgendwas Neues an der
Datei, ändern irgendwas, fixen einen Fehler, dann machen Sie auch
wieder Git-Add, um die Datei auf den Commit vorzubereiten.
Dann machen Sie Git-Commit, damit landet im Grunde die Änderung in
Ihrem lokalen Depot.
Mit Push übertragen Sie es in ein entferntes Depot.
Mit Patch holen Sie die Änderungen aus entfernten Depots mit Merge.
Legen Sie die Änderungen aus einer anderen Variante, das ist zum
Beispiel die andere Variante, die von dem entfernten Depot kommt,
legen das in Ihre eigene Version ein.
Und Pull ist eine Abkürzung, das machen einfach Patch und Merge
zusammen.
Das heißt, wenn Sie einfach sagen, hol mir das, was auf dem Server ist
und mach alle Änderungen bei mir in mein lokales Depot rein, dann
machen Sie Pull und dann sind Sie an der Stelle fertig.
Gut, das habe ich schon gesagt.
Init legt ein neues Depot an, da brauche ich glaube ich nichts mehr
weiter zu sagen.
Git-Add habe ich im Wesentlichen auch schon erklärt.
Wichtig ist noch, wir haben vorhin über Konflikte gesprochen, die
passieren können, wenn man Dinge einbucht.
Das kann Ihnen jetzt lokal bei Git erstmal nicht passieren, weil in
Ihrem lokalen Depot sind Sie natürlich Herr und Meister.
Sie sind der einzige, der darauf arbeitet.
Das heißt, da können an sich erstmal keine Konflikte auftreten,
normalerweise.
Seitdem man benutzt sehr, sehr viel Gewalt.
Sie bekommen also beim Einbuchen keine Konflikte.
Jetzt nochmal eine andere Sichtweise, aus Sichtweise einer Datei.
Ich habe vorhin gesagt, Git denkt in Objekten, aber wenn wir jetzt mal
mit unserer naiven Sichtweise über Dateien nachdenken, denn das ist
das, was wir normalerweise machen wollen, Dateien irgendwie verwalten
mit Git, dann sieht das so aus.
Ich habe schon gesagt, am Anfang interessiert sich Git einfach
überhaupt nicht für die Dateien.
Das heißt, Sie müssen erst explizit sagen, bitte kümmere Dich um diese
Datei, liebes Git.
Das machen Sie mit dem git add-Befehl.
Dann sind Sie in diesem unmodified Zustand, das heißt, Sie haben
einfach eine Datei, die liegt in Git drin, die kann man irgendwie
verwenden, kann man Änderungen machen und damit arbeiten.
Und das erste, was man dann vielleicht tun möchte, man möchte
irgendwie was ändern, dann kommt man in diesen modified Zustand,
ändert irgendwas an der Datei, fixt einen Fehler, wie auch immer, dann
ist man hier in diesem modified Zustand.
Was man dann macht, ist, man ruft nochmal git add auf und überführt
die Datei in diese staging area.
Wenn man da dann ist, dann kann man wieder ein commit ausführen und
zurück in den unmodified Zustand gelangen, weil dann hat man ja
eingebucht und dann geht man wieder davon aus, okay, jetzt sind wir in
einem festen Zustand und naja, dann ist die Datei erstmal wieder in
dem Zustand, wie ich sie haben wollte.
Wir haben davor die Änderungen eingebucht.
Jetzt haben wir vorhin einfach nur über Einbuchungen gesprochen und
ich erzähle Ihnen jetzt die ganze Zeit irgendwie was von, man muss
erstmal git add machen und erstmal in so einer staging area oder die
Datei ist staged.
Warum will man denn sowas überhaupt machen?
Das ist doch einfach nur so ein zusätzlicher Schritt, der wirkt doch
erstmal irgendwie total kontraintuitiv.
Ich mache einfach die Datei, überführe die staging area und dann mache
ich ein commit.
Warum mache ich das nicht nur einmal?
Kann sich jemand vorstellen, warum man das in zwei Schritte aufteilen
möchte?
Hier melden sich ganz viele Leute.
Wer war denn heute noch nicht dran?
Sie haben mich heute noch nicht sprechen hören.
Okay, also Ihr Kommilitone sagt, man möchte vielleicht Zwischenstände
sichern.
Das ist so die Kurzform, glaube ich, davon.
Also Sie arbeiten an zwei Klassen, möchten aber erstmal nur die eine
committen.
Ja, das könnte ein Anwendungsfall sein, das ist aber nicht der
eigentliche Grund.
Okay, da war jetzt sehr viel verändern dabei in der Antwort.
Ihr Kommilitone sagt, wenn zwei Leute an derselben Datei Änderungen
durchführen an unterschiedlichen Stellen, damit man dann besser
entscheiden kann, was man davon verwendet, so ungefähr.
Dazu hilft Ihnen die staging area erstmal nicht.
Das ist ja dann eher eine Frage, in welcher Granularität Sie
committen.
Warum man das tatsächlich macht, da oben melden sich noch mehr Leute.
Ich mache jetzt einfach mal weiter, weil das geht schneller.
Tut mir leid.
Was Git ermöglichen möchte, ist im Grunde das semantische
Zusammenwirken von Änderungen.
Das heißt, Sie wollen einen Fehler fixen in Ihrem Projekt und naja,
der steht halt nicht in einer Datei, sondern dazu müssen Sie fünf
Dateien anfassen.
Das heißt, dann können Sie einfach in den fünf Dateien Änderungen
machen, in die staging area überführen und in dem Moment fällt Ihnen
ein, ah Mist, in der sechsten Datei muss ich ja auch noch was
anfassen.
Das heißt, dann können Sie auch noch sagen, jetzt mache ich auch noch
die Änderungen in der sechsten Datei und füge die auch noch zur
staging area dazu und erst dann mache ich den commit.
Also sowas geht mit Git, geht aber genauso auch andersrum.
Man kann auch sagen, ich habe jetzt ganz viel gearbeitet den ganzen
Tag über, aber eigentlich sind das unterschiedliche Dinge, an denen
ich gearbeitet habe.
Dann können Sie auch sagen, ok, jetzt nehme ich von der Datei nur die
ersten drei Zeilen und füge die in die staging area dazu.
Also sowas geht auch mit Git, wenn man es richtig beherrscht.
Und dann kann man einfach seine commits, seine Einbuchungen kann man
einfach sinnvoll, semantisch gliedern.
Das ist auch so ein bisschen das, was wir in der Übung von Ihnen
fordern.
Sie sollen also semantische Einheiten bilden, wenn Sie denn etwas
einbuchen.
Gut.
Gibt es ansonsten Fragen bis hierher zu Git?
Gibt es nicht.
Wunderbar.
Wie sieht jetzt so ein Logbuch-Eintrag aus?
Wir haben ja irgendwann schon mal gesagt, naja, wenn ich so eine
Einbuchung mache, dann soll da bitte auch drinstehen, was denn da
eigentlich passiert ist.
So sieht ein Logbuch-Eintrag in Git aus.
In SVN, wer damit gearbeitet hat, ist es im Wesentlichen so ähnlich.
Man sieht hier den Autor, das war in dem Fall mal ich.
E-Mail-Adresse zu Änderungstag.
Wir sehen, welche Datei verändert wurde und man sieht hier diese
Nachricht.
Das sind diese Nachrichten, wo wir auf dem Übungsblatt dann sagen,
bitte schreiben Sie da was Sinnvolles rein.
Im Wesentlichen sollte da das drinstehen, was ich gerade als
semantische Einheit bezeichnet habe.
Also Sie lösen Problem XY und haben dafür fünf Dateien angefasst, dann
schreiben Sie in diese Logbuch-Nachricht genau rein, dass Sie eben
folgenden Fehler gelöst haben.
So sieht das aus.
Wir sehen hier allerdings ein Problem.
Und wir haben die ganze Zeit jetzt über so schöne Versionsnummern
gesprochen, wir haben uns ja diese Deltas angeschaut und wir haben
gesehen, wir kommen von Version 1.0 auf 1.1, auf 1.2, dann irgendwann
zu 2.0.
Und dieses komische Git, das macht jetzt was anderes, das schreibt
hier so ehnend lange Zeichenketten dahinten.
Können Sie sich vorstellen, warum das so gemacht wird?
Jemand eine Idee?
Oder was wird überhaupt gehen?
Hier, melden Sie sich eine Kommilitone.
Genau, genau.
Zum Beispiel.
Ja, genau.
Also.
Ihr Kommilitone sagt, das ist einfach die Denkweise von Git.
Statt jetzt irgendwelche Versionsnummern zu verteilen, rechnen wir
einfach ein Hash aus.
Und das hat mehrere Gründe.
Mit so einem Hash können wir im Grunde ein Kommit eindeutig zuordnen,
das geht mit Zahlen vielleicht nicht.
Wir haben ja gerade gesagt, Git denkt da sehr verteilt.
Wir können an 5 Leute die gleiche Version des Depots austeilen und
jeder arbeitet jetzt einen Schritt weiter und macht aus Version 1.0 1
.1.
Und jetzt buchen wir alle ein, super, haben wir 5 mal Version 1.1.
Okay, das könnte man vielleicht noch auflösen, wenn man sich ein
bisschen Gedanken macht.
Man kann aber mit diesen Hashes hier noch ein bisschen mehr
erschlagen.
Man kann nämlich genau das tun, was ich auf der ersten Folie
vollmundig versprochen habe, nämlich diese kryptografische Sicherheit
sicherstellen.
Mit diesem SHA1 Hash ist es glaube ich bei Git, rechnen Sie im Grunde
einen eindeutigen Wert mit diesem Hash aus für diesen Kommit.
Und der setzt sich aus unterschiedlichen Dingen zusammen, wie zum
Beispiel dem Benutzer, der das getan hat, Zeitpunkt, Log-Nachricht,
Dateien, die verändert wurden.
Das heißt, der ist ziemlich eindeutig.
Es gibt da eher keine Kollision.
Den kann man eindeutig ausrechnen und damit kann man eben
sicherstellen, dass dieser Kommit tatsächlich einzigartig ist.
Und das Schöne dabei ist, wenn ich den jetzt später nochmal raushole
und sage, okay, ich möchte hier aber was an der Historie ändern, dann
kann ich das tun, aber dann verändert sich der Hash und dann fällt er
irgendwie aus der Historie raus, weil Git dann nicht mehr weiß, was
ist denn das da eigentlich für ein Hash-Wert gewesen, den kenne ich
gar nicht aus meiner Historie.
Denn in den Hash steckt auch immer der Vorgänger mit drin.
Das heißt, wenn Sie da irgendwie Ihren Chef betrügen wollen, dann
müssen Sie schon sehr sehr viel Arbeit investieren.
Um das zu tun.
Das stellt halt Git sicher, dass das eben nicht passiert.
Und deshalb sehen die so aus.
Diese Hashes, normalerweise reicht es, um auf einen zuzugreifen, die
ersten vier oder fünf Zeichen zu benutzen.
Damit können Sie dann sagen, okay, ich hätte gerne Kommit 818f gehabt
und würde gerne an der Stelle weiterarbeiten.
Es gibt auch sehr viele sehr schöne grafische Oberflächen.
Man kann sie jetzt auch in der Kommandozeile grafisch als Graph
ausgeben lassen, indem Sie dann im Grunde sehen, welche Kommits wie
aufeinander gefolgt haben.
Genau, das ist nochmal für den Ausdruck.
Was haben wir hier?
Ah ja, genau.
Ein Delta.
Hier sehen Sie im Grunde genau so eine Änderung.
Wir haben vorhin gesagt, wir wollen hier vielleicht dieses Hallo Welt
anpassen.
Dann sehen Sie, Git denkt zeilenweise und sagt, okay, diese Zeile, die
ist an mir rausgekommen, dafür ist die Zeile hinzugekommen.
Damit können Sie sich zum Beispiel, wenn Sie den Unterschied anzeigen
lassen wollen von einem zum nächsten Kommit, dann machen Sie es eben
mit diesem Git-Diff-Aufruf, der war, glaube ich, auf den Befehls
vorhin nicht mit dabei, und sagen halt diesen Kurz-Hash und dann zeigt
Ihnen Git genau an, was denn eigentlich Ihr Kommilitone vom letzten
Mal geändert hat oder was vielleicht auch Sie selber geändert haben.
Vielleicht haben Sie es ja vergessen.
So kommen Sie an ein Git-Depot, wenn Sie entfernt darauf zugreifen
wollen.
Ich glaube, das ist für uns nicht so interessant, weil wir arbeiten
nur mit Git-Lokal.
Wer sich das anschauen will, den verweise ich hier unten auf die
Internetseite.
Das habe ich auch schon gesagt, mit Clone macht man das.
Wie genau, das dürfen Sie sich selber anschauen.
Und jetzt schauen wir uns mal so ein bisschen an, wie Git denn
eigentlich intern funktioniert.
Wenn man das so ein bisschen verstanden hat, dann arbeitet es sich
leichter damit.
Ich habe schon gesagt, Git merkt sich keine Deltas, sondern macht eher
Schnappschlüsse.
Sie können sich das im Grunde so vorstellen wie Dateisystem.
Da ist vielleicht eine ganz gute Sichtweise drauf.
Und wir merken uns eben Schnappschlüsse von einem gewissen
Dateisystem.
Das heißt, wir wissen immer, welche Datei oder wie die Dateien
aussehen, die wir jetzt gerade vor uns sehen, in sogenannten
Schnappschlüssen.
Die werden dann eben in den Komits abgebildet.
Und das ist so, wie SVN denkt, naja, wir haben hier Datei A, B und C
und dann machen wir jetzt hier zu Version 1, machen wir einen Delta an
Datei 1 und so weiter und so fort.
Ja, so denken alle anderen Versionskontrollsysteme.
Und so denkt Git.
Wir haben hier im Grunde Schnappschlüsse und in jedem Schnappschluss
haben wir einen Zustand von unserem, sag ich jetzt mal in
Anführungszeichen, Dateisystem.
Das ist der Unterschied.
Das heißt, wir sehen hier diese Schnappschlüsse.
Intern werden da natürlich auch Deltas.
Ausgerechnet passiert viel Magie.
Aber das ist die Denkweise.
Also wenn Sie sich so einen Komit, wie wir vorhin gesehen haben,
holen, dann haben Sie immer so einen Schnappschluss von Ihrem
Dateisystem vor sich hin.
So ist die Denkweise.
Zoomen wir noch ein bisschen weiter rein.
Ich habe vorhin gesagt, wir wollen vielleicht irgendwie sagen, wir
haben drei Dateien in unserem Depot und jetzt sagen wir, liebe Git,
bitte kümmere dich drum.
Und dann sage ich auch Komit und sage, das ist jetzt mein erster Komit
auf dem Depot.
Dann sieht das ungefähr so aus.
Ich bekomme für jede Datei, die ich habe, so einen Blob.
Mit dem kann ich noch relativ wenig anfangen.
Der repräsentiert halt irgendwie die Dateien, mit denen ich arbeite.
Warum ist das eigentlich so unscharf?
Und darüber habe ich so ein Tree-Objekt gelegen, was im Grunde sagt,
okay, die drei, die sind jetzt eben in dem Komit drin, diese drei
Dateien.
Aber damit sind wir natürlich auch nicht fertig, weil damit wissen wir
zwar, welche Dateien da drin waren und in welchem Zustand.
Aber wir wissen sonst noch nichts über den Komit.
Die ganzen Metadaten fehlen uns noch und das kommt halt in diesem
Komit -Objekt dazu.
Da sehen wir dann auch hier, wir haben den Ausruf vorhin bei echters,
jetzt ist das der liebe Spot.
Und wir wissen, an diesem Komit hängt dieser Tree dran.
Das ist also der Schnappschuss, den wir in diesem Komit sehen von
unserem Dateisystem.
Und jetzt denken wir mal weiter, jetzt machen wir mehrere Komits
aufeinander, folgen, wir ändern Dinge in unseren Dateien, machen immer
wieder giveAdd, giveKomit und dann sieht das irgendwann so aus.
Da sehen Sie schon, da gibt es sich irgendwie so ein Graph.
Hier war unser erster Komit und der nächste Komit, der weiß, was sein
Vorgänger war.
Und damit kann man eben immer sicherstellen, das heißt, Sie sehen
hier, erster Komit hieß 98CR9 und der zweite Komit 34AC2 und der weiß,
was sein Vorgänger war.
Und damit ist eben sichergestellt, dass ich da nicht irgendwo
zwischendrin reingreifen kann und auch mal was ändern kann, ohne
weiteres.
Genau, Sie sehen schon, es ergibt sich im Grunde so ein Graph und den
kann man dann immer weiter fortsetzen.
Und das passiert, und das habe ich auch schon zum Anfang gesagt, geht
immer integral auf Varianten.
Es gibt immer eine Hauptvariante, das ist die Master-Variante, der
Master -Zweig wird es genannt.
Das ist die Hauptvariante, die Sie ganz am Anfang, als wir über
Versionsverwaltung gesprochen haben, gesehen haben.
Darauf wird normalerweise gearbeitet.
Wenn Sie so ein Depot anlegen, der ist immer da.
Und wenn ich jetzt aber sage, okay, ich möchte eine andere Variante
haben.
Sie erinnern sich vielleicht an unser kleines Schauspiel, Kollege Hai
hat irgendwie Mist gebaut und müsste doch bitte mal jetzt noch den
Fehler fixen.
Wenn er da Versionskontroller eingesetzt hätte und Git verwendet
hätte, dann hätte er gesagt, okay, von meinem aktuellen Zustand her
möchte ich jetzt mal irgendwie was verändern.
Das heißt, ich bilde jetzt eine Variante.
Ich bilde jetzt einen neuen Zweig, den nenne ich jetzt Testing.
Vielleicht wäre in dem Fall Fixing besser gewesen, aber könnte ja auch
Testing sein.
Das ist das, was passiert.
Das heißt, mit dem Befehl Git-Branch-Testing lege ich so einen neuen
Zeiger an, auf den letzten Commit oder auf dem Commit, auf dem ich
gerade bin.
Und sage, okay, ab sofort bin ich auf dem Zweig Testing.
So, und jetzt kommt die Frage an der Stelle, woher wissen wir denn
jetzt eigentlich, wo wir gerade sind, auf welchem Zweig.
Jetzt haben wir zwei Zweige, zwei Varianten, die auch das gleiche
zeigen.
Genau, das ist nämlich jetzt die Frage, die jetzt kommt, woher wissen
wir denn jetzt eigentlich, was der aktuelle Commit ist und auf welchem
Zweig wir denn eigentlich sind.
Weiß das jemand?
Da meldet sich wieder jemand, aber den hatten wir heute schon ein paar
Mal.
Noch jemand anders?
Ah, ihr Kommilitone sagt, da gibt es noch so einen Head.
Genau, das ist vollkommen richtig.
Also zusätzlich zu diesen Zeigern, die sagen, okay, auf diesem Zweig
bin ich gerade, gibt es noch einen Head-Zeiger.
Der ist vielleicht, so ziemlich sicher, am Anfang erstmal auf diesen
Master, diesen Master-Branch, auf diesen Master-Zweig gerichtet.
Und wenn ich jetzt Checkout mache, und ich habe vorhin versprochen,
wir sprechen noch über Checkout, dann kann ich im Grunde diesen Head
-Zeiger verschieben.
Das ist die Hauptaufgabe von Git-Checkout.
Wenn ich also jetzt sage, Git-Checkout-Testing, dann wandert dieser
Head -Zeiger auf diesen neuen Zweig, den ich angelegt habe.
Und jetzt weiß ich, okay, jetzt arbeite ich ab sofort auf diesem Zweig
weiter.
Ich kann auch so wilde Sachen machen wie, naja, ich möchte einfach mal
hier auf diesen Kommit-34ac2 zurück.
Dann kann ich auch sagen, Git-Checkout-34ac2.
Und dann bin ich da vorne und dann sehe ich den Zustand meines Depots,
wie er damals war.
Gut.
Was passiert jetzt, wenn ich in diesem Testing-Zweig eine Änderung
mache?
Wir gehen nochmal zurück.
Also wir sind hier, der Head ist auch hier auf diesem Testing-Zweig.
Was passiert, wenn ich jetzt einen neuen Kommit anlege?
Möchte jemand ganz vorne?
Genau.
Und was passiert außerdem noch?
Das war richtig.
Was passiert noch was?
Also ihr Kommilitone sagt, hier wird noch irgendwie so ein neuer
Kommit angelegt und mit einem Zeiger auf den davor.
Das ist vollkommen richtig.
Was passiert außerdem noch?
Ja.
Genau.
Testing wird auf den neuen Kommit verschoben.
Das ist genau das, was passiert.
Das sehen wir jetzt hier.
Der Head sieht jetzt ein bisschen anders aus, aber das ist das, was
passiert.
Und wenn Sie sich das jetzt vorstellen, dass der nicht hier hängt,
grafisch, sondern hier drunter hängt, dann sehen Sie auch besser die
Variante, gedanklich.
Stellen Sie sich vor, der hängt hier.
Dann ist das nämlich die Variante.
Und wenn ich jetzt hier zurück auf den Master gehe, Git-Checkout
-Master und da weiterentwickele, dann habe ich nämlich sofort die
Variantenbildung.
Ich habe da auch noch ein Beispiel mitgebracht.
Das ist jetzt, glaube ich, auch klar, wie wir zurück zum Master
kommen.
Das ist nicht so spannend.
Deshalb zeige ich Ihnen lieber noch dieses Beispiel, wo man das mal
ein bisschen besser sieht in der Variantenbildung.
Wir haben ähnliche Situationen.
Wir haben diese drei Kommits, die wir gemacht haben.
Wir haben den Master und der Kollege Hi hat festgestellt, naja, ich
habe hier irgendwie einen Fehler gemacht.
Ich müsste doch da einmal noch Feature 42 einbauen.
Also macht er eine neue Variante und die heißt Feature 42.
Und er kommittet da etwas.
Der Zeiger auf dem Zweig wandert entsprechend mit.
Was wir jetzt nicht sehen, was implizit ist, ist der Head-Zeiger.
Aber wir stellen uns einfach mal vor, wir hätten den da.
Und gleichzeitig habe ich vielleicht noch einen Entwickler hingesetzt,
der seinen Fehler ausüben soll.
Also das ist im Grunde die Weiterentwicklung.
Sie erinnern sich, Kollege Hi hat noch andere Hello-World-Nachrichten
hinzugefügt, hat aber nicht gemerkt, dass er davor Quatsch gebaut hat.
Deshalb habe ich jemanden Fähigeren hingesetzt und gesagt, okay, macht
doch mal bitte von der alten Version jetzt den Hotfix.
Das heißt, bilde hier wiederum eine neue Variante, die nenne ich
Hotfix.
Und macht er auch einen Commit.
Behebe seinen Fehler, ausgehend von der alten Variante.
So und weil das, naja, relativ einfach war, kann ich dann auch den
Master an der Stelle nachziehen.
Kann an der Stelle einen sogenannten Merge machen.
Das geht an der Stelle.
Wenn man das übernimmt, geht für sie Fast-Forward, weil wir haben hier
vielleicht nur eine Zeile geändert.
Dann kann Git diesen Merge automatisch machen.
Dann lösche ich auch wieder diesen Zweig, weil okay, der Fehler ist
gefixt, die Variante ist nicht mehr nötig.
Wir haben die jetzt eingepflegt.
Unser Hauptzweig ist an dieser Stelle.
Währenddessen arbeitet Kollege Hi weiter an dem tollen neuen Feature,
hat jetzt die zweite Hello-World-Nachricht schon hinzugefügt.
Es geht voran.
Das geht also immer weiter.
Hat damit Nummer 5.
Und was wir jetzt machen wollen, wir wollen jetzt seine neuen
Änderungen wieder in den Hauptzweig übertragen, weil wir wollen das
vielleicht in Version 2.0 an den Kunden ausliefern.
Und an der Stelle machen Sie wieder ein Git Merge.
Dazu gehen Sie auf den Masterzweig und sagen dort einfach Git Merge
und den Namen des anderen Zweigs, den Sie verschmelzen möchten.
Und was dann Git macht, normalerweise, wenn Sie ihm nicht sagen, dass
Git was anderes tun soll, geht zurück auf diesen C2-Commit und schaut,
sind denn diese Änderungen vereinbar.
Und dann führt er die eben zusammen ausgehend von diesem C2-Commit.
Dann schaut er sich an, okay, was ist hier in C4 passiert, was ist in
C3 passiert, was ist in C5 passiert.
Und am Ende kommen wir eben in dieser Commit 6 Variante heraus.
Das heißt, wir führen das hier zusammen.
Und wenn wir das getan haben, dann können wir auch den Commit 42
wieder löschen.
Das heißt, an der Stelle haben wir dann nicht nur den Commit 42,
sondern die Variante 42 hier unten wieder löschen.
Das heißt, wir haben das neue Feature da reingebracht.
Alles fertig, alle Fehler behoben.
Sind also an der Stelle erstmal fertig.
Jetzt ist bloß die Frage, Kollege Hai hat ja einen Fehler gemacht.
Ich habe es fixen lassen von jemand anders, weil der konnte das
vielleicht besser.
Auf jeden Fall ist der Fehler jetzt erstmal gelöst, wir wissen aber
wann er auftritt.
Jetzt wollen wir sicherstellen, dass zumindest dieser Fehler nie
wiederkommt.
Wir wollen irgendwie sicherstellen, dass dieser eine Fehler, den der
Hai da gemacht hat, nicht nochmal vorkommt in unserer Firma.
Und wir wollen sicherstellen, dass egal welche Änderungen wir
durchführen an unserem Projekt, eben genau der Fehler nicht nochmal
auftritt.
Und er darf Ihnen jetzt selber erklären, wie man das am besten macht.
Ich dachte, ich bin nicht geeignet dazu, aber naja, dann muss ich das
jetzt wohl machen.
Was haben Sie denn für eine Idee, wie könnte man denn jetzt
verhindern, dass man einen Fehler, den man schonmal gemacht hat,
nochmal macht in einem Projekt?
Hat jemand eine Idee?
Ich glaube, das Werkzeug dazu haben Sie alle schon letztes Semester
kennengelernt.
Ja?
Genau, also Ihr Kommilitonen hat vorgeschlagen, einen Testfall dazu zu
schreiben.
Genau das.
Ja, Sie haben wahrscheinlich schon alle Programmieren 1 gehört,
wahrscheinlich, die meisten von Ihnen zumindest.
Das heißt, Sie wissen schon, sollten wissen, was Tests sind.
Wir werden jetzt auch nochmal kurz das Ganze einführen, nochmal kurz
auf den Stand bringen, dass Sie das wissen, was wir für die
Übungsblätter benötigen.
Genau, was verstehen wir denn unter Testfällen?
Testfälle sind Ausführungen eines Programms unter bekannten
Bedingungen.
Das heißt, wir wissen, welche Eingabe wir an das Programm senden und
wissen, was wir erwarten von dem Programm.
Das heißt, wir testen unter diesen Bedingungen, unter vorgegebenen
Eingabedaten, ob das zurückkommt, was wir eigentlich erwartet haben.
Und das Ziel dabei ist, dass wir Defekte aufdecken.
Das heißt, wir können aber auch immer nur die Defekte erkennen, die
wir durch unsere Eingabedaten überhaupt erzeugen können.
Das heißt, wir können mit Tests immer nur Defekte abdecken, die wir
auch erwarten können oder mit den Sachen, die wir testen.
Das heißt, man kann nicht davon ausgehen, dass es keine Defekte in
einem Programm gibt, wenn wir alles getestet haben, was uns
eingefallen ist.
Was ist das Vorgehen bei Testfällen normalerweise?
Man könnte jetzt natürlich jede Schnittstelle des Programms oder
alles, was wir mit dem Programm machen können, händisch
durchprobieren.
Oder irgendwelche Sysouts oder sonstiges einfügen und schauen, jedes
Mal händisch kommt jetzt das raus, was ich eigentlich erwartet habe.
Naja, das wäre vielleicht bei einem kleinen Projekt wie Hello World
noch recht einfach machbar.
Ich meine, man muss nur einmal kurz auf die Kommandozeile gucken und
schauen, ob da Hello World ausgegeben wird.
Aber wenn man sich jetzt vorstellt, man hat ein großes Projekt mit
mehreren hunderttausend Zeilen Code und man hat über 50 Sachen, die
man testen möchte oder noch viel mehr, dann ist es vielleicht nicht
mehr möglich, dass man auf jedes Testergebnis einfach mal kurz drauf
schaut und schaut, ob das korrekt ist.
Das heißt, man möchte diesen Prozess eigentlich automatisieren.
Das heißt, man möchte für jeden Testfall, den man sich überlegt hat,
eine Ausgabe bekommen.
Ist denn jetzt das passiert, was ich eigentlich erwartet habe?
Also eigentlich ein Boolchen-Wert, ist dieser Testfall erfolgreich
oder ist er fehlgeschlagen?
Man kann natürlich auch überlegen, wenn man jetzt Boolchen-Werte
ausgibt, dass man das Ganze auch über einen anderen Mechanismus löst,
nämlich über Exceptions, also Ausnahmen.
Das heißt, immer wenn eine Ausnahme ausgelöst wird, die ich nicht
erwarte, kann ich auch davon ausgehen, dass der Testcase oder der
Testfall nicht so abgelaufen ist, wie ich das erwartet habe.
Das Schöne an diesen automatischen Testfällen ist, wie ich eben schon
sagte, man kann große Mengen von Testfällen haben, die zusammensetzen
und automatisiert ablaufen lassen, sodass man nicht jedes Mal alles
händig machen muss dazu.
Das wird häufig gemacht, in größeren Software-Projekten, über Nacht.
Das heißt, sogenannte Nightly Builds werden gemacht, es werden die
Testfälle durchgeführt, es wird geschaut, ob das, was über den Tag
produziert wurde,
den Qualitätsanforderungen entspricht, die man eigentlich für den
Testfällen definiert hat.
Außerdem dazu kann man die Testfälle dann natürlich auch zu
Regressionstests nehmen.
Das heißt, man kann eine gewisse Menge von Testfällen definieren für
die Software, die immer erfüllt sein muss.
Das heißt, wenn ein Entwickler eine Änderung an dem Tool macht, man
selber aber schon festgestellt hat, zum Beispiel, dass wenn man
gewisse Sachen abändert, wie Sebastian es eben schon beschrieben hat,
das heißt, wir haben einen Fehler vorher schon festgestellt, haben
dafür einen Testfall geschrieben, kann den meinen Kollegen zur
Verfügung stellen und die Kollegen wissen dann, wenn sie das nächste
Mal dieselbe Änderung oder eine ähnliche Änderung machen, die diesen
Fehler produzieren, dass das halt die Software kaputt macht.
Entschuldigung.
Genau.
So, was ist jetzt das Werkzeug, was wir dazu benutzen?
Hier in der Übung und auch in der Vorlesung benutzen wir JUnit 4.
Ich glaube, das haben die meisten von Ihnen schon während
Programmieren eingesetzt.
Das ist ein Rahmen in der Architektur, der einem die Möglichkeit
bietet, automatisiert Testfälle durchzuführen.
Sie liefert einem dann dabei die fehlgeschlagenen Testfälle zurück,
beziehungsweise gibt einem auch...
Wo waren wir stehen geblieben bei?
Gibt Testfälle zurück.
Genau, damit können wir ja automatisch alle unsere Testfälle ausführen
lassen.
Es gibt natürlich auch, nicht nur für Java, JUnit, sondern, naja, Sie
können das im Wesentlichen auch für PHP.
PHP-Unit heißt das, glaube ich sogar.
Ich weiß es gar nicht mehr.
Gibt sowas auch.
Also für alle möglichen Programmiersprachen gibt sowas normalerweise.
Das heißt, das ist kein Problem, das auch für andere
Programmiersprachen einzusetzen.
Wir zeigen es Ihnen hier für Java, weil das ist, was wir benutzen.
Was ist jetzt in so einer JUnit-Testklasse eigentlich drin?
Also ich möchte sagen, naja, ich möchte hier gewisse Stellen von
meinem Programm testen.
Das heißt, ich lege mir eine neue Testklasse an und da sind gewisse
Testfälle drin, in Form von Methoden normalerweise.
Und in diesen Methoden sage ich, ok, baue mir das jetzt mal wie folgt
zusammen, mein Programm, und dann teste folgende Eingabe.
Und da haben wir logischerweise irgendwie Referenzen auf die
zukünftigen Testobjekte, die wir überhaupt testen wollen.
Und was wir dann natürlich machen wollen, die soll und ist Werte
vergleichen.
Das ist genau das, was Kollege Haik gerade so ein bisschen motivieren
wollte.
Das Sysout sind irgendwie eine blöde Idee, weil das hilft für Hello
World.
Für größere Sachen ist das aber doof.
Sie wollen nicht jedes Mal über die kompletten Sysouts überscrollen
und schauen, ob überall 4 gleich 4 ist und 5 gleich 5.
Sondern sie wollen da das irgendwie automatisch vergleichen.
Deshalb gibt es diese soll-ist-Werte-Vergleiche mit diesen Asserts.
Und wir sagen auch immer wieder auf den Übungsblättern, also
Entschuldigung, lieber Student, aber JUnit-Test ohne Assert ist halt
irgendwie kein Test.
Also wenn sie da irgendwie nur ein Sysout machen oder sagen, okay,
mein Programm ist durchgelaufen und es ein Null-Pointer-Exception gab,
ist super.
Ja, so ist es richtig.
Also sie müssen in einem Testfall schon echt irgendwie so ein soll-ist
-Werte -Vergleich machen, sonst sehen wir das nicht.
Und damit JUnit weiß, was denn jetzt eigentlich so eine Testmethode
ist und was vielleicht auch andere Methoden sind, die sie brauchen, um
ihren Testfall aufzubauen, gibt es Annotationen.
Und da darfst du jetzt wieder weitermachen.
Ich glaube, du kannst wieder.
Ich kann wieder, ja.
Genau.
Also es gibt Annotationen in JUnit.
Die meisten von Ihnen kennen sie wahrscheinlich schon.
AtTest, AtBefore, die man an Methoden dran schreiben kann.
Diese Annotationen gibt es schon seit Java 5.
Das heißt, man kann sie nicht nur für JUnit benutzen, sondern sie sind
eingebaut in Java.
Eine weitere, ziemlich häufige von diesen Annotationen ist die
AddDeprecated Annotation.
Kennt die jemand?
Weiß jemand, was die macht?
Ja?
Genau, ihr Kommilitone sagt, die AddDeprecated Annotation sagt, dass
man die Methode nicht mehr benutzen soll.
Genau, das ist auch der Sinn und Zweck des Ganzen.
Das heißt, man kann hiermit als Entwickler sagen, diese Methode wird
demnächst auslaufen, wird irgendwann aus dem Programm herausgenommen
und sollte nicht mehr verwendet werden.
Warum möchte man so etwas tun?
Hat da jemand eine Idee?
Ja?
Ihr Kommilitone hat vorgeschlagen, man könnte bei Utility-Klassen die
Konstruktoren auf Deprecated setzen, damit man sie nicht mehr benutzt.
Da ist die Frage, warum man das vorher überhaupt angeboten hat.
Genau.
Also, man kann das tun, aber ich glaube, das wäre nicht der richtige
Weg, um das zu verhindern.
Da hinten noch eine?
Ja, sie.
Also, ihr Kommilitone hat gerade gesagt, dass man diese Annotation
dann benutzen kann, wenn man große Bibliotheken oder sonstige größere
Software anbietet, an mehrere Menschen oder andere Entwickler.
Vielleicht sind es nicht immer Menschen, weiß man nicht.
Dann möchte man vielleicht, wenn man mehrere Versionen hintereinander
immer wieder rausgibt, nicht sofort von einer Version auf der nächsten
sagen, diese Methode gibt es nicht mehr, die wird aus dem Support
rausgenommen.
Sondern man möchte vielleicht sagen, erstmal kann man diese Methode
noch weiterverwenden, aber in der nächsten Zeit solltet ihr euch
Gedanken machen, diese Methode nicht mehr zu benutzen, sondern die
neuen Methoden, die jetzt angeboten werden.
Das ist genau der Grund, wofür es diese Annotationen gibt.
Das heißt, solche Annotationen in Java stellen Metainformationen zu
Methoden, Klassen und sonstigen zur Verfügung.
Gut, aber jetzt kommen wir wieder zurück zu JUnit.
Jetzt habe ich hier eine kleine Testklasse mitgebracht, die auch schon
diese Annotationen mit drin hat, die wichtig sind für JUnit.
Nämlich hier das AddBefore vor einer Methode und das AddTest und
außerdem noch das AddAfter hier unten.
Hat jemand eine Idee, wofür diese einzelnen Annotationen in diesem
Fall stehen?
Ihr Kommilitonin hat gesagt, dass das AddBefore immer ausgeführt wird
vor jedem Test, also diese Methode hier bedeutet, sie wird vor jedem
mit AddTest annotierten Methode ausgeführt und das AddAfter nach jeder
mit AddTest annotierten Methode.
Das heißt aber auch, die AddTest Methoden sind die eigentlichen
Testmethoden, in denen dann auch die Zusicherungen aufgezählt werden
müssen, von denen Herr Beigelt gerade eben schon gesprochen hat.
Hi, ich habe da nochmal eine Frage, wozu brauchen wir denn dieses
Before und dieses After überhaupt?
Ich möchte auch einfach nur Sachen in meinem Code testen.
Was mache ich da jetzt noch vorher und hinterher?
Ich mache einfach den Test fertig.
Naja, warum braucht man jetzt dieses AddBefore und dieses AddAfter?
Naja gut, man muss vielleicht für einen Testfall oder für mehrere
Testfälle immer wieder neue Sachen initialisieren.
Man benutzt diese Methoden dafür, Initialisierungen zu machen, die für
jeden Testfall wichtig sind und je nachdem möchte man diese Sachen
auch wieder aufräumen, damit der Zustand für jeden Test der gleiche
ist oder wieder ein neuer, frischer Zustand ist auf der grünen Wiese,
auf dem wir diesen Test ausführen können.
Und nicht Abhängigkeiten zwischen den Tests verursachen wollen.
Das ist nämlich etwas, was wir vor allen Dingen vermeiden wollen.
Noch ein Punkt, den man bei Testen auf jeden Fall vermeiden sollte,
dass die einzelnen Tests voneinander abhängen.
Denn so ist es schwierig, diese Tests nachher einzeln wieder zu
benutzen oder überhaupt ist es schlechter Stil, diese Abhängigkeiten
zu erzeugen.
Jetzt kommt hier noch ein bisschen was für Ihren Ausdruck.
Ich glaube, das habe ich alles gesagt.
Die Annotation von JUnit hatten wir eben schon kurz.
Es gibt diese AddTest, die einfach die Testfälle selbst markieren.
Man kann an dieses AddTest noch in Klammern eine erwartete Exception
dran schreiben.
Das ist die einzige weitere Variante außerhalb der Zusicherung, die
für uns einen gültigen Testfall darstellt, beziehungsweise auch noch
das mit dem Timeout hier hinter.
Man kann nämlich, anstatt eine Zusicherung zu schreiben, dass da jetzt
eine Exception oder eine Exception zu fangen und dann da ein Assert
True irgendwas zu werfen, was wiederum schlechter Stil wäre, nutzt man
einfach diese Annotation und sagt, ich erwarte in diesem Testfall,
dass jetzt die Exception, SQL Exception geworfen wird.
Und dann ist dieser Testfall auch grün.
Nur dann grün, wenn diese Exception auch geworfen wird.
Also nur dann ist dieser Testfall erfolgreich.
Das gleiche gilt für die Timeout-Geschichte.
Man möchte also festlegen, dass dieser Test in 42 Millisekunden
durchgelaufen ist.
Und man hat diese Information als das, was man als Zusicherung quasi
hat.
Der Add-Ignore oder die Add-Ignore-Annotation sagt hierbei jetzt, dass
dieser Testfall erstmal ausgeschlossen wird von der Ausführung.
Das heißt, man möchte vielleicht schonmal anfangen, einen Test zu
entwickeln, hat aber festgestellt, dass dieser Test noch gar nicht
erfüllt werden kann, da die Funktionalität, die man dort testen will,
noch gar nicht implementiert ist.
Dann kann man dies einfach mit Add-Ignore an diesen Test schreiben.
Er wird also nicht ausgeführt.
Man kann dann am besten noch in Klammern und dahinter schreiben, warum
das Ganze jetzt nicht ist.
In dem Fall, die Funktionalität fehlt halt noch.
Man kann dann später, wenn diese Funktionalität hinzugefügt wurde,
einfach dieses Ignore wegnehmen und diesen Testfall trotzdem
ausführen.
Das wird häufig gemacht, da man meistens getrennte Entwicklerteams für
das Testing und für die Entwicklung hat.
Das heißt, es ist normalerweise so, dass nicht unbedingt derjenige,
der entwickelt, auch die Tests für die Software schreibt.
Und dann ist es häufig so, dass die Tester vielleicht schon Sachen
testen, die noch gar nicht implementiert sind.
Dann braucht man genau das.
Genau, das Add-Before, Add-After hatten wir eben schon.
Da gibt es noch die zwei Notationen Add-Before-Class und Add-After
-Class.
Diese werden jetzt einmal für eine Testklasse ausgeführt.
Das heißt, Before-Class wird am Anfang der Testklasse, vor allen
Testcases und vor allen Befores ausgeführt.
Und Add-After-Class nach allen anderen Methoden, die in der Testklasse
ausgeführt werden.
Das macht man meistens für Dinge, die sehr lange brauchen, um
initialisiert zu werden.
Irgendwelche Verbindungen zu irgendwelchen Datenbanken oder sonstiges.
Das will man vielleicht nur einmal machen und nicht jedes Mal vorm
Ausführen jedes Testfalles.
Jetzt schauen wir uns nochmal kurz diese Ausführungsreihenfolge an.
Wir haben jetzt hier die Klasse Bibliothekstest wieder, die jetzt noch
ein paar mehr Methoden hat.
Wir haben also jetzt hier eine Add-Before-Class Methode, die sich mit
irgendeiner Datenbank verbindet.
Wir haben aber auch eine After-Class Methode, die diese Verbindung
wieder trennt.
Das heißt, man sollte auch immer alles, was man aufbaut für die
Testfälle, auch wieder abbauen.
Das sollte Ihnen aber ja eigentlich schon bewusst sein aus
Programmieren.
Dann haben wir hier eine Add-Before- und eine Add-After-Methode, die
irgendwas aufbauen und irgendwas aufräumen, was auch immer.
Und zwei Testfälle.
Die Reihenfolge, wie diese Methoden jetzt aufgerufen werden, ist
zunächst, wie ich eben schon sagte, die Add-Before-Class Methode.
Also die verbindet mit der Datenbank.
Und jetzt wird ein Testfall aufgerufen, da aber davor natürlich immer
die Bevor-Methoden vor jedem Testfall aufgerufen werden, wird also
erst die Bauer-auf-Methode aufgerufen und jetzt eine der Testmethoden.
Wie ist denn das mit den Testmethoden?
Wird da immer die erste aufgerufen oder ist das irgendwie anders?
Ja, da hinten.
Genau, der Kommilitonen hat gesagt, es ist zufällig.
Das ist tatsächlich so.
Bei JUnit ist nicht garantiert, dass die Tests in der Reihenfolge
aufgerufen werden, in der sie dort stehen.
Es gibt eine Annotation, die man über die Klasse schreiben kann, die
dafür sorgt, dass es eine gewisse Reihenfolge der Testfälle gibt.
Aber im Normalfall sollten die Testfälle ja sowieso unabhängig
voneinander sein.
Also es ist vollkommen egal, in welcher Reihenfolge diese aufgerufen
werden.
Das heißt, gehen wir jetzt erstmal davon aus, es wäre jetzt
zufälligerweise der erste von den beiden.
Dann wird dieser als nächstes aufgerufen.
Daraufhin die Räume-auf-Methode.
Und jetzt, da wir ja einen weiteren Testfall noch haben, der
ausgeführt werden muss, wird wieder die Bevor-Methode aufgerufen.
Da diese ja vor jedem Testfall aufgerufen wird.
Und daraufhin dann erst der Buch-Ausleihen-Test.
Das hatte ich gerade schon gesagt.
Und erst jetzt, nachdem wiederum die After-Methode aufgerufen wurde,
wird die After-Class-Methode aufgerufen, weil alle Testfälle und alle
anderen Sachen, die in sehr klassischem Geschehen sind, durchgeführt
sind und erst dann wird die After-Class-Methode aufgerufen.
Diese Reihenfolge muss man verinhaltlichen, wenn man Testfälle
schreibt, denn sonst kann es sehr schnell zu irgendwelchen nicht
erwarteten Funktionalitäten führen, die man irgendwie nicht versteht,
weil man nicht genau weiß, weil man vielleicht After-Class benutzt
hat, anstatt After.
Das passiert recht häufig.
Achten Sie darauf.
Genau.
Gut.
Man kann JUnit...
Eigentlich ist JUnit auch ein Kommandozeilen-Werkzeug, das heißt man
benutzt es eigentlich auf der Kommandozeile, aber für die schöne Optik
hat auch Eclipse hier ein Plugin, was das Ganze sehr schön grafisch
darstellt.
Ob Sie das jetzt so verwenden oder auf der Kommandozeile, ist uns
prinzipiell egal.
Ich zeige jetzt nur mal kurz, wie das Ganze aussieht.
Man kann nämlich in Eclipse einfach mit Rechtsklick, also im
Kontextmenü, der einzelnen Klassen oder auch auf den einzelnen
Methoden sagen, führe jetzt diesen Testfall aus oder führe alle
Testfälle dieser Klasse aus oder führe alle Testfälle dieses Paketes
aus.
Man kann aber auch sagen, führe einfach alle Testfälle aus, die du
findest in dem Projekt.
Das heißt, je nachdem auf was man klickt, mit Rechtsklick und dann Run
as JUnit, kriegt man unterschiedliche Ausführungsvarianten.
Genau.
Das ist jetzt die Anzeige, wenn ein Testfall fehlschlägt.
Denn wir haben hier den Testfall, Buch ist in Bibliothek.
Dieser schlägt fehl.
Das sieht man daran, dass hier ein Failure kommt und das Ganze rot
ist.
Außerdem kriegt man meistens noch eine Nachricht darüber, welche
Zusicherung dort jetzt nicht funktioniert hat und was der Wert ist,
der dort jetzt überprüft wurde.
Wenn man zum Beispiel einen AssertEquals macht, kriegt man ausgegeben,
welche beiden Werte da jetzt nicht übereingestimmt haben.
Wenn das Ganze aber durchläuft und der Test erfolgreich ist, ist alles
grün und man kann das Ganze einfach so weiterverwenden.
Genau.
Das haben wir jetzt hier gesehen.
Sehr kurze Einführung in Testing.
Ich hoffe aber, Sie haben zumindest verstanden, auf was es ankommt.
Es ist wichtig, dass wir das Ganze automatisch durchführen können,
denn gerade in großen Projekten wird es sonst sehr unhandlich.
Und man könnte keine Registrierungstests machen, also jedes Mal, wenn
man wieder einbucht, dieselben Tests auf den Code, der sich jetzt
verändert hat, ausführen.
Genau diese Registrierungstests will man aber ja haben, da man ja
nicht Defekte, die man schon mal gemacht hat, noch einmal einbauen
möchte.
Denn man hat sie ja eigentlich schon erkannt und versucht halt damit
immer wieder zu verhindern, dass Fehler mehrmals gemacht werden in
einem Projekt.
Man kann natürlich auch immer schauen, ob das, was man jetzt gerade an
neuem Quelltext geschrieben hat, das erfüllt, was man eigentlich
erwartet.
Genau.
Hi, ich habe da nochmal eine Frage.
Was denn?
Jetzt habe ich da irgendwie so Testfälle geschrieben, aber woher weiß
ich denn, ob ich das überhaupt alles geprüft habe, was ich gecodet
habe vorher.
Also ich sehe Sie da immer so Sachen coden und dann machen Sie Tests
dazu.
Oder wissen Sie, dass das eine zum anderen passt, dass hier alles von
Ihrem Code getestet ist?
Ja, das ist genau der Punkt, den ich jetzt erzählen wollte, Herr
Weigelt.
Vielen Dank.
Stellen Sie mir die richtigen Fragen.
Deshalb bin ich der Chef.
Danke.
Sie haben die Krawatte nicht mehr an.
Sie sind nicht mehr Chef.
Das ist Freude.
Da kann man auch mal ohne Krawatte kommen.
Gut.
Genau.
Der Punkt ist, wir haben jetzt JUnit zwar gesehen und wissen jetzt,
dass wir Testfälle für einzelne Methoden schreiben können, aber das
heißt noch nicht, dass wir auch alles, was in diesen Methoden
auftritt, mit einem Testfall abgedeckt haben.
Und auch hierfür gibt es Werkzeuge, die uns genau das liefern, was wir
da haben wollen.
Wer von Ihnen hat schon mal Emma benutzt?
Eine Person?
Gut.
Zwei.
Der Chef hat schon mal Emma benutzt.
Das ist auch gut.
Weiterbildung.
Ich habe aber nur darauf geklickt, was Sie da gesagt haben.
War das Ihre Oma oder war das wirklich?
Bitte?
Heißt Ihre Oma Emma?
Nee, nee, nee, nee.
Das war wirklich...
Gut.
Alles klar.
Also, Emma ist ein Werkzeug zur Ermittlung der Testüberdeckung.
Das heißt, man kann mit diesem Werkzeug herausfinden, wie viel des
eigentlichen Quelltexts haben wir wirklich mit einem Testfall
überdeckt.
Das ist deswegen relevant, da man, wenn man jetzt vielleicht 100
Testcases geschrieben hat, immer noch nicht sicher gehen kann, dass
man wirklich alles getestet hat und auch wenn man 100% Überdeckung mit
Emma erreicht hat, dass das immer noch nicht gewährleistet ist, denn
die Eingabe oder die Richtigkeit eines Programms hängt natürlich von
den Eingabewerten ab.
Oder die Möglichkeit, ob man alle Defekte findet.
Aber es ist trotzdem möglich, mit Emma schon mal ein Gefühl dafür zu
kriegen, wie viel seines Quelltextes man wirklich abgedeckt hat und
wie gut man denn jetzt bisher getestet hat.
Das heißt, man benutzt Emma eigentlich genauso wie JUnit, nur dass man
jetzt quasi mit dem anderen Laufsymbol hier oben, wenn man das Ganze
mit Eclipse machen möchte, direkt die Überdeckung angezeigt bekommt.
Das heißt, man bekommt pro Klasse, die man getestet hat, oder pro
jeder Klasse, die es überhaupt gibt, angezeigt, wie viele Zeilen man
dort überdeckt hat in den jeweiligen Methoden.
Wir haben jetzt hier, die linke Ansicht ist das, was wir eben schon
für JUnit gesehen haben.
Hier wird uns gesagt, wir haben jetzt die ganzen Testfälle hier
ausgeführt.
Und hier unten haben wir die Ansicht, welche Pakete und welche Klassen
dort und auch welche Methoden in den einzelnen Klassen jetzt zu
wieviel Prozent überdeckt wurden.
Das heißt, wir haben jetzt hier die Information, dass die meisten,
oder hier unten die Methoden, auch sehr schön benannt, alle mit XXX
und XYX, lässt sich gut lesen.
Zumindest gibt es hier zwei Methoden, die gar nicht überdeckt wurden,
also 0% Überdeckung haben.
Das sind die hier oben.
Ich muss zugeben, das ist auch nicht so ganz sinnvoll, weil hier jetzt
gerade Testfallüberdeckung, also die Überdeckung des Quelltextes der
Tests, angezeigt wird.
Normalerweise würde man sich jetzt anschauen, ob der Quelltext von den
Testen überdeckt worden wäre.
Man kriegt aber hier ein sehr gutes Indiz dafür, wie viel Prozent des
eigentlichen Quelltextes man denn jetzt überdeckt hat in seinen
Testfällen.
Das ist genau das, was man haben möchte.
Normalerweise würde ich jetzt an der Stelle sagen, so bitte nicht.
Also bitte nicht Ihre Testfälle XXXX nennen.
Ist irgendwie blöd.
Bitte geben Sie entsprechenden Namen.
Aber wer mal genau hingeschaut hat, das ist an der Stelle passiert.
Was da nämlich implementiert wurde, war eine State Machine und die
Eingabe war jetzt halt gerade XXXX.
Insofern ist sogar entsprechender Name tatsächlich da, auch wenn es
nicht so aussieht.
Trotzdem zum Vorzeigen.
Ja, ja, kann man mal darüber nachdenken.
Aber man muss ja auch mal was zeigen, wenn man es nicht macht.
Ja, das ist okay.
Gut, hier nochmal ein bisschen was für Ihren Ausdruck.
Ich glaube, das ist alles relativ klar.
Gibt es Fragen zu Emma und Coverage?
Keine?
Gut, dann machen wir mal eine Folie zurück.
Willst du einleiten?
Will ich nochmal ein bisschen so überleiten, weil vielleicht erinnern
Sie sich noch an unser kleines Schauspiel.
Nachdem er da den Quatsch zusammen programmiert hat, habe ich ihn auch
noch dazu gezwungen, das irgendwie für den Kunden benutzbar zu machen.
Habe ihn in JAR bauen lassen.
Normalerweise würde ich noch wollen, dass er vielleicht vorher auch
noch alle Testfelder durchlaufen lässt.
Und dass er mir noch eine Dokumentation zusammenbastelt.
Und seien wir mal ehrlich, billige Arbeitskraft, der könnte das schon
alles händisch machen, klar.
Aber es ist irgendwie jedes Mal das Gleiche.
Warum automatisieren wir das denn nicht?
Geht das nicht irgendwie besser?
Und Sie ahnen die Antwort, die finde ich ja.
Es geht natürlich besser.
Es gibt so ein paar Schritte, die müssen wir machen, wenn wir
Änderungen an unserem Projekt durchgeführt haben.
Bevor wir etwas ausliefern können oder zum Auslieferungszeitpunkt.
Wir möchten vielleicht testen, ob der Herr H.
sich an die richtigen Guidelines für den Code-Style gehalten hat.
So was möchte man machen.
Man möchte die Testfelder durchführen, man möchte Testüberdeckung
prüfen.
Und wenn die dann alle Tests grün sind, dann möchte ich vielleicht,
dass das alles in ein schönes JAR verpackt wird.
Und ich als Chef möchte vielleicht auch noch einen Report haben.
Man möchte außerdem noch, dass da so eine neue Revision und die
Revisionskontrolle eingecheckt wird.
Die Abhängigkeiten, vielleicht habe ich irgendwelche Bibliotheken, die
ich verwende für mein Projekt.
Die sollen doch bitte alle zusammengesucht werden.
Macht das doch mal bitte jemand für mich.
Und dann am Ende möchte ich das ausliefern.
Ja, okay, dann habe ich jetzt hier so eine JAR zusammengepackt und die
brenne ich dann auf eine CD.
Hat noch jemand einen CD-Brenner in seinem Laptop?
Ja, super.
Sehr sympathisch.
Oder ich mache das auf dem USB-Stick, wie wir das gesehen haben.
Das sind also Möglichkeiten, die man hat, aber irgendwie möchte man
das vielleicht nicht machen.
Und vielleicht möchte man auch diesen Auslieferungsschritt automatisch
machen.
Und ja, das geht.
Wir benutzen dazu Maven.
Es gibt da noch tausend andere Möglichkeiten unter Java oder mit Java
kann man mit Maven ziemlich gut arbeiten.
Deshalb machen wir das in der Vorlesung und Sie auch im Übungsbetrieb.
Sie müssen da ein bisschen sich durchkämpfen und deshalb gibt es jetzt
hier auch eine kurze Einleitung dazu, was denn dieses Maven, mit dem
Sie wahrscheinlich das erste Mal arbeiten.
Wer hat schon mal Maven benutzt vor der Vorlesung?
Ja, ja, das sind nämlich deutlich weniger als bei Git noch vorhin.
5, 6, 8 vielleicht.
Mal grob überschlagen, Sie müssen das jetzt also das erste Mal
wahrscheinlich tun.
Und naja, was Maven für Sie tut, ist eben genau das, was ich gerade so
angekündigt habe.
Also Maven macht alles, was Sie nach dem Quellcode produzieren, mit
Ihrem Quellcode passieren soll.
Das heißt, es kann für Sie automatisch übersetzen, es kann alle
Abhängigkeiten einsammeln, es kann Ihren Code testen, also die
Testfälle anstoßen, Ihren Code verpacken zum Beispiel als JAR, kann
aber auch installieren, kann Dokumentationen automatisch generieren
aus Ihrem Code, kann Berichte erstellen, kann also Ihrem Chef eine E
-Mail schicken, der freut sich, wenn er dann 10 Mal am Tag eine Mail
bekommt mit den aktuellen Änderungen.
Also all das geht mit Maven und deshalb benutzen wir das.
Und Maven ist somit also ein Werkzeug zur Teilautomatisierung von
gewissen Aufgaben im Entwicklungsprozess.
Und dafür benutzt Maven ein standardisiertes Dateiformat, in dem im
Wesentlichen spezifiziert ist, welche Aufgaben gibt es denn überhaupt
jetzt tun für mich als kleines Maven, welche Abhängigkeiten hat denn
das Projekt, was muss ich denn da alles einsammeln, welche Daten
werden denn überhaupt im Entwicklungsprozess benötigt, was muss ich
denn zusammensammeln, wenn ich so ein Artefakt zusammenbaue, wenn ich
so ein JAR zum Beispiel zusammenbaue.
Das spezifizieren Sie für Maven in einer Datei, das ist diese ominöse
.xml -Datei, die Sie vielleicht schon auf dem Übungsblatt gesehen
haben sollten, wenn Sie denn schon drauf geschaut haben, was ich Ihnen
strengestens geraten haben wollte.
Das heißt, die haben Sie schon mal gesehen, angefasst, da steht alles
drin, was Maven für Sie erledigt, damit konfigurieren Sie Maven.
Was man dann damit machen kann, ist eben genau so
Entwicklungsprozessaufgaben abbilden.
Man kann zum Beispiel sagen, okay, ich führe alle Modultests aus, und
dazu muss ich aber erstmal mein Programm übersetzen, und wenn ich das
getan habe, dann kann ich es auch noch zusammenbauen, aber eben nur,
wenn die Tests alle grün waren.
Genauso könnte auch Maven sagen, okay, du hast mir irgendwie gesagt,
du brauchst die Bibliothek XY, die habe ich aber jetzt hier gerade
nicht vorliegen, dann hole ich die mal für dich.
Also all das macht Maven für Sie, und dann merken Sie schon, das nimmt
Ihnen einen Haufen Arbeit ab, wenn Sie dann verstanden haben, wie es
funktioniert, und deshalb zwingen wir Sie in der Übung so ein bisschen
dazu, das zu tun, weil wenn man es erstmal kann, ist es super
hilfreich, insbesondere wenn man mit anderen Menschen zusammenarbeiten
muss, oder aber wenn man seine Lösung auf der LEZ abgeben muss, und
man einfach nicht weiß, was dort auf der LEZ passiert, dann ist es
auch sinnvoll, irgendwie so eine gemeinsame Ahnung davon zu haben, wie
das Projekt dann aussehen soll, und das stellen wir eben über diese
COM -Dateien sicher.
So, um das benutzen zu können, dieses Maven, da muss man sich an so
ein paar Konventionen halten, die aber einem auch einfach
zusammengestellt werden.
Wenn man zum Beispiel in Eclipse ein neues Maven-Projekt anlegt, dann
bekommt man automatisch die Ordnerstruktur geliefert, die man denn
eigentlich haben möchte.
Im Wesentlichen, hier ist es noch ein bisschen größer, besteht das aus
einem Source-Ordner, in dem es einen Main- und einen Test-Unterordner
gibt, und dort liegen wiederum Ihre Quellen in einem Java-Ordner, und
Ressourcen, die Sie benutzen, in einem Resources-Ordner, und das
gespiegelt gibt es auch für Tests, weil auch für Tests brauchen Sie
gegebenenfalls noch irgendwelche Dateien, und dann gibt es einen
Target -Ordner, da liegt in einem Grunde alles drin, was ausgeliefert
wird.
Zum Beispiel Klassen, zum Beispiel Ihr gebautes Java, oder Ihre
Reports, die Sie automatisch erstellt haben, und alles wird definiert,
was getan werden soll in dieser Promix.
Wenn Sie ein neues Projekt aufsetzen, da hat er einen gewissen Typ,
diesen Archetype, da kann man gewisse Dinge definieren, wir in der
Übung benutzen eigentlich nur den Standard-Typen, also da brauchen Sie
keine großen Gedanken machen, der hat dann die Struktur, die ich Ihnen
gerade vorgebetet habe.
Naja, wie gesagt, die hier ist zu groß, also wir haben nur Main, Test
und Java und Ressources und das gleiche unter Test.
Target ist da nicht dabei.
Standardmäßig, der wird generiert, sobald Sie Maven dazu bringen, Ihr
Projekt zu bauen, dann wird dieser Target-Ordner angelegt.
Die Pfiffigen unter Ihnen haben jetzt schon gemerkt, der Target
-Ordner, das ist vielleicht was, was in der Git Ignore drinstehen
sollte.
Und warum sollte der drinstehen?
Naja, das kann ich jederzeit wieder bauen.
Wenn ich Maven sage, pack mir mein Programm zusammen, dann entsteht
dieser Target-Ordner sowieso.
Das heißt, ich muss mein fertig gebautes Programm, verpacktes Programm
nicht immer mit in ein Git-Depot übertragen, weil das kann ich
jederzeit aus den Quellen wiederherstellen.
Wie gesagt, es gibt einen Typen und dann muss ich natürlich irgendwie
meinen Projekt identifizieren können.
Und dafür gibt es so eine Artifact-ID.
Die ist bei uns immer Ihre Matrikelnummer, damit wir Sie eindeutig
identifizieren können, Ihren Artefakt.
Und dann gibt es eine Group-ID, die ist bei uns vorgegeben über das
Übungsblatt.
Das ist im Wesentlichen zur Identifizierung da.
Also stellen Sie sich vor, Sie haben ein großes Projekt, das aus
kleinen Teilprojekten besteht.
Dann wählen Sie vielleicht eine einheitliche Group-ID, weil es geht
immer, dieses Projekt gehört zu einer gewissen Gruppe.
Und da gibt es wiederum Teilmodule und da benutzen Sie halt andere
Namen für Artefakte.
Wichtig ist, wir haben auch immer noch eine Versionsnummer.
Ich hoffe mal, die kommt noch auf eine Folie.
Ah ja, gut.
Also diese Artefakte, die haben auch immer eine Version.
Ist irgendwie logisch, wenn ich irgendwas weiterentwickele, dann
möchte ich vielleicht auch einfach mal eine neue Version vergeben
können.
Das hilft dann später beim Zusammensammeln der Artefakte enorm, wenn
man weiß, welche Version man eigentlich haben möchte.
Vielleicht möchte man auch mal eine alte Version verwenden.
Gut.
Noch ein bisschen Vokabular.
Wie funktioniert dieses Maven?
Wie gesagt, Sie können das aus Eclipse aufrufen.
Das zeige ich Ihnen auch gleich noch, wie das funktioniert.
Sie können das aber auch aus der Kommandozeile aufrufen.
Und da sehen Befehle bei Maven immer so aus, dass wir sagen, welches
Plugin soll denn bitte bedient werden und was ist denn das Ziel, was
dieses Plugin ausführen soll.
Maven arbeitet stark Plugin-orientiert.
Das heißt, Sie können dieser POM-XML angeben, welche Plugins verwendet
werden sollen, zum Beispiel zum Kompilieren, zum Beispiel zum Testen.
Und für jedes Plugin können Sie immer noch sagen, okay, folgende Ziele
kannst du haben.
Und das ist genau das, wie Sie das aufrufen.
Das heißt, damit können Sie dann das, was Sie vorher in der POM
definiert haben, zum Beispiel eben, wie gesagt, ein Test-Plugin,
können Sie dann sagen, okay, jetzt Maven-Test.
Und dann führt Maven für Sie alle Unit-Tests aus.
Das ist also noch eine andere Möglichkeit, um alle Tests auszuführen
für Ihr Projekt.
Genau.
Hier sehen Sie, wie Sie ein leeres, neues Projekt erzeugen,
beziehungsweise ein Artefakt erzeugen.
Das zeige ich Ihnen jetzt aber nicht, weil, ganz ehrlich, wer benutzt
das schon?
Ich zeige Ihnen dann lieber gleich noch, wie man das auch in Eclipse
machen kann.
Wer das tatsächlich aus der Kommandozeile machen möchte, der kann das
gerne nachlesen.
Wie gesagt, man kann dann eben Gefehle aufrufen.
Ich habe gerade eben schon Test gesagt, man kann aber sagen,
kompiliere mir doch mal bitte alles mit Maven Compile.
Auch das ist ein Plugin, was Maven benutzen kann.
Das ist im Wesentlichen genau das Gleiche, was passiert, wenn Sie den
Play -Button in Eclipse drücken.
Dann wird auch kompiliert.
Testen ist eine andere Möglichkeit, was man machen kann.
Genau, man kann auch noch verpacken.
Ich überlege gerade, wie viel kommt denn eigentlich noch?
Lohnt das, noch weiterzumachen?
Das habe ich schon gesagt.
Viele können voneinander abhängen.
Denn wenn ich zum Beispiel sage, ok, verpack mir das doch mal in einen
Jar, dann weiß Maven automatisch selber, naja, bevor ich was verpacke,
sollte ich vielleicht sicherstellen, dass das sinnvoll ist, was ich da
verpacke.
Das heißt, ich rufe alle Tests erstmal auf.
Und bevor ich verpacke, stelle ich sicher, dass alle Tests grün sind,
also durchlaufen.
Solche Sachen werden in Maven auch abgebildet.
Und ich glaube, den Rest erkläre ich Ihnen am Montag.
Allerdings, noch bitte kurz Ruhe.
Ich mache noch ganz kurz die letzte Folie auf.
Ich hoffe, dass das funktioniert.
Ha, wunderbar.
Es fehlt nicht mehr viel zu Maven, es sind noch zehn Folien.
Wer möchte, kann sich die gerne schon anschauen.
Ich werde am Montag nochmal vorbeikommen und werde Ihnen nochmal den
Rest zu Maven erklären.
Sie müssen es jetzt schon verwenden auf dem ersten Übungsblatt.
Das heißt, machen Sie sich damit vertraut.
Alles, was wir hier in der Vorlesung erzählen, kann man auch
nachlesen.
Es gibt auch ein Tutorial, das heißt, glaube ich, Maven in 10 Minuten.
Damit kann man das auch wunderbar lernen.
Und noch was, bevor hier große Unruhe ausbricht.
Maven ist am Anfang ein bisschen frickelig, aber es lohnt sich, das
jetzt gerade am Anfang zu lernen.
Ein Kollege von mir hat mal gesagt, das hat eine rechteckige
Lernkurve.
Die ist aber nicht besonders hoch.
Das heißt, springen Sie da drüber.
Also versuchen Sie wirklich, Maven so weit zu verstehen, wie wir es
für die Übung brauchen.
Und dann haben Sie auch kein Problem über das Semester.
Dann sehen wir uns am Montag wieder.