Folge 19

Clean Coding – Wie du als Entwickler deinen Arbeitsplatz sauber hältst

„Also ich finde als Entwickler, wenn man länger an einem Stück Code arbeitet, dann bekommt man so eine Art Tunnelblick. Ich sag auch gerne, man wird ein bisschen "Codeblind".“

Hallo und Willkommen zurück zu unserem Podcast "Informatiker erklären die Welt". Die heutige Folge dreht sich um fleckenlosen, staubfreien, blitzblanken Code. Consistec Softwareetwickler Dennis und Kevin beantworten Fragen zum Thema "Clean Coding": Was bedeutet Code Style? Warum ist dieser so wichtig? Wie sieht guter Code eigentlich aus und wie schreibt man diesen? "Clean Coding - Wie du als Entwickler deinen Arbeitsplatz sauber hältst"

Viel Spaß beim Hören !

Transkription

 

Dennis: Hallo. Herzlich willkommen zu einer neuen Episode in unserem Podcast, Informatiker erklären die Welt. Ich bin wieder dabei, der Dennis, Softwareentwickler bei der Consistec. Aber ich habe euch heute mal ein neues Gesicht mitgebracht, den Kevin. Kevin stelle dich mal vor.

Kevin: Ja, hallo, ich bin Kevin. Bin Software Entwickler bei der Consistec seit letztem Jahr. Und vorher war ich Zuhörer vom Podcast. Bin auf die Consistec aufmerksam geworden und jetzt sitze ich hier selbst auf der Couch, mit dir und wir nehmen den Podcast auf.

Dennis: Ja, Kevin, dann erkläre den Leuten doch mal über was wir heute sprechen wollen.

Kevin: Wir wollen heute über Clean Code und Code Style reden. Was macht guten Code aus, was ist schlechter Code. Wie erkenne ich den schlechten Code. Und auch so ein bisschen über die Methodik, wie wir bei uns im Team vorgehen, um guten Code zu produzieren.

Dennis: Okay, dann fange ich mal an und frage dich: «Warum ist es eigentlich wichtig, ob ich jetzt einen guten Code schreibe oder einen schlechten Code? Was, was bedeutet denn das jetzt für mich? Hat das irgendwie mit Nebenwirkungen für den Kunden oder jetzt für den Entwickler oder ist es einfach nur Code Ästhetik? Um was geht es da genau?»

Kevin: Das kann sich zum einen auf verschiedenen Ebenen niederschlagen. Guter Code oder schlechter Code. Was mir da zuerst einfällt, ist halt, wenn ich eine schlechte Codebase habe, dann ist der Code meistens auch schlecht zu testen oder es ist sehr aufwendig Tests zu schreiben. Und im Endeffekt ist Testen in der Entwicklung ja sehr wichtig, um zu verifizieren, dass dein Code halt funktioniert und auch das macht, was du möchtest. Deswegen möchte man halt auch gut testbaren Code haben. Ein anderes Problem ist halt auch das Verständnis, wenn ich schlechten Code schreibe und ich bin jetzt krank oder im Urlaub und du musst jetzt meinen Code warten, weil ein Back Off aufgetreten ist. Dann ist das für dich deutlich einfacher, sich im Code zurechtzufinden, um zu sehen «Das war die Intension von Kevin und deswegen hat er das auch so gemacht.»

Dennis: Ja.

Kevin: Genau.

Dennis: Im schlimmsten Fall hast du die Firma verlassen. Keiner versteht mehr dein Code. Das ist ja, was wir im Fachjargon Legacycode Base nennen. Keiner weiß so richtig, wie der funktioniert. Im schlimmsten Fall gibt es auch keine Dokumentation oder Tests, die darauf hinweisen, ob es überhaupt funktioniert. Und dann ist es wirklich fraglich, ob ein Projekt in Zukunft auch nochmal weitergeführt werden kann.

Kevin: Ja, genau. Und ein anderer Punkt ist halt da auch, dass sich so schlechter Code oder so ein Legacy Code Base, die schlägt sich natürlich im Endeffekt auch auf das Unternehmen, auf den Kunden nieder, weil das verursacht einfach Kosten. Die Wartung, der Support werden dadurch teuer und neue Features umzusetzen kostet mehr Zeit und somit natürlich auch dann mehr Geld dem Kunden oder halt je nachdem die Firma, wenn sie was erneuern muss.

Dennis: Ja. Es ist glaube ich auch in dem Zusammenhang, wichtig zu erwähnen, dass man versucht, auch so wenig Code wie möglich zu schreiben. Weil je mehr Code ich habe, desto mehr potenzielle Probleme habe ich auch im Code. Und dann kann es halt sein, dass der Kunde sich meldet und irgendetwas geht nicht. Also ich versuche, wenn ich Code verbessere, wir nennen das dann Refactoring, versuchen wir heute auch immer den Code ein bisschen zu reduzieren. Weil es dann einfacher ist für den Programmierer, das Ganze zu überblicken. Da sind schon mal einige Punkte, die schon mal plausibel machen, warum das so interessant ist, wirklich Clean Code zu schreiben. Jetzt will ich dich mal gerne fragen: «Wann hast du denn das letzte Mal einen schlechten Code geschrieben? Kannst du dich daran erinnern?»

Kevin: Ja. Da muss ich erstmal nachdenken, was mir da so einfällt. Ist natürlich jetzt eine, eine raffinierte Frage von dir. Ja, ich kann mich da an eine Situation tatsächlich erinnern, da wollte ich mir einfach eine einfache Hilfsmethode schreiben, die eine Auswertung macht von variablen und mir einen Boolean zurückgibt. Und irgendwann ist mir aufgefallen, «Die verhält sich gar nicht so wie ich das dachte.» Und eigentlich dachte ich, «Die ist ja trivial, die Funktion.» Und dann, habe ich gedacht «Okay, die verhält sich nicht so, wie ich es gerne hätte. Ich schreibe jetzt erstmal mir einen Test mit meinen ganzen Testfällen und schaue, wie soll sich die Funktion verhalten, teste die Funktion.» Und dann habe ich gesehen, die wird hier an zwei, drei Stellen rot. Habe mir das nochmal genauer angeschaut, genauer Gedanken gemacht und konnte die Funktion dann auch anpassen. Dann hat sie auch hinterher so funktioniert, wie ich es wollte. Wann hast denn du, das letzte Mal schlechten Code geschrieben?

Dennis: Das ist tatsächlich nur zwei Wochen her. Eine Kollegin von uns, die Kim, die ich jetzt an dieser Stelle auch mal Grüße, die hat ein Review gemacht, von einem Code, den ich geschrieben habe. Da habe ich einen relativ umfangreichen Test geschrieben und beim Schreiben vom Test haben wir mal festgestellt «Da gibt es so verschiedene Eingabeparameter von Testen und das könnte mal eine Funktion sein, das könnte mal ein Objekt sein. Und dann habe ich-, die Testbasis habe ich immer weiter ausgebaut. Dann wurde dieser Test, diese Testparameterklasse immer komplexer. Da gab es generische Typen, dann noch einen zweiten, noch einen dritten. Und das wurde alles relativ kompliziert. Hat nachher super funktioniert. Kim hat auch gesagt, funktioniert im Review, weiß halt nicht wie. Und dann bin ich dann aber auch nochmal an die Sache rangegangen und habe dann lieber verschiedene Testklassen gemacht, so, dass man das nachher auch einfach besser nachvollziehen kann. Weil jemand anderes möchte vielleicht in Zukunft da nochmal ein Test schreiben. Der muss dann verstehen, wie das genau funktioniert oder auch ich. In zehn Wochen habe ich das nicht mehr genauso im Kopf wie das ging. Und dann muss ich selber nochmal ein bisschen gucken, wie das funktioniert hat. Kevin, jetzt haben wir ja so ein bisschen schon darüber geredet, was wir da so verbockt haben. Ist natürlich die Frage: «Wie sieht eigentlich guter Code aus? Wie schreibe ich jetzt guter Code? Auf was muss ich da achten?»

Kevin: Das kommt zum einen immer auf die Programmiersprache, die wir verwenden. Weil die Programmiersprachen verfolgen halt unterschiedliche Paradigmen, haben andere Syntax und auch einen anderen Syntactic Sugar. Dass es dir einfach macht, Code zu schreiben. Genau. Aber grundlegend kann man daher auch vereinfacht sagen, wenn ich in einer Firma arbeite und eine bestimmte Programmiersprache nutze, dann kann ich mir auch immer Best Projects Lists anschauen. Und wie machen denn andere das? Wie machen dann zum Beispiel auch große Unternehmen das? Wie schreiben die ihren Code? Gibt es da irgendwelche Lessons Learned? Was kann ich einfach prinzipiell schon mal gut machen, wenn ich Code schreibe. 

Dennis: Also, wenn wir das jetzt so runterbricht, mal so ein Extremfall nimmt und eine Sprache wie Java, die ist sehr stark objektorientiert. Da programmiere ich natürlich auch sehr stark objektorientierter Code. Wenn ich jetzt zum Beispiel Python nehme, was eine Skriptsprache ist, ist das so ein bisschen Laissez fairer, sagt man glaube ich. Da kann ich vielleicht auch eher funktionalen Code schreiben. Und das hat natürlich auch eine Auswirkung. Schreibt die Python Community natürlich einen anderen Code. Die haben andere Codeideale als jetzt zum Beispiel die Java Community. Das heißt aber nicht, dass einer von beiden recht hat und der andere schreibt halt einfach falschen Code. Es ist einfach ideomatischer Code und Python vielleicht anders zu schreiben als Java. Und die zweite Komponente ist natürlich, wenn ich jetzt als Entwickler-, du, du kennst das ja, in eine Firma reingehe, dann haben die auch so ein gewissen Code Style. Gewisser Sachen: «Wie schreibt man Conditions zum Beispiel? Wie rückt man das ein?» Das sind vielleicht Details, aber das sind Sachen, das sollte man vorab mit den Kollegen, wo man jetzt dazu gekommen ist, mal abklären. Um dann halt einfach zu wissen, «Wie schreibe ich den Code am besten?», dass man da so eine gewisse Konsistenz halt einfach drin hat. Ja, aber wie du gesagt hast, gibt natürlich trotzdem auch so ein paar objektive-, ich sage jetzt einfach mal Richtlinien, wie man guten Code schreibt. Das setze ich jetzt über mehrere Programmiersprachen hinweg. Und da wollen wir auch heute mal näher darauf eingehen. Dann lege mal los, Kevin. Was fällt dir da so als Erstes ein?

Kevin: Und zwar fällt mir da halt ein, weil wir uns grade mit roten Namen und Variablen betrachten, da ist dann natürlich schon immer sinnvoll kurze Namen zu wählen, aber die sollten halt dann auch immer aussagekräftig sein. Also, so eine Variable sollte nicht X heißen, sondern sollte einen aussagekräftigen Namen haben, wo der Entwickler, der da mal drüber liest, einfach auch weiß, «Für was steht die Variable?» und im Fall einer, einer Methode oder Funktion, sollte man halt schon am Namen erkennen können, «Was ist denn hier der Input zum Beispiel, was ist der Output der Funktion?» Weil am Ende des Tages sind wir Entwickler größtenteils damit beschäftigt, Code zu lesen, anderen Code zu lesen. Und nur ein Bruchteil eigentlich damit beschäftigt, selbst Code zu schreiben.

Dennis: Genau. Vielleicht auch so ein bisschen im Kopf, das Umdenken, dass, dass es nicht Code und Dokumentation gibt, sondern der Code oft halt auch selber sich dokumentiert. Wenn ich jetzt gute Methoden und Variable Namen nehme, dann muss ich da nicht noch extra Dokumentation schreiben, weil das sich von selbst erklärt und das ist für uns, als Entwickler, natürlich viel einfacher wenn wir nicht noch erstmal das Handbuch dazunehmen müssen, sondern direkt anhand vom Code sehen, «Was passiert da eigentlich?»

Kevin: Genau. Also sollte man trotzdem nicht vergessen, dass Dokumentation halt auch immer wichtig ist. Es gibt durchaus Fälle, wo man vielleicht auch mal eine Methode oder eine Klasse besser dokumentiert, weil man sagt, «Okay, ich hatte hier vielleicht eine Intention dahinter, warum ich sie jetzt gerade so gelöst habe.» Dann kann man so was auch gerne mal vermerken, damit der, der darüber liest einfach die Intension versteht. Aber wenn man halt die Namen ordentlich wählt und die Funktion klein hält, dann ist der Code eigentlich schon in seiner eigenen Dokumentation.

Dennis: Ich sehe halt gerade bei, bei Kollegen, die jetzt ganz frisch sind und anfangen, was wir halt immer Captain Obvious Kommentare nennen und da gibt es eine Methode, die heißt Execute Command und darüber steht ein Doc String, der sagt Execute Command. Also, da, da bringt dir der Doc String einfach nichts. Das heißt ja nicht, dass du, nur weil Dokumentation wichtig ist, dass du für jede Methode unbedingt ein Doc String haben musst. Manchmal ist das einfach auch schon direkt erklärend, was es tut. Manchmal muss man auch nicht erklären, was die Methode tut, sondern halt irgendwelche Zeiteneffekte, mit denen man gar nicht rechnet. Ich habe da eine Methode, die schreibt auf einmal irgendeine Jason Datei noch auf Highsysteme. Dann ist es natürlich cool, wenn ich oben ein Doc String sagt, dass die Methode das halt auch macht. Genau. Du hast schon Methoden angesprochen, die Benennung. Das ist natürlich ein sehr wichtiger Punkt. Aber was ja auch wichtig ist «Wie schreibe ich Methoden? Schreibe ich jetzt Methoden idealerweise mit 500 Zeilen, 300 Zeilen, vielleicht nur zehn?» Was ist denn da so deine Einsicht?

Kevin: Was man da oft auch so in der Literatur oder was man oft hört oder gesagt wird, ist immer dieses klassige-, eine Funktion oder Methode sollte genau eine Sache machen. Das sorgt auch immer für einen Entwickler, der erst anfängt, sage ich mal, dann wenn man startet im Beruf ist die Sache «Was ist denn immer diese eine Sache?» (I: Genau.) «Wie grenze ich das denn ein?» Das ist immer gar nicht so einfach festzulegen.

Dennis: Ja, Kevin, du hast gesagt, Methoden sollen eine Sache machen und die sollen sie gut machen. Das wollen wir jetzt natürlich jetzt ein bisschen konkreter erklären. Es ist natürlich sehr abstrakt. Also, der Grundgedanke ist, ich hole eine relativ große Methode, die halt relativ viel tun soll und ich staffele das. Also ich breche diese Methode in mehrere kleineren Methoden auf und meine große Methode ruft dann die Hilfsmethoden auf. Und jede Hilfsmethode hat dann so ein kleinen Teil von der Gesamtordnung. Die macht dann nur einen kleinen Teil und nicht das Ganze. Und wenn ich das clever mache, dann habe ich zum einen halt eine Hierarchie, da gibt es halt Methoden, die in der Hierarchie ein bisschen höher sind, die benutzen dann Hilfsmethoden. Und dann gibt es halt Methoden, die sind tiefer in der Hierarchie, die machen dann konkrete Sachen. Vielleicht willst du da mal so ein Beispiel bringen, damit man es noch ein bisschen veranschaulichen kann.

Kevin: Genau, da können wir uns ja erstmal abstrakt vorstellen, was wir dann Informatiker oft haben beim Programmieren, dass wir irgendwie so eine Serverkommunikation haben. Also, wir haben einen Client und der will halt mit dem Server reden, die wollen kommunizieren, also muss der Client auch eine Funktionalität haben, eine Funktion haben, wie er den Server ansprechen kann. Genau. Und dafür benötigt man dann auch verschiedene Sachen. So, so was wie zum Beispiel die Adresse und gerade, wenn wir jetzt hier beim http Protokoll sind, brauchen wir auch einen Header in dem bestimmte Metainformationen gesetzt werden. Und wir haben natürlich auch noch unsere eigentliche Nachricht, unsere Message, die im Body ist und dann muss das Ganze ja auch versendet werden. Das Versenden funktioniert dann ja schon wieder eher Low Level über das Protokoll. Genau. Und jetzt könnten wir natürlich hingehen, wie du schon gesagt hast, die haben eine Funktion. Eine Funktion mit 100, 200 Zeilen und die macht alles. Die geht hin und die setzt halt die Header, die setzt den Body, kümmert sich um alles, versendet das Ganze, empfängt das Ganze, packt die Antwort vielleicht auch aus und dann wird das alles recht schnell unübersichtlich. Und dann müssen wir halt einfach hingehen und müssen das Ganze aufsplitten, quasi so nach so einem Teile und herrsche Prinzip in kleine Funktionen, packen in Hilfsfunktionen und dann haben wir vielleicht einfach eine Hilfsfunktion, die uns einen Header zusammenbaut. Wir haben eine Funktion, die uns den Body zusammenbaut und nochmal eine Funktion, die den eigentlichen Request absetzt. Und auch noch wieder eine Funktion, die mit dem Response umgehen kann. Und wenn wir das halt zum Beispiel in diese vier Teile unterteilt haben, und wir schauen uns das Ganze an, dann können wir direkt sehen, «Was passiert in unserer eigentlichen übergeordneten Funktion?» Wir haben halt das Zusammenbauen, das Versenden und das Empfangen. Wenn wir jetzt genauer wissen wollen, wie das funktioniert, dann schauen wir wieder in die einzelnen Funktionen rein und sehen dort, wie es dort funktioniert. Wie funktioniert es dann im Low Level.

Dennis: Also, du hast so ein bisschen die Hierarchie, du hast Top Level, dann diese Methode, die soll halt die den ganzen Request zum Server senden. Also vielleicht, um das nochmal aufzufangen, auf der einen Seite den Client, zum Beispiel dein Computer, auf der anderen Seite haben wir einen Server, der steht jetzt irgendwo im Rechenzentrum drum rum. Und wir benutzen so ein Protokoll wie http, das sagt im Prinzip, wie so eine Kommunikation genau stattfindet. Und was der Client dann macht, ist-, der macht halt ein Request. Der muss natürlich vorbereitet werden und sendet das dann über das Internet zum Server und der Server schickt dann nochmal was zurück. Und jetzt hast du dann schon identifiziert, um das zu machen. Auf der Clientseite müssen wir halt verschiedene Sachen machen. Den Header zusammenbasteln, der enthält da so ein bisschen Metainformation, wir müssen eine Verbindung zum Server aufmachen, wir müssen das senden, wir empfangen nochmal eine Response, nennen wir das, und müssen da halt auch nochmal ein bisschen die Response bearbeiten. Genau. Und die Idee ist halt, dass ich halt Top Level-, natürlich dann diese Methode habe send Request to Server zum Beispiel. Aber dieser send Request to Server, die benutzt Hilfsmethoden, nämlich die Methoden, um den Header vorzubereiten, die Minute, um die Verbindung aufzumachen und einen Quest zu senden und das-, und die Response auszulesen. Und jetzt kann ich als Entwickler zum Beispiel sagen, «Ich bin jetzt gerade irgendwie ein Problem am Analysieren und ich vermute, dass das Problem mit dem Header zusammenhängt.» Dann kann ich halt reingucken in die send-request Methode und sehe dann, okay-, werden diese vier Methoden aufgerufen. Ich will aber jetzt wissen, wie das mit dem Header passiert. Ich gehe jetzt in die Prepare Header Methode. Also es erleichtert dir im Prinzip auch die Navigation durch den Code, wenn du das ein bisschen runterbrichst. Im Vergleich-, du könntest natürlich-, es hält dich keiner davon ab, alles in einer Methode zu machen. Kannst in einer Cent Request Methode alles auf einmal machen, stehen dann da 400 Zeilen Code drin, aber dann musst du den ganzen Code von der Methode lesen, um halt zu verstehen, wo diese Header gesetzt werden. Und wenn du es dir schön aufteilst, eine schöne Hierarchie hast, dann kannst du dir genau die Segmente angucken, die für dich jetzt eigentlich interessant sind. Und das ist auch einer der Gründe, warum es wichtig ist, guten Code zu schreiben. Weil es auch einfach in der Zukunft wichtig ist, dass wir effektiver sind, dass wir schneller entwickeln können, dass wir Fehler besser analysieren können, weil die Navigation durch den Code einfach deutlicher wird.

Kevin: Ein anderer Punkt, der mir da noch einfällt, bei-, wenn wir über schlechten Code reden, ist es gerade so was wie die Parameter von einer Funktion. Da können wir auch gerne mal darüber reden, wie viele Parameter wir da so verwenden und was da die Vor- oder Nachteile sind.

Dennis: Ja. Da kann man vielleicht mal dein, dein Beispiel, was du gesagt hast mit der Hilfsmethode am Anfang, wo du ganz viele Parameter hattest und gemerkt hast, «Oh, die tut ja nicht das, was sie soll.» Da ist ja dieses klassische Beispiel, ich habe eine Methode, da fange ich an, die hat so eine Funktionalität und dann kommt ein neues Feature dazu und dann packen wir einfach noch so eine Flac als Parameter mit in die Methode und dann guck ich dann auf die Flac weil die jetzt True oder Fault  und dann verhält sich die Methode anders. Und dann kommt noch eine zweite Flac dazu und eine dritte. Und was eigentlich passiert ist, wir haben ganz viel verschiedene Aufgaben in die gleiche Methode verpackt und haben das Ganze kaschiert, indem wir solche Flacs da rein gemacht haben. Das ist immer so ein klassisches Beispiel und das weist darauf hin, dass ich eigentlich zu viel in dieser Methode mache und dass ich das hätte eigentlich aufteilen müssen. Und ich würde mal unterstellen, dass grundsätzlich, wenn du ganz viele Parameter hast-, also wir reden jetzt davon, dass drei, vier, fünf, sechs Parameter-, ist das ein relativ guter Anhaltspunkt, dass deine Methode mehr tut, als sie soll. Und auf der anderen Seite ist es aber auch sehr schwierig, einen guten Namen für eine Methode zu finden, wenn sie so viele Parameter hat, weil ihre Funktionalität natürlich immer davon abhängt, was du da reingibst.

Kevin: Genau. Und vor allem ist halt auch das Problem, dass bei so Methoden, die so viele Parameter oder so viele Flacs haben, dass die einfach unberechenbar werden und du immer einen deterministischen Outcome von der Funktion erwarten kannst. Und dann sitzt du halt, grade wenn es zu einem Fehler kommt, da-, sitzt du da sehr lange daran, um zu verstehen, «Wieso ist denn der Fehler aufgetreten und in welchen Fällen, die Flacs True oder Fault sein, damit genau der Fehler auftritt?» Und, genau. Wenn man halt da einfach kleinere Methoden hat, dann ist es einfacher zu debuggen und einfacher zu fixen am Ende.

Dennis: Und halt auch zu testen. Wenn ich jetzt eine Methode testen will, mit fünf verschiedenen Parametern, dann muss ich ja alle möglichen Testfälle für alle Parameter durchspielen. Und das kann sehr komplex sein und da kann es dir schnell passieren, dass du halt was übersiehst, so ein sogenannten Edge Case, also ein Randfall übersehen hast und den deine Methode dann halt nicht richtig behandeln kann. Also, ist halt grundsätzlich die Idee, wenn ich jetzt Methoden habe mit vielen Parametern mal darüber nachzudenken «Tut diese Methode jetzt immer noch eine Sache oder tut sie jetzt vielleicht schon viele verschiedene Sachen? Und bin ich jetzt vielleicht an den Punkt, wo ich diese eine Methode vielleicht in mehrere kleinen Methoden aufbreche?» Das ist eigentlich jetzt auch schon ein gutes Stichwort, das Aufbrechen in mehrere Methoden. Ich würde gerne mit dir auch mal über das Refactoring sprechen. Also, was ist Refactoring und wie geht man da vor? Oder wie geht man grundsätzlich beim Programmieren vor? Schreibe ich jetzt Code, der perfekt ist direkt oder taste ich mich daran? Wie programmieren wir Code, Kevin?

Kevin: Genau. Ich würde halt jetzt auch erstmal auf das Refactoring eingehen. Was ist denn eigentlich Refactoring? Da haben wir halt einfach eine ältere Codebase. Eine-, mehrere Funktionen vielleicht, die etwas Bestimmtes tun und wir sehen halt, okay, das ist schlechter Code, sage ich mal, die Funktionen sind zu groß, lässt sich schlecht testen. Dann ist, ist man gut beraten, wenn man sich die Zeit nimmt und das Ganze refactet, also neu schreibt. Und da kann man dann auch gerne hingehen und einfach erstmal Tests schreiben, die die Funktionalität generell testen, damit die Tests grün sind. Und im nächsten Schritt kann man halt hingehen und kann sagen, «Okay, ich zerteile jetzt die Funktionalitäten. Ich mache mir nochmal Gedanken um die Struktur, refactere das Ganze und am Ende kann ich dann auch sehen ob meine Tests noch grün bleiben.» und dann war das Refactoring halt auch erfolgreich.

DennisI: Ich könnte jetzt natürlich sagen, ist natürlich schwer jetzt zu refactern und vorher Tests zu schreiben, weil du änderst ja dein Code. Aber die Idee ist, dass ich mir den Code angucke und dann gibt es ja so eine gewisse Stelle, da ziehe ich dann den Strich, sage, «Alles was darunter liegt, das ist so ein bisschen suboptimal, das möchte ich eigentlich gerne mal refactern. Aber alles, was darüber liegt, die Methoden, die jetzt, sage ich mal, höher in der Hierarchie sind, die sind jetzt okay. Und dann kann ich aber Tests schreiben für die Methoden, die etwas höher in der Hierarchie sind, weil wenn ich refactert habe, da soll ja noch das gleiche Ergebnis rauskommen. So, und wenn ich die Tests geschrieben habe, dann kann ich effektiv jetzt anfangen den Code darunter halt zu ändern. Weil wenn ich ihn geändert habe, bin ich mir nachher auch noch sicher, dass es funktioniert, weil die Tests halt grün sind.  Die Alternative ist, ich vertraue da auf meine Programmier-Skills und ich gehe da halt rein und refacter. Aber dann ist halt schwierig nachher zu sagen oder zu garantieren, dass es halt wirklich in allen Fällen geht. Dann habe ich die zweite Sache, Kevin. Code schreiben. Ich glaube, dass viele, viele Menschen, die mit dem Programmieren anfangen, so ein bisschen sich selber unter Druck setzen. Die denken, wenn ich jetzt Code schreibe, dann muss der direkt perfekt sein. Aber das ist glaube ich etwas, was man in der Praxis so nicht wirklich machen kann. Wie gehst du daran? Also, wie schreibst du Code normalerweise?

Kevin: Ich würde dir da definitiv zustimmen. Also, ich glaube angehende Entwickler und auch erfahrene Entwickler sollten vielleicht generell den Gedanken zur Seite schieben, dass man direkt perfekten Code schreibt. Das passiert vielleicht in trivialen Fällen, aber in den seltensten Fällen ist der Code wirklich perfekt. Genau. Und ich bin da jetzt auch noch so ein bisschen eigentlich im Finden drin. «Wie gehe ich denn konkret vor beim Code schreiben?» Was sich jetzt für mich immer so ein bisschen bewährt hat, war eigentlich, dass ich mal so ein Grundgerüst geschrieben habe. Ich habe mir-, in so einem Code habe ich mich zurechtgefunden, habe gesehen, «Okay, ich habe hier zwei, drei Stellen, an denen muss ich den Code anpassen, kommt eine neue Funktion hinzu.» Dann habe ich die Funktion, das Grundgerüst aufgeschrieben, dass ich so eine grobe Funktionalität habe. Und im nächsten Schritt war dann mein Ansatz, ich schreibe mir meine Tests und ich decke die Funktionalität durch Tests ab. Ich schaue, was gebe ich in die Funktion rein, was soll rauskommen?» Und habe dann angefangen, die Funktion richtig zu implementieren, dass meine Tests erstmal grün werden.

Dennis: Also, das ist halt so dieser Test Driven Development Ansatz. Zuerst die Tests und dann das Entwickeln. Was da ist-, natürlich beinhaltet ist, dass ich mir zunächst mal wirklich genau Gedanken gemachen habe, was ich da machen möchte. Also, was wir halt selten machen ist, dass wir ein Feature Request zum Beispiel haben und dann direkt loslegen zum Programmieren. Das ist bei uns oft so, dass wir erstmal mit einem Kollegen so ein bisschen diskutieren. Haben wir wirklich genau verstanden, was gemacht werden muss? Und dann diskutiert man aber auch so ein bisschen über die konkrete Lösung. «Mache ich das eher so oder so?» Weil je früher man quasi diese Missverständnisse aus dem Weg räumt, bevor man angefangen hat zu programmieren, desto einfacher lässt sich das noch ändern. Wenn ich jetzt erstmal zweitausend Zeilen Code geschrieben habe und gemerkt habe, dass der Plan nicht so aufgeht, wie ich mir das überlegt habe, dann muss ich ja alles nochmal löschen, nochmal von vorne anfangen. Also es ist erstmal dieser Findungsprozess, «Was möchte ich da eigentlich genau machen?» Und erst wenn ich mir sicher bin, fange ich dann an zu überlegen «Wie teste ich das?» Und dann schreibe halt erstmal diese Tests.

Kevin: Mir persönlich hilft es da halt auch immer wirklich dann zu einem Kollegen zu gehen, mit ihm über so ein Feature zu reden, «Wie würde ich das lösen? Sieht er da irgendwelche Probleme. Hat er einen anderen Blickwinkel? Kann er mir da noch ein paar Tipps geben?» Genau. Und dann setze ich das Ganze um und für mich ist auch die Entwicklung halt einfach so ein interaktiver Prozess, so eine Evolution, die der Code dann durchmacht. Ich würde sagen, zuerst ist der Code mal schlecht und funktioniert. Und dann schaue ich nochmal darauf und sage «Okay, jetzt mache ich ihn gut und jetzt refactore ich ihn.» Zwar drückt sich das in Hilfsmethoden aus, man verbessert den Namen von Variablen oder von Funktionen und macht das Ganze besser. Das Gute ist, da ich schon meine Tests habe und weiß, es funktioniert, dann kann ich auch hinterher nach einem Refactoring prüfen, ob es funktioniert. Und dann ist das immer so ein evolutionärer Prozess, dass der Code erst schlecht ist und dann besser wird.

Dennis: Also es ist ein bisschen vom Mantra her, die Idee wie jetzt ein Bildhauer eine Skulptur erstellt. Da habe ich erstmal den groben Stein und dann muss ich erstmal die, die Proportionen rausarbeiten. Da habe ich natürlich etwas-,das sieht erstmal abstrakt aus, aber das hilft mir dann beim nächsten Schritt. Und dann kommen vielleicht mal Körperform rein und dann erst zum Schluss arbeite ich zum Beispiel am Lidstrich oder an der Mimik, am Gesicht. Kein Skulpteur, oder-, ich, ich lehne mich wohl aus dem Fenster und sage, wenig Skulpteure würden jetzt sagen «Ich habe da jetzt ein Stein und jetzt mache ich zu erstmal die Nase und das Gesicht und das ist dann, das ist halt direkt perfekt ist und dann fange ich erstmal an, überhaupt die Körperstatur herauszuarbeiten. Und so ähnlich ist es bei uns auch. Also, wir sind jetzt an dem Punkt, wir wissen, was wir programmieren wollen, wir haben die Tests geschrieben und jetzt geht es halt wirklich los. Wir machen den Editor auf, wir wollen jetzt Code schreiben und dann schreiben wir erstmal etwas, was halt funktioniert. Die Tests werden grün? Super. Ich weiß schon mal, es tut, was ich will. Und dann kann ich halt anfangen zu gucken und dann sage ich «Okay, diesen Teil vom Code, den habe ich halt mehrfach drin.» So eine Code Redundanz. Das ist ja ein Punkt und will man auf Teufel komm raus halt verhindern, dass man Redundanzen im Code hat. Und dann sage ich «Okay, dann mache ich daraus jetzt aber eine Hilfsmethode und so bildet sich das. Wie gesagt, das ist dieser iterative Prozess. Ich gucke dann immer nochmal darüber und was kann ich denn noch ändern, was kann ich denn noch verbessern daran? Und irgendwann ist man so an den Punkt, wo man dann selber sagt «Jetzt habe ich es so weit verbessert wie ich es kann.» Und dann kommt der nächste Schritt, dann kommt halt das Code Review bei uns. Und da wollen wir natürlich auch mal darüber reden. Warum machen wir Code Reviews? Was ist ein Code Review? Warum ist ein Code Review überhaupt wichtig für uns?

Kevin: Genau. Also, ich finde, als Entwickler hat man halt, wenn man länger an einem Stück Code arbeitet- fällt man immer in so ein Tunnelblick. Ich sage auch gerne, man wird so ein bisschen Codeblind. Man sieht vielleicht offensichtliche Fehler oder Unschönheiten im Code nicht mehr. Und dann kann man halt so Code Reviews machen, wie wir es ja dann auch regelmäßig machen. Das heißt, ein anderer Entwickler bekommt halt den Code, der schaut sich an «Stimmt die Funktionalität?» und schaut sich dann den Code an, «Verstehe ich das denn?» Das hat verschiedene Vorteile. Zum einen bekommt man einfach einen neuen Blickwinkel auf seinen Code und auf die Funktionalität. Uns fallen vielleicht noch Sachen auf. Zum anderen hat so ein Code Review den Vorteil, es gibt dann in der Firma schon mal zwei Personen, die sich mit Code auskennen und man hat einfach ein Wissenstransfer. Und das ist halt ganz wichtig. Denn man arbeitet ja nicht allein als, als Warrior an diesem Projekt, sondern man ist ein Team. Man arbeitet im Team und es müssen sich alle mit dem Code auskennen. Und man sollte dann halt auch dafür sorgen, dass so ein Wissenstransfer da ist, und gerade Code Reviews, finde ich, die sind dafür ideal, um Wissenstransfer zu ermöglichen und auch einfach zu lernen. Beide Seiten lernen davon.

DennisI: Ja. Du kriegst aber, das finde ich auch echt wichtig, also kriegst einfach mal eine andere Perspektive geliefert. Es ist oft nicht klar, was es besser ist, was ist schlechter. Es ist auch manchmal so eine Überzeugungsfrage. Welcher Code Style ist denn der Beste? Aber es ist immer schön, im Code Review auch einfach mal die andere Seite zu sehen. Wenn du von mir ein Review machst und schreibst mir darunter, «Pass mal auf, ich hätte das jetzt zum Beispiel ein bisschen anders geschrieben.» dann kann ich, kann ich ja auch entscheiden, ob ich das so mache oder nicht. Aber auf jeden Fall nehme ich mal deine Perspektive mit. Und ich glaube, dass, dass viele falsch verstehen. Im Code Review geht es nicht um kontrollieren, sondern es geht tatsächlich darum, objektiv die Qualität vom Code zu verbessern. Auch zum Beispiel zu gucken, «Sind da jetzt genügend Tests da?». Also, das ist so der Klassiker, wo der Review sagt, «Pass mal auf, du hast jetzt diesen Fall nicht getestet.» Da geht es darum halt, das Ding Wasserdicht zu machen. Und auf der anderen Seite , wie du gesagt hast: Wissen austauschen. Und ich glaube, das ist der Punkt, den vielen nicht bewusst ist. Okay, jetzt haben wir natürlich jetzt schon ein paar interessante Punkte gebracht, warum die Code Reviews interessant sind. Jetzt würde ich mal gerne fragen, was ist denn deiner Meinung noch eigentlich, so von der Organisation her, die Voraussetzung, dass man halt wirklich eine Code Review Kultur einbringen kann.

Kevin: Was ich da ganz wichtig finde ist einfach generell erstmal eine, eine ordentliche Fehlerkultur im Unternehmen zu haben und auch im Team. Das heißt, per se würde ich halt auch einfach sagen, Fehler zu machen, das ist überhaupt nicht schlimm, denn aus Fehlern lernt man. Und nur so, wenn man lernt, kann man besser werden. Genau. Deswegen sollte man da auch wirklich ganz offen für Reviews sein an der Stelle. Und wenn da jemand was anmerkt, dann sollte man auch immer darüber diskutieren können oder vielleicht sich austauschen können, zu sagen, «Okay, ich habe das jetzt aus dem und dem Grund so gelöst.» Und vielleicht versteht der Gegenüber das und sagt, «Okay, dann hast du da wirklich recht.» oder er sagt, «Du kannst aber anders da lösen.» dann sollte man aber auch so was einfach annehmen und daraus lernen.

DennisI: Ja. Also, nicht diese, diese defensive Haltung, dass die Kritik persönlich jemanden berührt. Sondern es ist einfach etwas Objektives. Es geht halt einfach um Code. Wir wollen alle gucken, dass die Codequalität richtig gut wird. Und deshalb nehmen diese Ratschläge auf einem professionellen Niveau entgegen. Das andere, was du gesagt hast, finde ich auch wichtig, wie mit Fehlern umgehen. Was mir da so einfällt, ist so dieser "blame culture". Dass wenn jemand ein Fehler gemacht hat, sind dann drei Personen direkt da und stecken den Finger in die Wunde. Das ist natürlich ganz schlecht, wenn man Code Reviews machen will, weil das führt dann ja auch zu diesem defensiven Verhalten. Dann machen die Leute zu. Die haben halt Angst, einen Fehler zuzugeben, weil es unter Umständen vielleicht auch Konsequenzen hat. Dann gibt es ein Personalgespräch, dann wird das nochmal aufgegriffen. Man muss einfach akzeptieren, dass auch Programmierer nur Menschen sind. Natürlich gibt es Mittel und Wege, die Qualität von einer Software zu verbessern über Tests, aber es gibt immer dieser ein Prozent Use Cases, wo es dann doch schiefgeht. Und Fehler passieren und wir müssen alle aber auch lernen professionell damit umzugehen und daraus zu lernen. Weil was nicht passieren darf, ist, dass der gleiche Fehler immer wieder passiert. Das ist dann auch der Punkt, wo es dann wirklich schwierig ist, dem Nutzer oder dem Kunden zu erklären, warum der Fehler wieder auftaucht.

Kevin: Wir sind jetzt am Ende von unserem Podcast angelangt, Dennis. Wie entsteht denn guter Code?

Dennis: Wie wir gesagt haben. Eigentlich steht am Beginn erstmal schlechter Code und da arbeitet man sich so ein bisschen ran. Aber warum, Kevin?

Kevin: Weil der Code sich einfach entwickelt und incromentel verbessert wird und evolutionär wird der Code dann Stück für Stück einfach besser.

Dennis: Es geht so ein bisschen nach dem Bildhauer Prinzip. Dass man halt erstmal sich grob heranarbeitet und dann erst später die Feinheiten aus dem Code herausarbeitet. Und das geht halt, wie du gesagt hast, am besten durch so ein incromentellen Prozess.

Kevin: Und ganz wichtig ist auch, dass der gute Code sich selbst dokumentiert. Darüber haben wir auch ausführlich geredet. Mit den variablen Namen und den Methodennamen und dass die Methoden auch klein sein sollen.

Dennis: Ja. Und wir haben auch darüber geredet, dass Code nicht von einer Person kommt, sondern da steht immer ein Team dahinter. Da gibt es Reviews, da gibt es Feedbackschleifen, da übernimmt das ganze Team Verantwortung dafür und versucht sich auch gegenseitig zu unterstützt. Das ist jetzt nicht ein Einzelkämpfer, der jetzt eine Aufgabe bekommen hat und das bis zum bitteren Ende durchziehen muss.

Kevin: Genau. Und letzten Endes steht hinter jedem guten Code ein gutes Team. Das war es von mir. Ich bin Kevin.

Dennis: Das war es von mir, von Dennis und wir sehen uns beim nächsten Mal, beim nächsten Consistec Podcast. Tschüss.

Kevin: Tschüss.

 

 

Das wars schon wieder von uns!

Wir hoffen die heutige Folge hat euch erfreut und dass wir euch das Thema "Clean Coding" etwas näher bringen konnten.Weiterführende Links zur aktuellen Folge findet ihr in den Shownotes und wenn ihr euch für die wunderbare Welt der Softwareentwicklung interessiert freuen wir uns natürlich wenn ihr uns abonniert. Unsere nächste Folge findet ihr ab 05 Mai auf all unseren Podcastkanälen!

Bis dahin eine sonnige Zeit und bleibt gesund!

Ihre Cookie-Einstellungen

Technisch notwendige (essenzielle) Cookies

Informationen zu den einzelnen Cookies

  • Mehr anzeigen

    Technisch notwendige (essenzielle) Cookies

    Notwendige Cookies helfen dabei, eine Webseite nutzbar zu machen, indem sie Grundfunktionen wie Seitennavigation und Zugriff auf sichere Bereiche der Webseite ermöglichen. Die Webseite kann ohne diese Cookies nicht richtig funktionieren.

    Name fe_typo_user
    Anbieter consistec.de
    Zweck Sichert die Anti-Spam-Maßnahmen bei Benutzen des Kontaktformulars
    Ablauf Session
    Typ HTTP
    Name conCookieSettings
    Anbieter consistec.de
    Zweck Speichert die Zustimmung zu Cookies
    Ablauf 30 Tage
    Typ HTTP
    Name mtm_consent_removed
    Anbieter consistec.de
    Zweck Wird von Piwik Analytics Platform (matomo) genutzt, um festzustellen, dass dem Tracking widersprochen wurde.
    Ablauf 1 Monat
    Typ HTTP
  • Mehr anzeigen

    Statistiken

    Statistik-Cookies helfen Webseiten-Besitzern zu verstehen, wie Besucher mit Webseiten interagieren, indem Informationen anonym gesammelt und gemeldet werden.

    Name matomo.php
    Anbieter consistec.de
    Zweck Erfasst Statistiken über Besuche des Benutzers auf der Website, wie z. B. die Anzahl der Besuche, durchschnittliche Verweildauer auf der Website und welche Seiten gelesen wurden.
    Ablauf Session
    Typ HTTP
    Name _pk_id#
    Anbieter consistec.de
    Zweck Erfasst Statistiken über Besuche des Benutzers auf der Website, wie z. B. die Anzahl der Besuche, durchschnittliche Verweildauer auf der Website und welche Seiten gelesen wurden.
    Ablauf 1 Jahr
    Typ HTTP
    Name _pk_ses#
    Anbieter consistec.de
    Zweck Wird von Piwik Analytics Platform (matomo) genutzt, um Seitenabrufe des Besuchers während der Sitzung nachzuverfolgen.
    Ablauf 1 Tag
    Typ HTTP
    Name _pk_testcookie..undefined
    Anbieter consistec.de
    Zweck Wird von Piwik Analytics Platform (matomo) genutzt, um zu überprüfen, ob der verwendete Browser Cookies unterstützt.
    Ablauf Session
    Typ HTTP
    Name _pk_testcookie.#
    Anbieter consistec.de
    Zweck Wird von Piwik Analytics Platform (matomo) genutzt, um zu überprüfen, ob der verwendete Browser Cookies unterstützt.
    Ablauf Session
    Typ HTTP