Warum lehnen Menschen #region-Tags in Methoden so stark ab?

27

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?

jjoelson
quelle
4
Ich arbeite zurzeit mit einer Klasse, die ziemlich groß ist. Es folgt dem Prinzip der Einzelverantwortung; alles in der Klasse ist Funktionalität erforderlich. Es hat eine Menge privater Methoden, hauptsächlich aufgrund von Refactoring. Ich benutze #region, um diese Methoden in funktionale Kategorien zu unterteilen, was für uns sehr gut funktioniert hat. Es gibt viele andere Klassen in diesem Projekt, die eine solche Behandlung nicht benötigten. Das richtige Werkzeug für den richtigen Job, sage ich.
Robert Harvey
4
@RobertHarvey: Die Verwendung in einer Klasse unterscheidet sich von der Verwendung in einer Methode.
CaffGeek
18
@Chad: Ah, habe das nicht bemerkt. Ihre Verwendung in einer Methode scheint ein bisschen extrem zu sein. Wenn eine Methode so lang ist, dass sie #regions erfordert, zerlege ich sie in separate Methoden.
Robert Harvey
8
Keine wirkliche Antwort, aber ich hasse nicht nur alle #regionTags, ich deaktiviere das Falten von Code in Visual Studio insgesamt. Ich mag keinen Code, der versucht, sich vor mir zu verstecken.
Daniel Pryden
2
"Darüber hinaus ist jede dieser Stufen nur für die Berechnung dieser Methode relevant. Wenn wir sie also in neue Methoden extrahieren, können wir den Code nicht wiederverwenden." OTOH, ich finde, dass, wenn ich eine Funktion in 3 teile, ich später oft finde, dass die einzelnen Teile <i> später </ i> nützlich sind, z. Wenn einige Eingangsdaten nur eine Phase ändern, können Sie dies isoliert testen, usw.
Jack V.,

Antworten:

65

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.

  1. Sie können keine Regionen testen, aber Sie können echte Methoden isoliert testen.
  2. Regionen sind Kommentare, keine syntaktischen Elemente. Im schlimmsten Fall widersprechen sich die Verschachtelungen Ihrer Regionen und Ihrer Blöcke. Sie sollten sich immer bemühen, die Semantik Ihrer Struktur mit den syntaktischen Elementen der von Ihnen verwendeten Sprache darzustellen.
  3. Nach dem Refactoring zu Methoden muss nicht mehr gefaltet werden, um den Text zu lesen. Man könnte sich den Quellcode in jedem Tool ansehen, das keine Faltung hat, wie z. B. einem Terminal, einem Mail-Client, einer Webansicht für Ihr VCS oder einem Diff-Viewer.
  4. Nach der Umgestaltung auf Methoden ist die resultierende Methode mindestens so gut wie bei Regionen. Außerdem ist es einfacher, die einzelnen Teile zu verschieben.
  5. Das Prinzip der Einzelverantwortung sieht vor, dass jede Einheit eine Aufgabe und nur eine Aufgabe haben sollte. Die Aufgabe der "main" -Methode besteht darin, die "helper" -Methoden zusammenzustellen, um das gewünschte Ergebnis zu erzielen. Die "Helfer" -Methoden lösen ein diskretes, einfaches Problem für sich. Die Klasse, die alle diese Methoden enthält, sollte auch nur eine Aufgabe erfüllen und nur die Methoden enthalten, die sich auf diese Aufgabe beziehen. Die Hilfsmethoden gehören also entweder in den Klassenbereich, oder der Code sollte nicht an erster Stelle in der Klasse enthalten sein, sondern zumindest in einer globalen Methode oder besser noch in die Klasse eingefügt werden .

Ebenfalls relevant: Jeff Atwoods Gedanken zum Code-Falten

back2dos
quelle
9
1. Die meisten Programmierer testen nicht alle privaten Methoden. 2. Ein Methodenname kann nicht alles vermitteln, was man über diese Methode wissen muss. Welche Ausnahmen könnten geworfen werden? Ist null eine gültige Eingabe? Manchmal ist es in Ordnung, nicht-syntaktische Konstrukte zu verwenden, um den Code verständlicher zu machen. In vielen Sprachen sind Dateien ein Beispiel für ein nicht syntaktisches Element, das als Mittel zum Organisieren von Code weitgehend akzeptiert wird. 3. Das Eintauchen in die Funktionsweise einer Methode wird am besten in einer IDE aus verschiedenen Gründen versucht. Situationen, in denen Regionen Sie in Ihrem VCS oder E-Mail-Client beißen könnten, sind eher selten.
Jjoelson
3
4. Aber Sie haben gerade eine ernsthafte Komplexität in den Rest Ihrer Klasse exportiert. Lohnt sich das? Außerdem können Regionen so einfach wie ein Methodenaufruf verschoben werden. 5. Nun geht es darum, Ihren Namespace mit mehr Klassen zu verschmutzen, die nur an einem einzigen Ort verwendet werden. Warum sind Klassen und Methoden die einzigen Kapselungseinheiten, die Sie akzeptieren werden? Sie können diese neue Klasse später jederzeit erstellen, wenn (oder wenn) dies erforderlich wird.
jjoelson
7
@ jjoelson: 1. Na und? 2. Genau mein Punkt: Es ist in Ordnung, nicht-syntaktische Konstrukte zu verwenden, wenn (und nur wenn) Syntax allein nicht ausreicht. 3. "Selten?" - Ich nehme an, Sie haben Zahlen, die das belegen. Ich kann Ihnen mit Sicherheit sagen, dass das mit TortoiseSVN gelieferte Diff-Tool (oder die Schuld oder was auch immer) keine Funktion hat. 4. Wie hängt das mit dem Punkt zusammen, den ich angesprochen habe? 5. Deshalb haben die meisten modernen Sprachen verschachtelbare Namespaces. Sie greifen auf ASCII-Kunst zurück, anstatt eine breite Palette verfügbarer Sprachelemente zum Strukturieren Ihres Codes zu verwenden.
back2dos
4
@jjoelson: 1. Das ist deine Meinung und liegt außerhalb des Rahmens dieser Frage. 2. Nach meinem Argument sind verschachtelte Funktionen besser als Regionen, ja. 3. Weil ich manchmal mehrere Revisionen durchsuchen muss, um ein Problem zu verfolgen. In jedem Fall ist der Quellcode für Menschen geschrieben, nicht für IDEs. 4. Zum einen hat das Argument nichts mit meinem Punkt zu tun, zum anderen ist das wieder nur Ihre Meinung, zum dritten liegt es außerhalb des Rahmens dieser Frage. 5. C # bietet andere Möglichkeiten zur Strukturierung von Code als die Verschachtelungsfunktion. Sie sollten entweder diese oder eine Sprache verwenden, die Verschachtelungsfunktionen ermöglicht.
back2dos
13
Ihr solltet dies zum Plaudern nehmen, wenn ihr noch diskutieren wollt ... Ich habe nichts, was es wert wäre, dem OP gesagt zu werden, er ist ein typischer Junior-Entwickler, der nach seiner Überzeugung eine Meinung hat. Nichts wird seine Meinung ändern, aber mehr Erfahrung IMO.
maple_shaft
15

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.

"Zuerst bekommt es die Dinge, und dann treibt es sie herum, dann, wenn sie es brauchen, macht es das, sonst prüft es, ob sie blau sind und kehrt ihren Copernicus-Wert um. Dann, wenn das zweite Ding größer ist als das erste Ding, wir brauche die Saftbox und lege sie ein ... "

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:

  • Klareres Verständnis dessen, was wo passiert, auch wenn nur der Name der Methode ausschlaggebend ist. Und Sie sind falsch , dass ein Verfahren nicht vollständig dokumentiert werden - fügen Sie die Dokumentation Block (Hit ///) und geben Sie die Beschreibung, Parameter, Rückgabetyp und auch exception, example, remarksKnoten zum Detail dieser Szenarien. Das ist, wo es hingeht, dafür ist es da!
  • Es gibt keine Nebenwirkungen oder Probleme mit dem Anwendungsbereich. Sie können sagen, dass Sie alle Ihre Variablen in einem Unterbereich mit deklarieren {}, aber muss ich jede Methode überprüfen, um sicherzustellen, dass Sie nicht "betrogen" haben? Benutze dodgyObjectich 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).
  • In meinem Ereignisprotokoll ist angegeben, in welcher Methode eine Ausnahme aufgetreten ist. Ja, ich kann möglicherweise den fehlerhaften Code mit einer Zeilennummer finden, aber wenn ich den Namen der Methode kenne (insbesondere, wenn ich sie richtig benannt habe), kann ich dies sehr gut nachvollziehen Was ist passiert und was ist schief gelaufen? "Oh, die TurnThingsUpsideDownMethode ist fehlgeschlagen - sie schlägt wahrscheinlich beim Drehen einer schlechten Sache fehl" ist viel besser als "Oh, die DoEverythingMethode 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.

Kirk Broadhurst
quelle
Die XML-Kommentaranalyse von Visual Studio fällt zusammen mit den Tags #region unter die Kategorie der Visual Studio-Features. Mein Punkt ist, dass es nicht falsch ist, sich auf diese Funktionen zu verlassen, wenn jeder in Ihrem Projekt Visual Studio verwendet. Was die Probleme mit Nebeneffekten und dem Umfang betrifft, können Sie die Dinge immer noch mit globalen Feldern vermasseln. In beiden Fällen müssen Sie sich darauf verlassen, dass die Programmierer keine dummen Dinge mit Nebenwirkungen tun.
jjoelson
5
@jjoelson Sie können die XML-Kommentare auch ohne Visual Studio lesen, aber die Regions-Tags sind außerhalb von VS fast völlig nutzlos. Die logische Erweiterung Ihres Arguments ist eine riesige Methode, mit der Ihre gesamte Anwendung ausgeführt werden kann, solange Sie sie in Regionen unterteilt haben!
Kirk Broadhurst
2
@jjoelson, bitte fang nicht damit an, wie schlecht globale Felder sind. Etwas zu sagen ist nicht nützlich, weil Sie eine "Problemumgehung" haben, um es irgendwie zu vermasseln, ist einfach albern. Halten Sie Ihre Methoden einfach kurz und Variablenbereich.
OliverS
@OliverS, Kirk war derjenige, der Shared State als Problem mit meinem System der Regionen in einer Methode ansprach. Grundsätzlich habe ich genau das gesagt, was Sie sagen: Die Tatsache, dass ein Programmierer den Zustand missbrauchen könnte, indem er zu viele Variablen zwischen Regionen teilt, ist keine Anklage für das gesamte Schema, genau wie die Fähigkeit, den zwischen Methoden über globale Variablen geteilten Zustand zu vermasseln, nicht. t eine Anklage gegen das Mehrmethodenschema.
jjoelson
7

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 #regionist, 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, #regionsollte 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:

//
// ---------- COMPUTE SOMETHING OR OTHER ----------
//

Diese helfen jemandem, der im Code browst, die einzelnen Teile Ihrer Methode zu sehen, ohne sich mit dem Erweitern und Reduzieren von #regionTags befassen zu müssen .

Kyralessa
quelle
2
All dies für eine Methode, die an einem Ort aufgerufen wird ? Selbst die meisten Hardcore-Lispers werden erst dann eine Funktion höherer Ordnung abstrahieren, wenn sie mindestens zwei Stellen identifiziert haben, an denen sie zur einfacheren Definition einer Funktion verwendet werden können.
Jjoelson
1
@jjoelson Ist es so schwer, eine neue Klasse zu bilden? Was ist das, eine Linie, eine öffnende Klammer und eine schließende Klammer. Oh, und Sie müssen drückenctrl+n
Kirk Broadhurst
2
Es ist nicht so, dass es schwierig ist , eine neue Klasse zu bilden, aber es ist mit einem gewissen Aufwand verbunden , eine zusätzliche Klasse zu haben. Es ist eine weitere Indirektionsebene, die es für eine Code-Betreuerin schwieriger macht, das zu finden, wonach sie sucht. Es ist keine so große Sache, aber es bringt Ihnen auch nichts, wenn es unwahrscheinlich ist, dass dieser Code von irgendwo anders aufgerufen wird. Und, wie Sie erwähnt haben , ist es ganz einfach , dass die neue Klasse zu machen und den Code dort setzen , wenn sich herausstellt, Sie zu tun Notwendigkeit , dieses Stück Code rufen an mehreren Stellen.
jjoelson
2
@jjoelson, das ist eine ziemlich häufige Reaktion. Es war meins, als ich zum ersten Mal etwas über SRP und DI erfuhr, und es war die Reaktion meiner Mitarbeiter, als wir anfingen, Abhängigkeiten aufzubrechen. Wenn Sie sich einen Einzelfall ansehen , scheint es sich nicht zu lohnen. Der Nutzen liegt in der Summe. Sobald Sie beginnen, SRP mit all Ihren Klassen durchzuführen, stellen Sie fest, dass es viel einfacher ist, einen Teil Ihres Codes zu ändern, ohne dass die Änderungen die Hälfte Ihrer Anwendung durchdringen.
Kyralessa,
@Kyralessa, das sind Methoden, die nur an einem Ort verwendet werden. Wenn Sie eine solche Methode ändern, wird die Hälfte Ihrer Anwendung davon nicht beeinträchtigt. Wenn ein solcher Code als Region in der Methode implementiert ist, die ihn verwendet, haben Sie eine perfekte Kapselung. Nur die enthaltende Methode verwendet den Code. Sie können ihn also beliebig ändern, ohne sich Gedanken über die Auswirkung machen zu müssen, außer bei dieser Methode.
jjoelson
4

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.

maple_shaft
quelle
Unit-Tests sind sicherlich ein fairer Punkt, aber ich bin mir nicht sicher, ob sie eine Verschmutzung des Klassenbereichs in jedem Fall rechtfertigen. Realistisch gesehen, testet jemand tatsächlich jede kleine private Methode, die er schreibt? Ich würde sagen, die Leute neigen dazu, die privaten Methoden zu testen, die häufig verwendet werden, das heißt, private Methoden, die ohnehin Kandidaten für die Wiederverwendung von Code wären.
jjoelson
@jjoelson Wenn die Methode eine sinnvolle Logik hat und keine andere Funktionalität enthält, schreibe ich immer einen Komponententest dagegen. Unit-Test-Methoden haben nichts mit der Wiederverwendung von Code zu tun. Sie sollten Unit-Test-Methoden anwenden, um zu überprüfen, ob für bestimmte Eingaben die erwarteten Ausgaben auf konsistente und wiederholbare Weise erzielt werden. Wenn Sie feststellen, dass der Klassenbereich beim Aufrufen verschmutzt wird, verstößt Ihre Klasse möglicherweise gegen das Prinzip der Einzelverantwortung.
maple_shaft
2
Die meisten Programmierer, denen ich begegnet bin, sind mit der Idee nicht einverstanden, jede private Methode einzeln zu testen. Es lohnt sich einfach nicht, Tests für alle privaten Methoden zu implementieren und zu warten.
jjoelson
3

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. Was sind dann die Vorteile einer Extraktion jeder Phase in eine eigene Methode? 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).

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.

Mason Wheeler
quelle
1
ctrl-f10- Lauf zum Cursor
Steven Jeuris
2

Meine 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:

  1. 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.

  2. 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.

PeterAllenWebb
quelle
2

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.

Steven Jeuris
quelle
Nun, ich benutze im Wesentlichen Regionen, um Code-Absätze abzugrenzen (Regionen können Kommentare enthalten, die auch dann sichtbar sind, wenn der Code gefaltet ist). Ich benutze gerne Regionen dafür, weil der Betreuer die Wahl hat, den Code zu sehen, wenn er die Implementierung untersuchen oder falten möchte, wenn er nur das "große Ganze" sehen möchte.
jjoelson
1

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.

class Foo : IComparable
{
  private String name;
  private int foo;
  private Bar bar;

  public int CompareTo(Foo other)
  {
#region Ascending on name
     if (this.name < other.name) return -1;
     if (this.name > other.name) return 1;
#endregion
#region Usual order on bar
     int compBar = bar.compareTo(other.bar);
     if (compBar != 0) return compBar;
#endregion
#region Descending on foo
     if (this.foo > other.foo) return -1;
     if (this.foo < other.foo) return 1;
#endregion
     return 0; // equal
  }

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.

Sjoerd
quelle
0

Ich glaube nicht, dass es eine einzige Antwort dafür gibt, warum sich bestimmte Personen oder Teams gegen eine Verwendung entscheiden, #regionaber wenn ich ein paar auflisten müsste, wären dies die Hauptgründe, die ich gesehen habe.

  • Die Namen und die Reihenfolge der Regionen verdeutlichen die Reihenfolge und Organisation des Codes, der einen bestimmten Stil erzwingt, der zu einer Quelle von Konflikten und Bikeshedding werden kann.
  • Die meisten Konzepte passen nicht sauber in eine kleine Anzahl von Regionen. Normalerweise beginnen Sie mit Regionen, indem Sie die Zugriffsmodifizierer public , private und dann möglicherweise den Elementtyp (z. B. Methode, Eigenschaft, Feld) angeben. Wie sieht es dann mit Konstruktoren aus, die diese Modifizierer, statischen Varietäten all dieser Elemente, geschützten Elemente, internen Elemente und geschützten internen Elemente umfassen? Elemente, implizite Schnittstellenelemente, Ereignisse usw. Aufgrund der detaillierten Kategorisierung hätten Sie am Ende am besten entworfene Klassen, in denen Sie in jeder Region eine einzelne oder Methode haben.
  • Wenn Sie in der Lage sind, pragmatisch zu bleiben und Dinge nur in etwa drei oder vier gleichbleibende Arten von Regionen zu gruppieren, kann das funktionieren, aber welchen Wert bringt es wirklich? Wenn Sie Klassen gut entwerfen, sollten Sie wirklich keine Codeseiten durchsuchen müssen.
  • Wie oben angedeutet, können Regionen hässlichen Code verbergen, wodurch er weniger problematisch erscheint als er ist. Wenn Sie es als Auge wund halten, kann es hilfreich sein, es in Angriff zu nehmen.
jpierson
quelle