Ich höre viel darüber, Methoden kurz zu halten, und ich habe viele Programmierer sagen hören, dass die Verwendung von #region-Tags in einer Methode ein sicheres Zeichen dafür ist, dass sie zu lang ist und in mehrere Methoden umgestaltet werden sollte. Es scheint mir jedoch, dass es viele Fälle gibt, in denen das Trennen von Code mit #region-Tags innerhalb einer Methode die überlegene Lösung für das Refactoring in mehrere Methoden ist.
Nehmen wir an, wir haben eine Methode, deren Berechnung in drei sehr unterschiedliche Phasen unterteilt werden kann. Darüber hinaus ist jede dieser Stufen nur für die Berechnung dieser Methode relevant. Wenn Sie sie also in neue Methoden extrahieren, wird der Code nicht erneut verwendet. Welche Vorteile hat es dann, jede Phase in eine eigene Methode zu extrahieren? Soweit ich das beurteilen kann, erhalten wir nur eine gewisse Lesbarkeit und einen separaten Variablenbereich für jede Phase (wodurch verhindert wird, dass Änderungen an einer bestimmten Phase versehentlich eine andere Phase unterbrechen).
Beides kann jedoch erreicht werden, ohne jede Phase in eine eigene Methode zu extrahieren. Region-Tags ermöglichen es uns, den Code in eine Form zu bringen, die genauso lesbar ist (mit dem zusätzlichen Vorteil, dass wir unseren Platz in dieser Datei nicht mehr verlassen müssen, wenn wir den Code erweitern und untersuchen möchten), und einfach jede Phase einzuschließen {}
erstellt einen eigenen Arbeitsbereich.
Dies hat den Vorteil, dass der Gültigkeitsbereich auf Klassenebene nicht mit drei Methoden verschmutzt wird, die eigentlich nur für das Innenleben einer vierten Methode relevant sind. Die sofortige Umgestaltung einer langen Methode in eine Reihe kurzer Methoden scheint mir die Wiederverwendung von Code zu sein, die einer vorzeitigen Optimierung entspricht. Sie führen zusätzliche Komplexität ein, um ein Problem anzugehen, das in vielen Fällen nie auftritt. Sie können eine der Phasen später jederzeit in eine eigene Methode extrahieren, falls sich die Möglichkeit zur Wiederverwendung von Code ergibt.
Gedanken?
quelle
#region
Tags, ich deaktiviere das Falten von Code in Visual Studio insgesamt. Ich mag keinen Code, der versucht, sich vor mir zu verstecken.Antworten:
Sie sollten sich nur darum kümmern, dass Ihr Code verwendbar und nicht wiederverwendbar ist. Ein Affe kann verwendbaren Code in wiederverwendbaren Code umwandeln, wenn überhaupt Transformationen durchgeführt werden müssen.
Das Argument "Ich brauche das nur hier" ist arm, um es höflich auszudrücken. Die Technik, die Sie beschreiben, wird oft als Schlagzeilentechnik bezeichnet und ist im Allgemeinen verpönt.
Ebenfalls relevant: Jeff Atwoods Gedanken zum Code-Falten
quelle
Es sind nicht die Regionen in den Methoden, die das Problem darstellen, sondern der Fall, wenn Regionen in Methoden eingefügt werden müssen (oder sogar verwendet werden müssen).
Nachdem ich viele 200-300-Zeilen-Methoden debuggen musste, kann ich Ihnen sagen, dass ich es niemandem wünschen würde. Wenn Sie Ihren eigenen Code schreiben und pflegen, ist das in Ordnung - machen Sie, was Sie wollen. Aber wenn sich jemand anderes das ansieht, sollte sofort klar sein, was eine Methode tut.
Nein, das ist nicht gut genug. Teilen Sie es in Regionen auf, wie Sie wollen, aber ich schüttle immer noch den Kopf, wenn ich nur daran denke.
Wenn Sie in Methoden einbrechen, erhalten Sie viele Vorteile:
///
) und geben Sie die Beschreibung, Parameter, Rückgabetyp und auchexception
,example
,remarks
Knoten zum Detail dieser Szenarien. Das ist, wo es hingeht, dafür ist es da!{}
, aber muss ich jede Methode überprüfen, um sicherzustellen, dass Sie nicht "betrogen" haben? BenutzedodgyObject
ich das hier nur, weil es in dieser Region verwendet wird, oder kommt es von woanders? Wenn ich in meiner eigenen Methode wäre, würde ich leicht erkennen können, ob sie mir übergeben wurde oder ob ich sie selbst erstellt habe (oder vielmehr, ob Sie sie erstellt haben).TurnThingsUpsideDown
Methode ist fehlgeschlagen - sie schlägt wahrscheinlich beim Drehen einer schlechten Sache fehl" ist viel besser als "Oh, dieDoEverything
Methode ist fehlgeschlagen - es könnten 50 verschiedene Dinge gewesen sein, und ich muss eine Stunde lang herumgraben, um sie zu finden" .Dies ist alles bevor es um Wiederverwendbarkeit oder Verbesserbarkeit geht. Richtig getrennte Methoden erleichtern offensichtlich die Wiederverwendung und ermöglichen es Ihnen, eine Methode, die nicht funktioniert (zu langsam, zu fehlerhaft, geänderte Abhängigkeit usw.), einfach zu ersetzen. Haben Sie jemals versucht, eine dieser riesigen Methoden umzugestalten? Es gibt keine Möglichkeit zu wissen, dass das, was Sie ändern, nichts anderes bewirkt.
Bitte kapseln Sie Ihre Logik richtig in Methoden mit angemessener Größe. Ich weiß, dass es für sie leicht ist, außer Kontrolle zu geraten, und zu argumentieren, dass es sich nicht lohnt, an diesem Punkt einmal umzugestalten, ist ein weiteres Problem. Sie müssen jedoch akzeptieren, dass es keinen Schaden und zumindest keinen potenziellen Nutzen bringt, wenn Sie ordnungsgemäß gekapselte, sauber geschriebene und einfach gestaltete Methoden verwenden.
quelle
Wenn Ihre Methode so komplex ist, dass sie in drei unterschiedliche Phasen unterteilt werden kann, sollten dies nicht nur drei separate Methoden sein, sondern Ihre Methode sollte auch eine separate Klasse sein, die für diese Berechnung vorgesehen ist.
"Aber dann wird meine Klasse nur eine öffentliche Methode haben!"
Du hast recht, und daran ist nichts auszusetzen. Die Idee des Einzelverantwortungsprinzips ist, dass Ihre Klasse eine Sache tut .
Ihre Klasse kann nacheinander jede der drei Methoden aufrufen und das Ergebnis zurückgeben. Eine Sache.
Als Bonus ist Ihre Methode jetzt testbar, da sie keine private Methode mehr ist.
Aber egal eine Klasse; In Wirklichkeit sollten Sie vier haben : Eine für jedes der Teile Ihrer Methode und eine, die jede der drei als Abhängigkeit nimmt und sie in der richtigen Reihenfolge aufruft und das Ergebnis zurückgibt.
Das macht Ihre Klassen noch mehr prüfbar. Es macht es Ihnen auch leicht, eines dieser drei Teile zu wechseln. Schreiben Sie einfach eine neue Klasse, die von der alten erbt, und überschreiben Sie das geänderte Verhalten. Oder erstellen Sie eine Schnittstelle für das Verhalten jedes Ihrer drei Teile. und dann, um eine zu ersetzen, schreiben Sie einfach eine neue Klasse, die diese Schnittstelle implementiert, und ersetzen Sie sie durch die alte in Ihrer Konfiguration des Abhängigkeitsinjektionscontainers.
Was? Sie verwenden keine Abhängigkeitsinjektion? Nun, Sie haben die Notwendigkeit wahrscheinlich noch nicht erkannt, da Sie nicht dem Prinzip der Einzelverantwortung folgen. Sobald Sie beginnen, werden Sie feststellen, dass der einfachste Weg, jeder Klasse Abhängigkeiten zuzuweisen, die Verwendung eines DI-Containers ist.
EDIT :
OK, lassen Sie uns die Refactoring-Frage beiseite legen. Der Zweck von
#region
ist, Code auszublenden, dh Code , der unter normalen Umständen nicht bearbeitet werden muss. Generierter Code ist das beste Beispiel. Es sollte in Regionen ausgeblendet sein, da Sie es normalerweise nicht bearbeiten müssen. Wenn nötig, erhalten Sie beim Erweitern einer Region eine Warnung im "Here be Dragons" -Stil, um sicherzustellen, dass Sie wissen, was Sie tun.Daher würde ich sagen,
#region
sollte nicht in der Mitte einer Methode verwendet werden. Wenn ich eine Methode öffne, möchte ich den Code sehen. Die Verwendung von #region gibt mir eine weitere Ebene des Versteckens, die ich nicht brauche, und das wird ärgerlich: Ich entfalte die Methode ... und sehe immer noch keinen Code.Wenn Sie sich Sorgen darüber machen, dass die Struktur der Methode von anderen gesehen wird (und Sie sich weigern, sie umzugestalten), fügen Sie folgende Bannerkommentare hinzu:
Diese helfen jemandem, der im Code browst, die einzelnen Teile Ihrer Methode zu sehen, ohne sich mit dem Erweitern und Reduzieren von
#region
Tags befassen zu müssen .quelle
ctrl+n
Ich denke, dass das Beispiel, das Sie in Ihrem Argument angeben, weniger YAGNI betrifft (Sie werden es nicht brauchen), als vielmehr das Schreiben von einwandfreiem Qualitätscode, der leicht zu warten ist.
In den ersten Programmierkursen haben wir gelernt, dass eine Methode mit einer Länge von 700 LOC wahrscheinlich zu umfangreich ist und mit Sicherheit einen enormen Aufwand darstellt, um sie zu testen und zu debuggen.
Zweitens, wenn ich die Methoden A, B und C schreibe, die nur in Methode D verwendet werden, kann ich AB und C einfacher unabhängig von D testen, was robustere Komponententests in allen 4 Methoden ermöglicht.
quelle
Das sind zwei Vorteile. Aber für mich ist Debugging sowieso das Wichtigste . Wenn Sie diesen Code nachverfolgen müssen, ist es viel einfacher, zwei der drei Abschnitte zu überspringen und nur den nachzuverfolgen, den Sie interessieren. Refactoring in kleinere Methoden ermöglicht dies; Region Tags nicht.
quelle
ctrl-f10
- Lauf zum CursorMeine persönliche Regel lautet: Wenn eine Methode länger als ein Bildschirm ist, z. B. 40 Zeilen, ist sie zu lang. Wenn eine Klasse länger als 500 Zeilen ist, ist sie zu groß. Ich verstoße manchmal gegen diese Regeln, manchmal sogar um ein Vielfaches, aber ich bereue es im Allgemeinen innerhalb eines Jahres.
Selbst eine Methode mit 20 bis 30 Zeilen ist in den meisten Fällen etwas lang. Daher würde ich sagen, dass die Verwendung von Regionen in einer Methode normalerweise eine schlechte Idee ist, einfach weil es fast nie Sinn macht, eine Region mit 20 bis 30 Zeilen in mehrere Unterregionen zu unterteilen.
Das Aufteilen von Funktionen, die nach dieser Definition lang sind, hat mindestens zwei Vorteile:
Sie können einen Namen für die von diesen Unterfunktionen ausgeführten Vorgänge eingeben, was Ihr gegenwärtiges Denken verdeutlicht und die Aufgabe späterer Betreuer vereinfacht.
Durch die Zerlegung in kleinere Funktionen müssen Sie nur die Parameter übergeben, die diese kleineren Funktionen benötigen. Der Umfang der Daten, die sie benötigen und ändern, ist also sehr klar. Dies setzt voraus, dass Sie nicht in hundert verschiedenen Blattfunktionen auf den Objektstatus zugreifen und ihn ändern, was ich auch entmutigen würde.
Nach meiner Erfahrung erzeugen diese Regeln Code, der einfacher zu schreiben ist, ohne häufige Fehler zu machen, und der später verstanden und geändert werden kann, ohne subtile Verhaltensweisen zu beeinträchtigen. Es ist egal, ob die Person, die den Code verstehen / ändern muss, jemand anderes ist oder ich selbst, nachdem ich alles geschlafen und vergessen habe.
Daher würde ich Regionen in Methoden als "Code-Geruch" betrachten, der darauf hinweist, dass nicht nachhaltige Praktiken angewendet werden. Wie immer gibt könnten Ausnahmen, aber sie treten so selten , dass sie diskutieren fast nicht wert sind.
quelle
Hier geht es wieder los ... Es gibt viele andere Themen zu Programmierern, die in der gleichen Diskussion gelandet sind.
Sie weisen auf einige sehr interessante Argumente im Zusammenhang mit Kurzfunktionen hin. Es ist keine populäre Aussage, aber ich bin mit Ihnen in dieser Sache . Nachdem ich es schon oft diskutiert habe, ist es mein Eindruck, dass die Diskussion in der Regel darauf hinausläuft, ob Sie sich in erster Linie auf die richtige Verkapselung konzentrieren oder die testgetriebene Entwicklung auf das Maximum bringen. Dies sind die beiden Hauptkonkurrenten in einem weiteren heiligen Krieg, und ich fürchte, wir sind auf der untermächtigen Seite.
Jedoch ...
Die Lösung ist meiner Meinung nach definitiv nicht, die "Phasen" in Regionen einzuschließen. Das Falzen von Codes wird verwendet, um Code unter den Teppich zu kehren. Lassen Sie den Code so wie er ist, er könnte Sie daran erinnern, dass Sie ihn zu einem späteren Zeitpunkt überarbeiten möchten! Um es auf ein Argument in Ihrer Frage zu beziehen: Wie können Sie eine Gelegenheit zur Wiederverwendung von Code sehen, wenn Sie keinen Code sehen? Lange Code-Segmente sollten genau das sein, ein Dorn im Auge, der Sie dazu bringt, ihn umzugestalten.
Als angemessener Ersatz für Regionen empfehle ich die Verwendung von Code-Absätzen, die Alex Papadimoulis in einem Kommentar benennt . Möglicherweise verwenden Sie bereits einen ähnlichen Ansatz. Es handelt sich einfach um Codeblöcke mit einem Kommentarkopf, der erklärt, was der gesamte Block tut. Sie verfügen über die Lesbarkeit von Funktionen, können jedoch normale englische Sätze verwenden und verlieren keine Kapselung.
quelle
Obwohl ich der Meinung bin, dass es normalerweise besser ist, Code umzugestalten, als ihn zu verwenden
#region
, ist dies nicht immer möglich.Lassen Sie mich ein Beispiel geben, um diese Aussage zu stützen.
Es ist einfach, die Regionen neu anzupassen, um die Reihenfolge zu ändern oder zu erweitern, wenn der Klasse zusätzliche Felder hinzugefügt werden. Kommentare sind sowieso erforderlich, um schnell zu sehen, wie die Bestellung funktionieren soll. Und vor allem: Ich verstehe nicht, wie Refactoring in diesem Fall die Lesbarkeit verbessert.
Diese Ausnahmen sind jedoch selten. Normalerweise ist es möglich zu refaktorieren, wie es in vielen anderen Antworten heißt.
quelle
Ich glaube nicht, dass es eine einzige Antwort dafür gibt, warum sich bestimmte Personen oder Teams gegen eine Verwendung entscheiden,
#region
aber wenn ich ein paar auflisten müsste, wären dies die Hauptgründe, die ich gesehen habe.quelle