{"id":220,"date":"2015-03-22T11:54:43","date_gmt":"2015-03-22T09:54:43","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=220"},"modified":"2015-09-06T09:52:53","modified_gmt":"2015-09-06T07:52:53","slug":"aus-prinzip-nur-eine-verantwortlichkeit","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/aus-prinzip-nur-eine-verantwortlichkeit\/","title":{"rendered":"Aus Prinzip nur eine Verantwortlichkeit"},"content":{"rendered":"<p>Hallo Spa\u00df-Coder.<\/p>\n<p>Wie viele Verantwortlichkeiten haben eure Klassen? Das <i>Eine-Verantwortlichkeit-Prinzip<\/i> (Single-Responsibility-Principle [SRP]) spricht bei Verantwortlichkeiten bzw. Aufgaben von Klassen dar\u00fcber, wie viele Gr\u00fcnde es gibt, eine Klasse zu \u00e4ndern. Das mag dann etwas seltsam anmuten, wenn ich die Aussage treffe: &#8222;Ich \u00e4ndere die Klasse weil ich den Code in der Klasse \u00e4ndern muss\/will.&#8220;. Schauen wir uns genauer an, was hinter diesem Design Prinzip steckt.<\/p>\n<h2>Single-Responsibility-Principle<\/h2>\n<p>Das SRP ist das erste Design Prinzip von f\u00fcnf zusammengefassten Prinzipien, die wir in nachfolgenden Artikel gerne vorstellen werden (SOLID). Eine Definition findet ihr z.B. unter <a title=\"http:\/\/de.wikipedia.org\/wiki\/Single-Responsibility-Prinzip\" href=\"http:\/\/de.wikipedia.org\/wiki\/Single-Responsibility-Prinzip\">http:\/\/de.wikipedia.org\/wiki\/Single-Responsibility-Prinzip.<\/a><\/p>\n<h2>Erl\u00e4uterung des Prinzips<\/h2>\n<p>Habt ihr euch beim Lesen von Quellcode einer Klasse schonmal die Frage gestellt &#8222;Was macht diese Klasse eigentlich?&#8220; und die Frage nicht innerhalb von 2 Minuten beantworten k\u00f6nnen? Habt ihr euch schonmal von einem Klassennamen in die Irre f\u00fchren lassen, da die Klasse etwas ganz anderes macht, als dran steht bzw. die Klasse deutlich mehr leistet?<\/p>\n<p>Zun\u00e4chst Frage ich mich, warum es \u00fcberhaupt ein Problem sein soll, dass eine Klasse mehrere Dinge macht. Monolithen und God-Classes gibt es doch viele in der Softwareentwicklung. Immer wieder laufen mir solche Klassen \u00fcber den Weg, sei es bei Open-Source-Code, in Legacy-Code und nat\u00fcrlich auch in unserem eigenen Code.<\/p>\n<p>Wenn wir &#8222;Einmal-Code&#8220; oder &#8222;Wegwerf-Code&#8220; schreiben, spielt es keine Rolle, ob die Klasse nur eine Aufgabe erf\u00fcllt, oder wir f\u00fcr alle Anforderungen nur eine Klasse verwenden. Wir entwicklen diese Klasse einmal und fassen sie nie wieder an (besser ist das). Leider ist dies nur selten Realit\u00e4t. Sogar sehr h\u00e4ufig \u00e4ndern sich Anforderungen an bestehende Software und eine God-Class mal eben wegzuwerfen und komplett neuzuschreiben wird wohl in den seltesten F\u00e4llen m\u00f6glich sein &#8211; auch wenn das sicherlich manchmal die bessere Alternative w\u00e4re.<\/p>\n<p>Somit schlagen wir uns mit der Erweiterung oder \u00c4nderung dieser Klasse rum und sind dabei erstmal damit besch\u00e4ftigt zu verstehen, was eigentlich wo genau passiert und warum macht die Methode ganz was anderes als dran steht und wer benutzt eigentlich diese Methode noch im Projekt oder dar\u00fcber hinaus!?! Fragen \u00fcber Fragen.<\/p>\n<p>Genau der letzte Punkt wird h\u00e4ufig zum Problem, insbesondere bei nicht automatisert abgesichertem Code durch Unit Tests. Eine Klasse, deren Methoden niemand nutzt, kann ich mit gutem Gewissen \u00e4ndern, ohne dass etwas anderes dabei kaputt geht &#8211; allerdings w\u00fcrde ich diese Klasse dann besser einfach l\u00f6schen (siehe YAGNI).<\/p>\n<p>Wer hat schonmal eine umfangreiche Klasse ge\u00e4ndert und an verschiedenen anderen Stellen in der Software hat etwas nicht mehr funktioniert wie vor der durchgef\u00fchrten \u00c4nderung? Je umfangreicher die Klasse, je mehr Aufgaben und Verantwortlichkeiten eine Klasse hat, desto st\u00e4rker sind Abh\u00e4ngigkeiten zu anderen Klasse und desto h\u00f6her ist die Wahrscheinlichkeit, dass bei einer \u00c4nderung irgendeine der Abh\u00e4ngkeiten kaputt geht.<\/p>\n<p>So eine God-Class entsteht bei Neuentwicklungen z.B. dadurch, dass der Name der Klasse sehr generisch ist und damit mir selbst gar nicht so klar ist, was die Verantwortlichkeit dieser Klasse genau ist. So sind Klassen mit den Appendizes &#8222;Manager&#8220; oder &#8222;Service&#8220; von vornherein dazu verdonnert, alles m\u00f6gliche zu verwalten und anzubieten. Alleine diese Klassennamen laden im Weiteren dazu ein, hier Code zu platzieren, weil ja noch Platz am Ende der Klasse ist. Beim Einf\u00fcgen von neuem Verhalten in bestehende Software stellt sich oft die Frage, wohin denn mit diesem Verhalten. Wenn vorhandene Klassen unspezifisch sind, findet sich leicht eine (un)geeignete Stelle zum Einf\u00fcgen des neuen Codes.<\/p>\n<p>Eine Unterst\u00fctzung beim Schneiden von Klassen, also der Separation von Verantwortlichkeiten in entsprechende H\u00e4ppchen, gibt die Koh\u00e4sion einer Klasse. Eine starke Koh\u00e4sion einer Klasse entsteht dann, wenn alle in der Klasse enthaltenen Methoden m\u00f6glichst alle Klassenvariablen verwenden und\/oder ver\u00e4ndern. Dies zeigt auf, dass alle Methoden an einer Aufgabe arbeiten &#8211; an einem Strang ziehen. Wird beispielsweise eine kleine Hilfsmethode einer bestehenden Klasse hinzugef\u00fcgt, welche nur mit \u00fcbergebenen Parametern Arbeitet, so hat diese Methode sehr wahrscheinlich nichts mit der eigentlichen Aufgabe zu tun und kann ausgelagert werden. Wenn andererseits nur eine einzige Methode eine bestimmte Klassenvariable nutzt, k\u00f6nnen Methode mit samt Variable in eine neue Klasse extrahiert werden.<\/p>\n<p>Manche Leser m\u00f6gen hier das Argument anbringen, &#8222;Ja, aber dann entstehen ja ganz viele kleine Klassen und ich verliere den \u00dcberblick.&#8220;. Ersteres ist erstrebenswert, zweiteres durch organisatorische Mittel zu beheben. Hierauf werden wir in einem sp\u00e4teren Artikel noch genauer eingehen. Wie klein eine Klasse sein solte, l\u00e4sst sich kaum in Form von Anzahl Codezeilen festlegen und ist abg\u00e4ngig von der Komplexit\u00e4t der <strong>einen<\/strong> Aufgabe.<\/p>\n<p>&nbsp;<\/p>\n<h2>Unsere Erfahrung mit dem SRP<\/h2>\n<p>Unser &#8222;running gag&#8220; ist die Klasse &#8222;<em>Playfield<\/em>&#8220; aus unserem Projekt &#8222;Jewels&#8220; (was wir zur eigenen \u00dcberraschung tats\u00e4chlich fertiggestellt haben). Es handelt sich dabei um eine Implementierung eines Spielklassikers, bei dem auf dem Spielfeld Steine in derselben Farbe horizontal oder vertikal durch anklicken entfernt werden. Je mehr Steine derselben Farben, desto mehr Punkte. Zur\u00fcck zur Klasse Playfield.<\/p>\n<p>Ein Code-Smell, also ein Indikator f\u00fcr schlechten Code, ist hier bereits die L\u00e4nge der Klasse. Mit 987 Zeilen sicherlich nicht die l\u00e4ngste Klasse die ich kenne, aber m\u00f6glicherweise hat sie mehr als eine Verantwortlichkeit. Nur die Methoden Signaturen hier zu posten w\u00fcrde den Rahmen des Artikels sprengen.<\/p>\n<p>F\u00fcr was ist bei einem Spiel eigentlich das Spielfeld zust\u00e4ndig? Ich wei\u00df es nicht genau und genau so hat sich eben auch diese Klasse entwickelt. &#8222;Irgendwie passt es ja hier rein bzw. wir haben keine andere Klasse, in die der neue Code gut reingeh\u00f6rt&#8230;(oje)&#8220;. Dies beginnt beim Verwalten der Steine bis hin zu den Spielz\u00fcgen und Benutzereingaben.<\/p>\n<p>Die Anwendung des SRP ist nicht immer einfach, aber die \u00c4nderung unserer Klasse Playfield ist noch viel schwieriger!<\/p>\n<p>Insbesondere die Anwendung des <a title=\"Wenn Daten flie\u00dfen\" href=\"http:\/\/invidit.de\/blog\/wenn-daten-fliessen\/\">Flow-Patterns <\/a>unters\u00fctzt sehr dabei, des Fokus auf die eigentliche Aufgabe und Verantwortlichkeiten zu behalten. Dar\u00fcber hinaus beitet ein gut strukturiertes Projekt (verschiedene Bibliotheken, JARs, Namensr\u00e4ume, Pakete) auf grober Ebene eine Richtlinie, welche Verantwortlich im Projekt ben\u00f6tigt werden und damit gute Anhaltspunkte f\u00fcr die Definition von Klassen.<\/p>\n<p>&nbsp;<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>Wenn es tats\u00e4chlich nur einen Grund gibt, eine Klasse \u00e4ndern zu m\u00fcssen, wirkt dies ungemein befreiend, gibt Sicherheit bei der Durchf\u00fchrung der \u00c4nderung und unters\u00fctzt die Fokussierung auf das Wesentliche. Das SRP anzuwenden mag zun\u00e4chst ungewohnt sein, aber auf lange Sicht gewinnen alle Beteiligten &#8211; und insbesondere die Kunden durch weniger Fehler in der Software auf Grund von Abh\u00e4gigkeiten im Code.<\/p>\n<p>&nbsp;<\/p>\n<p>Viel Spa\u00df beim Anwenden.<\/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<ul>\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\">Feathers, Michael C. <i>Effektives Arbeiten mit Legacy Code: Refactoring und Testen bestehender Software<\/i>. mitp Verlags GmbH &amp; Co. KG, 2011.<\/div>\n<\/li>\n<\/ul>\n<div class=\"gs_citr\" tabindex=\"0\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder. Wie viele Verantwortlichkeiten haben eure Klassen? Das Eine-Verantwortlichkeit-Prinzip (Single-Responsibility-Principle [SRP]) spricht bei Verantwortlichkeiten bzw. Aufgaben von Klassen dar\u00fcber, wie viele Gr\u00fcnde es gibt, eine Klasse zu \u00e4ndern. Das mag dann etwas seltsam anmuten, wenn ich die Aussage treffe: &#8222;Ich \u00e4ndere die Klasse weil ich den Code in der Klasse \u00e4ndern muss\/will.&#8220;. Schauen wir [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":235,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[90],"tags":[44,47,21],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/220"}],"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\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=220"}],"version-history":[{"count":15,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/220\/revisions"}],"predecessor-version":[{"id":285,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/220\/revisions\/285"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/235"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}