Also gibt es im Buch "Clean Code" die Regel "Do One Thing". Aber wie weit müssen wir das wirklich nehmen?
Zum Beispiel die folgenden Aussagen:
%Vor%Ok, sicher gibt es mehr als eine Aussage hier, aber es fühlt sich für mich so an, als würden sie nur eine Sache machen. Speichern der Einstellungen.
Ich habe das in einer einzigen Funktion. Würdest du das wirklich nehmen? und haben Sie eine einzige Methode für jede Einstellung?
Wann halten Sie sich an diese Regel und wann nicht?
Sieht perfekt für mich aus. Der offensichtliche Methodenname für diesen Code ist SaveSettings
, was anzeigt, dass die Methode genau eine Sache macht. Nichts, worüber man sich Sorgen machen müsste.
Der nächste Abschnitt des Buches, Eine Ebene der Abstraktion pro Funktion , ist ein großer Schritt zur Beantwortung dieser Frage. Alle diese Anweisungen sind auf der gleichen Abstraktionsebene, daher macht diese Funktion bereits eine Sache und speichert die Einstellungen.
Ja, jede Methode sollte nur ein Ding machen. Aber was ist das eine Sache?
Dies hängt von der Abstraktionsebene ab, in der sich Ihre Methode befindet . Eine Methode (Eigenschaft) zum Speichern einer einzelnen Einstellung ist eine ziemlich geringe Abstraktion. Die nächsthöhere Abstraktion wäre dann die vorgeschlagene SaveSettings
-Methode.
Ganz oben haben Sie eine einzige Methode / Funktion main
, die auch nur eins macht: Das ganze Programm ...
Ich gehe davon aus, dass diese Regel darauf verweist, wann eine Funktion in mehrere Unterfunktionen aufgeteilt werden soll.
Sie haben die richtige Idee - das Speichern von Einstellungen ist "eine Sache" und könnte in einer eigenen Funktion sein. Jede Einstellung in eine eigene Funktion zu bringen, wäre übertrieben.
Eine andere Richtlinie, die ich gehört habe, könnte Ihnen beim Verständnis des "Eine-Sache" -Konzepts helfen: Wenn die Funktion länger als ein oder zwei Seiten ist, kann sie wahrscheinlich besser geschrieben werden, indem ihr Inhalt in mehrere Unterfunktionen aufgeteilt wird / p>
Wenn Sie Ihren Code isoliert betrachten, ist es schwer zu sagen. Sie könnten argumentieren, dass Ihre Funktion zwei Dinge tut - Aktualisieren der Einstellungen und Speichern der Änderungen. Wie bevölkern Sie die Werte, werden sie als Argumente an Ihre Funktion übergeben (bevorzugt) oder erhält Ihre Funktion die Werte selbst (macht etwas anderes)?
Ich würde dem Grundsatz der einheitlichen Verantwortung folgen, der wie folgt zusammengefasst ist:
Es sollte niemals mehr als einen Grund geben, dass eine Klasse geändert wird
und kann gleichermaßen auf Methoden angewendet werden. In Ihrem Beispiel würde es immer einen Grund geben, die Einstellungen zu aktualisieren, aber nicht zu speichern?
Ich habe dieses Buch nicht gelesen, aber was das Konzept betrifft ...
"Eine Sache" bedeutet nicht "eine Zeile Code". "Eine Sache" bedeutet, dass alles in der Funktion logisch zusammenhängen sollte.
Ich würde mit einigen der früheren Poster sagen, dass "saveSettings" "eine Sache" ist. Vielleicht ist es nur eine Nachlässigkeit mit Worten, aber ich werde die Gelegenheit nutzen, um auf die potenzielle Falle hinzuweisen. In Ihrem Fall ist es mehr wie "saveCommunicationSettings", was meiner Meinung nach leicht zu der "one thing" Definition passt. Wenn Sie "Settings.Default.customerLoyaltyDiscount = ..." zu dieser Liste hinzugefügt haben, würde ich sagen, dass Sie sich wahrscheinlich auf einer gefährlichen Basis befinden, da Sie jetzt Kommunikationseinstellungen mit Preisberechnungseinstellungen mischen.
Im wirklichen Leben ist die Entscheidung, was vernünftiger Zusammenhalt ist, keine Formel, sondern ein Urteilsspruch, der die Ausübung von Intelligenz erfordert. Sollte eine Funktion, die den Gesamtbetrag eines Auftrags berechnet, eine Umsatzsteuerberechnung enthalten? Das sind zwei Dinge: der Gesamtpreis aller Artikel auf Bestellung UND die Mehrwertsteuer berechnen. Man könnte aber auch argumentieren, dass es nur eines ist: Finde den Gesamtpreis des Auftrags, was auch immer das beinhaltet. In der Praxis treffe ich die Entscheidung oft aufgrund der Komplexität der Logik. Wenn alles, was erforderlich ist, um eine Auftragssumme zu berechnen, eine einfache Schleife durch alle Elemente ist, die ihre Preise addieren und dann eine Umsatzsteuersatz aus einer Tabelle holen und multiplizieren, würde ich wahrscheinlich alles in einer Funktion tun. Wenn es mehr als das gibt - wie das System, an dem ich gerade arbeite, beinhaltet die Preisberechnung die Bestellung von Lagerbeständen im Vergleich zu Sonderbestellungen, die Suche nach möglichen Rabatten, das Hinzufügen von Garantien usw. - wir müssen es wirklich brechen hoch.
In unserem Team versuchen wir, den einen Zweck für jede Funktionsrichtlinie zu befolgen. Um Entwicklern zu helfen, fügten wir unseren Standards einen Vorschlag hinzu, den sie in Betracht ziehen, wenn eine Funktion 25 Zeilen überschreitet. Wenn Sie also über 100 Zeilen Codeeigenschaften verfügen, können Sie diese nach Kategorien wie SaveUserSettings, SaveNetworkSettings usw. aufteilen.
Das Endziel ist es, den Code lesbarer zu machen. Wenn Sie Ihre Methode nehmen und sie in 20 Aufrufe aufteilen, die jeweils eine Eigenschaft festlegen, würde ich denken, dass es zeitaufwendiger wäre, sie zu befolgen und zu unterstützen.
Der Beispielcode würde besser mit der Frage umgehen, wann Eigenschaften verwendet werden sollen und wann Parameter in einem Konstruktor oder einer Methode zum Festlegen des Objektstatus verwendet werden sollen. Ich weiß, dass es einen Abschnitt dazu in den .NET Framework-Richtlinien gibt. Dort wird das Basismuster der Komponente (viele Eigenschaften und der interne Zustand der Komponenten können zwischen der ersten und letzten Zuweisung ungültig sein) und das andere Muster (viele Konstruktorparameter und Methodenparameter und der interne Zustand der Objekte sind nach jeder Codezeile gültig führt aus.
Wenn Sie Ihre Methode aufteilen wollten, würde ich das Mapping der Werte von der tatsächlichen Speicherung des Objekts abbrechen. Man könnte sagen, dass das Mapping von Werten eine separate Abstraktionsebene ist. Sie hätten also:
%Vor%Es sieht so aus, als könnte das Mapping woanders wiederverwendet werden oder Sie wollen es. Wenn die Zahleneinstellungen größer wurden, konnten sie auch nach Kategorie aufgeschlüsselt werden.
In Fällen wie diesem würde ich nicht behaupten, dass es das wert ist, und ob ich es tat oder nicht, würde von meiner Stimmung oder der Menge der Wolken am Himmel abhängen. Aber ja, technisch gesehen gibt es hier zwei Ebenen, die man aufteilen könnte.
Wie kann man wissen, ob eine Funktion eine Sache oder mehr macht? es hängt vom Grad der Abstraktionen ab. Ich versuche das Abstraktionsniveau in zwei Beispielen zu beschreiben (sauberes Codebuch, Kapitel 3) siehe diesen Code
%Vor%Diese Funktion macht nur eine Sache und alle Unterfunktionen sind Teil der buildPage-Phrase
%Vor%Diese Funktion benötigt Benutzer-E-Mail, so dass sendMail mit Hilfe der getUser-Funktion den Benutzer per E-Mail erreichen kann. aber $ user = getUser () wird in der sendMail-Phrase nicht beschrieben Best Practice für diese Funktion ist
%Vor%Tags und Links c# coding-style