Zu Kellner mäßig und Kellner, also Roboter, Kellner, so Roboter, Kellner klingt wieso ein Film Ey Coding Buddies Dein Podcast rund um Softwareentwicklung und aktueller Tech News. Herzlich Willkommen. Halli Hallo und herzlich Willkommen zur neuen Folge des Coding Buddies Podcast. Schön, dass du wieder eingeschaltet hast, deine Gastgeber.
Und wie soll es anders sein? Meine Wenigkeit, der Tino und der fantastische Fabi, der mich hier angrinst, schon der hat Bock. Ich seh es schon förmlich. Ich begrüße dich, fabi, was geht ab, was geht ab, Tino, wie geht's hier steht's alles gut, alles fit, alles. Super. Ich hab für die Anmoderation ja. War richtig energiegeladen. Ich bin so reingerannt weißt du immer so? Jaja, geklappt, so yeah, was geht, was geht, was geht so ganz alleine durch den Raum gerannt,
das. Geht in meinem Kopf vor. Nein, also ich seh wir haben Bock ich hab. Doch ein geiles Thema, aber 1 vorweg noch ganz kurz Werbung in eigener Sache und zwar, liebe Zuhörerin, lieber Zuhörer, falls du noch auf der Suche nach einer richtig geilen id i bist, empfehlen wir dir wärmstens die Jet Brains ID is. Die haben für sämtliche Sprachenlösungen, die Mega geil sind, die wir auch selbst verwenden kannst dich gerne davon überzeugen, in einem von unseren Livestreams auf Twitch,
da verwenden wir sie auch immer. Und warum merke ich das an? Weil du mit dem Code Coding Buddies 25% auf die Jahreslizenzen sparen kannst und das sogar Stacked mit deinen vielleicht vorhandenen Ersparnissen, die du eh schon hast, weil nach einem Jahr zum Beispiel kriegt man eh schon Rabatte. Ganz genau. Und der Code ist auf jeden Fall noch mal den Shownotes verlinkt, findet ihr aber auch auf unserer Website. Also einfach mal reingucken und Spaß haben mit einer.
Jetbank schaut euch mal an. Genau. Werbung Ende jetzt kommen wir zum eigentlichen Thema Fabi. Es ist ne Weile her, schon da haben wir uns um so Coding Principles gekümmert, was heißt gekümmert sie besprochen zum Beispiel das jagni Prinzip. Kiss zum Beispiel.
Kiss hatten wir gemacht, genau und da würde ich heute gerne noch mal ansetzen und ein sehr bekanntes und verbreitetes Prinzip. Noch mal besprechen mit dir heute, aber es geht n bisschen mehr in die Architekturrichtung bei dem Thema. Deswegen an der Stelle ne Triggerwarnung für alle, die Objektorientierung nicht so geil
finden. Heute wird es n bisschen objektorientiert hier und wir versuchen es natürlich mit Analogien und einfach zu erklären, werden aber nicht drum rum kommen das auch so n bisschen an vereinfachten Codebeispielen zu erklären. Und zwar fabi. Was ist das Thema, Hau mal raus. Das Thema Es geht um Solid, das sind ja quasi mehrere Prinzipien in der Softwareentwicklung, die kommen auch von Robert C. Martin, also Onkel Bob, Wir hatten ja auch mal über. Onkel Bob?
Ja, geil. Wir hatten ja auch mal eine cleancode Reihe gehabt hier im Podcast und da kann man vielleicht ne also. Der ist ja auch der Verfechter Gründer von Clean Code. Genau deswegen noch mal sei, sei das noch mal angemerkt, wenn dich das interessiert, dir liebe zuhören, hör auch gern mal in die Reihe in die Clean Code Reihe von uns rein, ganz genau und solid sind ja wie ich meinte mehrere Prinzipien und es sind quasi jeder Buchstabe steht für ein Prinzip. Ja.
Und da würd ich sagen, lass uns doch einfach mal durchgehen durch die einzelnen Prinzipien. Das sind ja im Endeffekt sind das ja 5 ne, also einmal für das SOLID und dann gehen wir einfach mal durch, nehmen uns jeden Buchstaben raus, geben vielleicht ne kleine Analogie dazu, dass man sich es erstmal schön entspannt vorstellen kann, was das ist, beschreiben, worum es da geht, gehen halt auch mal n bisschen auf so n paar Codebeispiele, vereinfacht wie du meintest ein ja und ja, ja
das ist der Fahrplan. Ja, würde ich sagen, solide vorgestellt, Fabi, sorry, der muss so sein. Ich würde aber noch mal noch so ganz kurz um das Thema so ein bisschen smooth einzutauchen, noch sagen, warum ist es denn überhaupt wichtig, eine gute Softwarearchitektur zu haben, also weil das Prinzip oder die 5 wie du gesagt hast, zielen ja ganz klar darauf ab, genau das zu verbessern, also wirklich eine gute Architektur umzusetzen um gewisse Vorteile daraus zu
ziehen. Und fällt dir zum Beispiel n Beispiel, fällt dir zum Beispiel ein Beispiel ein. Meine Güte, wo du gemerkt hast, ey, hätte ich es mal vielleicht nach so einem Prinzipien umgesetzt, wo du gemerkt hast, so an diesem Projekt ist die Architektur wirklich echt nicht vorteilhaft, ich stoß hier gerade so an Grenzen, was wären so typische Grenzen, die man da, auf die man stoßen könnte, das wäre vielleicht mal so das Ganze noch n bisschen motivieren.
Gute Frage, da muss ich natürlich erstmal mein Gehirn rumkramen also ich, ich glaube, dass man auf jeden Fall, gerade wenn man irgendwann anfängt und immer weiter sag ich jetzt mal ne, also unser Weg ja zum Beispiel Studium, da hat man ja auch angefangen Programme zu machen, Programme zu implementieren, die jetzt aber noch nicht so ne Architektur
benötigt haben. Sag ich jetzt mal, weil das waren halt kleine Programme. Je größer dann ne Anwendung Programm ne Anwendung wird, desto wichtiger ist es natürlich sich um eben die die die Architektur zu kümmern, dass man halt auch wirklich die Möglichkeit hat zu sagen, ich verändere jetzt was an meiner Software, ohne dass ich aber gleich die ganze Software umkrempeln muss und das ist ja im Endeffekt, darauf zielen ja eigentlich diese Prinzipien ab.
Und ich überlege gerade, wo ich so was mal hatte. Also ich hatte auf jeden Fall diese, diese diese Situation schon mal, dass du wirklich gesagt hast, ey, ich habe jetzt zum Beispiel eine Klasse und möchte jetzt irgendwie eine Klasse ändern, oder ich will da noch was hinzupacken, also angenommen, du hast vielleicht irgendwann mal eine Klasse gehabt, die hieß zum Beispiel weiß nicht Payment Service oder so was auch immer und und darüber wird bezahlt, so und
dann hast du einen. Payment, was du irgendwie also eine Möglichkeit zu bezahlen und das reicht erstmal.
Und dann fügst du irgendwann noch mal was hinzu und dann denkst du so ja OK das das passt auch erstmal so und dann sagst du aber hast du irgendwie so n IF Else und sagst ja gut wenn es wenn zum Beispiel der Kunde Variante 1 auswählt, dann bezahl halt mit Variante 1 Else ne also ansonsten bezahl mit Variante 2 so und dann kommt man irgendwann relativ schnell in so n struggle und sagt Na OK warte mal aber jetzt muss ich vielleicht
irgendwie. Noch 1 hinzufügen und dann bist du bei einem IF LS if LS, dann sieht es irgendwie eklig aus. Dann hast du vielleicht noch andere Verhaltensweisen, wie sich so n bezahlservice dann im Endeffekt wirklich verhält und dann codest du alles in ein so ne Klasse rein und denkst dir irgendwann. Oh Gott, wenn ich das jetzt
anfasse, warte mal. Ich hab jetzt hier ne private Funktion, die aber überall aufgerufen wird und wenn ich die verändere, dann verändere ich ja vielleicht irgendwas anderes in in einer Bezahlmethode, was ich gar nicht. Möchte aber nicht genau. Also nur mal als Beispiel jetzt ne, also es war jetzt nicht explizit das was ich erlebt hatte, aber sowas ähnliches ne, dass du erst mal anfängst sagst OK ich hab jetzt das so und so und.
Also ich hab jetzt eine bestimmte Sache, die muss dann erweitert werden und dann aufgrund von muss man dann sagen früher aufgrund fehlendem Wissens hat man erstmal drauf los programmiert bis man dann irgendwann gemerkt hat oder bis ich dann irgendwann gemerkt hab boah ey, das skaliert ja überhaupt nicht ne. Und das ist halt auch schon Gutes. Stichwort Skalierbarkeit und Wartbarkeit. Ich mein, die Worte fallen sehr oft bei uns im Podcast, weil sie halt in der Softwareentwicklung
so unfassbar wichtig sind. Und das sind halt so die Erfahrung, die man glaub ich gerade als Einsteiger macht und vielleicht auch in den ersten Projekten, wie du so schön sagtest. So kleine Programme oder vielleicht so kleine Prototypen und Du entwickelst sie immer weiter, dann kommt halt noch mehr Anforderungen dazu, mehr Funktionalität und du kommst irgendwann an den Punkt, wo du dir denkst, oh mein Gott, jetzt ist das wirklich so.
N Spaghetti Spaghetti Code geworden, es ist so verschachtelt und wenn ich jetzt an der Stelle die Funktion änder. Soll sich aber nur auf A und B auswirken, aber nicht auf C und D. Aber so wie das hier gerade umgesetzt ist, zieht sich das durch die ganze Software und ich hab eigentlich schon gar keinen Überblick mehr was passiert, wenn ich jetzt diese Funktion anfasse und das sind so Klassiker und sowas haben wir
auf jeden Fall selbst erlebt. Also wenn du dann noch keine Tochter hast, wenn du dann noch keine Test eieieiei und die hatte ich damals auf jeden Fall nicht. Ich ja auch nicht. Und da denkt man sich so, ha, wie hätte man das denn besser machen können?
Also wie hätte ich von Anfang an dafür sorgen können, nicht in diese Falle zu laufen oder quasi mit dem Rücken zur Wand zu stehen und sich zu denken, ich glaub ich muss von vorne anfangen, ich bin an einem Punkt wo das erweitern schwieriger wird als das vielleicht von Grund auf noch mal neu zu entwickeln weißt du also ich mein da, deshalb gibt es ja auch Neuentwicklung, weil du an diesen Punkt kommen kannst, dass es zeitlich oder vom Aufwand her gesehen.
Besser ist es, neu zu machen, als irgendwie zu versuchen, da noch was reinzufriemeln so in dem was du hast in der Codebasis definitiv. Hat man auch schon öfter mal erlebt oder kennt man vielleicht auch, hat man gehört. Wie auch immer, aber gerade bei bei den Solid ich find das lustig weil wie du meintest ne. Man, man wusste das vielleicht
nicht, oder? Oder wie kann man sowas vermeiden und zu dem Zeitpunkt wo ich jetzt meinen Riesen payment Service geschrieben hab ne wo ich Milliarden verloren hab nein wie gesagt war ja nicht genau das Beispiel ich mir kommt das Beispiel nicht mehr richtig in den Kopf aber deswegen hab ich jetzt versucht das sozusagen nachzukonstruieren mit einem anderen Beispiel aber. Ich, ich kannte zum Beispiel Solid zu dem Zeitpunkt noch gar nicht.
Ne, also diese Prinzipien, beispielsweise ne und irgendwann, das fand ich noch ganz lustig, da hatte ich irgendwann mal so n Moment, da stand stand ich so ne Runde ne mit auch so alten Kollegen irgendwo und dann meinte einer so ja und auf jeden Fall solid dies und das und alle so hm ja ja ja so solid ja ist auf jeden Fall wichtig danach ne und so. Und jeder im Kopf. So was ist solid, verdammt, das
war ich, das war ich in dem. Moment, und dafür so ja, warte mal erst mal aufschreiben, gucken. Was soll das eigentlich? Ist so, während du noch Nickst im Kreis das Handy rausgeholt, gegoogelt und das war so finde ich so lustige Situation ne auch noch mal zum puncto Poster Syndrom ich dachte mir in dem Moment natürlich ey du kennst mal wieder gar nichts hier, alle anderen kennen das, aber ich mein ich hab ja auch genickt so nach dem Motto so ja.
Ja, auf jeden Fall. Also vielleicht, vielleicht waren da ja so 50% der Leute dabei, die auch sich dachten, das muss ich mal nachgucken. Ja, sicherlich sicherlich sehr witzig, ja, aber kenn ich so ne Situation?
Man muss natürlich sagen, die Prinzipien die wir jetzt gleich erklären werden, also gleich geht es wirklich los, sind ja unter dem Namen Solid bekannt, aber was dahinter steckt kennen manche vielleicht auch ohne an Solid zu denken oder zu wissen, dass das so in Solid alles zusammengefasst ist.
Also dann das noch mal so als Anmerkung ne, also ich denke, dass du die Prinzipien zu dem Zeitpunkt schon kanntest, dass man darauf achten sollte, aber vielleicht nicht als diese Zusammenfassung und trotzdem stehst. Steht man dann in dem Moment da, oh mein Gott, was ist das denn jetzt schon wieder euch? Oh mein Gott, da klickt dann wirklich so das imposter Syndrom wieder.
Aber dann kommt er noch dazu, kurz noch bevor wir jetzt ruhig reinstarten da kommt er noch dazu, dass man es vielleicht kennt, aber nicht anwenden kann so. Ja. Der oder denn halt wirklich nicht im Hinterkopf hat. Und genau das wollen wir jetzt schärfen, denn jetzt geht es los, also kommen wir mal zum Solid Prinzip, es ist halt wirklich sehr verbreitet und bekannt und es wurde auch schon viel thematisiert, also an der Stelle angemerkt, falls du, liebe Zuhörer, liebe Zuhörer
nach dieser. Grundlegenden Folge heute noch Fragen dazu hast, kannst du dich erstens gerne bei uns dann melden über die Podcast Mail, ansonsten können wir auch empfehlen, einfach mal auf youtube nach dem Prinzip zu gucken, da gibt es auch viele Videos, die das erklären und veranschaulichen darstellen ist auch immer noch eine coole Ergänzung und deswegen jetzt geht es los, Fabi erster Buchstabe das S von Solid, wofür steht das?
Stell dir erstmal vor, jetzt kommt so das es rein ins Bild Spam es. Genau, es steht für Single Responsibility Principle. Das heißt im Grunde genommen, dass eine Klasse jetzt immer wieder bei Klassen eine Aufgabe übernehmen soll und auch wirklich nur eine und nicht mehrere und das ist, finde ich ganz interessant, weil wenn man sich jetzt mal überlegt und jetzt mal jeder auch für sich Hand aufs Herz, ist es schon mal vorgekommen, dass man vielleicht
eine Klasse geschrieben hat, die irgendwie hieß sowas wie. Weiß nicht irgendwas XYZ utils xyz Helper was auch immer irgendwas ne also irgendwas Manager genau setzt das setzt für XYZ irgendwas ein und dann hängen Utils Helper Manager hinten dran und jetzt noch mal Hand aufs Herz ist es auch schon mal jemandem passiert, dass diese Klasse völlig ausgeufert ist und tausende Fachlichkeiten in.
In einer Klasse oder in einem Pfeil gebündelt hat und wenn ja, dann wird immer Hand. Heben ja, also 2. Hände sehe ich gerade genau. Also das ist finde ich genau, dass der Knackpunkt an diesem Prinzip, weil es geht wirklich darum, dass du eine Klasse hast, die sich darum kümmert, um genau eine Verantwortlichkeit, also eine oder Fachlichkeit, wie du es nennen möchtest und. Und nicht, dass du mehrere Sachen ineinander sag. Ich jetzt mal verbandelst.
Also wenn du jetzt noch mal, weil wir gesagt hatten, wir versuchen mal eine Analogie zu geben, angenommen, du hast ein Werkzeug, ne und dieses Werkzeug ist ein Multifunktions alles Werkzeug, du kannst damit du kannst damit schneiden, sägen, schrauben, bohren, du kannst alles machen so. Also bohren ist krass. Bis eben wollte ich noch sagen, so typisches Schweizer Taschenmesser. Ne, das Bohren wäre krasser, das ist noch viel viel. Krasser. Damit kannst du wirklich alles
machen und. Und jetzt geht dir auf einmal der Bohrer kaputt und du denkst dir so, ah misten echt blöd, ich kauf mir halt wieder dieses super multifunktionale Ding, weil es gibt ja auch nur das muss man sich natürlich vorstellen, es gibt nur das ne, dann kaufst du dir natürlich den Bohrer noch mal, kannst wieder bohren, aber hast dazu natürlich noch mal wieder ne Säge und du hast wieder weiß nicht n was hab ich gesagt akkubohrer frag mich nicht, ich weiß selber wieder
was drin war, du hast also quasi alles noch mal doppelt, obwohl du ja eigentlich nur den Bohrer gebraucht hättest. Ne. So, und jetzt wär es ja viel cleverer ne einfach zu sagen ey ich mach n eigenes Werkzeug was n Bohrer ist und n eigenes Werkzeug was ne Säge ist und so weiter ne Oh Wunder gibt es auch, ist tatsächlich in der Realität so und das ist halt genau der Punkt.
Du willst ja wenn dir irgendwas kaputt geht beispielsweise nicht noch mal das Ganze dann sozusagen nachbestellen, in diesem Fall ne ja. Das ist ne ganz gute, ne gute Analogie. Jetzt kann sich natürlich der eine oder andere denken, ja, aber ich möchte so n Schweizer Taschenmesser haben, weil da halt alles dran ist und das
schön kompakt ist. Ja klar, das ist in dieser Analogie der Vorteil, aber wenn wir das jetzt mal auf n Code Münzen, dieses Beispiel erkennt man, dass es halt architekturtechnisch gesehen schon Sinn macht diese Verantwortlichkeiten aufzusplitten. Ich würd mal als Beispiel was reinhauen, was was vielleicht
der ein oder andere kennt. Mal angenommen du hast so ne Art Report Klasse oder log klasse oder irgendwas mit Textverarbeitung ja. Stell dir vor, du erzeugst jetzt ne Klasse Report und sagst ja gut was.
Was muss die jetzt können und du fängst an und sagst na ja ich möchte, ich krieg das Halt in einem gewissen Format und möchte das jetzt in einem für mein Programm lesbares Format formatieren, ne, also du kriegst zum Beispiel jetzt n String rein und willst das jetzt aufsplitten in ein Format was du.
Verarbeiten kannst. Das heißt, du hast so ne Formatfunktion zum Beispiel, das heißt Deine Klasse Report hat jetzt ne Formatfunktion und bietet die Funktionalität formatieren an. Soweit so gut ist eine Verantwortlichkeit passt, könnte man jetzt sagen Report der Name vielleicht nicht so gut, aber lassen wir das mal so stehen. Auf einmal denkst du dir aber, na ja, aber diese diese Formate muss ich ja auch mal abspeichern. Ich muss ja irgendwie diese Reports ablegen können.
Ja gut, dann ich hab ne reportklasse, dann werd ich jetzt ne safe Funktion einbauen. Klar. Da geb ich n Pfad rein, hab meinen meinen formatierten Bericht ja sozusagen schon und den kann ich jetzt abspeichern. Cool super, ganz Lean, nicht viel Code, kleine Klasse super. Hab jetzt aber schon 2 Verantwortlichkeiten drin.
Einmal das Formatieren und das Abspeichern richtig so und dann heißt es auf einmal ja, aber wär irgendwie cool wenn ich über die Software diesen Bericht auch an Kollege XY schicken kann, kannst du das nicht als Mail oder über über ne API rausschicken. Wie auch immer, aber dass du auf einmal noch ne Funktionalität send hast und sagst. Na ja gut, dann bereite ich jetzt die Daten noch mal auf in ein Format, was ich verschicken
kann. Ja, so Report ist noch Platz ist noch nicht so groß, die Klasse Hau ich da auch mit 3 sind schon 3 Verantwortlichkeiten, jetzt kann man sich denken ja gut es ist aber ne sehr übersichtliche Klasse, das Problem ist aber was ist wenn sich das Format ändert wenn du sagst meine Formatfunktion ändert sich weil ich intern meine Daten anders darstellen möchte, dann ändere ich das Format und gleichzeitig wird meine Send. Nicht mehr funktionieren, weil
ich nicht mehr von der gleichen Datenbasis in vielleicht diese zu übertragende Format quasi umwandeln kann.
Das heißt, du musst dann einfach schon mehrere Funktionen, mehrere Funktionalitäten und Verantwortlichkeiten, wie das Prinzip ja sagt, Anpassen, deshalb wäre es da, um auch Solid einzuhalten, der bessere Ansatz zu sagen, ich splitte das einfach in diese Verantwortlichkeiten auf und hab zum Beispiel ne formata Klasse. Ich hab ne Art Klasse, die das speichern, die Funktionalität und Verantwortlichkeit hab, dass ich zum Beispiel dieses Formatieren und das Abspeichern
der Daten oder das Cent was ich jetzt meinte einfach wirklich Kapsel und. Voneinander trenne weil dann spielt es nämlich keine Rolle, wenn ich bei avas änder, dann ist b davon nicht betroffen, richtig und vor allem könntest du auch rein theoretisch in deinem Formata oder wie du den genannt hattest ne, also dieser dieser Formatierer nenn ich den jetzt einfach mal. Könntest du ja auch verschiedene
Funktionen einbauen. Zu sagen, ey ich möchte jetzt aber zum Beispiel auch, also wenn du es in verschiedene Formate formatieren möchtest, weißt du, dann kannst du ja zum Beispiel sagen, ey, ich brauch das zum Beispiel fürs Senden, brauch ich das oder ich brauch es zum Beispiel fürs Speichern oder was auch immer, dann kannst du Format for send machen oder Format for for safe oder was auch immer ne also Namen austauschbar, aber du weißt was ich meine.
Das heißt, du hast die Möglichkeit zu sagen, okay, du hast etwas, was formatiert für eine bestimmte, also also eine Klasse, die sich nur um das Formatieren kümmert, und du kannst halt sagen, was formatiert, also wie es formatiert werden soll, zum Beispiel genau, es ist auf jeden Fall ein sehr guter Punkt und sehr wichtig, dass man dann genau diese Aufspaltung macht und.
Und genau das mein ich auch. Wenn du jetzt zum Beispiel so n, sagen wir mal du also was ich am Anfang eingehends meinte, du hast ne utils Klasse oder so ne und da haust du erstmal alles rein so und denkst dir so ach komm hör mal, ich hab jetzt irgendwie ne utils klasse die ach die benutze ich da noch mal und dann hast du aber nutzt du diese utils Klasse zum Beispiel und du hast ne Funktion da drin Funktion HBC frag mich nicht ne
und die wird aber per. Perspektivisch in über über die Zeit der Alterung der Software, so in der in der Implementierungszeit. Je weiter fortgeschritten die Implementierungszeit ist, desto höher ist die Wahrscheinlichkeit, dass diese Funktion ABC auch an ganz vielen
Stellen genutzt wird. Und wenn du jetzt aber dann dahin kommst und sagst okay ich muss jetzt aber mal, du bist an einer Stelle im Code anstelle a und sagst ich muss jetzt hierfür, muss ich aber diese Funktion ändern, die Funktion
heißt. ABC, aber ich geh da mal rein ABC, ich änder das einfach mal ne ist natürlich keine gute Practice einfach zu sagen ich änder einfach was da drin, aber rein theoretisch könnte es ja sein, dass wenn du ABC änderst an 8 anderen stellen oder an noch mehr stellen im Code das genauso verwendet wird, aber vielleicht nur an dieser einen Stelle A, über die ich gerade geredet hab, es wichtig war, dass eine, dass etwas anderes passiert, dass die Funktion ABC
etwas bisschen anders macht, ne? Und das ist natürlich dann schwierig, wenn du sagst, ey, also das, das kann natürlich fehleranfällig sein zu sagen, ich ändere jetzt hier was und alle anderen stellen kriegen diese genau diese gleiche Änderung, aber vielleicht ist diese Änderung, die du eigentlich haben willst, eine fachlich ganz andere und müsste eigentlich in eine ganz andere Klasse, also in Utils 2. In utils 2. Genau. Also weißt du was ich meine und das ist ja genau.
Der Punkt zu sagen und ich find das ist sehr sehr wichtig, sich immer wieder zu fragen und das kommt heute auch ja immer noch vor. Es ist ja nicht so, dass du irgendwann sagst, ich weiß sofort, was meine Fachlichkeiten sind, auch noch mal Stichwort refactoring, da kommst du ja relativ schnell hinzu sagen. OK, warte mal. Ich hab jetzt hier was gemacht, aber eigentlich ist das eine Fachlichkeit und das ist ne andere Fachlichkeit.
Das heißt irgendwann vielleicht im Verlaufe dein der Implementierung merkst du das sind ja tatsächlich 2 fachlichkeiten oder vielleicht kristallisiert sich das über die Zeit heraus, dass du sagst, früher war es eine, aber mittlerweile sind es eigentlich 2. Lasst uns das mal aufsplitten. Ne. Genau also dieses diese Awareness sag ich jetzt mal zu
haben. Und zu gucken, also immer daran zu denken und vielleicht auch noch mal mit einem anderen Blick später auf gleiche Klassen zurück zu gucken und sagen muss man die vielleicht auftrennen, sind das mittlerweile vielleicht mehr Verantwortlichkeiten als nur eine, wie es mal war. Ja, das ist ein guter Punkt, dass genau dafür auch refactoring da ist. Und an der Stelle auch noch mal die Anmerkung, dass diese Prinzipien, die wir hier erklären, ja auch Richtlinien sind.
Ja, also es heißt nicht, ich muss jetzt jede einzelne Funktion in ne eigene Klasse packen, weil das jetzt unterschiedliche Verantwortlichkeiten sind. So ist es ja nicht, sondern man muss es geschickt clustern und wie du meinst herauskristallisieren, was die Verantwortlichkeiten sind, wo lohnt es sich es zu splitten und
wo nicht? Ja also das auch noch mal angemerkt ne, nicht dass man so ins Extreme verfällt, das ist auch bei den Cleancode 3 haben wir das oft erwähnt, das sind Richtlinien und man muss es nicht immer. Ins völlige extreme sag ich mal wirklich übertrieben umsetzen, weil dann gehst du leider wieder ins Negative von von den Benefits her, die bleiben dann aus sag ich mal so genau genau, wir haben ja noch 4 Prinzipien, deswegen geh ich mal direkt zum nächsten Let's go und zwar bei Solid.
Das O steht für Open closed principle, also OCP. Und besagt im Prinzip, dass wenn ich ein softwaremodul hab, also beispielsweise jetzt auch wieder unsere Klasse, dass diese offen für Erweiterung sein soll, aber geschlossen für Modifikation. Und das ist eigentlich auch relativ gut zu erklären, da würde ich nämlich noch mal dein Beispiel aufgreifen, was du eingangs quasi gebracht hattest. Vorhin mit mit dem Bezahlen. Wie du meintest, so, es gibt eine Bezahlmöglichkeit.
Ja dann hab ich ne Funktion, die heißt Pay in meiner Payment klasse und da bau ich jetzt den Code ein den Ich brauche um dieses Pay auszuführen ne und dann kommst du aber zu dem Punkt, dass du sagst ja ich muss das jetzt erweitern, es gibt jetzt wir binden noch ne Bezahlmöglichkeit an, zum Beispiel keine Ahnung das Erste war Kreditkarte und jetzt machen wir auf Rechnung. Mhm. So ja OK, warte mal. Die Pay Methode ich sehe schon da ist die Kreditkartenzahlung drin.
Ich brauche jetzt auf Rechnung ja gut if Aids wie du meintest zum Beispiel so gut OK ist entschieden ich hab jetzt zum Beispiel NI Namen was sagt was quasi identifiziert was für ne Bezahlung und fertig weiter geht es ja OK wäre aber auch echt wirklich cool das Ganze keine Ahnung mit Paypal. Paypal zum Beispiel zu bezahlen. So, dann bist du schon bei 345, was alles noch mit reinkommt, ne und dann kommst du an den Punkt.
Was ist wenn jetzt irgendwas in dieser Pay angepasst werden muss was alle betrifft, was nur eine Bezahlmöglichkeit betrifft, dann kommst du halt in Teufelsküche wie man so schön sagt, du musst extrem aufpassen, dass du die anderen Bezahlmöglichkeiten nicht kaputt machst, sage ich mal. Wenn du jetzt zum Beispiel eine ergänzt oder bei einer was abändern muss, die anderen nicht betroffen sind.
Du musst dir überlegen, welche sind alle betroffen von meiner Änderung in der Pay Methode und das ist richtig tricky irgendwann und auch wirklich ein heißes Ding so also das ist gefährlich und deswegen sagt dieses Prinzip, du musst dafür sorgen, dass du erweiterbar bist. Also du kannst neue Bezahlmöglichkeiten reinbringen, aber geschlossen für Modifikation.
Du darfst nicht die bisherigen Bezahlmöglichkeiten beeinflussen damit, und das kann man denn eigentlich sich auch ganz gut vorstellen, indem du sagst, ich hab jetzt nicht nur ne klasse, wo ne Pay drin ist, sondern ich erzeuge für jede Bezahlmöglichkeiten hab ich eine eigene Klasse, die eine Pay implementiert, das heißt ich hab jetzt zum Beispiel ne Abstrakte.
Payment Klasse. Die wird zum Beispiel abstrakt mit einer Methode Pay und ich implementiere jetzt meine Bezahlmöglichkeiten davon und implementiere die Pay und kann denn abhängig von der gewählten Bezahlmöglichkeit die richtige Pay Methode aufrufen. Ich hoffe man konnte das mir folgen. Wie gesagt, die haben ne Triggerwarnung gegeben. Im Endeffekt so ne Art einfach ne Art Interface, was sozusagen implementiert wird dann am Ende.
Und dann hab ich den Vorteil, wenn ich jetzt sage, bei der Rechnung muss ich zum Beispiel irgendwie wie ich ne Rechnung da noch mit ranhänge oder wie ich die Ausliefer wie auch wie auch immer, also wirklich was rechnungsspezifisches, muss ich in der Pay jetzt anders aufrufen oder? Kommt, wird komplett abgewandelt, dann betrifft das, betrifft das aber nicht meine anderen Bezahlmöglichkeiten, weil die Pay Methode ja quasi extrahiert ist. Sozusagen. Ja, und das ist halt eine schöne
Sache dabei. Das finde ich zum Beispiel noch, um noch mal vielleicht eine kleine Analogie noch mal da zu lassen, falls das jetzt vielleicht zu verwirrend oder zu objektorientier lastig war. Was auch immer. Will nicht sagen, dass man sich versteht. Ich habe es fantastisch verstanden.
Aber. Wenn du jetzt zum Beispiel, sagen wir mal, du hast du den Rechner und du willst jetzt zum Beispiel deinen deinen Speicher aufstocken, dann kannst du ja sagen okay, ich möchte meinen Speicher erweitern, so demzufolge kannst du zum Beispiel hast du einen extra Slot dafür und kannst halt eben einen neuen Speicherriegel einsetzen, relativ einfach super ohne Probleme.
Ne. Und es ist ja nicht so, dass du erst zum Beispiel sagst, ey, ich muss jetzt aber noch irgendwie mein Motherboard irgendwie auseinander schrauben, da noch was dran löten sozusagen oder vielleicht den vorherigen Speicherriegel, sozusagen die, die die Schnittstelle, wo ich es drauf stecke, sozusagen verändern, weil der gar nicht passt oder so ne, also diese Modifikation sollte ich mein, das ist selbsterklärend bei einem Rechner, dass man das
nicht tut, ne, aber? Genau darum geht es halt eben zu sagen. OK, ich kann es erweitern, aber ich will es nicht modifizieren, weil angenommen du modifizierst es würden ja vielleicht deine alten Speicherriegel gar nicht mehr passen und dann hast du auch nichts gewonnen. Und der Vorteil ist natürlich, wenn ne Pay Methode wegfällt, zum Beispiel jetzt noch mal in dem Beispiel, dass du sie einfach. Entfernen kannst und musst nicht in deiner vorherigen globalen Pay Methode gucken.
Wo muss ich jetzt überall Codezeilen löschen um diese Pay Methode rauszukriegen und funktionieren die anderen noch zum Beispiel? Also du hast halt diese Erweiterbarkeit, aber natürlich auch den Umkehrschluss, dass du Sachen auch wieder sehr gut, weil sie so Gekapselt sind, entfernen kannst. Richtig genau also wie gesagt, ist natürlich auch wieder. Eine Richtlinie sozusagen ist jetzt kein kein Must have. Es ist aber immer gut.
Wie gesagt, bei solchen Dingen daran zu denken und sowas im Hinterkopf zu haben und zu sagen, okay ist es denn vielleicht sinnvoll in diesem Moment, es nach diesem Prinzip, nach diesem o Prinzip, dem OCP oder Open closed principle vielleicht zu betrachten? Beziehungsweise könnte man es einbringen, ist es an der Stelle sinnvoll.
Das ist ja sozusagen immer der Gedanke, der dann mitschwingen könnte, sollte vielleicht um es eventuell dann besser zu machen oder vielleicht genau das zu vermeiden, was du eingangs beschrieben hast, sozusagen das Problem an der Sache, an der Sache. Ja, du hast es schon gesagt, es ist so Awareness ne, dass man einfach das im Hinterkopf hat und dran denkt dann. Das wird schon dafür sorgen.
Allein wenn man davon gehört hat und das immer im Hinterkopf hat, sorgt schon dafür, fortan bessere Softwarearchitekturen zu erstellen. Definitiv auf jeden Fall, also zumindest aus unserer Erfahrung her, wo wir uns damit, also als wir angefangen haben, uns damit auseinanderzusetzen, hat das dafür gesorgt, bessere Softwarearchitekturen erstellen
zu können. Ich finde, was auch auf jeden Fall hilft ist oder was mir auf jeden Fall auch öfter mal geholfen hat, ist einfach mal zu sagen, es gibt so ein Prinzip und ich versuche mir jetzt aber mal.
Vom Beispiel zu nehmen, um es einfach mal nach zu programmieren, weil ich finde, es sind es sind immer noch 2 Sachen auf der einen Seite, das kenne ich, das okay mehrere Sachen, Entschuldigung, das ist quasi so eine Art Kette, dass du sagst auf der einen Seite kenne ich überhaupt dieses Prinzip, wenn ja Check super Sache, dann weiß ich wie es funktioniert okay alles klar Check habe ich es einfach mal ausprobiert um zu
fühlen. Wie das wirklich funktioniert, wie es sich auch anfühlt, im Code ne. Und da ist es dann einfach hilfreich, einfach mal zu sagen, OK, ich nehm mir mal n Beispiel Programmier das einfach mal und kann sozusagen live mitkriegen, wie dann sozusagen.
Wie dieses Prinzip dann angewendet aussieht, selbst mal programmiert und so weiter ne, also das ist halt einfach auch noch mal hilfreich klingt finde ich immer sehr trivial zu sagen, ja gut, du weißt doch wie es geht, aber einmal programmieren einmal selber n Beispiel sag ich jetzt mal auf die Beine stellen und dann ist es noch mal n bisschen was anderes, zumindest
geht es auf jeden. Fall. So auf jeden Fall das da geh ich mit, so kommen wir mal zum dritten Solid l. Das ist das lisco Substitution Principal und da muss ich sagen das ist das Prinzip von den 5 was ich persönlich damals am schwierigsten fand. Zu verstehen und zu verinnerlichen. Deswegen würde ich da auch direkt mit einer Analogie starten, nicht auf n Codebeispiel gehen, in der Hoffnung, dass man es dann n bisschen besser greifen kann. Ich. Bringe danach n Codebeispiel.
OK, sehr gut. Dann machen wir es diesmal so rum und zwar möchte ich, liebe Zuhörer, liebe Zuhörer, dass du dir mal vorstellst, wieso eine universelle Steckdose aussieht und wie man sie quasi verwendet. Und dann stell dir vor, du hast jetzt verschiedene Elektrogeräte wie? Ja, was habe ich hier gerade ein Laptop, Ladekabel, ich habe einen Kaffee, also eine Kaffeemaschine noch in der Küche, Staubsauger, Staubsauger auch eine super Sache.
Also du hast so verschiedene Elektrogeräte mit ganz unterschiedlichen Anwendungsfällen, die aber die gleiche Steckdose verwenden, das heißt du kannst jedes Gerät in diese Steckdose stecken und verwenden. Also der Laptop lädt, die Kaffeemaschine kann Kaffee machen und der Staubsauger saugt so.
Und das ist im Prinzip dann lisco Substitution Principle konform, das heißt jedes Gerät ist untereinander ersetzbar mit dieser Steckdose. Du kannst erst das Laptop Ladekabel ranstecken, dann ziehst du es raus wenn der Laptop geladen ist, dann steckst du die Kaffeemaschine ran, zapfst dir einen Kaffee. Ziehst sie wieder raus, machst einen Staubsauger ran und saugst dein Arbeitszimmer
beispielsweise. Das heißt, sie erfüllen alle die gleichen elektrischen Anforderungen, um mit dieser Steckdose verwendet werden zu können. Was ist jetzt jedoch, wenn du beispielsweise ein amerikanisches Gerät hast, was eine andere Spannung benötigt, dann funktioniert das eben nicht mehr, weil wenn.
Ja, keine Ahnung, bis zum Kurzschluss, keine Ahnung was passieren kann, aber es verstößt halt gegen dieses Prinzip, weil du die Geräte nicht mehr willkürlich, was heißt willkürlich, also wie du möchtest einfach austauschen kannst, weil dieses amerikanische Gerät eine andere Spezifikation der elektrischen Anforderungen hat und das würde gegen dieses Prinzip verstoßen. Du kannst es halt nicht mehr frei austauschen, es ist halt nicht kompatibel am Ende.
Ich mein das System in dem Sinne und so Steckdose ich mein das fängt ja rein theoretisch genau bei der Steckdose schon an, aber selbst wenn du den Stecker gleich machen würdest, würde ja wahrscheinlich trotzdem irgendwas nicht funktionieren, da bin ich kein Elektrotechniker, ich weiß nicht genau was passieren würde, wenn man mehr oder weniger Volt dann da reinstecken würde, du meintest ja Kurzschluss fängt der Staubsauger da an zu brennen, ich weiß.
Es nicht versaugt richtig krass. Nein, wir werden es mal nicht so auf die Elektrotechnik Ebene hin, weil davon haben wir keine Ahnung. Aber da genau das ist ne gute Anmerkung selbst. Also meistens ist ja so, dass der Stecker dann schon gar nicht passt. Aber selbst wenn der Stecker passt, würde es halt nicht funktionieren, weil du halt von einer anderen Spezifikation ausgehst. Bei dem Gerät genau als die anderen vorher genannten. Richtig.
Und es ist ja im Endeffekt so. Also diese Ersetzbarkeit, worum es ja in diesem Prinzip geht, ne? Da ist es. Es ist, das bedeutet in dem Fall, dass wenn ein Programm ne, also in dem Fall sozusagen jetzt die Steckdose soll, nicht merken ob es quasi ne Oberklasse oder ne Unterklasse verwendet, ne also es ist egal was verwendet wird, es muss funktionieren an dieser Schnittstelle sozusagen
ne ja und da geht es quasi. Also das das ist ja im Endeffekt genau diese diese Ersetzbarkeit. Aus Programmsicht natürlich als Programmierer oder Programmieren weißt du natürlich, klar, ich weiß jetzt, was ich da verwende, aber das Programm weiß es zum Beispiel, dann sollte es nicht wissen, ne, also kleines Beispiel, wenn man jetzt zum du hast zum Beispiel so so Vögel so ne vogelklasse ne und? Es ist ja ein richtiges Lehrbuchbeispiel, finde ich. Gut, aber.
Pass auf, weil ich finde, ich finde das wirklich gut, weil in. Im Normalfall was. Was können Vögel?
Vögel können fliegen, ne so das weiß man so und das können ja eigentlich alle Vögel so, aber es gibt ja zum Beispiel Vögel, die können das dann doch nicht, ne, also sind doch nicht alle so, ja, aber man denkt ja erstmal ne, also wenn er also angenommen man fängt jetzt an und sagt Ey ich brauch jetzt vielleicht für irgendein Game oder so irgendeine irgendeine Klasse ne vogelklasse weil ich will irgendwie Gegner haben, die
Fliegen ne so und. Und es soll aber auch irgendwie auf der anderen Seite auch wieder sehr realistisch sein. So, dann fängst du an, denkst du so, ja, ich habe ja die und die Vögel kämpfende Vögel kennt man, fliegen draußen die ganze Zeit nur rum. Ultra aggressiv, immer genau. Aber so, dann hast du halt auf einmal einen Pinguin.
So ein Pinguin kann halt vielleicht nicht fliegen, also er kann nicht fliegen, aber vielleicht im Game auch nicht so und dann hast du halt ne also ne du hast jetzt ne Klasse
erstellt. Vogel und dieser, diese Vogelklasse, diese Oberklasse, diese Superklasse, die kann halt die Funktion fliegen, so fly ja so und dann hast du jetzt diesen Pinguin, der ja sagt Ey, ich bin aber ein Vogel, also kann ich ja auch Fly aufrufen, weißt du so und dann hast du das Problem, dass du aber an der Stelle ja eigentlich nicht fliegen kannst. Also angenommen es würde ein String zurückkommen, so was wie ja ich kann fliegen, ich bin ein Vogel, dann würde ja beim
Pinguin genauso zurückkommen. Ja, ich kann fliegen, ich bin ein Vogel. So was nicht stimmt. Was nicht stimmt. Genau so, das heißt, das wäre ja in dem Fall dann falsch so, also würdest du dich ja dann vielleicht hinstellen und sagen naja, aber ich möchte ja genau in diesem Fall vom Fliegen möchte ich dann vielleicht eine Exception werfen, das heißt, ich überschreibe die Funktion.
In der Klasse Pinguin und sage ja gut, pass auf ich wenn wenn Fly aufgerufen wird, dann werf ich einfach ne Exception und sage ja das funktioniert aber nicht weil n Pinguin kann halt nicht fliegen, sorry. Ja, so weißt, dann ist natürlich der Pinguin an der Stelle fein raus und sagt so, ich hab mitgeteilt ich kann nicht fliegen, richtig, aber was ist das Problem wenn ich jetzt in meiner Software mit genau dieser Vogelklasse arbeiten möchte? Genau das ist nämlich das Ding.
Angenommen, du hast jetzt dein, also du du. Arbeitest immer mit Vögeln und gehst davon aus.
Okay du hast einen Vogel, so und wie gesagt, das Programm soll nicht wissen, ist es eine Oberklasse oder eine Unterklasse eine Subklasse so, das heißt das Programm sagt ich nehme mir halt irgendwas was ein Vogel ist und ruft darauf fly auf und erwarte dann okay ich kriege jetzt, dass der Vogel fliegt, genau dass der Vogel fliegt beziehungsweise ich meinte ja so, du kriegst vielleicht einen String zurück um sich das einfacher vorzustellen, da steht drin ich kann fliegen so das erwartet das
Programm und was aber bei einem Pinguin passiert es fliegt eine Exception so. So, das heißt, das Programm kann in dem Moment vielleicht gar nicht damit umgehen, weil man, weil man sich als Programmierer oder Programmiererin gedacht hat, ja, da muss ich eine Ausnahme machen und denkt aber an einer anderen Stelle nicht, vielleicht ist man selbst für diese Stelle gar nicht zuständig, dass da ja dann eine Exception fliegt, die gar nicht behandelt wird und es gar nicht
vorgesehen ist, dass da eine Exception behandelt wird. So, und dann hast du halt genau das Problem, und das kann man im
Endeffekt, oder? Wenn man sagt okay ich möchte aber dieses Lsp, also so heißt das Prinzip ja abgekürzt, möchte ich konform sein, dann wäre die Lösung an der Stelle zu sagen okay, du hast eine klasse Vogel und du hast vielleicht aber auch noch eine Klasse Flying oder oder fliegbarer Vogel Flying Bird nenne ich das jetzt mal, der sozusagen, also ein Vogel, der Fliegen kann, diese klasse, und die also ein fliegender Vogel ist. Natürlich ein Vogel, das heißt
das. Also fliegender Vogel ist eine Unterklasse von Vogel. So weit, so gut. Wenn du jetzt aber zum Beispiel irgendeinen anderen Vogel hast, wie zum Beispiel ein Rabe oder so ne also oder eine Möwe, wie zum Beispiel bei unserem Flappy Buddy Programmierwettbewerb. Genau das ist ein reales Problem. Leute, ja genau, auch wenn es bei uns keine Pinguine gibt.
Aber angenommen, Du hast jetzt zum Beispiel Rabe oder Möwe ne als Vogel und das sind beides Vögel, die wiederum Unterklassen von von einem fliegenden Vogel sind. Das heißt, Rabe ist ein fliegender Vogel und ist aber auch ein Vogel. So genau. Und jetzt kommt noch ein Pinguin und sagt, ein Pinguin ist ein Vogel, was ja bedeutet, dass im Endeffekt der fliegende Vogel die Funktion fly hat und demzufolge Rabe oder eine Möwe auch, aber der Pinguin nicht, weil die klasse Vogel hat.
Diese Funktion fliegen nicht so, demzufolge muss oder oder hat jeder Vogel 2. Zwar nicht die Möglichkeit, fliegen aufzurufen, als Funktion aber n fliegender Vogel und der Pinguin selber, der nur vom Vogel, dann sag ich jetzt mal abhängig ist oder ne Unterklasse vom Vogel ist der dem kann man dann vielleicht noch so ne Art schwimmen oder so verpassen, ne? Genau, und dadurch ist quasi die die basisklasse Vogel ja nicht verletzt am Ende durch die Unterklassen.
Wenn ich jetzt die Basisklasse in meiner Software verwende, weil ich denn nicht mehr sagen kann Vogel Punkt fliegen oder fly was du meintest, dann kann es nicht mehr passieren, dass ich da auf einen Pinguin komme, der aber nicht fliegen kann, weil ich das Halt aufgeteilt habe und das ist halt der entscheidende Punkt dabei. Genau also. Also du kannst dich natürlich hinstellen und sagen, OK, Pinguin ist jetzt ne sub klasse auch von flyingbird, aber dann
macht man ganz. Andere Sachen, aber dann kannst du, kannst es aber in deiner Software differenzieren einfach und kannst damit dieses Prinzip einhalten. Genau also wie gesagt noch mal an der Stelle, es ist n bisschen komplizierter und ich hab auch damals gebraucht das so wirklich zu verinnerlichen und zu verstehen.
Ich hoffe wir haben es gut rüber gebracht also ich konnt ihr gut folgen, ansonsten wenn es Fragen dazu gibt lieber zur lieber zur gerne ne Mail dann werden wir es noch mal vertiefen. Oder noch mal kurz zur Steckeranalogie zurück sprechen. Oder noch mal noch mal die Steckdosenanalogie.
Ansonsten würde ich sagen, gehe ich mal zum vierten Prinzip, es kommen ja noch 2. Stimmt so, dann sind wir bei dem I und das ist das Interface Segregation Principle, also dass man quasi spezifische Schnittstellen verwenden soll anstatt riesige Interfaces. Wo wir auch wieder beim Thema sind, super klasse oder super Interface wo du alles also wirklich wie wenn wir noch mal die Stecker nehmen, da kannst du einfach alles anstecken und auf der anderen Seite kann auch
alles rausgehen und du hast so n riesen Konverter da, der kann alles so ne aber keiner weiß mehr wirklich was da drin abgeht. Oder oder stell dir ne ne ne ne universelle Fernbedienung vor, eine Fernbedienung die alles kann, die hat einfach 100 Knöpfe und du kannst alles damit steuern. Hast du mal so eine gesehen? Ich hatte wirklich mal so ne Universalfernbedienung, die kannst du dir ja kaufen, gab es früher ja immer so für alle.
Fernseher so ne und ich hab zu Ende mal irgendwie bei einem Kumpel oder so gesehen dachte was ist das denn Alter und eigentlich brauchst du ja am Ende nur irgendwie wieviel. So 5 Tasten oder so. Ich, ich tatsächlich hab ich mal ne Fernbedienung gesehen, die konntest du umdrehen und die hat auf der anderen Seite auch noch Knöpfe gekauft.
Das ist aber das ist halt n perfektes Beispiel, das ist eigentlich die perfekte Analogie die wir gerade gefunden haben, weil wie du schon so schön meintest, du hast vielleicht. Nächstes Programm vorheriges laut, leise Mute vielleicht noch. Also du brauchst vielleicht ne Handvoll Knöpfe, hast dann aber so n universelles Ding mit 100 Dingern, also 100 Knöpfen, wo du theoretisch sogar noch NDVD Player bedienen könntest. Weißt du? Falls man noch weiß, was du hast zu Hause.
Und da ist halt genau die Frage, wäre es nicht besser eine spezialisierte Fernbedienung und so wie man sie auch zum Fernseher dazu bekommt? Zu haben die wirklich die auf die Funktion des Fernsehers eingeht und nicht noch 1000 extra Funktionen, die quasi unjusted sind noch drauf zu
haben. Und genau darum kümmert sich das Prinzip. Ist auf jeden Fall auch ein super spannendes Prinzip. Ich habe das auch tatsächlich auch schon öfter selber erlebt, dass man irgendwie man erstellt ein Interface und sagt, Ja, komm, ich habe jetzt.
Also das ist aber auch wieder so n so n so n Work and progressing weißt du, du fängst an und sagst OK ich hab ein Interface und mein Interface hat 2 Funktionen ne und wenn du sagst OK ich möchte jetzt dieses also irgendwie dieses Interface implementieren, dann hab ich jetzt zum Beispiel, also wie nehmen wir noch mal das Payment Beispiel ne und du sagst OK.
Du hast ein Interface mit Pay drin, als Beispiel ne und jede einzelne Bezahlmöglichkeit muss ja irgendwie Pay implementieren, vielleicht auf eine andere Art und Weise ne, dann hast dann hast du ja im Endeffekt den, du hast es ja relativ, das ist ein schlankes Interface, ein Payment Interface sozusagen ne wo nicht wirklich viel dabei ist. Aber wenn du jetzt anfängst und sagst Ey, aber da kommt jetzt zum Beispiel noch dies rein und das rein und jenes und hast du nicht gesehen, dann.
Hast du vielleicht im Payment Service 1? Nutzt du 2 Funktionen von 20 im Payment Service 32 nutzt du dann was weiß ich sagen wir mal 10 Funktionen und in dem anderen auch noch mal 10 aber eigentlich sind mindestens immer 10 Funktionen die im Interface eigentlich insgesamt verfügbar
sind ungenutzt und dann? Ne, wie gesagt, das ist manchmal auch so. N work and progress, dass man dann vielleicht irgendwann es es baut sich auf in deiner Software und du denkst dir, irgendwann gibt es nicht vielleicht irgendwie Gemeinsamkeiten wo man sagt das ist ein Interface was rein theoretisch richtig Sinn macht, ne also dass man die Interfaces sozusagen dass du, dass du einfach vielleicht 3 Interfaces aufsplittest, weil zum Beispiel eine Funktion,
nämlich die Pay Funktion, das ist wirklich die Funktion, die jedes. Jeder Payment Service verwendet, also ist das auch wirklich ein Interface, ein eigenes Interface, ne? Ja, hast du da vielleicht ein kleines Minimalbeispiel, was wir noch so geben könnten, weil wir jetzt überall immer so Beispiele hatten? Fällt dir gerade was ein? Also wenn du jetzt zum Beispiel sagst, nehmen wir mal Roboter, kommen ja jetzt gerade, sind ja voll im Kommen, ne. Mit KI und können dir was abnehmen. So ja.
Geil das hau raus das Beispiel. So, und jetzt hast du zum Beispiel, sagen wir mal in in in Lagerristen ne. Weil ich glaube, in in, in vielen so Logistikzentren oder so werden ja auch mittlerweile Roboter eingesetzt, die Pakete durch die Gegend tragen. Und du hast jetzt so. Ich war letztens kurz off topic war ich in so einem Diner, wo mir hier dieser so n Roboter das Essen an Tisch gebracht hat. OK, und wie fandst du das? Das war voll witzig, aber du hast doch das als Beispiel nehmen.
Das ist auf jeden Fall, das kann ich nicht zeugen. Aus der Realität OK, cool. Also du hast, du hast n Roboter, also sagen wir mal du hast n Restaurant in dem.
Du Servierkräfte hast also menschliche Servierer, Serviererin und Kellnermäßig und Kellner, also Roboter, Kellner, so Roboter, Kellner klingt wieso ein Film, ey die Rückkehr der Roboter, Kellner auf jeden Fall so dann diese beiden hast du und dann hast du zum Beispiel einmal den den Arbeiter sozusagen und einmal den Roboter so und beide könnten ja rein theoretisch auf
jeden Fall arbeiten. Also so, und dann hast du aber zum Beispiel noch den Punkt, dass du sagst okay, aber also ein Arbeiter, der möchte ja auch oder der Mensch, der möchte auch, der muss ja auch essen, so was wie eine Essenspause machen, also dass du halt einfach sagst, Mittagspause komm, ich gehe essen, das braucht der Roboter aber nicht, der muss aber vielleicht laden, was auch immer, vielleicht schafft er auch den ganzen Tag, aber sagen wir mal, du hast im Endeffekt
eine Klasse, die das ist sozusagen klasse Arbeiter so im. Im Großen und Ganzen. Und dieser Arbeiter muss arbeiten können, logischerweise, die Funktion braucht er, weil er
arbeiten soll und er muss essen. So und jetzt hast du aber zum Beispiel den Roboter wieder und wenn der Roboter aber ein Arbeiter ist, genauso wie ein Mensch ein Arbeiter sein kann in diesem Restaurant, dann kannst du ja rein theoretisch auf dem Arbeiter wieder, weil der Arbeiter die Funktion Work und Eat hat, also er darf arbeiten und kann essen. Könntest du ja rein theoretisch, wenn der Roboter ein Arbeiter ist, auch auf dem Roboter die Funktion eat aufrufen.
So und jetzt hast du natürlich wieder das so n bisschen ähnliches Prinzip was wir vorher also vorhin hatten, ne andere also die Subklasse macht was anderes oder? Oder reagiert vielleicht anders weil dann vielleicht ne Exception geworfen wird und da steht dann drin als Exception Message Roboter müssen nicht essen so ja aber. Hier geht es ja auf einen anderen Punkt hinaus und zwar, dass du die Interfaces oder die Oberklassen oder wie du es
nennen möchtest ist. In dem Fall ist ein Interface würde ich jetzt mal sagen, schlanker machst ne, das heißt im Endeffekt spezifischer. Genau spezifischer finde ich gut, also du hast mehr, aber spezifischer, das heißt im Endeffekt hast du das Interface workable ne wenn wir jetzt von Worker oder Arbeiter ausgehen, das heißt also.
Arbeitend, wenn es auf Deutsch machen willst oder so und eatable so. Das heißt du hast sozusagen n Interface. Was sagt OK es ist möglich zu essen und n Interface was sagt es ist möglich zu zu. Arbeiten so und bitte an der Stelle nicht übersetzen als n essbarer Mitarbeiter sagen genau, aber ich weiß was du meinst. So, und dann genau. Und dann hast du ja zum Beispiel kannst Du sagen, OK der der Mensch, ne der ist zum Beispiel, also der ist.
Rockable und die und der Roboter ist halt nur rockable so und demzufolge hast du dann den Effekt, dass der Mensch 2 Interfaces implementiert, also zum Beispiel einmal das Interface für Essen und das Interface für Arbeiten und der Roboter hat nur das Interface für arbeiten, was aber auch gleichzeitig in deiner Software bedeutet, dass wenn du sagst, ey, ich möchte jetzt alle losschicken, angenommen sagen wir mal, du hast eine kleine Simulation von dem Restaurant
und. Und du möchtest in deiner Simulation alle Arbeiter losschicken in Anführungsstrichen? Dann kannst du ja sagen okay, ich nehme alle meine Instanzen von Workern sozusagen und lass die arbeiten so und dann kann ja ein Worker, ist ja zum Beispiel entweder ein Mensch oder ein Roboter, aber wenn du jetzt sagst, schick mal bitte alle worker in Anführungsstrichen zum Essen. Also beziehungsweise die die
auch essen können. Die, die sozusagen das eatable Interface implementieren, dann funktioniert das, aber die Roboter werden sozusagen gar nicht dann bedient an der Stelle, weil die das ja gar nicht überhaupt nicht in ihrer Funktionalität dann drin haben, oder halt dieses eatable Interface gar nicht implementieren. Genau. Und. Jetzt kann man sich natürlich denken, OK, das sind jetzt 2 Eigenschaften, sozusagen, das Krieg ich schon noch irgendwie
verwaltet. Ne, das wär so n Grundgedanke wenn Gedanke, wenn man quasi immer weitergeht und sagt, nee ich brauch so ne Prinzipie nicht, das geht schon, das passt schon so, jetzt sagst du aber irgendwann jetzt hab ich aber auch noch Mitarbeiter die in der Pause draußen rauchen gehen, so ne dann will ich noch wissen wer raucht von denen zum Beispiel oder? Du baust die Aufgaben ein.
Wer bringt zum Tisch, Wer bereitet die Getränke zu, wer geht in die Küche und so weiter und es kommen immer mehr Eigenschaften rein in dieses Interface und es wird quasi so riesig wie unsere Fernbedienung. Aber es gilt halt nicht für jeden. Weil der, der draußen die Teller abräumt, muss ja nicht noch Funktionen implementieren, wie er Getränke zubereitet. Jemand, der nicht raucht, muss nicht wissen, wie die Funktion aussieht, um rauszugehen und zu
rauchen. Weißt du also, das ist ja genau das der Punkt den du meinst, weil wenn man sich so denkt ja 2 Funktionen Come on es wird 100 Pro irgendwann mehr und dann ist es genau richtig diese spezifischen Interfaces zu verwenden um dann auch spezifisch drauf zugreifen zu können am Ende oder unterscheiden zu können, richtig. Im Endeffekt hast du ja auf jeden Fall ein gutes Beispiel. Im Endeffekt hast du ja, wenn du es in deiner Software siehst, irgendwann Objekte, auf denen du
irgendwas aufrufen willst. Und du willst ja wissen, auf welchen Objekten kann ich denn was aufrufen und es soll dann auch so funktionieren. Ne, und damit du das besser auch differenzieren kannst zwischen diesen Objekten auch unterscheiden kannst, hast du halt eben dann auch spezifischere Interfaces sozusagen. Ja, genau. Ja, cool, erklärt Fabi, vielen
Dank dafür. Lass uns mal zum letzten Prinzip kommen, wir sind auch schon n bisschen fortgeschritten in der Zeit, aber wir müssen auf jeden Fall es noch unterbringen, das wär jetzt so richtig mies und das nächste erfahrt ihr in der nächsten Folge. OK, das D in Solid steht für Dependency Inversion Principle und das finde ich sehr spannend und auch sehr wichtig ist ne sehr gute Sache und im Prinzip geht es um Dependency Injection als Lösung dahinter.
Aber wie kann man sich das Ganze vorstellen, wenn man sich jetzt vorstellt, man hat zum Beispiel eine Anwendung, wo du so eine Business Geschäftslogik drin hast, die halt wirklich intern in deiner Software quasi regelt, wie gewisse Sachen umgesetzt werden, verarbeitet werden und. Je mehr ich zu den Eingabe zum Beispiel. Ich hab jetzt ganz klassisch eingabeverarbeitung Ausgabe ne, nehmen wir mal so das Eva Ding und diese Verarbeitungslogik ist riesig, da passiert unglaublich
viel. Wir haben sehr viele Eingaben und jetzt erzeug ich aber Abhängigkeiten von diesen Eingaben und bin halt so unglaublich verzwickt. Oder man stellt sich das vor, so keine Ahnung im Webbereich, wo
ja auch viele unterwegs sind. Ich habe halt so eine API, das ist meine Eingabe und die Verarbeitung ist wie ich auf der Datenbank mit diesen Daten arbeite und wenn ich jetzt aber so unglaublich verzwickt und Verwurstelt nenne ich es mal mit der Eingabe bin, dann kriege ich halt riesenprobleme wenn ich das ganze quasi durch diese Abhängigkeiten verändern will, weil ich dann an allen Stellen wieder eingreifen muss. Kannst, kannst du mir folgen? Definitiv.
Also ich hab halt das Problem, dass es nicht mehr flexibel ist, dass es vor allem nicht mehr testbar ist, weil das ist jetzt n riesen Punkt. Dieses Prinzip sag ich mal fördert unglaublich die Testbarkeit, da können wir gleich noch mal drauf eingehen und ich kann es auch nicht mehr gut erweitern am Ende, weil ich halt diese Kopplung hab. Und wie schaffe ich es jetzt diese Eingabe und Verarbeitung
voneinander zu entkoppeln? Und genau da greift halt die Dependency Injection und magst du, hast du vielleicht so ein Minimalbeispiel? Also ich finde wir können ja das ruhig mit dieser API und Datenbank ruhig weitermachen, weil ich glaube das ist so ein Bereich wo viele unterwegs sind im Webbereich wie man jetzt so eine Dependency Injection verwenden könnte dafür. Also im Endeffekt kannst du, ich hoffe ich kann das Beispiel jetzt richtig aufgreifen was du
meinst. Also angenommen du hast jetzt eine eine eine sagen wir mal Anwendung und diese Anwendung hat auf jeden Fall, also hat eine Zugriff auf eine Datenbank so ne so und dann ist diese Datenbank zum Beispiel einfach festgeschrieben in diesem Programm, das heißt du hast so. Sozusagen irgendwie einen Service.
Also sagen wir mal, du gehst über eine API und du hast in dieser API eine Anfrage und du hast irgendwie einen Service, der diese Anfrage verarbeitet und sagt zum Beispiel okay ich muss jetzt aber diese diesen Request in meine Datenbank schreiben oder Daten aus dieser Datenbank rausholen, genau, und jetzt hast du in deinem Service zum Beispiel eine Datenbank instanziiert so weil dieser Service sagt zum Beispiel okay ich brauche eine Datenbank und wenn du jetzt aber zum Beispiel
sagst okay ich. Habe jetzt zum Beispiel eine My SQL Datenbank, die ich über diesen Service anspreche. Dann wird jeder request immer nur gegen eine My SQL Datenbank gehen und wenn du aber jetzt zum Beispiel sagst ich möchte jetzt aber eigentlich gegen eine andere Datenbank gehen, weil ich noch eine andere habe, wie willst du das machen weil du immer nur diesen einen Service hast der.
Quasi wo drin, wenn dieser Service hochgefahren wird oder existiert, dann hat er eine feste Instanz von einer Datenbank oder einen festen Zugriff auf eine Datenbank, besser gesagt eine Connection dazu.
So und wenn du jetzt aber zum Beispiel sagst, ich möchte das ganze Injekten sozusagen, also dependency Injection nutzen, dann gibst du quasi die Datenbank von außen rein, das heißt im Endeffekt sagst du okay ich möchte diesen User Service haben mit dieser Datenbank. Das bedeutet, dass du im Endeffekt nicht sagst, okay, ich habe jetzt eine eine feste Datenbank, sondern ich sage diesem diesem Service, dem sage ich pass auf, ich brauche jetzt Daten, diese Daten brauche ich
aus einer Datenbank und ich gebe dir mit, welche Datenbank das ist, von der du diese Daten holen sollst beziehungsweise wo wo du die Daten reinschreiben sollst. Das ist sozusagen der kleine Unterschied. Ja, und das kannst du ja halt auch auf allen Ebenen packen. Also das war jetzt quasi die Funktion mit dem Datenbankzugriff. Du kannst es aber auch genauso eine Ebene höher packen. Wie sieht denn deine Rest api, deine Calls, deine Requests aus und was passiert in deiner
Software? Da kannst du das ja genauso auf der Ebene einziehen, dass du sagst, ich möchte ja nicht, dass jeder request genau wenn ich den Entgegennehme schon quasi.
Quasi in sich selbst tragend. Die Implementierung hat, wie ich auf der Datenbank arbeite, also wie der Service aussieht, weil dann ist jeder Request an den Service gekoppelt, da haben wir wieder ne Kopplung und wenn du jetzt aber sagst ich hab zum Beispiel ne Art Controller, ist so n klassischer klassische Klasse klassische Klasse dafür für so die für die Request die sich nur darum kümmert auf welchen Calls nehm ich denn was entgegen? Und gebe da den Service auch
noch mal rein. Dann hab ich das auch noch mal entkoppelt und das ist auch dependency Injection, dass ich sage, dieser Controller instanziiert sich keinen Service und ist damit exakt gekoppelt an diesen Service, sondern ich gebe von draußen einen Service rein, der dafür sorgt auf diese Request zu reagieren und der ist austauschbar.
Ja, genauso wie dein Beispiel. Ich habe dann den Service, der wiederum von außen die Datenbank bekommt, damit die Datenbank austauschbar ist, dass es halt nicht in sich selbst instanziiert und implementiert ist. Und das ist halt n Riesenvorteil, weil wir auch meinten, Testbarkeit angenommen, ich möchte jetzt sagen wir mal
den Controller testen. Ja, ja, also ich will jetzt einfach, ich tue jetzt so, als wenn n request reinkommt und ich möchte wissen, ob ich auf 200 mit 200 OK antworte, weil alles OK war oder nen 404 beispielsweise und ich will das jetzt testen und hab jetzt aber in dem Controller selbst diesen Service implementiert, da muss ich diesen ganzen Rattenschwanz irgendwie in diesen Test reinbringen, damit ich den
Abtesten kann. Wenn ich jetzt aber diesen Service von draußen in den Controller gebe, dann kann ich
ja nen. Sag ich mal n gemobbten Service da reingeben und simulieren wie der reagiert und kann mir so viel besser Testfälle bauen, dass ich zum Beispiel sag, wie sieht der Request aus, alles klar, ich tu mal so als wenn ich in der Datenbank jetzt den Eintrag finde und ah OK 200 OK geht zurück super der Test funktioniert jetzt tue ich so als wenn ich den Eintrag nicht finde ja OK 404 beispielsweise.
Wenn ich das aber so nicht machen müsste, dann bräuchte ich den richtigen Service. Dann bräuchte ich die richtige Datenbank, um irgendwie nach oben wieder zu bekommen. Ob der User jetzt da drin war oder nicht beispielsweise, und das ist halt das coole an Dependency Injection und das ist halt auch das D in Solid am Ende.
Ja, richtig. Also ich finde Dependence Injection ist an sich auch ein relativ großes Thema, wenn man da jetzt noch mal, wie du ja eingangs auch schon meintest, wenn es bestimmte Themen gibt, über die wir noch mal ein bisschen genauer eingehen sollen, Liebe zuhören, lieber zuhören, dann schreibt uns auf jeden Fall gerne wie gesagt über unsere Podcast Mail oder auch auf unseren Plattformen, wie gesagt, alles in den Show Notes verlinkt, um das Ganze noch mal
abzuschließen, um das vielleicht noch mal auch ein bisschen, also dieses D in Solid, um da noch mal ein kleines Bild vor Augen zu rufen. Ja.
Ich meine. Guck mal, es geht ja jetzt auch langsam wieder Richtung Sommer. Das bedeutet langsam ne, so dauert ein bisschen noch, aber man sag ich jetzt mal urlaubsplanung ist vielleicht ist real so und angenommen du als Mensch jetzt ne hast du bist eine Instanz und wirst erzeugt so und wenn du jetzt keine Dependency Injection hast und sagst OK ich möchte jetzt aber zum Beispiel mit einem Flugzeug fliegen so. So, dann wird dir zum Beispiel
eingeimpft, ne in in deiner DNA, du darfst nur von Hamburg fliegen, weil du sozusagen in dir selber den Flughafen instanziierst. Also. Ne, also eine Instanz anlegst und das ist immer Hamburg beispielsweise und nie was anderes. Das bedeutet also, du könntest zwar nach Angeboten gucken und sagen, Oh guck mal, ich könnte vielleicht von Berlin fliegen oder von München oder was auch immer, geht nicht, weil du darfst, genau, du darfst nur von Hamburg fliegen und von nirgends
woanders. Wenn du jetzt aber zum Beispiel sagst, ey, ich könnte jetzt aber die dependency Flughafen Injekten. Dann hast du die Möglichkeit zu sagen, ich gucke erstmal, welchen Flughafen ich denn überhaupt ansteuern möchte. Und wenn ich mir einen ausgesucht habe, dann nehme ich diesen und gebe ihn sozusagen
von außen rein. Also ich sag jetzt mal gedanklich, du kaufst dir die Tickets und bekommst deine Tickets und checkst dir in die Tasche so genau und dann weißt du ja, aber okay ich, ich kann mich entscheiden, weil ich erstmal sage, welcher Flughafen und dann nehme ich diesen Flughafen anstatt zu sagen, ich nehme erst den Flughafen und dann gucke ich mal was von da fliegt und wo es hingehen könnte so. Und das ermöglicht dir halt diese ganze Implementierung drumrum.
Oder sagen wir mal in deinem Beispiel, diesen ganzen Ablauf, sei es das. Stellen der Tickets, den Flug buchen oder auch zum Beispiel, was vor Ort am Flughafen passiert, was geführt bei jedem Flughafen gleich ist. Ja, aber wenn ich dann immer von Hamburg aus gehe, bringt mir das nichts. Genauso kann ich den Flughafen von draußen reingeben, also was wir mit inject Minen, falls das
nicht ganz klar ist. Ist ja im einfachen übertragenen Sinne n Eingabeparameter in einer Funktion zum Beispiel richtig oder in den Konstruktor einer Klasse richtig.
Und dann hab ich halt den Vorteil, dass ich den Rest der der Funktion nicht anpassen muss, vielleicht für so kleine spezifische Sachen. Beispielsweise Flughafen Hamburg parke ich direkt vor Ort, bei Flughafen Berlin kann ich nicht direkt vor Ort weißt du so so flughafenspezifische Sachen, die sich unterscheiden können, würden dann die ganze Funktion beeinflussen, was aber total unnötig ist, weil vor Ort muss ich ja trotzdem mein Gepäck aufgeben, durch ne
Sicherheitskontrolle gehen und in n Flieger steigen, was vor allem wieder gleich ist. Weißt du deswegen das ist n cooles Beispiel abschließend finde ich sehr gut danke dir. So genau, und damit sind wir ja quasi jetzt einmal durch die 5 Prinzipien durch Solid ist auf jeden Fall super spannend und wie gesagt immer eine wichtige Sache das im Hinterkopf zu
behalten. Man muss nicht strikt danach arbeiten, es ist auch überhaupt nicht schlimm mal irgendwann in in der Entwicklung seiner Software zu sehen um Mensch das das sind jetzt aber zum Beispiel mehrere Fachlichkeiten, da muss ich jetzt zum Beispiel mal was auf splitten, da muss ich vielleicht mal wieder was refact an, aber.
Alles kein Problem, wenn man denn zum Beispiel einfach auch mal so bestimmte Infos mal im Hinterkopf hat und und danach vielleicht so seinen eigenen Code oder seine Software, in der man arbeitet, scannt. Sag ich jetzt mal ne ja und dann kann es einfach sag ich mal nachhaltig besser werden. Ja, also auch noch mal ganz kurz abschließend die Tech Home Message. Ich würde noch mal ganz, ganz kurz durchgehen, noch mal so zur Zusammenfassung.
Also solid ist. Im Prinzip sind 5 Prinzipien für jeden Buchstaben 1. Wir haben das S mit Single Responsibility Principle im Prinzip eine Klasse, eine Aufgabe, eine Verantwortlichkeit, dann haben wir das Open Close principle, was im Prinzip besagt sei offen für Erweiterung und geschlossen für Modifikation.
Drittens war das lisco Substitution principle, was im Prinzip die Ersetzbarkeit von den Subklassen beinhaltete, das Vogelbeispiel. Ich hoffe, man kann sich noch dran erinnern mit den Pinguinen, viertens war Interface Segregation Principle, was im Prinzip sagt nicht die universelle Fernbedienung, sondern speziell für deinen Fernseher, das heißt lieber spezifische Interfaces statt riesige Schnittstellen und jetzt zum Abschluss hatten wir
dependency Inversion Principle mit der Dependency Injection. Was ja im Endeffekt sagt, diese Abhängigkeiten, die man hat, lieber auf Abstraktionsebene packen und nicht auf konkrete Implementierung, wo du ja gerade das Flugbeispiel gebracht hattest. Wenn ich implementiere in meiner buchungsfunktion Flughafen oder so. Start ist immer Hamburg ungünstig. Richtig, ganz genau so sieht es aus, gut zusammengefasst, Kino, dann sind wir eigentlich auch, würde ich sagen, durch wie
gesagt bei. 2 genaueren Fragen weitere weiterführenden Podcast folgenden Themen schreibt uns einfach an. Ansonsten danke Tino fürs für die Folge, hat Spaß gemacht und war sehr cool. Wir haben versucht es möglichst kurz zu halten und es ist wieder länger geworden als man denkt wie? So immer. Es sind aber auch 5 Prinzipien man so. Genau. Und ansonsten würde ich sagen, bewertet gerne den Podcast. Das würde uns mega freuen.
Empfiehlt ihn auch gerne weiter, wenn ihr sagt das ist ein Hammer cooler Podcast. Genauso könnt ihr uns auch unterstützen mit einem kleinen Spenden Link gibt es alles unten in den Shownotes einfach mal reinschauen und mal durchlesen, mal reinschnuppern sozusagen, ansonsten bleibt mir nichts anderes übrig als zu sagen bis zum nächsten Mal, also bis zur nächsten Woche. Wir hören uns habt einen schönen Tag, deine Cordon balis gemeinsam besser.