Ok, dann sollten wir langsam anfangen.
Ich würde euch wieder bitten, dass Reden langsam einzustellen,
damit dann diejenigen, die zuhören wollen, auch zuhören können.
Prima. Ja, hi, herzlich willkommen zur zwölften Vorlesung OOPM,
SE2. Es geht aufs Ende zu. Ich glaube,
nach dieser Vorlesung gibt es noch zwei weitere Vorlesungen,
bei denen ich nicht mehr dabei sein werde.
Das heißt, das ist heute hier meine letzte Vorlesung an
der Uni. Ja, ja, ganz traurig.
Lacht ihr nur. Heute geht es um das Thema Refactoring.
Also sozusagen ein ganz, ganz schönes, kleines isoliertes Thema,
das in der Softwareentwicklung inzwischen eine relativ große Rolle spielt.
Kommt aus der Welt der agilen Softwareentwicklung,
in der das sozusagen selbstverständlich war,
dass man
das machen muss
Da gibt es also eine relativ große Kultur. Ich werde
kleine Motivation machen wieder, warum man überhaupt das Thema betrachten sollte.
Wir werden dann gucken, was heißt Refactoring,
beziehungsweise auch, was heißt es nicht.
Gucken wir uns dann so ein bisschen die Anhaltspunkte an,
bei denen man üblicherweise ansetzt, um zu refactern.
Dann gucken wir uns ein bisschen genauer an,
wie die Mechanik von Refactories aussieht. Das heißt,
aus welchen elementaren Schritten sich so ein Refactoring zusammensetzt. Das heißt,
wir werden uns auch sehr genau mal ein Refactoring ansehen,
um einfach auch würdigen zu können, was da passiert,
wenn ihr die Werkzeugunterstützung für Refactorings in Entwicklungsumgebung in Anspruch nehmt.
Da passiert nämlich relativ viel, was euch möglicherweise gar nicht
bewusst ist. Und es ist auch teilweise nicht das,
was ihr euch wünscht. Und das werden wir hoffentlich am Beispiel
uns dann mal ansehen können. Das, sagen wir,
die gründlichste Aufarbeitung des Themas Refactoring hat natürlich Martin Fauler vorgenommen.
Das ist sozusagen der The good father of refactoring ist natürlich völlig unangemessen.
Der Mensch kann einfach nur gut schreiben und hat das entsprechend auch gut festgehalten,
hat ein sehr, sehr gründliches Buch zum Thema Refactoring geschrieben.
Das heißt, Refactoring in kann man eigentlich immer sagen,
objektorientierten Systemen, das ist schon quasi implizit klar.
Und Kollegen von mir, die ehemaligen Kollegen hier in der Softwaretechnik,
in Hamburg an der Uni, die haben auch ein Buch geschrieben,
wenn man mal so ein bisschen eher so in größere Kontexte hineinkommen will.
Also das, was der Martin Fauler beschrieben hat,
sind sehr kleine, zielte Änderungen am Quelltext.
Und ich werde gleich auch nochmal darauf eingehen,
dass er auch der Meinung ist, dass man die auch so klein lassen sollte.
Okay, die Motivation ist nicht neu. Das ist eine
Folie, die habe ich mindestens schon einmal gezeigt.
Also Guido hat sie auf alle Fälle schon mal gezeigt.
Das ist immer wieder der Anhaltspunkt, wo wir überlegen müssen,
naja, das eine ist, dass die Software das leistet,
was sie leisten soll, dass sie ihre Funktionalität erfüllt,
dass sie ihren Zweck erfüllt, sehr schön.
Aber es reicht nicht, wenn Software lauffähig ist,
sie muss so geschrieben sein, dass sie auch über Jahre,
vielleicht sogar Jahrzehnte gepflegt werden kann, von Programmierern,
die möglicherweise nicht selbst das Programm entwickelt haben.
Das passiert ständig und überall. Es ist sogar so,
dass man sagen kann, wenn Software nicht angefasst wird,
nicht überarbeitet wird, nicht von irgendjemandem weiter gepflegt wird,
dann ist sie relativ schnell veraltet.
Dann stirbt sie. Also die Software selbst tut gar nichts,
aber das Umfeld, in dem wir uns bewegen mit Software,
das ist ziemlich schnelllebig. Nach wie vor ist es so,
dass da ziemlich schnelle Zyklen sind, Hardwarezyklen, Softwarezyklen,
Betriebssystemzyklen und so weiter. Das heißt,
wenn man da nicht am Ball bleibt, mit einer Software,
dann ist die Software irgendwann veraltet und funktioniert teilweise gar nicht mehr
oder macht nicht mehr das, was sie machen sollen.
Ich habe das, auf der anderen Folie ist das ein
bisschen begründet mit einem oder untermalt mit einem Zitat von David Partners.
Ich habe hier ein Zitat von Martin Fowler aus seinem Buch,
das ich sehr schön prägnant finde, dass man aber auch ein bisschen differenzieren muss.
Er sagt hier, any fool can right code that the
computer can understand
Good program as right code that humans can understand.
Das heißt, was er hier behauptet, jeder Fool,
any fool, jeder Dummkopf kann Software schreiben,
die ein Computer versteht, das ist natürlich nicht wahr.
Auch das ist schwierig. Auch das ist schwierig zu verstehen,
was macht ein Java-Programm, was bewirkt es im Speicher,
wie kriege ich die Software dazu,
dass sie genau den Zweck erfüllt.
Das ist schon nicht leicht, wenn es so leicht wäre,
dann würdet ihr hier nicht sitzen, dann gäbe es kein Informatikstudium.
Das ist anspruchsvoll. Das ist tatsächlich anspruchsvoll.
Aber es ist eben halt nur der halbe Weg,
wenn man nachhaltig Software entwickeln will
Also irgendwas hinhackeln, was irgendwie läuft. Gut, kann man machen.
Was richtig spannend ist, ist Software so zu schreiben,
dass jemand anders die auch gut weiterpflegen kann.
Also die Entwurfsentscheidung gut darzulegen, gut klarzumachen,
warum die Software an einer Stelle so gebaut ist,
wie sie gebaut ist.
Das sind alles Sachen, die sind schwierig.
Oder einfach nur Software so zu schreiben,
dass man einfach vom Lesen sofort weiß, was da eigentlich passiert.
Nicht irgendwelche kryptischen Variablen Namen zu nehmen und ähnliches.
Das ist also so quasi das Mantra,
die unterschwellige Grundannahme
Vor dem man jetzt das Ganze auch betrachten muss,
was hier wir zum Thema Refactoring uns ansehen werden.
Der Ausgangspunkt in Foulers Buch ist genau die Frage von üblen Gerüchen.
Also Bad Smells hat er je genannt. Und die Idee ist,
ist immer wieder, wenn ich, wenn ich Software habe,
die geändert werden muss und das passiert immer wieder,
dass ich Software anpassen muss,
entweder neue Anforderungen oder ich stelle fest,
dass Teile der Software geändert werden müssen,
weil ich einen anderen Entwurf machen will,
sobald ich über Änderungen nachdenke in einer bestehenden Softwarearchitektur
Das ist alles das, was meine Änderungen erschwert, problematisch.
Und das werdet ihr, wenn ihr mit Software zukünftig umgeht,
noch an ganz vielen Stellen sehen. Es gibt einfach immer wieder,
ja, die Situation, wo man sagt,
oh Mensch, wenn ich das jetzt hier reinbaue,
dann ist das richtig aufwendig, dann muss ich alles umbauen,
dann ist das total kompliziert, muss ich den ganzen Entwurf ändern.
Und da gibt es eben halt kleine und große Hindernisse,
die da existieren können für solche Änderungen.
Und er nennt die halt üble Gerüche, Bad Smells,
also Der erste Hinweis, den ich jetzt so geben kann,
ich habe ja schon die Vorlesung gehalten, über auch Klassenentwurf und über Entwurfsregeln.
Das sind so die klassischen Sachen so, eine Methode ist zu lang,
um sie auf den Bildschirm überblicken zu können.
Eine große Methode, Bad Smell, keine gute Idee,
das ist schon hinten Anlass, die vielleicht mal so ein bisschen zu zerkleinern.
Oder dieselbe Fallunterscheidung wird an mehreren Stellen in einem System vorgenommen.
So diese Code-Duplizierung habe ich ja auch schon erwähnt,
das sind so Sachen, das riecht nach Problemen.
Und wenn man eben halt Erfahrung hat mit Softwareentwicklung,
dann versteht man, was gemeint ist, dass das so riecht,
dass man hat so ein Gefühl dafür, oh,
das könnte jetzt hier,
das sehe ich jetzt hier schon mehrfach und das ist eigentlich der gleiche Code,
aber es ist nicht wirklich explizit in eine Methode ausgelagert oder ähnliches
Das heißt, generell, das sind diese Verstöße gegen bekannte
Entwurfsregeln, durchaus erstmal Kandidaten für üble Gerüche. Okay,
bevor wir da jetzt nochmal genauer drauf eingehen,
erstmal jetzt, was heißt Refactoring und ich glaube,
die knapste und treffendste Definition steht hier auf der Folie,
das ist mehr oder weniger das, was der Foul da auch schreibt.
Refactoring bedeutet, die interne Struktur einer Software zu verbessern,
ohne ihr beobachtbares Verhalten zu ändern. Das ist schon eine relativ wichtige Definition,
da steckt einiges drin, also was man sofort sieht,
was Refactoring demnach eben nicht ist, das Einfügen zusätzlicher Funktionalität.
Also wenn ich eine Software habe und neue Funktionalität hinzufüge,
dann ist das kein Refactoring.
Es wird so häufig so lapidar oder so ein bisschen beiläufig dann gesagt,
ich muss das mal refactoren, da bin ich da,
muss ich jetzt hier was Neues reinbauen, muss das refactoren.
Refactoren heißt nicht einfach ändern. Im Deutschen wird oft
Refactoren übersetzt mit, ich ändere meine Software.
Das ist auf jeden Fall nicht richtig. Also es gibt Änderungen,
wie zum Beispiel das Einfügen neuer Funktionalität, das ist kein Refactoring.
Auch wenn ich Fehler in Software behebe, ist das kein Refactoring.
Man könnte jetzt argumentieren, naja, wenn ich einen Fehler behebe,
dann ist das ja nur was,
was in der internen Struktur auftritt und möglicherweise nach außen gar nicht sichtbar wird.
Aber meistens ist es schon so, dass man sagt,
dass das Beheben von Fehlern kein Refactoring ist.
Insbesondere dann, wenn natürlich diese Fehler nach außen hin wirken,
dann ist es sowieso klar.
Also wenn es ein Fehler in der Software ist,
der durch einen Benutzer erkennbar ist, durch den Benutzer der Software,
also die sozusagen nach außen sichtbar wird,
dann ist das Beheben eines solchen Fehlers garantiert kein Refactoring.
Also alles das,
was von außen beobachtbar ist.
Kein Refactoring
Auch was nach außen beobachtbar ist, aber sagen, vielleicht kaum auffällt.
Also wenn ich zum Beispiel eine Änderung am Layout der Gui mache,
also einfach so,
ich ziehe das Fenster größer und dann zieht sich irgendwie ein anderer Bereich,
wird größer und anderer bleibt stabil.
So dieses, was ihr von den Swing-Komponenten kennt.
Auch das ist schon beobachtbar und somit nicht mehr ein Refactoring.
Es gibt aber auch Änderungen an der Gui-Struktur,
die das nach außen beobachtbare Verhalten,
also welche Bereiche werden größer gemacht,
gleichhalten und trotzdem intern andere Klassen verwendet werden.
Das wäre dann wieder
ein Refactoring
Also das erst mal so als ganz wichtige Grundannahme.
Refactoring heißt erst mal, ich ändere etwas an der
internen Struktur, was nach außen nicht sichtbar ist.
Der Fouler hat dann irgendwie Jahre später auch noch mal das
ein bisschen konkretisiert und hat auch noch mal deutlich gemacht,
dass er unter Refactoring schon sehr speziell versteht, kleine Änderungen.
Er sagt, hier, refactoring is a very specific technic,
founded on using small behaviour preserving transformations.
If you are doing refactoring your system should not be broken
for more than a few minutes at the time.
And I don't see, how you do it on something
that doesn't have a well defined behavior. Das heißt,
wenn ich das Verhalten der Software gar nicht genau scharf habe,
wenn ich es gar nicht so genau weiß, was das Verhalten ist,
dann wird es relativ schwierig zu garantieren, dass das Verhalten sich nicht ändert.
Also man muss schon eine sehr klare Vorstellung haben,
was denn das definierte Verhalten ist,
um dann auch sagen zu können, genau, mit dieser Änderung,
in der internen Codestruktur ändere ich das Verhalten nicht.
Aber er sagt ihm halt auch vor allen Dingen,
so ein Refactoring sollte nur so ein System für ein paar Minuten in einen instabilen Zustand bringen.
Also es gab dann eine Zeit lang so diese Untersuchung in Richtung von großen Refactorings,
wo man dann sowas hatte wie Über mehrere Monate ist das System in einem instabilen Zustand,
weil einfach große Änderungen vorgenommen werden müssen.
Diese großen Änderungen waren dann eigentlich in der originären Definition von fauler
keine Refactorance. Also es sollte wirklich so sein,
Refactoring sollten relativ kleinschrittig sein und auch immer, ja,
behavior prezay, preserving, preserving sein.
Das heißt also, das Verhalten beibehalten. Okay,
jetzt hat er hier schon drüber geschrieben,
irgendwie Refactoring is is Technique, also irgendwie eine Tätigkeit.
Und dann diese kleinen Transformations, das sind auch Refactorings,
die haben im Self-Called Refactorings, also er sagt auch schon.
Man muss aufpassen, wie man den Begriff verwendet.
Und das ist auch für uns erstmal jetzt ganz,
ganz sinnvoll, nochmal genau zu gucken.
Es gibt da drei verschiedene Deutungen des Begriffs Refactoring.
Also einmal kann ich eine konkrete Restrukturierung in einem Software-System,
die kann ich ein Refactoring nennen. Ich habe eine Methode,
füge ein und ich benenne die um, in Einfügen.
Das ist keine großartige Wahnsinns-Spannende Änderung,
aber ich habe eine konkrete Klasse, ich habe eine konkrete Methode,
vielleicht auch ein Interface, wie auch immer, eine Klasse.
Ich benenne eine Methode und das ist ein konkretes Refactoring
Einer bestimmten Stelle. Dann gibt es die, das,
was eigentlich der Fouler in seinem Buch beschreibt,
er beschreibt nämlich Klassen von Restrukturierung. Das heißt,
diese Tätigkeit, dass man generell irgendeine Methode umbenennt,
das ist eine ganze Klasse von Refactorings,
die er dann Rename Method nennt.
Also Methode umbenennen oder Methode extrahieren. Das sind so Tätigkeiten,
die man generell machen kann. Die kann man also sozusagen vom
konkreten Quelltext abstrahieren und sagen, das kann ich auf jedes beliebige Quelltextstück anwenden.
Also eine Klasse von Restrukturierungen,
die aber sehr konkret benannt werden können in diesem Buch,
Buch von dem Fowder sind so 60, 70,
glaube ich, Refactorings benannt, aufgeführt.
Das ist ein ganzer Katalog von Refactorings.
Und das im Sinne von so Klassen von Restrukturierung.
Ihr kennt ja diesen Zusammenhang, Klassen und Exemplar.
Also ich habe die allgemeine Klasse Rename Method, also Methode umbenennen.
Und dann habe ich eine konkrete Umbenennung, kann ich dann benennen in einem Quelltext.
Und man kann aber auch noch dann betrachten, die Tätigkeit des Restrukturierens.
Also wenn ich refactore, schön denglisch, dann ist das
auch eine Möglichkeit, Möglichkeit, das zu benennen.
Das heißt, beim Refactoren zum Beispiel haben wir festgestellt,
dass wir noch einige Leichen im Keller haben, bei unserer Software.
Das heißt, das muss man schon immer so
ein bisschen genauer unterscheiden, was da gerade gemeint ist.
Und weil das unterschiedliche Bedeutungen hat teilweise,
habe ich das jetzt hier auch mal so ein bisschen hervorgehoben.
Also diese Klasse von Restrukturierung mit einem K und die anderen mit einem Tee.
Das heißt immer, wenn die Tätigkeit gemeint ist, steht dann in Klammern das Tee dahinter. Also hier zum Beispiel, was ist denn eine schlechte Metapher für Refactoring? Also wenn Leute sagen,
was Refactoring ist, dann gab es in der Frühzeit dieses Aufkommens von agiler Softwareentwicklung gab es durchaus Leute,
die gesagt haben, ach ja, naja, Refactoring,
ja, so ein bisschen den Quelltext aufhübschen, ja,
also wir haben irgendwie eine Wohnung und wenn wir ein paar Bilder aufhängen und die Fände streichen,
dann sieht es halt netter aus,
dann fühlen wir uns wohler und das ist,
kann man machen, aber ist eigentlich albern, ja, so,
das war durchaus so eine ablehnende Haltung gegenüber dem Thema Refactoring,
so, wir dekorieren es, wir hübschen unseren Quelltext auf,
Quelltextkonventionen sind ja auch nur, ach, damit es hübsch aussieht,
nö, es hat ganz pragmatische Zwecke,
das ist also eigentlich keine gute Metapher
Also das wird diesem Anspruch dieser Tätigkeit von Refactory überhaupt nicht gerecht.
Geht nicht um Schönheitspreise, so elegant, sondern es geht
um schlichte Notwendigkeiten. Deswegen auch, wie ich finde,
eine deutlich bessere Metapher ist restrukturieren, ist wie Müll raustragen.
Also Refactoren heißt, in einem Softwaresystem passieren viele Änderungen,
ständig wird irgendwas geändert, angepasst und so weiter.
Da wird viel bewegt und da bleibt immer mal so
ein bisschen so ein Krümel liegen.
Da lässt man mal so ein Kommentar stehen,
der nicht mehr dazu passt zu der Methode.
Da passiert immer mal was. Das ist so ein bisschen
eher die Metapher,
die Küche
Wenn ich in einer Küche nicht regelmäßig aufräume,
dann werde ich irgendwann nicht mehr vernünftig daran arbeiten können.
Also, dass die Standardanekdote, die ich an dieser Stelle erzähle,
ist, als ich Wimi war in Ulm,
an der Uni, war ich mal auf einer Studentenparty.
Und das war so eine WG-Küche. Und da lagen dann
irgendwie in der einen Ecke fünf gelbe Säcke.
Und ihr wisst ja, wenn Gelber sagt,
eine Weile liegt, dann riecht er nicht mehr so gut.
Das war also ein insgesamt anstrengender Geruch in der Küche,
den man nur mit ausreichend Alkohol irgendwie ertragen konnte
Das ist einfach unschön. Das ist aber nicht nur unschön,
sondern es wird dann irgendwann tatsächlich nicht mehr praktikabel.
Dann kann ich nicht mehr vernünftig arbeiten.
Also wenn ich nicht immer meine Sachen wegräume,
die ich irgendwie mal so beim Arbeiten liegen gelassen habe,
dann geht es irgendwann schief.
Und dann erstickt man in seinem eigenen Müll und das ist nicht
so angenehm. Also das ist eher die bessere Metapher.
Müll raustragen. Das mit dem Dinge in Ordnung halten und
Dinge, ja, auf dem Stand halten.
Es ist nicht nur eine Frage der Ästhetik
Wie gesagt, nicht nur eine Frage der Ästhetik,
sondern auch Notwendigkeit, aber es gibt auch eine psychologische Komponente.
Und diese psychologische Komponente, die wird so in der Broken
Window Theory formuliert. Könnt ihr vielleicht auch noch mal nachlesen,
wenn ihr das wollt, aber das ist eigentlich verkürzt relativ einfach,
die Idee, wenn irgendwo etwas kaputt ist,
dann zieht das auch weitere defekte Verschmutzungen und Ähnliches nach sich.
Das heißt, ein Beispiel ist, wenn an Wänden Graffitis sind,
und jetzt spreche ich nicht von richtig coolen Graffitis, von Künstlern,
sondern ich spreche von irgendwelchen blöden Parolen oder von irgendwelchen, einfach nur Spraydosen-Schmierereien.
Wenn da erstmal was ist an der Wand, dann kommt da relativ schnell mehr dazu.
Das ist also so, das zieht das einfach an.
Anderes konkretes Beispiel war diese Geschichte da in den USA.
Ein Auto steht irgendwie wochenlang auf einem Parkplatz, nichts passiert.
Dann wird ganz gezielt bei dem Auto, dass diesem Versuch irgendwie gedient hat,
eine Scheibe eingeschlagen und siehe da in den nächsten paar Tagen ging es relativ schnell,
dass dieses Auto weiter kaputt gemacht wurde, weitere Scheiben wurden eingeschlagen.
Es wurden Räder geklaut und so weiter. Also Jungen,
wo man sagt, Wenn man sieht, das Auto ist kaputt,
scheint es, die psychologische Hürde zu senken, sich verkehrt zu verhalten.
Das heißt also, Leute haben dann einfach auch Scheiben eingeschlagen,
haben dann auch Dinge demontiert und so weiter.
Und ich habe das auch in Ulm gehabt,
da gab es irgendwie so ein Abbruchreifes Haus,
eingeschlagene Scheiben und bin dann da so eine Scheibe noch so ein Stück steht,
dann ist man auch eher mal versucht,
da nochmal vielleicht ein Steinchen hinterher zu werfen,
was ich natürlich nicht gemacht habe.
Aber man ist eben stark versucht, der psychologische Aspekt ist nicht zu verachten.
Und das ist tatsächlich in Software-System genauso. Wenn ihr in ein Software-System hineinkommt,
also ihr kommt in ein Team rein und sollt da mitarbeiten.
Und es gibt keine Quelltextkonventionen. Jeder Programmierer macht, was
er will. Alle haben so richtig keinen Bock und ach
naja, kannst du machen, wie du willst.
Und dann seid ihr alleine wahrscheinlich relativ in einer schwachen Position zu sagen,
hier, wir müssen Quelltextkonventionen eingeführt werden, wir müssen irgendwie einheitlich das Ganze gestalten,
damit wir das besser warten können und so.
Da müssen alle mitziehen. Und wenn eben halt sozusagen die
Moral schon niedrig ist, dann ist es relativ leicht,
dann auch relativ schnell sich da mit reinziehen zu lassen.
Und dann gibt sich eben niemand mehr Mühe und das ist genauso dieser verhängnisvolle Effekt.
Das geht also relativ schnell. Das heißt also so,
Das ist schon durchaus sinnvoll, Software auf einem guten Stand
zu halten, auch in der internen Struktur.
Okay, ich hatte eben erwähnt, üble Gerüche ist das,
was Martin Fauler so als Anlass nimmt, um Refactorings vorzunehmen.
Ich gehe jetzt nochmal so ein bisschen auf kleinere Beispiele ein,
also so die Code-Duplizierung zum Beispiel,
ich habe ja schon über Code-Duplizierung gesprochen, als eine Entwurfsverletzung,
es führt zu, es gibt eine implizite Kopplung,
ich habe denselben Tod an drei Stellen,
dann sind die irgendwie identisch und wenn ich jetzt an der einen Stelle feststelle,
oh, da ist was faul,
ändere ich das Korrigieren einen kleinen Fehler, weiß aber nicht,
dass derselbe Code nochmal an zwei anderen Stellen ist.
Dann ist diese implizite Kopplung blöd, weil ich eigentlich es
auch an den beiden anderen Stellen korrigieren müsste.
Ich weiß es aber gar nicht, weil sie nur implizit gekoppelt sind.
Das heißt, das ist schwierig und ich hatte ja auch schon gesagt,
das ist auch ein Zeichen von niedriger Korrision.
Also wenn da irgendwo dasselbe an drei Stellen passiert,
dann sollte man darüber nachdenken, ob man das nicht eigentlich an einer anderen Stelle einmal implementieren sollte.
So und da geht es dann schon in die Richtung von so,
was kann man dann machen und da geht es in Richtung von Refactoring.
Anderes Beispiel, große Einheiten, die Gottklasse ist für alles zuständig,
macht alles, hält 90 Prozent des Quelltextes oder große Methoden, die über mehrere Bildschirmseiten gehen.
Das sind so die Bloater, also diese Dinge,
die Software groß und unhandlich machen und unhandliche Software erschwert,
Änderungen und deswegen ein klarer Hinweis, das riecht komisch,
also auch da sollte man mal mit Refactoring rangehen.
Als ich nochmal durch den Fauler geblättert habe, da fiel mir auch ein,
dass er auch ein bisschen was sagt über Kommentare.
Das finde ich ganz interessant, er hat also die Haltung,
dass Kommentare fast immer ein Zeichen von üblem Geruch sind.
Also Kommentare schreiben sieht er als eine Form von üblem Geruch an.
Das finde ich interessant. Ich glaube, er meint das
nicht ganz so hart. Also es ist sicherlich sinnvoll,
bei einem Interface zu schreiben, was denn die Operationen tun.
Das ist ungenommen. Aber eigentlich sagt er im Code,
also wenn ich wirklich in die Methodenrümpfe reinschaue und da Kommentare sehe,
dann ist das fast immer überflüssig. Ich habe,
glaube ich, auch mal irgendwann hier so erwähnt,
dass es sowas gibt wie Lärm und Schweigen,
also so Quelltext-Kommentare, die eigentlich das Gleiche sagen wie das,
was im Quelltext schon zu lesen ist.
Wenn ich eine Variable deklariere, eine lokale Variable, in Zähler.
Und dahinter steht dann irgendwie die intvariable Zähler als Kommentar.
Das ist totaler Schwachsinn. Ja, das kann jeder,
der lesen kann, selber lesen. Was spannender ist bei solchen Kommentaren,
wenn man sie denn tatsächlich mal diskutieren will,
ist meist nicht, was die Software an der Stelle tut,
das kann man teilweise auf einer etwas höheren Ebene vielleicht auch mal kommentieren.
Also da ist irgendwie so eine mehrfach geschachtelte Schleife und
ich schreibe daneben hier Deixtra Algorithmus implementiert.
Dann hilft einem das vielleicht schon, das schneller zu verstehen.
Dann ist das vielleicht ein Kommentar, der hilft.
Aber oft ist ein Kommentar auch dann hilfreich,
wenn er beschreibt,
warum etwas so ist
Also nicht, was passiert hier, sondern warum haben wir
das denn so gemacht? Also welche Entscheidung hat dazu geführt,
dass wir an dieser Stelle jetzt diesen Weg gewählt haben?
Das sind also so Sachen, die sollte man im Quertext
bei Kommentierung stark am Auge behalten.
Man kann also relativ blöde Kommentare schreiben. Und das ist das,
was er auch unter anderem miterwähnt bei seinen Refactoring-Betrachtungen.
Weiteres Beispiel hier die Verletzung des Law auf die Mieter,
habe ich ja ein bisschen was drüber erzählt.
Also diese sehr häufig auftretenden Ketten von Aufrufen hier,
tatsächlich also ein Objekt, an dem Get Record aufgerufen wird,
an dem resultierenden Objekt, wird Get Exam Antry aufgerufen,
dann wird die Sache wieder add
Result 93 aufgerufen. Also das ist so eine klassische Ausprogrammierung
in einer Zeile von einer ganzen Objektstruktur. Das heißt,
da wird an dieser Teile festgebunden, diese Objektstruktur muss so sein.
Ich muss sie genauso travisieren. Das heißt,
wenn ich diese Struktur ändern will, das passiert ja häufig,
dass man irgendwie in einem Objektgeflecht sagt, hier würde ich jetzt,
glaube ich, die Struktur ein bisschen ändern,
das würde zukünftig das alles ein bisschen leichter machen.
Jetzt gibt es aber 15.000 Stellen im Quelltext,
wo diese Struktur explizit mit solchen Zahlen travisiert wird.
Dann muss man das alles restrukturieren. An allen Stellen muss
da wieder hingeguckt werden. Deswegen ist sowas immer unglücklich.
Und auch das wieder ein Hinweis auf Bedarf für Refactoring.
Und wir haben da ja schon mal so ein bisschen so angeguckt,
wie das dann aussehen könnte,
dass ich gar nicht irgendwie ich als Programmierer jetzt an der Stelle sage,
ich traversiere das alles selber, ich muss jetzt die Aufgabe lösen,
sondern ich überlege mir, wer ist dafür zuständig?
Und ich kann ja sagen, hallo, Studentobjekt,
du hast so eine Operation Adscore und ich gebe dir so
eine Score-Tabelle rein und du holst dir das dann da selber raus.
Du weißt ja, du kennst deine eigene Matriko-Nummer und weißt jetzt,
an welcher Stelle du jetzt da das Ergebnis rausholen musst.
Ich muss es nicht alle selbst machen,
sondern das kann tatsächlich, können die Objekte selber machen.
Ich kann die Objektenverantwortung abgeben, Zuständigkeiten. Also dieses Entwerfen nach Zuständigkeiten. Okay. Was,
wenn man sich jetzt mit diesen Refactorings von dem Foul ein bisschen näher beschäftigt,
dann kommt man relativ schnell darauf, dass er das sehr kleinschrittig beschreibt.
Also diese Refactorings wirklich in so kleine Schritte zerlegt,
in so Subschritte, in so kleine mechanische Einheiten.
Und das ist für das Verständnis von Refactoring ist ziemlich wichtig.
Und wenn man sich jetzt gleich mal,
wenn wir uns gleich mal eins angucken, dann sieht man auch,
dass das teilweise ganz schön clever ist, was da so gemacht wird,
um einfach das in Schritten machen zu können, das Refactoring,
von denen jeder Schritt mehr oder weniger sicher ist.
Das heißt, diese Schritte sollten möglichst klein gewählt werden.
Das ist was, was ganz stark vertreten wird in der
Agil- und Softwareentwicklung, macht kleine Änderungsschritte.
Dann seid ihr immer sicher, dass ihr das auch wieder
leicht zurücknehmen könnt und dann auch möglichst schnell feststellen könnt,
wenn was schief geht. Und das ist bei Founder,
wie gesagt, bei seinen Refactorings, bei diesen Refactoring-Klassen,
die ihr definiert, sind immer diese Mechanics angegeben.
Da gibt es eben halt solche Sachen wie,
erzeuge eine neue Klasse mit einem bestimmten Namen oder füge eine neue Methode hinzu,
kopiere den Quelltext einer Methode in eine andere.
Das sind so Teilschritte, die dann zusammengesetzt werden zu einem Refactoring.
Und das, was da so beschrieben ist,
das klingt alles total einfach. Und der gute Erich Gamma,
der hat das Vorwort geschrieben zu dem Buch von Faula und hat irgendwie geschrieben,
some of the refactory is may seem obvious.
But don't be foold understanding the mechanics of such refactorings
is the key to refactory in the disziplin way.
Das versuche ich jetzt hier auch so ein bisschen aufzugreifen
Dass wir jetzt uns mal so ein Refactoring etwas genauer ansehen,
um dann zu sehen, was da so in den Mechanics passiert.
Ich weiß nicht, ob ich schon was zu Erich Gamma gesagt habe.
Das ist so in meinem Weltbild der Informatik so einer,
der auf der gleichen Stufe steht wie, was weiß ich,
ein Dixtra oder ein Horror oder ein Cantback.
Das ist also jemand, der ziemlich viel beigetragen hat.
Ich weiß nicht, wird euch das so bekannt ist,
aber der hat zum Beispiel eines der erfolgreichsten Bücher der Informatik mitgeschrieben.
Design-Patterns auf Object Orient de Software.
Da ist er Mitautor, dadurch ist er sehr bekannt geworden
Mitte der 90er
Dann hat er an Entwicklungsumgebung mitgearbeitet bei IBM und hat dann
unter anderem auch bei IBM OTI Eclipse mitentwickelt.
Das heißt, Eclipse, das, was ihr so benutzt,
das ist unter anderem auch von Erich Gamma gebaut worden.
Der gute Mann ist Schweizer,
sitzt auch in Zürich und ist so gut,
dass er immer da ist, also dass er immer da bleibt.
Und egal bei welcher Firma er arbeitet, bleibt er in Zürich.
Also er hat zum Beispiel jetzt neuerdings, seit ein paar
Jahren ist er bei Microsoft und arbeitet an Visual Studio mit.
Das heißt, er war schon immer sehr interessiert an
Entwicklungsumgebung,
sowas wie Eclipse
Und hat dann jetzt, ist er bei Microsoft, aber seine Gruppe,
mit der er da entwickelt sitzt, immer noch in Zürich.
Also der Mann ist einfach eine Institution in der Informatikwelt.
Ist aber ein totaler Praktiker. Also der hat zwar promoviert über Informatikthemen,
aber ist dann eben in die Industrie und hat dann Software entwickelt.
Also das ist ein großer Praktiker, genau wie der
Martin Fauler, der auch ein ganz klarer Praktiker ist.
Also der immer so ein bisschen reserviert ist gegenüber der akademischen Welt. Und das ist,
ja, ich will hier nicht so eine Reserviertheit mit aufbauen,
bin ja selber doch eher Akademiker, aber wenn man Softwareentwicklung betreiben will,
ist es schon gut, dass man die Leute fragt,
die das auch intensiv machen.
Und da gibt es eben halt eine ganze Menge Leute,
die das machen ohne einen großen akademischen Hintergrund.
Okay, ach ja, und Jay Unit übrigens ist
auch von Erich Gamma mitentwickelt, zusammen mit Can't Back.
Also das ist wirklich ein guter. Wenn ihr mal irgendwie
ein Interview mit ihm lest oder sowas oder was findet über ihn
, kann man alles lesen.
Der Mann hat wirklich was zu sagen. Gut, jetzt
konkret Mechanik von Methode umbenennen. Also eine konkrete Methode.
Ich habe eine Methode und ich stelle fest,
der Name ist nicht gut gewählt
So. Und ich möchte die jetzt umbenennen. Was ihr natürlich sofort als ersten,
also der naive erste Schritt ist, ich gehe in den Quelltext,
wo die Methode deklariert ist und ändere sie.
Den Namen kann ich einfach ändern. Wird nicht so ohne weiteres funktionieren,
weil es ja ganz viele Klienten geben kann, die die Methode aufrufen.
Das heißt, ich muss auch die Methoden Aufrufe irgendwie ändern.
Und das kann zu anderen Problemen führen. Und deswegen hier jetzt
ein systematisches Vorgehen, wie man Methode umbenennen, vernünftig machen kann.
Ich will das mal Also ich kann es erst mal so hier so durchgenannt,
werden wir das an einem konkreten Beispiel mal machen.
Also, die Idee ist erst mal ganz einfach.
Ich benenne nicht einfach die Methode stumpf um,
sondern der erste Schritt ist, ich deklariere die Claire eine,
ah, deklariere, fällt da, da fällt das I,
deklariere eine neue Methode mit einem neuen Namen.
Also mit dem neuen Namen, den die neue Methode haben soll.
Das heißt, ich führe einfach eine neue Methode ein,
die die gleiche Signatur hat, wie die andere Methode,
abgesehen vom Namen.
Und dann kopiere ich den alten Quelltext in die neue Methode rein.
Das heißt, ich habe da jetzt zwei Methoden nebeneinander.
Dann übersetze ich das
Warum übersetze ich an der Stelle schon? Was kann da schiefgehen,
wenn ich so eine neue Methode mit einem neuen Namen einführe?
Was könnte der Grund sein,
dass ich da jetzt nicht einfach weitermache, sondern erstmal übersetze?
Warum ist das sinnvoll? Hat da jemand eine Idee?
Das sieht hier eher Verhalten aus,
Ganz genau, ganz einfache Überlegung. Es kann sein,
dass es die Methode schon gibt. Es kann sein,
dass es in der Klasse, in der ich gerade arbeite,
eine Methode gibt, die so heißt und die Klasse,
die Klasse ist so groß, dass es jetzt nicht sofort sehe.
Oder es ist in der Klasse keine solche Methode zu finden,
aber in einer Oberklasse. Das ist hier so,
hier habe ich schon so Ober- und Unterklassen weitgehend ausgewendet,
aber das ist eben halt genau die Überlegung.
Das heißt, ich prüfe erst mal überhaupt,
ob die Methode eingeführt werden kann mit dem neuen Namen.
Aber alles andere bleibt noch so, wie es ist.
Das heißt, die ganzen Klienten benutzen noch die alte Methode.
Dann mache ich eine Umleitung. So, Umleitung ist so
eine dieser kleinen Grundmechanics, dass man sagt, naja,
aus der alten Methode, rufe ich jetzt die neue Methode auf.
Also alle Klienten rufen die auf und die rufen dann die
neue Methode auf und da steckt ja der gleiche Rumpf drin.
Also das übersetze ich und das teste ich.
Dann der nächste Schritt ist dann, finde alle Referenzen auf
die alte Methode und biege die um auf die neue Methode.
Also ich habe sozusagen jetzt hier die neue Methode und jetzt
gucke ich mir alle Klienten an und da ist ein Klient,
der ruft die alte Methode auf,
biege ich jetzt um auf die neue Methode,
also ändere den Namen um, den Aufruf.
Und das mache ich für alle Stellen.
Da muss ich schon teilweise auch sehr genau hingucken,
ob das auch drumherum alles so passt
Und wenn das alles geklappt hat und ich muss tatsächlich nach jeder Änderung,
nach jeder einzelnen Änderung, sollte ich eigentlich übersetzen und testen.
Nach jedem Klienten. Das ist so von der Disziplin her
erstmal, boah, das hört sich erstmal anstrengend an.
Am Ende entferne ich die alte Methode und da muss man
sehen, ob dann auch noch alles weiter läuft.
Das heißt, übersetzen und testen und auch da wieder testen.
Testen immer im Sinne von, die Tests prüfen ja,
ob die Funktionalität die gleiche geblieben ist.
Okay, und Das ist jetzt hier sozusagen erstmal die abstrakte Beschreibung.
Und das wollen wir uns jetzt mal ein bisschen konkreter angucken.
Und dazu habe ich hier mal ein bisschen geschürft in den Analen von SC2.
Ihr habt ja jetzt in den Übungen den Kinoticket-Verkauf vor der Nase.
Das heißt, ihr habt von uns ein Projekt bekommen,
in dem ein kleines Kinosystem gebaut ist,
wo man dann sozusagen so Plätze in einem Kinosystem verkaufen,
also so ein Kassensystem.
Das sieht für 2014 ungefähr so aus, all das,
was ihr da jetzt so habt, ist ungefähr dieses System.
Man hat also hier so diesen Plan, Platzbereich und dann
habe ich hier irgendwo links meine Liste von Vorstellungen und dann finden
die in verschiedenen Seelen statt, also hier Saal 3,
der ist ein bisschen luftiger bestuhlt und Saal 2 ist etwas
enger bestuhlt und ich kann hier irgendwie so zwischen den Tagen wechseln,
so und ich kann irgendwie hier konkret jetzt mal so zwei Plätze mir aussuchen und dann kann ich sagen,
verkauf die mal, also dann wird hier unten irgendwas angezeigt und dann wird das verkauft und dann sind die Plätze auch verkauft.
Das ist die Funktionalität, die in diesem System verbaut ist,
also das ist relativ intuitiv für jemanden,
der in der Kasse sitzt, denke ich,
ist das relativ einfach benutzbar und das ist auch die Funktionalität,
die wir seit Jahren in dem Kino-Ticket-System drin haben.
Also die Grundfunktionalität ist total gleich geblieben. Also wenn man sich jetzt anguckt,
wie das dann 2013 aussah, dann sieht das nicht viel anders aus.
Also gleiche Oberfläche hier wieder, also so, man sieht hier,
das ist schon alles sehr ähnlich. Hier ist jetzt,
ist es, glaube ich, eine Musterlösung,
die ich da dann schon habe von 2013, man sieht hier,
also hier ist es tatsächlich an einen Euro angegeben, der Preis.
Und wenn ich jetzt verkaufe, kommt hier tatsächlich noch dieses Bezahlwerkzeug,
was ihr bauen sollt oder solltet oder wie auch immer.
Also ich kann jetzt hier sagen, ich habe
nur einen Zwanziger und dann kriege ich 10 Euro wieder.
So, und dann ist der Platz hier verkauft.
Aber im Prinzip ist das die gleiche Software,
gleiche Oberfläche und so weiter
Das war auch 2012 so. Aber diese Systeme, 12,
13, 14, die waren gebaut, intern, in der internen Struktur,
wie ihr das jetzt kennengelernt habt, nämlich nach diesen Entwurfsregeln.
Also hier sieht man jetzt die Struktur hier 2014,
Fachwerte, Material, ein Start-up, Werkzeuge, genauso hier,
wenn ich mir hier das angucke, dann sehe ich hier genauso strukturiert.
Aber 2010 war es ganz anders. Da sieht man hier in den Quelltext reinguckt,
dann ist das eher so, Fachwerte gab es irgendwie auch schon,
aber dann irgendwie UI Vorstellungen und ja, dann ist das,
glaube ich, noch geschachtelt gewesen irgendwie so ein bisschen hier,
nee, da war noch irgendwie UI geschachtelt.
Nee, auch nicht, aber irgendwie so, das war
dann nach irgendwas intern strukturiert. Das System sah aber ziemlich ähnlich aus,
also wenn ich hier mir das 2010er-Kinokarten-Verkaufssystem angucke, sah das sehr ähnlich aus.
Ein bisschen anders, da war es noch so,
dass man hier noch sozusagen das Kino wählen konnte,
also ob das Kinostandard oder gehoben oder Luxus ist,
den Luxus dann irgendwie mit sehr luftiger Bestuhlung,
für Platz für die Nachos dazwischen und so.
Das war dann nur ein bisschen anders,
aber im Prinzip auch hier wieder die Funktionalität eigentlich gleich.
Und auch da war es so, ich konnte hier
zwei Plätze auswählen, verkaufen und dann waren die verkauft.
Ich konnte auch hier durch den Tag durchblättern und dann hatte ich irgendwie was anderes zu sehen.
Und wieder zurückgeblättert, dann hat man das wieder gesehen.
Also sehr ähnlich, aber in der internen Struktur ganz anders.
Und das ist auch ganz interessant,
dass wir tatsächlich dieses Thema Refactoring auch hatten,
also die Oberfläche, wie gesagt, relativ gleich funktioniert,
relativ gleich, aber intern war die Struktur durchaus anders.
Und wir hatten dieses Kino-Ticket-Verkaufssystem ist ziemlich alt.
Das haben wir, glaube ich, schon 2003 mal irgendwann
für Übungen für die Vorveranstaltung gebaut.
Und dann ist dieses System in der Lehre schön über
die Jahre immer weiter gepflegt worden
Ja, und wie das dann so ist,
wenn Software von verschiedenen Personen zu verschiedenen Zeiten bearbeitet wird,
dann zerfällt die, dann zerfasert die,
dann ist das, der Entwurf wurde immer komischer.
Ich habe hier nochmal das von 2008,
da sah es noch ganz anders aus, da war es noch so,
dass alles in einem Paket war, absichtlich von uns,
so wie das jetzt ist bei der Mediathek.
Jetzt war es ja so,
die Mediathek habt ihr erstmal bekommen in dem Zustand,
alles ist in einem Paket und ihr habt dann das Aufteilen in Pakete machen müssen.
Das war damals 2008 für die Studierenden so,
dass sie das eben halt mit dem Kinoticket
im Verkaufssystem machen sollten
Da sollten die das dann in diese verschiedenen Pakete aufteilen.
Da war also alles in einem Paket. Auch hier wieder,
wenn man sich das anguckt, wie das aussieht,
das sah mehr oder weniger genauso aus.
Also hier die 2008er-Variante, sieht also auch nicht viel anders
aus, so ein bisschen wie die 2010er.
Ich habe hier wieder meine Kinos, ich kann hier irgendwie
durch so einen Tag blättern und kann hier wieder verkaufen,
alles wie gehabt. Also durchaus sehr ähnlich in der Funktionalität,
aber in der internen Struktur sehr unterschiedlich.
Und das Nette an dieser Variante hier ist,
ich habe hier jetzt alles in einem Paket,
Das kann ich dann sehr schön auch in Blue Jam mir angucken.
Und tatsächlich habe ich dann hier das mal dabei,
dieses 2008er-System in Bluejay. Das sieht dann so aus.
Da seht ihr dann schon so eine UML-Diagramm, wird relativ schnell unübersichtlich.
Wobei das hier eigentlich noch relativ schön vom Layout ist.
Man kann hier schon, wenn man sich so ein bisschen reinguckt,
kümmern schon so ein bisschen was erkennen.
Also man sieht hier, und das war,
muss man dazu sagen, das war der ursprüngliche Ansatz von den Leuten,
die das System 2003 gebaut haben.
Da war die Idee, da war das noch ein System für SE1.
Am Ende von SE1 haben wir da in der SE1
gab es noch gar nicht immer
Am Ende von PA P2, egal. Sollte irgendwie objektorientiert
etwas entworfen werden, ja. Und da war aber das Thema Gui
noch gar nicht irgendwie Teil der Veranstaltung. Das heißt,
wir haben gesagt, wir schreiben die Gui in einem,
in einem eigenen Teil, und das geben wir den Studierenden vor,
und der Rest, das müssen sie dann selber schreiben.
Also hier irgendwie Vorstellungen und den Service und das Datum,
also diese Dinge sollten da irgendwie selbst geschrieben werden von den Studierenden,
aber dieser Teil, hier ist so ein Schnitt,
hier ist so ein Schnitt, den kann man hier so sehen,
hier geht das nur über dieses Interface-Ticket-Service.
Das heißt, die Gui Klassen sollten. Und das war
aber auch schon so ein bisschen von den Leuten,
die was vom Werkzeugmaterial selbst verstanden haben.
Die haben auch sowas in krassen Werkzeug gebaut mit krassen Werkzeug,
UI. Und das war so ein bisschen wammmäßig gebaut.
Und dann war aber, wie gesagt,
die Idee, wir machen hier so ein Interface.
Und dieses Interface hat irgendwie Operationen angeboten, die all das anbieten,
was in der Oberfläche angezeigt werden muss.
Also so Anfangszeiten müssen rausgegeben werden, können Anzahl Kiloseele,
Anzahl Reihen, Anzahl Sitze pro Reihe,
Anzahl verkaufte Karten,
Filmtitel mussten rausgegeben werden und ähnliches
Okay. Und die, die Implementation hier unten erfolgt dann
hier. Und was man auch eben gerade gesehen hat,
über dieses Interface sind nur primitive Typen gewandert.
Also auch die Logik war schon so eingebaut über so
ein Interface, was zur Gui geht.
In einer Gui sollten nicht irgendwie Materialien gehalten werden.
Sondern nur primitive Werte, die dann in der Gui auch angezeigt werden können.
Und das ist dann über die Jahre degeneriert.
Und dann gab es irgendwann diese 2010er-Variante und 2008er.
Und wo dann irgendwie irgendeine interne Struktur war,
wo dann Leute gesagt haben, ach, das gefällt mir nicht mehr,
aber es war eben halt nicht strukturiert nach dem,
was ihr jetzt kennt, im Sinne von, man findet sich schnell zurecht.
Also wenn ich jetzt hier so reingucke, sehe ich irgendwie Fachwerte,
UI-Vorstellungen, man kann halt so ein System nach beliebigen Kriterien
gestalten und dann wird es einfach möglicherweise nicht mehr ganz so einfach,
das zu restrukturieren.
So, was ich eigentlich zeigen will, ist,
in dem Kino-Ticket-Verkaufssystem, ich glaube,
ich habe jetzt hier einen kleinen Fehler gemacht,
da muss ich nach meinem Gucken,
wir suchen mal nach Gip-Film
Eigentlich habe ich das alles nur erzählt. Ja,
hier ist tatsächlich, das Ding heißt schon Filmtitel.
Das heißt, ich musste hier gleich nochmal,
da habe ich ja fünf Minuten Pause,
kann ich ja gleich nochmal ein bisschen rangehen.
Eigentlich möchte ich, hier war es so, dass diese Methode gibt Film hieß.
Also im Originalsystem. Leider ist das jetzt hier gerade,
ich habe irgendwo in der Vorbereitung anscheinend das falsche Ausgangssystem genommen,
muss ich gleich korrigieren. Aber hier diese Methode heißt,
hieß Gib Film und sie liefert einen String.
In dem System ist es aber so,
es gibt auch eine Klasse Film
Ja. Und wenn ich eine Methode lese, wo steht,
gib Film, dann würde ich ja erwarten, dass dann auch ein Film geliefert wird.
Nun war es aber so, dass hier an dieser Schnittstelle
ja gar keine Materialien oder ähnliches rausgegeben werden sollten,
an der Schnittstelle zu der Gui.
Also wurde das Ding einfach hier als Tring rausgegeben,
damit man dann das in der Oberfläche darstellen kann.
Das Ding hieß aber, gib Film. Und ja,
eigentlich, ja, das habe ich schon vorweggenommen,
der bessere Name wäre gewesen, gibt Filmtitel.
Und dieses Refactoring werden wir gleich, ich hoffe,
ich kriege das jetzt noch schnell gefixt,
dass ich die alte Version kriege, diese Version,
Werden wir gleich mal hier nach den Mechanics,
die wir gerade gesehen haben, für Renay Method mal umbauen.
Und dann sehen, an welchen Stellen da was schiefgehen kann.
Damit ihr einfach so ein Gefühl dafür kriegt, was da alles so passiert.
Hinter den Kulissen bei einem Renay Method. Okay,
aber dann würde ich jetzt sagen, dann gebt mir jetzt mal
eben fünf Minuten, um hier so ein bisschen zu fixen.
Das heißt, was wir jetzt machen,
und ich mache das explizit in Blue Jay.
Ich mache das bewusst in Blue Jay, diese Änderung.
Ihr wisst hoffentlich, dass man in Eclipse total einfach sagen kann,
Rename Meme Method. Ich kann ein Refactoring in den Clips
direkt eingebaut benutzen. Ich kann also hier zum Beispiel in
dieses System reingehen und in dem Multiplex-Ticket-Service hier sagen,
ja, gib mir mal, gib Film.
So, such mir mal, gib Film.
Dann könnte ich jetzt an dieser Stelle sagen, rechte Maustaste,
Refacte. Und dann gibt es hier Rename. So,
und dann fängt Clips an mir hier, Unterstützung anzubieten,
wie ich jetzt das Rename Method mache.
Das ist wunderbar,
sehr schön
Wollen ja ein bisschen mehr verstehen von Refactoring.
Deswegen machen wir es jetzt in einem System,
in dem die Unterstützung nicht da ist.
In Blue Jay gibt es die Unterstützung nicht. Insbesondere gibt es
in Blue Jay schon nicht die Möglichkeit, jetzt global zu suchen.
Das heißt, ich habe jetzt hier ziemlich viele Klassen.
Und wenn ich jetzt diese Methode umbenenne,
also in diesem Multiplex-Ticket-Service hier, diese Methode gibt Film,
umbenennen will in Gipfelm-Titel, dann kann ich jetzt gar nicht so leicht feststellen,
an welchen Stellen Diebfilm auftritt.
Ich kann jetzt hier nicht suchen,
ich kann zwar innerhalb einer Klasse suchen,
aber ich kann nicht
im ganzen Projekt suchen
Das bietet LuJ nicht an. Das heißt,
was ich jetzt mache, ist, ich gehe hier in
dieses Verzeichnis, in dem wir uns hier gerade bewegen.
Das ist das Verzeichnis, in dem dieses BlueJ-Projekt liegt.
Diesen Pfad kann ich hierher nehmen und kann hier jetzt wieder
eine Konsole mir geben lassen. Ihr kennt das Ding schon
. Und jetzt kann ich hier den Pfad benutzen,
also tatsächlich gehe ich in das Verzeichnis, in dem diese BlueJ-Dateien liegen.
Man kann jetzt hier sagen, dir, also Directory-Anzeigen,
dann sieht man, das sind genau die Dateien,
die auch in dem Verzeichnis liegen von dem BlueJ-Projekt
Ja. Und jetzt kann ich tatsächlich suchen nach,
also hier, es gibt so ein Feind in diesem wunderbaren Command-Tool,
also ganz schrecklich, da kann ich jetzt sagen,
Feind und dann irgendwie slash N,
das gibt mir dann auch die Zeilennummern mit aus, in den Dateien,
also an welcher Stelle in der Datei das dann steht,
dann sage ich hier irgendwie, was möchte ich haben,
gib,
gib Film,
soll gesucht werden und zwar in Stern.
Und das liefert mir jetzt, wenn ich das jetzt ausführe,
hoffentlich alle die Stellen, an denen das gibt, Film auftritt.
Ich will ja jetzt sozusagen gucken,
wo jetzt dieses Gip-Film-Umbenennen in Gip-Filmtitel eine Wirkung hat.
Und dann kann man eben halt hier sehen, naja,
das gibt eben halt dann so ein paar Stellen.
Also die Ausgabe ist hier, hier ist der Aufruf,
ist irgendwie, da wird also alles das aufgelistet an Java-Dateien,
die durchsucht werden, also zum Beispiel in All-Tests ist nichts drin,
in Datum auch nicht und so weiter.
Und dann gibt es so ein paar Stellen,
an denen wirklich was passiert.
Also einmal sieht man hier Kassenwerkzeug,
String-Film ist gleich,
Da wird also anscheinend dieses Interface, diese Interface-Operation,
gibt Film benutzt, von diesem Kassenwerkzeug,
um das dann irgendwie in der Gui anzeigen zu können.
Also hier wird das Gipfelm benutzt. Ja,
und dann haben wir hier noch, das gibt Film,
in dem Multiplex-Service selbst, das ist die Stelle,
an der wir das ja ändern würden,
dann gibt es hier noch irgendwo einen Gipfelm, aha,
das ist auch nochmal interessant.
Ja, das scheint dann, wenn es anderes gibt,
Film zu sein. Und dann hat man hier Multiplex-Service-Test-Gipfelm,
wird also auch ein Gipfelm aufgerufen
Und dann gibt es hier auch einen Gip-Filmaufruf. Und dann ist hier
noch im Ticketservice in dem Interface, gibt Film deklariert.
Und dann gibt es aber noch diese Stellen hier,
da wird tatsächlich bei Gip-Film einen Film geliefert.
Also da ist sozusagen die Benennung, gibt Film richtig gut.
Das heißt also, das sind jetzt erstmal nur rein textuelle Suche,
die ich jetzt hier gemacht habe, in Java-Dateien,
habe alle Stellen gefunden, an denen gibt Filmauftritt.
So, jetzt gehen wir mal das Refactoring einfach der Reihe nach durch.
Also ich deklariere eine neue Methode mit dem neuen Namen.
Ja, das kann ich mal als erstes machen.
Also ich gehe hier in diesen Multiplex-Ticketservice rein,
suche nach gib Film, da steht die Methode Gipfel.
So, und genau diese Methode möchte ich jetzt umbenennen und die Mechanics sagen,
macht das folgendermaßen, kopierst das Zeug, was du hast,
in eine andere Methode.
Also ich kopiere das mal und habe das jetzt hier verdoppelt.
Man sieht also, hier da oben ist ein Gipfel oder unten
ist es noch ein Gipfel. Dieses zweite gibt Film,
das nenne ich jetzt mal, gibt Filmtitel.
So, das ist jetzt mal eine neue Methode,
die so heißt, wie sie heißen soll.
Deklariere eine neue Methode mit dem, ups, mit dem neuen Namen,
kopiere den alten Quertext in die neue Methode hinein.
Habe ich jetzt ja implizit gemacht und mache die notwendigen Anpassungen.
So, jetzt kann ich ja schon mal übersetzen.
Ich kann ja jetzt schon mal sehen, konnte ich
diese neue Methode einfach einführen? Kann ich das übersetzen?
Da sagt er jetzt hier hoffentlich, ja, keine Syntaxfehler hat geklappt.
Okay, das heißt, das hat schon mal wunderbar geklappt.
Dann ende den Rumpf der alten Methode so, dass er die neue Methode ruft.
Auch das ist jetzt nicht so wahnsinnig schwierig.
Das heißt, hier habe ich meine Methode gib Filmtitel.
Hier ist die Methode gib Film. In der alten Methode soll jetzt die neue gerufen werden,
also mache ich jetzt hier Benutze ich jetzt Return,
gib Film, Titel und dann entsprechende Parameter,
also Kino, Saal, Uhrzeit und Datum.
So, jetzt habe ich sozusagen hier die Umleitung angerichtet,
das lässt sich auch übersetzen.
Dann sagt hier, das Refactoring übersetzen und testen. Okay,
also gehe ich jetzt mal hier rein,
übersetze mal wirklich das ganze System,
lässt sich alles übersetzen und jetzt kann ich mal alle Tests starten und siehe da,
die Tests schlagen nicht fehlen.
Ich habe also bisher noch nicht viel gemacht, ich habe
nur die neue Methode eingeführt Und jetzt wird sie noch nirgends benutzt.
Aber in der alten Methode wird die neue jetzt aufgerufen.
Okay, jetzt, was sagt das, was sagen die Mechanics hier?
Übersetzer, finde alle Referenzen auf die alte Methode und ändere
sie so, dass sie auf die neue verweisen.
So, das mit dem Suchen haben wir jetzt schon gemacht.
Das heißt, wir können jetzt hier mal gucken,
an welchen Stellen das denn auftritt.
Ja, das war also hier im Kassenwerkzeug.
Da haben wir jetzt also Ticketservice, gibt Film,
gehen wir mal in das Kassenwerkzeug rein.
Also hier eine Stelle, finde mir, gib Film.
So, da wird Gib Film aufgerufen
Wunderbar. Also an dieser Stelle mache ich jetzt
genau diese Umbenennung, also gib Filmtitel.
Und mal sehen, ob das jetzt übersetzbar ist.
Übersetzen, ah, cannot, fined Simple, Method,
gib Filmtitel. Was ist jetzt schiefgelaufen? Wer hat jetzt
aufgepasst und hat mitgekriegt, wo das Problem lag?
Das Kassenwerkzeug findet jetzt diese Methode, gibt für den Titel nicht.
Woran liegt es? Hat jemand gesehen? Ich kann es
hier nochmal zeigen. Das Kassenwerkzeug benutzt gar nicht den Multiplex-Service
direkt,
sondern den Ticket-Service
Das heißt, in dem Interface-Ticket-Service haben wir jetzt noch gar
nicht diese Operation, gibt Filmtitel. Da sieht man schon
genau diese Situation, wo es ein bisschen komplizierter ist.
Ich habe so eine implementierende Klasse für ein Interface.
Das heißt, ich würde jetzt an dieser Stelle auch neben
der Operation gibt Film, die hier vorgegeben ist.
Eine weitere Operation einführen, die da lautet, die Filmtitel.
Also hier habe ich jetzt zweimal gegipfeln.
Und hier würde ich jetzt sagen, gib Filmtitel.
So, und jetzt sehen wir auch schon mal,
was ganz interessant ist. Ich habe jetzt an dieser Stelle,
bin ich jetzt zu Fuß unterwegs,
ändere jetzt die Operation im Interface
in,
gib Filmtitel
Beziehungsweise ändere das nicht, sondern habe eine weitere Methode eingeführt,
eine weitere Operation. Und jetzt wäre es eigentlich schlau,
wenn ich an dieser Stelle auch den Kommentar mitändern würde.
Also ich sehe ja hier, hier wird ja gesagt,
gibt Filmtitel, es wird ein String geliefert, ja,
dann mache ich doch hier auch,
liefert den Film Titel einer Vorstellung.
Viel besserer Kommentar an der Stelle. Okay,
das müsste übersetzbar sein, diese Methode konnte ich hier einführen,
dann übersetze ich das ganze System und jetzt klappt es auch mit dem Kassenwerkzeug,
weil das Kassenwerkzeug jetzt tatsächlich
die Operation gibt,
Filmtitel aufruft
Okay, dann hatten wir hier noch weitere Stellen,
Multiplex-Ticketservice, da haben wir das GIP-Film ja umbenannt.
Aber es hätte jetzt an dieser Stelle nicht gut funktioniert,
wenn ich einfach ein Tool gehabt hätte,
das gesagt hätte, textuell ersetze mir Gipfeln durch Gipfelm-Titel,
weil in dem Multiplex-Ticket-Service, wir können das hier nochmal zeigen,
wenn ich jetzt in dem Multiplex-Ticket-Service nochmal gucke und nochmal nach GIP-Film-Titel suche,
dann steht hier auch Gipfeln.
Das ist aber das echte Gipfelm,
was an der Vorstellung aufgerufen wird,
wo ein Filmobjekt geliefert wird
Und das ist, an dieser Stelle wäre es jetzt nicht gut,
einfach stumpf, alles, was gibt, Film heißt,
ingibt Filmtitel umzunennen.
Okay, dann haben wir das, den Service-Test, Multiplex-Ticket-Service-Test.
Ja, haben wir hier auch. Da müsste es also
auch ein, gib Filmaufruf geben. Ja. Testet
die Operation, Multiplex. Hier sieht man schon,
das sieht auch im Kommentar mit drin. Also hier,
hier habe ich das jetzt anscheinend nicht gut umbenannt.
Also nicht zurückgemacht. Also hier müsste ich jetzt tatsächlich auch hinschreiben,
Gibt Filmtitel. Und auch hier gibt Filmtitel. Und hier stand vorher,
hatte ich jetzt in der Fünf-Minuten-Pause doch nicht alles,
was sich geändert hatte, wieder zurückgeändert.
Hier stand auch, gib Film. Und ich würde natürlich
jetzt hier an dieser Stelle sagen, das soll eigentlich heißen,
Teste gibt für einen Titel.
Und auch hier im Kommentar würde ich das eigentlich erwarten,
dass ich das dann so entsprechend umbenenne.
So, wunderbar. Das lässt sich hier hoffentlich auch übersetzen jetzt.
Das heißt, jetzt haben wir einen weiteren Klienten umgechincht.
Und jetzt bleibt noch, was bleibt noch über?
Ticketservice, haben wir Gib-Filme eingeführt
Und in der Vorstellung, also jetzt haben wir alle Stellen geändert,
an denen wirklich das echte semantische Gipfeln, was wir ändern wollten,
mit dem String als Ergebnis, in Gipfelmtitel umbenannt.
Also hat das hier seine Schuldigkeit getan. Wir können jetzt
hier übersetzen und wir können alle Tests ausführen und es müsste alles noch laufen.
Soweit, so gut. Jetzt sagen die Mechanics als nächstes
, entferne die alte Methode. Okay,
jetzt haben wir also hier zwei Stellen,
an denen die Methode steht, nämlich einmal im Service und
einmal in der Klasse.
Welche sollten wir
zuerst entfernen
Wo, ja, also, genau, also er sagt es richtig,
zuerst sollte man es im Interface entfernen, weil sonst kriegt man nämlich einen Fehler,
wenn ich jetzt erst hier die alte Methode entferne,
dann wird gemeckert, dass das Interface nicht implementiert wird.
Also ändern wir erst mal das Interface,
schmeißen also hier die alte Methode raus, die Operation,
gibt Film, jetzt gibt es nur noch,
gibt Filmtitel, jetzt müsste alles noch übersetzbar sein,
ja, zack, ja, wunderbar,
jetzt ist hier nur noch eine Methode zu viel in der implementierenden Klasse,
eine Klasse gibt Film, Und entsprechend schmeißen wir die jetzt hier raus.
So, jetzt gibt es hier nur noch die Klasse.
Gibt Filmtitel und die Operation gibt für den Titel und alles
lässt sich auch noch testen. Alle Tests laufen durch.
Das war jetzt einfach mal sehr konkret das durchgegangen,
damit ihr es einmal seht, wie das, was da so passiert.
Ich zeige das jetzt nochmal in Eclipse, deutlich schneller.
Ich kann an dieser Stelle jetzt sagen, hier,
Operation gib Film, dann gibt es hier
das Refactor
Und jetzt sage ich hier Rename. Und jetzt,
Enter new name, press Enter to refactor.
Aber hier wird jetzt noch so ein kleines Menü angeboten.
Das ist irgendwie auch ganz lustig. Dann kann man dann
sagen, hier, Preview. Das heißt,
wenn ich jetzt hier an dieser Stelle sage,
ich möchte also tatsächlich hier, gib, gib.
Ich fliege immer aus dem Netz, das ist ganz lustig.
gib Film
Achso, das kann ich jetzt natürlich nicht mehr machen.
Irgendwas ist hier schiefgelaufen. Also, nochmal, also, Refactor, Rename.
So, und jetzt kann ich hier sagen, gib Filmtitel.
Und jetzt könnte ich das einfach mit Return bestätigen.
Und dann würde tatsächlich das, was wir gerade von Hand gemacht haben,
an allen Stellen gemacht werden, automatisch von Eclipse.
Und da können wir uns auch noch eine Vorschau anzeigen.
Das heißt, jetzt haben wir hier die Preview.
Und dann wird hier sowas erzeugt. Ja, also eine richtig hübsche Darstellung,
wo man dann so sieht, so sah es vorher aus.
Also zum Beispiel hier, in dem Kassenwerkzeug,
wo wir es ja eben schon von Hand geändert haben, in dem Blue-Jay-Projekt.
Hier Kassenwerkzeug, da steht jetzt irgendwo hier, gib Film.
Und das würde, wenn ich das jetzt umbenennen würde, in gib Filmtitel umbenannt.
Also er macht hier so richtig so eine ausführliche Darstellung,
wo man dann sehen kann, ob das auch an der richtigen Stelle ist.
Was man aber auch sieht, ist hier jetzt,
hier noch nicht, hier ist die nächste Stelle, in dem Multiplex-Ticket-Service,
wird er natürlich dann in dem Interface auch das umbenennen.
Also diese Stelle hier sieht man hier,
da wird dann, gib Film, gib Filmtitel umbenannt.
Hier sieht man dann den Test, die Testklasse, Also hier,
Test gibt Film. So, und da ist jetzt genau der Punkt,
wo man jetzt sehen würde, hier würde er natürlich nur,
das gibt Film, in dem Filmtitel umbenennen,
aber er würde nicht den Namen der Methode hier auch umbenennen.
Das kann Eclipse ja gar nicht leisten. Ja,
das weiß ja gar nicht, dass dann zu semantischer Zusammenhang besteht,
dass da jetzt eigentlich gemeint ist, Teste gibt Filmtitel,
sondern was hier passiert ist, sehr hochwertig,
sehr semantisch reich ist Eclipse schon in der Lage zu erkennen,
dieser Methodenaufruf hier, das ist wirklich der Aufruf von Gib Film.
Aber sowas kann nicht mitgehen. Und auch hier
der Kommentar wird an der Stelle
nicht mitgeändert
Das heißt, da fallen jetzt schon so ein paar Krümel an manchen Stellen ab,
wo dann irgendwie eine Änderung, ein Rename Method bewirkt,
dass die Kommentare nicht mehr ganz zu den Methoden passen.
Also das ist dann einfach so ein Effekt,
den man bekommt, wenn man so eine Werkzeugunterstützung relativ unbedarft benutzt.
Und dann ist hier noch das Ticket Service,
das ist, glaube ich, das Interface gewesen.
Genau, da ist es dann hier die Umbenennung. Okay,
dann kann ich jetzt sagen, mach das einfach mal.
Und dann ist es eben halt im ganzen System jetzt geändert.
Aber, wie gesagt, an einigen Stellen sind da jetzt
so ein paar Sachen nicht mehr ganz so sauber mitgezogen worden
Okay, das war jetzt ein Beispiel von einem Refactoring,
Methode umbenennen, ist ziemlich prominent. Ein anderes Beispiel ist Methode Extrahirn.
Ihr kennt möglicherweise die Situation, ihr habt eine Methode,
die sehr recht groß ist, größer als eine Bildschirmseite.
Wir haben so als Maßgabe so maximal eine Bildschirmseite,
damit ich gut erkennen kann auf einen Blick, was die Methode macht.
Und auch da wieder dann so diese Mechanikbeschreibung,
also wie mache ich das denn jetzt,
dass ich aus einer Methode so einen Teil auslagere in eine eigene Methode.
Also extrahiere Methode, Methode extrahieren,
Extract Method
Also da wieder ganz einfach,
die Klariere eine neue Methode mit einem sprechenden Namen,
dann wird die übersetzt,
die ganze Klasse,
dann kopiere ich den zu extremen Abschnitt in die neue Methode und muss natürlich auch gucken,
ob dann lokale Variablen da irgendwie mit deklariert werden müssen und so weiter
und muss die dann tatsächlich auch zu Parametern oder zu lokalen Variablen machen,
dann übersetze ich und teste und dann ersetze ich in der alten Methode den extrahierten Quertext mit einem Aufruf der neuen Methode und dann übersetze ich und teste ich.
Das ist das, was man von Hand machen muss,
wenn man keine Refactoring-Unterstützung hat, in die Clips,
können wir das hier uns mal sehr schön an
einem Beispiel angucken
Hier gibt es die Klasse Start-up. Multiplex-Kino. Da passiert so
ein bisschen, was so, das System wird eingerichtet.
Ich habe hier so, werden irgendwelche Kinoseele angelegt und Filme
werden angelegt, irgendwelche Beispiele. Also diese Beispielbelegung mit Materialien
, dann werden so ein paar Uhrzeiten erzeugt hier.
Und dann werden hier Vorstellungen gebaut. Diese Methode ist,
wie man sieht, ja, das ist so quasi die Main-Methode,
die ist relativ groß, die geht hier deutlich über eine Wildschirmseite hinweg.
Ziemlich doof. Also werde ich jetzt einfach mal sagen,
naja, ich nehme mal diesen Abschnitt hier
Den würde ich jetzt gerne mal extrahieren. Und da geht es jetzt wieder sehr einfach,
rechte Maustaste, Refacte, Extract Method. So,
und dann fängt jetzt hier Eclipse an zu rödeln und sagt,
okay, die Mechanics, die wir gerade gesehen haben,
sind da umgesetzt.
Wie soll das Ding denn heißen? Na,
würde ich mal hier sagen, irgendwie Zeuge, Vorstellungen.
So, so soll die Methode heißen.
Und die liefert anscheinend hier ein Array von Vorstellungen,
weil das wird ja dann irgendwo auch benutzt.
Man sieht das hier irgendwo da,
ups, das wollte ich jetzt nicht,
also wieder zurück
Und dass man so ein bisschen zur Seite schieben.
Hier wird dann ein New Kassenwerkzeug, da wird dann aufgerufen,
die Vorstellungen sollen da übergeben werden. Also dieses Array von Vorstellungen,
dass hier von dieser Methode mir erzeugt wird. Und man sieht dann auch,
hier müssen dann einige Parameter übergeben werden,
weil Uhrzeit und Kinosaal Array und so weiter,
die werden ja in dem Quelltext hier schon vorher erzeugt,
aber die würden dann mit übergeben werden.
Ich würde es einfach nur mal zeigen,
wie mächtig das ihr ist in Eclipse. So,
wenn ich das jetzt einfach mal mache,
dann habe ich tatsächlich jetzt hier eine lokale Variable mit den Vorstellungen,
dann sage ich hier
erzeuge Vorstellungen
Ja, das ist eine statische Methode, deswegen ist die
hier so krisiv dargestellt. Also, das ist ja eine Main-Methode,
diese statische Methode ist hier. Und hier sieht man jetzt,
diese Methode, Private Static erzeuge Vorstellungen,
passt auf eine Seite und meine Main-Methode passt jetzt auch auf eine Seite.
Das heißt, es ist relativ übersichtlich geworden.
Also eine größere Methode in zwei kleinere zerlegt und habe aber
hier jetzt relativ viele Parameter übergeben werden müssen. Also,
das Seele Array, das Filme Array und dann so ein paar Datümer und irgendwelche Uhrzeiten.
Hätte man vielleicht noch ein bisschen schlauer machen können,
aber einfach mal,
und wenn man das jetzt von Hand gemacht hätte,
ihr schon, da hätte ich mir relativ viel Wolf programmiert,
um das alles so hier live zu machen oder beziehungsweise auch gar nicht live,
sondern einfach, es ist einfach mehr Arbeit.
Und da ist es dann schon ziemlich cool,
dass mir so ein Werkzeug wie Eclipse,
solche Refactoring-Unterstützung anbietet, die genau sowas dann machen kann.
Okay, das erst mal jetzt zu diesem konkreten Beispiel am Quelltext.
Ihr habt also jetzt gesehen, es gibt ja so diese
kleinen mechanischen Schritte. Da gibt es jetzt in dem Methodencutter,
in dem Refactoring-Katalog von dem Foul eine ganze Menge Zeug
und die lassen sich so ein bisschen kategorisieren,
also in so Rename-Sachen,
Rename-Class kann man ja durchaus
auch machen
Und Move, Change Signature, Bewege,
Methoden in der Hierarchie auf und ab, Extrahiere,
ein Interface, was ziemlich häufig benutzt wird, ist,
dass das Refactory Extract Interface,
wenn ich sozusagen aus einer Klasse einfach das Interface herausziehen möchte,
um das dann explizit zu machen.
Das sind so sehr bewährte Sachen. Was ganz interessant ist,
ich habe ja vor, glaube ich, einer Woche gerade erst,
hier die Vorlesung gehalten über das Thema Werte und Objekte.
Und damit ihr seht, dass das nicht nur so eine
spinnerte Idee von uns hier ist, das zu unterscheiden,
Auch der Foule hat so eine Ahnung davon,
dass es da irgendwo so unterschiedliche Dinge gibt.
Er beschreibt tatsächlich in seinem Katalog auch zwei Refactorings zum Thema Werte und Objekte.
Und zwar gibt es einen Effekt, das heißt Change Value to Reference.
Und das andere heißt Change Reference to Value.
Ist ein bisschen unglückliche Benennung. Das heißt,
für ihn ist dann irgendwie ein Objekt,
ist ein Reference-Objekt und ein Value ist dann ein Value-Objekt.
Muss man gucken, ob das sozusagen die technische Umsetzung,
dass das mit einer Referenz gemacht ist, ist eigentlich unabhängig davon,
ob es konzeptuell ein Wert oder ein Objekt ist.
Also der Mann hat da möglicherweise nicht so intensiv sich damit beschäftigt,
wie wir das hier gemacht haben die letzten Jahre
Aber auf jeden Fall gibt es eben genau diese Unterscheidung.
Er sagt, you can make a use food classification of objects in many systems. Referent,
ich sag jetzt einfach mal, Objects und Value Objects,
Reference Options are things like customer or account,
each objects stands for one objects in the real world and the use the object identity to test whether they are equal.
Value Objects are things like date or money, aha,
das sind genau die Beispiele von letzter Woche,
they are defined and tirely through they data Values,
das heißt you don't mind that copys as exist, das heißt,
ich habe technisch mehrere Wertobjekte, die aber alle denselben Wert repräsentieren,
dasselbe Datum zum Beispiel, ja, ist also egal,
ob man hunderte von 1.1.2000 hat, Aber man muss eben halt manchmal feststellen, ob sie gleich sind.
Deswegen wird die Equiels-Methode redefiniert und deswegen muss natürlich auch Hashcode redefiniert werden.
Also das beschreibt er hier schon relativ klar. Das ist also für jemanden,
der wie er auch in der Modellierungswelt zu Hause ist,
durchaus offensichtlich auch ein wichtiger Punkt,
dass man so wertartige Dinge beschreiben sollte.
Dann sagt er hier, the decision between reference and value
is not always clear. Also das ist so,
da bleibt er so ein bisschen im Unscharfen.
Aber es ist zumindest interessant zu sehen,
dass auch er diese Unterscheidung durchaus thematisiert,
dass dann eher so am Rande an dieser Stelle.
So, was ihr jetzt gesehen habt,
Refactorings sind so diese kleinen Verhaltensbehaltenden Änderungen.
Und da gibt es Werkzeugunterstützung. Werkzeugunterstützung ist auf jeden Fall
notwendig, um Dinge leicht machen zu können.
Also als ich das BlueJ-Buch übersetzt habe vor zehn Jahren ungefähr,
da habe ich die Projekte, die englischen Projekte auch in Deutsch übersetzt.
Also ich habe dann so die fachlichen Begriffe,
habe ich dann einfach auch in deutsche Begriffe umgesetzt.
Kann man darüber diskutieren,
was sinnvoll war,
ich habe es gemacht
Und das war extrem hilfreich, das mit Eclipse zu machen.
Wenn ich das in Blue Jay gemacht hätte,
dann hätte ich mir wirklich einen Wolf programmiert,
weil da mehrere Versionen von demselben Projekt auch in dem Buch vorkommen.
Und dann ist es einfach fürchterlich, wenn man dann irgendwie
eine Methode umbenennt von Englischen in den deutschen Begriff.
Und dann darauf achten muss, dass es an allen Stellen auch nachgezogen wird.
Also da ist dann so eine Refactory-Unterstützung durch Eclipse extrem hilfreich gewesen.
Und deswegen bieten IDEs heutzutage sowas an. Also Eclipse war der Vorreiter,
so Anfang der 2000er, die waren die ersten,
die wirklich so explizit sowas eingebaut haben, Unterstützung für Refactorings.
Kein Wunder, weil Erich Gamma ja mit den Leuten kennt,
Back und Martin Fauler auch gut bekannt ist
Inzwischen auch Intelligent Idea, auch Net Beans,
die bieten alle mehr oder weniger umfangreich Refactoring-Unterstützung an.
Wobei es auch interessant ist,
wir hatten mal den Dirk Bäumer bei uns im Oberseminar,
das ist ein ehemaliger Doktorand von Heinz Züllighofen,
der hat also auch bei Heinz dann promoviert.
Und der hat im Team von Erich Gamma mitgearbeitet, viele Jahre.
Und der hat uns mal ein bisschen was erzählt über das Refactoring in Eclipse,
also wie aufwendig das ist, das in den Clips reinzubauen.
Ihr habt gerade schon gesehen, da wird noch so eine Preview gemacht,
könnt ihr euch vorstellen, was das bedeutet,
das alles so im Hintergrund zu implementieren.
Aber er hat auch gesagt, die führen auch Statistiken darüber,
wie oft diese Refactorings benutzt werden.
Und so ein Refactoring wie Renay Method ist das fast Wichtigste überhaupt.
Extract method, Extract Interface, das sind noch so auch
noch wichtige, aber das sind die absolut heißen Kandidaten.
Rename Class, die werden ganz viel benutzt. Und da lohnt es sich wirklich,
dass so ein paar Programmierer in Zürich,
vielleicht mehrere Tage oder Wochen implementieren, um das sauber zum Laufen zu gehen.
Aber wir profitieren auch Millionen Entwickler davon. Inwiefern profitiert man,
weil man, wenn man so eine Unterstützung hat,
auch mal schneller etwas umbenennt,
wenn man diesen ganzen Aufwand treiben müsste,
den wir gerade von Hand getrieben haben,
bei jeder Umbenennung
Dann erschwert das einfach das Umbenennen. Und das Umbenennen ist etwas,
was für Refactoring wichtig ist, damit einfach Dinge richtig benannt sind,
damit sie klarer lesbar sind und besser wartbar sind.
Also es ist gut, wenn das Tool das erleichtert.
Was auch noch wichtig ist,
das hat uns Dirk Bäume auch nochmal sehr deutlich gemacht,
die Unterstützung für Refactorings hängt sehr stark von der Programmiersprache ab.
Eine Sprache wie Java ist zum Beispiel sehr gut geeignet,
um Refactorings in der IDE zu unterstützen,
weil in Java Alle Bezeichner typisiert sind.
Also man muss ja bei jedem,
bei jeder Variablen deklarieren, von welchem Typ sie ist.
Das seid ihr so gewohnt, ihr kennt das aus Java kaum anders.
Aber es gibt auch andere Sprachen. Es gibt so Sprachen
wie Ruby oder andere Skriptsprachen, wo man dann keinen Typ angeben muss.
Und dann ist es nicht mehr ganz so einfach für den Compiler zu erkennen,
was für einen konkreten Typ hat denn eine bestimmte Ausdruck.
Noch schlimmer ist es in C Plus Plus.
Also C Plus Plus ist auch eine statisch getypte Sprache,
aber ist trotzdem in ihrer Komplexität deutlich schwerer zu unterstützen.
Das heißt, so ein Rename Function oder wie es dann
in C-Plus heißt, ist viel, viel schwieriger zu implementieren.
Deswegen gibt es auch wenig Refactoring-Support in Visual Studio zum Beispiel für C-Plus.
Das ist hart zu bauen. Es ist fast zehnmal schwieriger
als in Java. Also da ist es einfach auch toll,
dass man so eine Sprache hat wie Java, die das irgendwie sehr leicht macht.
Also so eine einfache und gut getypte Sprache.
Das solltet ihr also auch im Hintergrund behalten,
dass Refactoring, wenn ihr es in Java gewohnt seid,
ihr werdet nicht in allen Sprachen, denen ihr möglicherweise irgendwann arbeiten werdet,
solche Unterstützung haben.
Das ist nicht garantiert
Okay, und dann, was Fouler auch nochmal ein bisschen betont,
was ihr beachten solltet, wenn ihr Refactorings macht,
also wenn ihr zum Beispiel Dinge umbenennt mit so einer Toolunterstützung,
die ja dann teilweise auch dann, wie gesagt,
Kommentare nicht mit umbenennt und so,
ist es auf jeden Fall wichtig, dass ihr eine Test-Sweet habt.
Das heißt,
diese ganze Idee von Refactoring kommt aus der agilen Welt,
in der agilen Welt ist dann ganz klar vertreten worden,
man muss Testklassen haben,
man muss eigentlich eine möglichst komplette Abdeckung von aller Funktionalität im
System haben über Testklassen
Nur dann kann ich auch wirklich einigermaßen mutig Dinge refactern,
weil sonst ich ja gar nicht mitkriege, wenn irgendwas kaputt geht.
Diese Testklassen sind extrem wichtig. Also anders gesagt,
wir factern ohne eine solide Testabdeckung,
ist so ein bisschen wie Autofahren ohne Sicherheitsgurt.
Wenn es mal kracht, dann kracht es richtig.
Also keine gute Idee. Okay. Ja, das ist
die Zusammenfassung. Ich habe hier noch mal so ein bisschen Verständnisfragen.
Wir können ja noch mal so ein bisschen Storessi machen hier
zum Schluss
Machen wir mal eben hier, er ist jetzt zwei,
weil er ist uns zwölf, Laden.
Braucht noch jemand wieder noch mal hier so den Barcode?
Ja, braucht noch jemand. Okay. Also, wer
noch mal teilnehmen will an dieser kleinen Storesi-Umfrage. So,
hier ist die Frage, durch welche Maßnahme wird beim Refactoring,
also bei der Tätigkeit des Refactors,
dass viele Risiko
am ehesten gering gehalten
A durch das Vermeiden übler Gerüche, B durch eine möglichst
hohe Testabdeckung, C durch das Einhalten von Quelltextkonventionen oder D
durch das Einhalten gängiger Entwurfsregeln.
Ich bin mal gespannt, wie viele jetzt noch hier
so dabei sind bei so einer Geschichte.
Das dürfte eine relativ einfache Abstimmung, also ein relativ klares Abstimmungsergebnis geben.
Vermute ich jetzt zumindest. Mal gucken. 20 Stimmen,
vielleicht kriegen wir noch
ein paar mehr zusammen
So viele sind jetzt hier nicht mehr dabei bei dem Sturesi. Ah, 23,
25, ja, vielleicht kommen wir noch über 30. 27,
na gut, ich glaube, dann 29. Gut,
also fast 30 Stimmen, 30 Stimmen, wunderbar.
Ich beende das mal. Wir gucken mal, was hier so
die Meinung ist. Und da sieht man, aha,
eine relativ, ja, doch gar nicht so klar.
Also immerhin eine klare Mehrheit ist der Meinung durch eine
möglichst hohe Testabdeckung. Das ist das, was ich,
ich glaube, eine Folie vorher gerade gesagt habe,
deswegen war es jetzt relativ leicht, zu erkennen hier.
Natürlich ist es schlau, üble Gerüche zu vermeiden,
aber wenn ich tatsächlich beim Refactor schon bin,
also ich bin bei der Tätigkeit dabei,
und da hat das Fehlerrisiko am geringsten zu halten,
das ist natürlich eine hohe Testabdeckung, das Wichtigste.
Das ist hier die richtige Antwort. Das Vermeiden übler Gerüche
ist eher sowas, was man generell tun sollte.
Quelltextkonventionen einhalten, klar, hilft auch,
aber das ist eben halt das, was hier das Wichtigste ist.
Also am ehesten. Gut, dann habe ich noch eine
etwas weniger leichte Frage. Warum sollten Refactoring und Erweiterungen
klar getrennt werden
Also, wenn ich an einer Software eine Erweiterung einbaue,
das hatte ich ja auf der Folie vorher jetzt nicht so genau erzählt,
aber das Erweitern sollte getrennt werden vom Refactoring.
Warum sollte das gemacht werden? Weil dann
die Semantik bestehender Tests beim Refactory nicht verändert werden muss,
um dem Kunden die Erweiterung besser in Rechnung stellen zu können.
Wenn ich das trenne, ich refactory und ich brauche einen
Tag zum Refactoren und zwei Tage, um die Änderung reinzubauen,
dann kann ich dem Kunden besser sozusagen in Rechnung stellen.
Hier, zwei Tage habe ich für die Änderung gebraucht.
Oder weil Veränderungen an bestehendem Quelltext
schon schwierig genug sind
Oder weil wir Korrisionen auch auf unser Vorgehen anwenden sollten.
Gucken wir mal, was hier so die Meinungen sind dazu,
was da so die besten Begründungen sind.
Warum sollte man Refactoring und Erweiterung klar trennen?
Ja, wie gesagt, ich erwarte jetzt eigentlich eine
nicht ganz so klares Meinungsbild
Gucken. Also wir haben wahrscheinlich jetzt wieder gleich 30 Stimmen zusammen.
Ja, okay. Ich äh 35, okay. So,
und jetzt sieht man hier eine relativ breite Verteilung.
Und tatsächlich gibt es hier keine richtige Antwort. Ich habe hier
keine richtige Antwort. Ich habe natürlich jetzt auch gerade festgestellt,
dass ich dummerweise, als ich das jetzt eben vorgestellt habe,
genau das nicht gesagt habe.
Also das habe ich nicht gut vorgestellt. When you have,
when you find you have to at a feature to a
program and the programs code is not structured in a convenient way to at the feature,
first refactor of the program to make it easy to at the feature, then at the feature.
Also er sagt wirklich nicht sozusagen, dass in einem Schritt machen,
so das Reinbauen und das, das Refactor,
sondern wirklich klar trennen, refactoren von dem eigentlichen Ändern.
Und dass es hier keine richtige Antwort gibt,
ist einfach, weil alles irgendwie durchaus Sinn macht.
Alle Antworten machen Sinn. Also, es ist sicherlich nicht verkehrt,
wenn ich beim Refactoring erstmal die Tests beibehalten kann,
dann kann ich einfach diese bestehenden Tests beibehalten,
hat Vorteile
Dem Kunden die Erweiterung besser in Rechnung stellen zu können,
naja, das ist so eine der fiesen Seiten,
wenn man Refactoring ernst nimmt, dann ist das unter Entwicklern inzwischen klar,
dass man sowas braucht wie Refactoren.
Aber einem Kunden gegenüber zu sagen,
wir haben jetzt einen Tag lang nur unsere interne Struktur geändert,
das möchten wir trotzdem bezahlt bekommen, ist relativ schwierig.
Das ist tatsächlich ein Problem in der Softwareentwicklung.
Weil Veränderungen an bestehenden Quelltext schon schwierig genug sind,
naja, klar, also da ist durchaus was dran,
man sollte das nicht sozusagen zwei Dinge auf einmal machen und
Korrision auch auf unser Vorgehen anwenden, naja klar,
da ist was dran.
Also Korrison ja im Sinne von Dinge,
die getrennt werden können, begrifflich sollten auch getrennt getan werden.
Also eine Änderung reinbauen ist was anderes als ein Refactoring machen auf
einer bestehenden Struktur. Deswegen sollte man es da auch ändern.
Gut, also das dann hier nochmal die Zusammenfassung.
Gibt es noch Fragen jetzt zum Thema Refactoring?
Ich habe nicht den Eindruck, dann verabschiede ich mich und
wir sehen uns nicht mehr wieder.
Danke, tschüss