{"id":297,"date":"2015-04-08T09:20:33","date_gmt":"2015-04-08T07:20:33","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=297"},"modified":"2015-07-01T11:38:34","modified_gmt":"2015-07-01T09:38:34","slug":"basics-funktionen","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/basics-funktionen\/","title":{"rendered":"Basics &#8211; Funktionen"},"content":{"rendered":"<p>Hallo Spa\u00df-Coder,<\/p>\n<p>im Artikel <a title=\"Basics? Kenn\u2019 ich doch schon\" href=\"http:\/\/invidit.de\/blog\/basics-kenn-ich-doch-schon\/\">Basics? Kenn\u2019 ich doch schon!<\/a> haben wir begr\u00fcndet, warum grundlegende Programmierpraktiken sinnvoll und hilfreich sind.<\/p>\n<p>Einige dieser Basics betrifft insbesondere Funktionen in unserer Programmierung. Dar\u00fcber m\u00f6chten wir im folgenden ein wenig sprechen.<\/p>\n<p>&nbsp;<\/p>\n<h3>Regeln f\u00fcr Funktionen<\/h3>\n<p>Frei nach Uncle Bob (Robert C. Martin) &#8211; es gibt zwei Regeln zu Funktionen:<\/p>\n<ol>\n<li>Funktionen sind klein!<\/li>\n<li>Funktionen sind noch kleiner!!<\/li>\n<\/ol>\n<p>Eine Funktion &#8211; oder in der Objektorientierung eine Methode &#8211; sind sehr kleine und \u00fcberschaubare Code-Fragmente. Habt ihr schonmal eine Methode (von euch selbst oder anderen) gelesen, die \u00fcber mehrere Bildschimseiten geht? Methoden dieser Gr\u00f6\u00dfe lassen sich schlecht erfassen, man braucht lange um sie zu verstehen. Gute Methoden hingegen sind schnell zu lesen und leicht zu verstehen. Ein typischer Programmierer verbringt in der Regel 80% seiner Zeit damit, Code zu lesen. Dieser sollte also leicht verst\u00e4ndlich und schnell erfassbar sein.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Benennung<\/strong><\/p>\n<p>Ein weiterer Punkt, der gute Funktionen ausmachen ist, sie erf\u00fcllen <a title=\"Aus Prinzip nur eine Verantwortlichkeit\" href=\"http:\/\/invidit.de\/blog\/aus-prinzip-nur-eine-verantwortlichkeit\/\">eine und nur genau eine Aufgabe<\/a>. Wird dieses Prinzip beachtet, l\u00e4sst sich eine Funktion viel leichter in einem Unit Test pr\u00fcfen. Sie wird dadurch auch besser wiederverwendbar.<\/p>\n<p>Was eine Funktion oder Methode genau macht, kann man am aussagekr\u00e4ftigen Namen ablesen. Das Thema haben wir <a title=\"Basics \u2013 Aussagekr\u00e4ftige Namen\" href=\"http:\/\/invidit.de\/blog\/basics-namen\/\">im entsprechenden Artikel<\/a> bereits ausf\u00fchrlich besprochen.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Einfachheit<\/strong><\/p>\n<p>Ein weiteres Problem von gro\u00dfen Methoden ist, dass diese oft eine hohe Verschachtelungstiefe haben. Viele if, for, switch oder \u00e4hnliche Anweisungen erschweren die\u00a0 Lesbarkeit (in der statischen Code-Analyse wird dies durch die Kennzahl der &#8222;Cyclomatic Complexity&#8220; ausgedr\u00fcckt).\u00a0 An jedem Entscheidungspunkt im Code halten wir kurz inne und versuchen ihn zu verstehen. Je weniger wir davon ineinander verschachtelt lesen und verstehen m\u00fcssen, desto leichter f\u00e4llt es uns und desto schneller verstehen wir den Code. Ein Code-Smell zur Erkennung ist die Einr\u00fcckungstiefe bei sauberer Formatierung des Codes. Diese sollte bei guten Funktionen h\u00f6chstens 2 sein, besser w\u00e4re nur eine Ebene oder gar ganz ohne Verschachtelungen auszukommen.<\/p>\n<p>Damit Funktionen auch aus Sicht des Aufrufers einfach bleiben, sollten sie m\u00f6glichst wenige Parameter haben. Denkbar sind hier 0, 1 oder maximal 2. Funktionen mit 3 Parametern oder mehr sollten wohl\u00fcberlegt sein und ihr solltet m\u00f6glichst alles daf\u00fcr tun, dies zu vermeiden.<\/p>\n<p>Mit jedem Parameter einer Funktion f\u00fcgen wir ihr eine Komplexit\u00e4tsstufe hinzu, die der Aufrufer unter Umst\u00e4nden gar nicht zu wissen braucht. Wenn wir in Klassen dem Prinzip der einen Verantwortung folgen (<a title=\"Aus Prinzip nur eine Verantwortlichkeit\" href=\"http:\/\/invidit.de\/blog\/aus-prinzip-nur-eine-verantwortlichkeit\/\">Single Responsibility Principle<\/a>), so ist es in manchen F\u00e4llen sinnvoller, der Klasse eine globale Klassenvariable zu geben, statt diese per Parameter an jede einzelne Methode \u00fcbergeben zu lassen.<\/p>\n<p>Es sollte niemals ein Parameter vom Typ bool oder boolean verwendet werden. Warum? Erinnert ihr euch noch an den Punkt &#8222;Eine Funktion hat genau eine Aufgabe&#8220;? Was werden wir mit einem boolchen Parameter wohl anstellen? Wahrscheinlich folgendes:<\/p>\n<pre class=\"lang:c# decode:true \">public void Foo(bool bar)\r\n{\r\n\tif(bar)\r\n\t{ \r\n\t\t\/\/ mach was\r\n\t}\r\n\telse\r\n\t{\r\n\t\t\/\/ mach was anderes\r\n\t}\r\n}<\/pre>\n<p>Methoden mit boolchen Parametern erf\u00fcllen also in aller Regel mehr als eine Aufgabe.<\/p>\n<p>Das gleiche Prinzip gilt auch f\u00fcr die Bedeutung eines Parameters mit dem Wert null. Wenn wir folgenden Methodencode haben, erf\u00fcllt die Funktion ebenfalls mehr als eine Aufgabe:<\/p>\n<pre class=\"lang:c# decode:true\">public void Foo(object bar)\r\n{\r\n\tif(bar == null)\r\n\t{ \r\n\t\t\/\/ mach was\r\n\t}\r\n\telse\r\n\t{\r\n\t\t\/\/ mach was anderes\r\n\t}\r\n}<\/pre>\n<p>Eine Pr\u00fcfung der eingehenden Parameter auf null ist demgegen\u00fcber allerdings g\u00fcltig:<\/p>\n<pre class=\"lang:c# decode:true \">public void Foo(object bar)\r\n{\r\n\tif(bar == null)\r\n\t{ \r\n\t\tthrow new ArgumentNullException(\"bar\", \"Parameter 'bar' darf nicht null sein.\")\r\n\t}\r\n\t\r\n\t\/\/ mach was\r\n}<\/pre>\n<p>Streng betrachtet erf\u00fcllt diese Methode zwar zwei Aufgaben (1. Pr\u00fcfen der Parameter, 2. &#8222;was machen&#8220;), halten wir uns aber an diese Struktur &#8211; erst pr\u00fcfen, dann den eigentlichen Code ausf\u00fchren &#8211; ist die Methode weiterhin gut lesbar.<\/p>\n<p>In .Net sollten wir zudem darauf achten, keine out-Parameter zu verwenden. Ein Beispiel:<\/p>\n<pre class=\"lang:c# decode:true\">bool TryGetCustomer(int customerId, out Customer customer)\r\n{\r\n\u00a0\u00a0 \u00a0customer = GetCustomerById(customerId);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0if(customer == null) \r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return false;\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0else\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return true;\r\n\u00a0\u00a0 \u00a0}\r\n}<\/pre>\n<p>Der Aufrufer der Methode muss nun zwei Werte verarbeiten: 1. den R\u00fcckgabewert (bool) und den eigentlichen, von der Methode ermittelten Wert (customer). Besser w\u00e4re es hier, direkt den Customer zur\u00fcckzugeben und den Aufrufer auf null pr\u00fcfen zu lassen (wie es etwa die Methode GetCustomerById(int customerId) macht, die hier aufgerufen wird). Alternativ k\u00f6nnen wir den Umstand des nicht gefundenen Werts als Ausnahme betrachten und eine entsprechende Exception werfen:<\/p>\n<pre class=\"lang:c# decode:true\">Customer TryGetCustomer(int customerId)\r\n{\r\n\u00a0\u00a0 \u00a0customer = GetCustomerById(customerId);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0if(customer == null) \r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0throw new CustomerNotFoundException(customerId);\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0return customer;\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0\u00dcberraschung!<\/strong><\/p>\n<p>Was f\u00e4llt euch beim folgenden Code auf?<\/p>\n<pre class=\"lang:c# decode:true\">void SetActiveCustomer(Customer customer)\r\n{\r\n\u00a0\u00a0\u00a0 this.activeCustomer = customer;\r\n\u00a0\u00a0\u00a0 this.customerList.Add(customer);\r\n}<\/pre>\n<p>Denkt mal kurz dar\u00fcber nach, was die Methode macht&#8230;&#8230;&#8230;.<\/p>\n<p>Sie setzt einen &#8222;aktiven Kunden&#8220; in einer Klasse. Das sagt zumindest der Name der Methode aus. Tats\u00e4chlich wird aber nicht nur der aktive Kunde auf den \u00fcbergebenen Wert festgelegt, sondern dieser \u00fcbergebene Wert auch in eine Kundenliste eingef\u00fcgt.<\/p>\n<p>Wollten wir das, wenn wir die Methode <em>SetActiveCustomer<\/em> aufrufen? Wahrscheinlich nicht. Dieses Verhalten ist f\u00fcr uns eine \u00dcberraschung&#8230;und \u00dcberraschungen k\u00f6nnen wir nicht leiden (wenigstens nicht im Code). Wenn wir sp\u00e4ter auf diese customerList zugreifen, sind dort pl\u00f6tzlich Werte enthalten, die wir dort gar nicht erwarten, weil wir sie nicht hinzugef\u00fcgt haben. Zumindest nicht wissentlich.<\/p>\n<p>Methoden sollten immer nur genau das tun, was ihr Name sagt. Sie sollten keine Nebeneffekte haben. Wenn der Aufrufer diesen Wert auch in diese Liste einf\u00fcgen will, dann soll er das explizit tun.<\/p>\n<h3>Zusammenfassung<\/h3>\n<p>Der Artikel ist ganz sch\u00f6n lang geworden. Bei Funktionen gibt es f\u00fcr uns so einiges zu beachten. Zun\u00e4chst sollen sie klein sein. Sehr klein. Noch kleiner. Funktionen k\u00f6nnen gar nicht klein genug sein. Dann sollten sie einen sprechenden Namen haben und genau die Aufgabe ausf\u00fchren, die in diesem Namen angegeben ist. Und nur genau diese eine Aufgabe. Keine weiteren Aufgaben, keine \u00fcberraschenden Aktivit\u00e4ten.<\/p>\n<p>Wenn wir dies beherzigen, werden unsere Methoden schon \u00fcbersichtlich, unser Code sprechend und viel leichter zu lesen und zu debuggen.<\/p>\n<p>Viel Spa\u00df beim Anwenden,<\/p>\n<p>Eure Spa\u00df-Coder<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder, im Artikel Basics? Kenn\u2019 ich doch schon! haben wir begr\u00fcndet, warum grundlegende Programmierpraktiken sinnvoll und hilfreich sind. Einige dieser Basics betrifft insbesondere Funktionen in unserer Programmierung. Dar\u00fcber m\u00f6chten wir im folgenden ein wenig sprechen. &nbsp; Regeln f\u00fcr Funktionen Frei nach Uncle Bob (Robert C. Martin) &#8211; es gibt zwei Regeln zu Funktionen: Funktionen [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":302,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[22,90],"tags":[23,18,37,35,29,36],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/297"}],"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=297"}],"version-history":[{"count":3,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/297\/revisions"}],"predecessor-version":[{"id":300,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/297\/revisions\/300"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/302"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}