{"id":237,"date":"2015-04-26T12:13:01","date_gmt":"2015-04-26T10:13:01","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=237"},"modified":"2016-02-22T19:42:06","modified_gmt":"2016-02-22T17:42:06","slug":"was-riecht-hier-so","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/was-riecht-hier-so\/","title":{"rendered":"Was riecht hier so?"},"content":{"rendered":"<p>Hallo Spa\u00df-Coder,<\/p>\n<p>heute m\u00f6chten wir mal mit einem Bilderr\u00e4tsel anfangen. Was assoziiert ihr im Zusammenhang mit Code-Qualit\u00e4t mit dem folgenden Bild?<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Green-Field.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-360 size-full\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Green-Field.jpg\" alt=\"Green Field\" width=\"700\" height=\"307\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Green-Field.jpg 700w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Green-Field-300x132.jpg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>Gr\u00fcne Wiese, Freiheit,\u00a0 M\u00f6glichkeiten, alles aber auch alles Erdenkliche hier zu erbauen. Ist es nicht so?<\/p>\n<p>&nbsp;<\/p>\n<p>Wie oft aber findet ihr eher folgendes in der Realit\u00e4t vor?<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Waste-Field.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone wp-image-361 size-full\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Waste-Field.jpg\" alt=\"\" width=\"700\" height=\"308\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Waste-Field.jpg 700w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Waste-Field-300x132.jpg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>Einen Haufen Schutt und M\u00fcll, unsaubere Strukturen und ein Chaos, in welches ihr nun eine neue Funktion, ein neues Feature implementieren sollt. Wie sch\u00f6n w\u00e4re es doch, immer auf der gr\u00fcnen Wiese arbeiten zu k\u00f6nnen, oder?<\/p>\n<p>Genau deshalb schreiben wir hier diese ganzen Blog-Artikel. Angefangen bei den Basics \u00fcber die SOLID-Prinzipien, bis hinzu agilen Methoden. Wir wollen, guten Code und wir wollen, dass auch ihr guten Code schreiben k\u00f6nnt und wollt.<\/p>\n<p>In diesem Artikel werden wir darauf eingehen, wie ihr schlechten Code erkennen k\u00f6nnt. Dabei spielt es keine Rolle, ob ihr den Code vorfindet und \u00e4ndern m\u00fcsst, oder selbst geschrieben habt.<\/p>\n<p>Das Schl\u00fcsselwort dazu lautet <em>Code-Smells.<\/em> Teile unseres Codes, der den Prinzipien widerspricht oder schlecht wartbar und damit fehleranf\u00e4llig ist. Wenn unser Code also anf\u00e4ngt zu riechen, wird es Zeit, f\u00fcr ein <a href=\"http:\/\/invidit.de\/blog\/refactoring-was-es-ist-und-warum-jeder-entwickler-es-machen-sollte\/\">Refactoring<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h3>Fokus: Einfachheit<\/h3>\n<p>Das Wichtigste Vorweg. Im Umfeld der agilen Softwareentwicklung ist Einfachheit ein wichtiger Faktor. Das Prinzip dahinter lautet KISS: Keep it simple, stupid.<br \/>\nZu deutsch bedeutet es je nach Lesart: <em>Halte es einfach, dumm<\/em> oder <em>Halte es einfach, Dummerchen<\/em>.<\/p>\n<p>Dieses Prinzip sollten wir uns bei allem was wir entwickeln immer vor Augen halten. Verlieren wir langsam den \u00dcberblick, wird\u00a0 es zu kompliziert oder haben wir nun zum 3. Mal angefangen, die Methode zu lesen, wird es Zeit f\u00fcr eine Pause. Tretet einen Schritt zur\u00fcck und \u00fcberdenkt nochmal, was ihr eigentlich erreichen wollt und ob es wirklich so kompliziert sein muss.<\/p>\n<p>Ein Spaziergang durchs &#8230; Gr\u00fcne &#8230; hilft hierbei oft, den Kopf frei zu bekommen&#8230;manchmal reicht es aber auch, sich einen Kaffee zu holen.<\/p>\n<p>&nbsp;<\/p>\n<h3>Sehr gro\u00dfe Klassen<\/h3>\n<p>Klassen, die sehr viele Zeilen Code haben, wiedersprechen wahrscheinlich dem <a href=\"http:\/\/invidit.de\/blog\/aus-prinzip-nur-eine-verantwortlichkeit\/\">Single Responsibility Principle<\/a>. Ein Beispiel, welches wir an andere Stelle schonmal gebracht haben ist die Klasse <em>Playfield <\/em>aus einem Spiel, welches wir mal fertiggestellt haben. Die Klasse hat stolze 987 Zeilen, 52 Methoden und 19 Klassenvariablen. Sich hierin zurechtzufinden ist nicht leicht. Und ja, die Klasse macht im Grunde nur Sachen mit dem <em>Playfield<\/em>. Aber was genau? Naja, alles halt.<\/p>\n<p>Es gibt keinen Richtwert, wie gro\u00df eine Klasse idealerweise sein sollte. So ab 100 Zeilen sollte man aber schonmal einen n\u00e4heren Blick auf die Klasse werfen, ob hier nicht doch zu viel passiert.<\/p>\n<p>&nbsp;<\/p>\n<h3>Sehr gro\u00dfe Methoden<\/h3>\n<p>Was f\u00fcr Klassen gilt, gilt in gleicher Weise f\u00fcr Methoden. Bei Methoden sollte es dem Leser m\u00f6glich sein, auf einen Blick zu sehen, wo die Methode beginnt und wo sie endet. Es sollte deutlich werden, was in der Methode passiert.<\/p>\n<p>Das Wichtigste ist aber, dass eine Methode sich m\u00f6glichst nur auf einem Detaillevel bewegen sollte. Es sollte also nicht Konzepte verschiedener Detailstufen miteinander vermischen.<\/p>\n<p>Auch hier ein Beispiel aus dem o.g. Spiel. Die Methode <em>CheckAndRemoveLines()<\/em> umfasst 82 Zeilen (davon 2 Kommentarzeilen). Sie durchl\u00e4uft zun\u00e4chst das <em>Playfield<\/em> Zeile f\u00fcr Zeile, f\u00fchrt Pr\u00fcfungen gem\u00e4\u00df eines gewissen Regelsatzes durch und entfernt dann ggf. Objekte aus dem <em>Playfield<\/em>. Anschlie\u00dfend erfolgt das gleiche f\u00fcr Spalten. Das Verarbeiten der Zeilen (und Spalten), das Pr\u00fcfen und das Entfernen der Objekte sind alles unterschiedliche Detailebenen in der Gesamtlogik. Dass sie in einer Methode implementiert sind, f\u00fchrt zu einer langen und un\u00fcbersichtlichen Methode. Das diese nicht gut testbar ist, sei hier nur am Rande erw\u00e4hnt.<\/p>\n<p>Derartige Methoden sollten aber leicht vermieden werden k\u00f6nnen, wenn ihr euch auch f\u00fcr Methoden an das <a href=\"http:\/\/invidit.de\/blog\/aus-prinzip-nur-eine-verantwortlichkeit\/\">Single Responsibility Principle<\/a> haltet. Eine Methode, die nur genau eine Aufgabe erf\u00fcllt, kann nicht sonderlich gro\u00df werden.<\/p>\n<p>&nbsp;<\/p>\n<h3>Namensgebung<\/h3>\n<p>\u00dcber gute Namen haben wir bereits im Artikel <a href=\"http:\/\/invidit.de\/blog\/basics-namen\/\">Basics \u2013 Aussagekr\u00e4ftige Namen<\/a> gesprochen. Warum das auch ein Code-Smell ist? Nun, Klassen mit dem Namen Manager, Utils und Helper neigen dazu, mit allem m\u00f6glichen gef\u00fcllt zu werden. Wir brauchen eine kleine Methode, die uns bei der Verarbeitung von Strings hilft? Dann legen wir doch eine Klasse StringHelper an und schreiben die Methode da rein. Brauchen wir eine weitere Hilfsmethode, kommt sie ebenfalls in StringHelper. Sie tut aber ggf. was ganz anderes. Ja, beide Methoden arbeiten mit Strings, aber sie haben v\u00f6llig verschiedene Zwecke.<\/p>\n<p>Wir haben also bei diesen beiden Methoden zwei Gr\u00fcnde, die Klasse zu \u00e4ndern (wenn sich die Anforderung an eine der beiden Methoden \u00e4ndert). Das ist ein klarer Versto\u00df gegen das <a href=\"http:\/\/invidit.de\/blog\/aus-prinzip-nur-eine-verantwortlichkeit\/\">Single Responsibility Principle<\/a> und f\u00fchrt &#8211; vor allem in Teams &#8211; zu doppelten Implementierungen, weil wir aufgrund der schlechten Namensgebung schwer eine Funktion in einem gro\u00dfen Projekt finden. Stattdessen schreiben wir lieber unsere eigene Implementierung&#8230;nat\u00fcrlich in einer eigenen Klassen namens <em>StringHelper<\/em>. Nein, bitte nicht.<\/p>\n<p>Ein Beispiel aus den o.g. Spiel. Hier gibt es einen Namespace <em>Helper <\/em>mit einer Klasse<em> SpielHelper<\/em>.<\/p>\n<pre class=\"lang:c# decode:true\">internal static Vector2 ToVector2(Vector3 vector)...\r\ninternal static Vector3 ToVector3(Vector2 vector)...\r\ninternal static Vector2 CalculateGemPositionInWorld(Vector2 positionInPlayfield)...\r\ninternal static void PlaySound(string soundName)...\r\ninternal static Sound GetSound(string soundName)...\r\ninternal static Vector2 GetGemPositionFromIndex(int index, int width)...\r\ninternal static int GetTimeElapsedSinceLastFrameInMillis()...<\/pre>\n<p>Was macht die Klasse? Sie l\u00e4dt Sound-Dateien, wandelt 3-dimensionale Vectoren in 2-dimensionale um, berechnet Positionen und f\u00fchrt Zeitmessungen durch. Kurz: alles M\u00f6gliche, wir haben wohl keinen besseren Platz daf\u00fcr gefunden. Schade auch.<\/p>\n<p>Alle unsere Klassen helfen uns, nicht nur diejenigen, die <em>Helper<\/em> im Namen tragen. Zeugen wir ihnen also den geb\u00fchrenden Respekt und benennen sie passend.<\/p>\n<p>&nbsp;<\/p>\n<p>Ein weiterer Punkt, an dem man erkennen kann, dass eine Methode vielleicht mehr als eine Aufgabe \u00fcbernimmt ist, wenn &#8222;and&#8220; im Namen vorkommt. Das Beispiel von oben: <em>CheckAndRemoveLines()<\/em> Was macht die Methode? Genau, sie p<span style=\"text-decoration: underline;\">r\u00fcft<\/span> und <span style=\"text-decoration: underline;\">entfernt<\/span> Zeilen. Das sind offensichtlich <span style=\"text-decoration: underline;\">zwei<\/span> Aufgaben. (Tats\u00e4chlich entfernt sie nichtmal Zeilen sondern Objekte vom Playfield&#8230;der Name ist also auch noch falsch).<\/p>\n<p>&nbsp;<\/p>\n<h3>Methodenparameter<\/h3>\n<p>Was durch das Wort &#8222;and&#8220; \u00fcber den Namen erfolgt, kann genauso \u00fcber einen boolschen Parameter ausgedr\u00fcckt werden. Eine Methode, die einen Parameter vom Typ <em>bool<\/em> erh\u00e4lt, wird mit gro\u00dfer Wahrscheinlichkeit mehr als eine Aufgabe haben. Hier erneut ein Beispiel aus der o.g. Klasse <em>Playfield<\/em>:<\/p>\n<pre class=\"lang:c# decode:true \">public void Update(bool handleInput)\r\n{\r\n\tif (handleInput)\r\n\t{\r\n\t\tHandleInputIfNoGemIsMoving();\r\n\t}\r\n\telse\r\n\t{\r\n\t\t...\r\n\t}\r\n}\r\n<\/pre>\n<p>So ein Konstrukt sieht man h\u00e4ufig, wenn boolsche Parameter verwendet werden. Wenn <em>true<\/em> mach dies, sonst das. Das ist wieder ganz klar mehr als eine Aufgabe.<\/p>\n<p>Zu unserer Entschuldigung sei gesagt, dass diese Methode von der von uns verwendeten Game-Engine so vorgeschrieben war&#8230;aber bei der Klasse helfen eigentlich keine Entschuldigungen mehr \ud83d\ude2e<\/p>\n<p>&nbsp;<\/p>\n<p>Auch die Anzahl der Parameter einer Methode sind ein Hinweis auf Code, der ein wenig riecht. Die besten Methoden erhalten keinen Parameter. Sie beziehen sich komplett auf die Klassenvariablen. Methoden mit einem oder zwei Parameter sind noch in Ordnung. Ab drei Parametern sollte man langsam dar\u00fcber nachdenken, ob man die Methode &#8211; oder ggf. das gesamte Design drumherum &#8211; nicht nochmal \u00fcberdenken sollte.<\/p>\n<p>&nbsp;<\/p>\n<h3>Regions in C#<\/h3>\n<p>In C# gibt es <em>Regions<\/em>. Regions bilden in C#-Code Bl\u00f6cke, die keine Funktionalit\u00e4t haben, sondern einfach nur einen Bereich im Code gruppieren, der dann eingeklappt werden kann. Hier nochmal das Beispiel <em>Playfield<\/em>:<\/p>\n<p><a href=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Regions.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-364\" src=\"http:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Regions.png\" alt=\"Regions\" width=\"569\" height=\"199\" srcset=\"https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Regions.png 569w, https:\/\/invidit.de\/blog\/wp-content\/uploads\/2015\/04\/Regions-300x105.png 300w\" sizes=\"(max-width: 569px) 100vw, 569px\" \/><\/a><\/p>\n<p>Und da soll nochmal einer sagen, die Klasse sei un\u00fcbersichtlich&#8230;<\/p>\n<p>Aber im ernst. Wenn ihr geneigt seid, <em>Regions<\/em> zu verwenden, um die \u00dcbersicht \u00fcber den Code zu behalten, denkt besser \u00fcber eine Aufteilung der Klasse in kleinere Bestandteile nach.<\/p>\n<p>&nbsp;<\/p>\n<h3>Dependency Injection<\/h3>\n<p>Hier ist erstmal nur wichtig zu wissen, dass es dabei um Abh\u00e4ngigkeiten einer Klasse geht, die von au\u00dfen mitgegeben werden k\u00f6nnen.<\/p>\n<p>Der Code-Smell hier ist die Anzahl der Dependencies. Wenn viele Abh\u00e4ngigkeiten <em>injected<\/em> werden oder viele Parameter an den Konstruktor \u00fcbergeben werden (Constructor-Injection), deutet das darauf hin, dass die Klasse zu gro\u00df ist und zu viele Aufgaben hat.<\/p>\n<p>Schaut euch die Abh\u00e4ngigkeiten genau an. M\u00fcssen diese wirklich alle sein, um den eigentlichen Zweck der Klasse zu erreichen?<\/p>\n<p>&nbsp;<\/p>\n<h3>Lange Ableitungshierarchien<\/h3>\n<p>Der letzte Punkt, auf den wir heute eingehen m\u00f6chten, ist eine sehr lange Kette von Ableitungen. Klassen, die voneinander abgeleitet sind, haben naturgem\u00e4\u00df eine sehr enge Kopplung zueinander. Muss an einer der beteiligten Klassen eine \u00c4nderung durchgef\u00fchrt werden, ist oft die ganze Ableitungskette betroffen. Dies f\u00fchrt dazu, dass die Klasse ohne Grund ge\u00e4ndert werden muss, nur weil eine der Elternklassen eine \u00c4nderung erfahren hat.<\/p>\n<p>Daher ist Komposition h\u00e4ufig einer Ableitung vorzuziehen (<a href=\"http:\/\/de.wikipedia.org\/wiki\/Komposition_an_Stelle_von_Vererbung\">Composition over Inheritance<\/a>). Zusammen mit dem <a href=\"http:\/\/invidit.de\/blog\/offen-und-geschlossen\/\">Open-Closed-Principle<\/a> schaffen wir so ein lose gekoppeltes Design, dass leicht erweiterbar ist.<\/p>\n<p>&nbsp;<\/p>\n<h3>Zusammenfassung<\/h3>\n<p>Wenn man gerade so sch\u00f6n dabei ist, den Code zu schreiben und endlich das Erfolgserlebnis hat, dass er funktioniert (Yeah!), \u00fcbersehen wir leicht, wie viel Dreck wir doch hinterlassen haben. Oft liegt an jeder Ecke M\u00fcll herum, die sch\u00f6ne gr\u00fcne Wiese, auf der wir begonnen haben, ist zu einer kleinen M\u00fcllhalde geworden.<\/p>\n<p>Wenn wir hier nicht gleich aufr\u00e4umen, wird das immer schlimmer. Ein Grund ist, dass wir nat\u00fcrlich viel lieber das n\u00e4chste Feature machen, als aufzur\u00e4umen. Aber vielleicht kennt das er ein oder andere aus seiner Kindheit (oder ihr beobachtet es bei euren eigenen Kindern): Nach dem Spielen die Spielsachen wegzur\u00e4umen macht einfach keinen Spa\u00df, also lassen wir sie liegen. Nun haben wir eine Stunde Zeit zum Spielen, bevor die Hausaufgaben dran sind&#8230;davon verbringen wir dann 45 Minuten damit, die Spielsachen zu suchen, mit denen wir spielen wollen. Nach dem wir sie gefunden haben, bleiben uns noch 15 Minuten.<\/p>\n<p>Auch die <a href=\"http:\/\/de.wikipedia.org\/wiki\/Broken-Windows-Theorie\">Theorie der Broken Windows<\/a> verst\u00e4rkt noch, dass unser Code immer schwerer lesbar wird.<\/p>\n<p>Alles in allem f\u00fchrt sauberer Code dazu, dass wir wirtschaftlich entwickeln k\u00f6nnen. Wenn wir erst stundenlang den Code verstehen m\u00fcssen, ewig nach Hilfsmethoden suchen oder schon wieder eine Klasse nicht wiederverwenden k\u00f6nnen, weil sie mehrere Aufgaben erf\u00fcllt, sind wir nicht sehr wirtschaftlich. Und Spa\u00df macht das auch keinen.<\/p>\n<p>R\u00e4umt also immer auf und verlasst den Code <a href=\"http:\/\/invidit.de\/blog\/basics-pfadfinderregel\/\">immer ein wenig sauberer, als ihr ihn vorgefunden habt<\/a>. Dann riecht das hier auch nicht mehr so.<\/p>\n<p>&nbsp;<\/p>\n<p>Viel Spa\u00df beim Ausprobieren und Happy Coding w\u00fcnschen<\/p>\n<p>eure Spa\u00df-Coder<\/p>\n<p>&nbsp;<\/p>\n<p>Dieser Artikel basiert neben unseren Erfahrungen auf den Ausf\u00fchrungen aus:<\/p>\n<ol style=\"list-style-type: lower-alpha;\">\n<li id=\"gs_cit0\" class=\"gs_citr\" tabindex=\"0\">Martin, Robert C. <i>Clean Code-Refactoring, Patterns, Testen und Techniken f\u00fcr sauberen Code: Deutsche Ausgabe<\/i>. MITP-Verlags GmbH &amp; Co. KG, 2013.<\/li>\n<li class=\"gs_citr\" tabindex=\"0\">\n<div id=\"gs_cit0\" class=\"gs_citr\" tabindex=\"0\">Fowler, Martin <em><a href=\"https:\/\/www.youtube.com\/watch?v=vqEg37e4Mkw\" target=\"_blank\">Workflows of Refactoring<\/a><\/em>.<br \/>\nOOP 2014<\/div>\n<\/li>\n<li class=\"gs_citr\" tabindex=\"0\">Hariri, Hadi <em><a href=\"https:\/\/www.youtube.com\/watch?v=2Y3kFpNvsvU\" target=\"_blank\">Refactoring Legacy Code Bases<br \/>\n<\/a>Basta Sprint 2013 <\/em><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Die ersten beiden Bilder stammen von http:\/\/www.freeimages.com<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder, heute m\u00f6chten wir mal mit einem Bilderr\u00e4tsel anfangen. Was assoziiert ihr im Zusammenhang mit Code-Qualit\u00e4t mit dem folgenden Bild? Gr\u00fcne Wiese, Freiheit,\u00a0 M\u00f6glichkeiten, alles aber auch alles Erdenkliche hier zu erbauen. Ist es nicht so? &nbsp; Wie oft aber findet ihr eher folgendes in der Realit\u00e4t vor? Einen Haufen Schutt und M\u00fcll, unsaubere [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":367,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[22,90],"tags":[58,17,29,20],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/237"}],"collection":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=237"}],"version-history":[{"count":13,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/237\/revisions"}],"predecessor-version":[{"id":940,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/237\/revisions\/940"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/367"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=237"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=237"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}