Ist es üblich, Teilklassen zu verwenden, um "Modularität" zu erreichen?

24

Ich bin kürzlich auf eine Situation in unserer Codebasis gestoßen, in der ein anderes Team eine 'Gott-Klasse' erstellt hat, die ungefähr 800 Methoden enthält, die als Teilklasse auf 135 Dateien aufgeteilt sind.

Ich habe das andere Team danach gefragt. Obwohl ich aus dem Bauch herausgeholt habe, bestehen sie darauf, dass es sich um ein gutes Design handelt, eine gängige Praxis ist und dass es die Modularität und die einfache Implementierung fördert, da neue Entwickler die Funktionalität fast ohne Wissen über den Rest weiterentwickeln können vom System.

Ist dies tatsächlich eine gängige Praxis oder in irgendeiner Weise eine gute Idee? Ich bin geneigt, sofort Maßnahmen zu ergreifen, um dieses Biest zu Fall zu bringen (oder zumindest zu verhindern, dass es weiter wächst), aber ich bin bereit zu glauben, dass ich falsch liege.

Joshua Smith
quelle
6
Töte es mit Feuer! Aber im Ernst, kann das andere Team irgendwelche Zitate für diese angebliche übliche Praxis vorlegen?
MattDavey
1
Keiner. Ich bin mir sicher, dass sie Rauch blasen, aber ich versuche, meine Sorgfalt zu wahren, bevor ich den Hammer fallen lasse.
Joshua Smith
Was ist ihre Begründung, warum sie das nicht die ganze Zeit tun?
JeffO
3
Bitten Sie sie, in einem Satz zu beschreiben, was die 800 Methoden in 135 Dateien miteinander gemeinsam haben. Es sollte möglich sein, dies für jede vernünftige und vernünftige Klasse zu beantworten.
Carson63000
3
@ Carson63000 "Er führt alle erforderlichen Funktionen des Projekts aus." da ist dein einziger Satz.
Ryathal

Antworten:

39

Dies ist in keiner Weise eine gute Idee.

Teilklassen helfen dem Formulardesigner. Die Verwendung aus einem anderen Grund (und möglicherweise für den beabsichtigten Zweck, aber das ist eine andere Sache) ist eine schlechte Idee, da dies zu aufgeblähten Klassen führt, die schwer zu lesen und zu verstehen sind.

Betrachten Sie es so: Wenn eine Gottklasse mit 800 Methoden in einer Datei, in der Sie wissen, wo sich alles befindet, eine schlechte Sache ist - und ich denke, jeder würde dem zustimmen -, wie kann dann eine Gottklasse mit 800 Methoden funktionieren Auf 135 Dateien verteilt, wo man nicht weiß, wo alles möglicherweise eine gute Sache ist?

Mason Wheeler
quelle
1
Ich stimme dem größtenteils zu, aber ich denke, es kann einige seltene Fälle geben, in denen partiales auch ohne generierten Code nützlich sein kann. Vielleicht, wenn Sie so etwas wie eine verschachtelte Klasse haben?
SVICK
1
@svick: Teilklassen sind interessant, werden aber normalerweise nicht benötigt. Ich bin mir nicht sicher, warum das Aufteilen einer Klasse in separate Dateien sinnvoll ist, wenn es verschachtelte Klassen gibt. Es sei denn, Sie möchten die verschachtelte Klasse in einer eigenen physischen Datei. In diesem Fall ... ist es in Ordnung. ;)
FrustratedWithFormsDesigner
5
Ich verwende manchmal Teilklassen für explizite Schnittstellenimplementierungen - insbesondere so etwas wie System.IConvertible. Irgendwie scheint es sauberer zu sein, als eine massive #Region in meine Klasse aufzunehmen.
MattDavey
1
Der verschachtelte Klassenkommentar ist eigentlich eine wirklich gute Idee, daran habe ich noch nie gedacht. Obwohl ... das mehr mit Organisation zu tun hat als mit 'Modularität'
Sheldon Warkentin
1
"Es gibt Teilklassen, die dem Formulardesigner helfen sollen." Im Allgemeinen richtig, aber ich würde "... und andere Codegeneratoren" hinzufügen. Ich stimme dem Rest deiner Antwort zu;)
Silas
14

Die Frage war also:

Ist dies tatsächlich eine gängige Praxis oder in irgendeiner Weise eine gute Idee?

Zu den derzeit verfügbaren Antworten gehört ein klares Nein . Es gibt also einige andere Dinge, die ich daran ändern könnte, wie z. Sogar der Verfahrenscode kann modular aufgebaut werden und alles einbeziehen. Mit Ausnahme der Küchenspüle erreichen Sie keine Modularität. Was eine in Teilklassen aufgeteilte Riesenklasse tut, summiert sich zu einem großen Durcheinander.

Diese Frage ist jedoch ein roter Faden für den wirklich kritischen Teil, der übersehen wurde. Da das OP auch folgendes zu der Situation zu sagen hat:

(...) Während meine Bauchreaktion darin bestand, es aus dem Orbit zu entfernen, bestehen sie darauf ...

(...) Ich bin geneigt, sofort Maßnahmen zu ergreifen, um dieses Biest zu Fall zu bringen (oder zumindest zu verhindern, dass es weiter wächst), aber ich bin bereit zu glauben, dass ich falsch liege.

HALTE DEINE PFERDE!

Dies hier ist etwas, das mein bildlich gesprochenes Monokel in meine bildliche Tasse Tee fallen lassen würde.

Ich war in ähnlichen Situationen und lass mich dir sagen: FALLE NICHT dem Drang nach. Natürlich können Sie den Nuke Hammer of Justice im Team ablegen, aber bevor Sie dies tun, müssen Sie sich mit dem folgenden Rätsel auseinandersetzen:

Was passiert , wenn Sie das Team sagen , dass ihr Code saugt und aus sod ?

(... oder so ähnlich, aber weniger offensiv, es spielt keine Rolle, denn sie werden beleidigt, egal was Sie tun, wenn Sie sich dazu entschließen, mit aller Kraft gegen sie vorzugehen.)

Wie ist die aktuelle Situation mit der Codebasis? Funktioniert es? Dann werden Sie große Probleme damit haben, ihren Kunden zu erklären, dass ihr Code im Wesentlichen scheiße ist . Egal aus welchen Gründen: Solange es funktioniert, kümmern sich die meisten Kunden nicht darum, wie der Code organisiert ist.

Versetzen Sie sich auch in ihre Lage, was würden sie tun? Lassen Sie mich Sie mit dem folgenden sehr möglichen Ergebnis amüsieren:

Teammitglied Nr. 1: "Da ist also dieser Typ, der uns sagt, dass wir es in den letzten Jahren falsch gemacht haben."

Teammitglied Nr. 2 und Nr. 3: "Was für ein Idiot."

Einflussreiches Teammitglied # 4: "Mach dir keine Sorgen, ich gehe einfach zum Management und melde es als Belästigung."

Sehen Sie, was einflussreiches Teammitglied # 4 dort getan hat? Er ging zur Geschäftsführung und reduzierte Ihr Karma in der Firma. Er könnte amerikanisch-italienisch sein und jedem sagen, er solle sich keine Sorgen machen, aber dann wäre ich rassistisch.

Es ist auch eine schlechte Idee, das beleidigende Team in eine Ecke zu schieben und zuzugeben, dass es so lange falsch gemacht hat. Sie verlieren Respekt und etwas büropolitisches Karma.

Auch wenn Sie es geschafft haben, ein paar Leute dazu zu bringen, sich zu melden, um dem Team eine Lektion zu erteilen, denken Sie daran, dass Sie dies ziemlich klugen Leuten antun, die anscheinend einige Dinge erledigen. Sobald der Code umgeschrieben / überarbeitet / behandelt / was auch immer behandelt wird, treten Probleme auf, die Sie als Feuerstarter zur Rechenschaft ziehen .

In solchen Situationen kontrovers zu sein, ist meistens ein Verlust / Verlust-Spiel, da es das Risiko birgt, ein Teufelskreis von Schuldzuweisungen zu werden. Dies ist ein suboptimales Ergebnis für diese Situation. Selbst wenn Sie gewinnen, werden Sie plötzlich über das Durcheinander gebracht, das jemand anderes angerichtet hat.

Es gibt andere (viel ausgereifte) Wege

Ich war einmal in einer ähnlichen Situation, aber dann nahm ich einen Pfeil in das Knie. Nach einer Weile mit dem plötzlichen Karrierewechsel im Hinterkopf bekam ich ein Buch Driving Technical Change von Terrence Ryan . Es werden verschiedene Muster von Skeptikern aufgelistet, die Leute handeln nicht nach guten Ideen. Sie sind alle höchstwahrscheinlich im Fall des OP anwendbar:

  • Die Uninformierten - Sie wussten wirklich nicht, dass es andere Wege gibt, oder sie verstanden es einfach nicht. Junior Entwickler passen normalerweise in diese Kategorie, aber nicht unbedingt. (Um ehrlich zu sein: Ich habe Nachwuchsentwickler getroffen, die heller wären.)
  • Die Herde - Sie kannten bessere Techniken als Teilklassen, wussten aber nicht, dass sie erlaubt waren.
  • Die Zyniker - Sie argumentieren nur gerne, dass es besser ist, Teilklassen zu haben als Ihre Idee, nur um zu argumentieren. Es ist einfach, das in einer Menschenmenge zu tun, anstatt vor einer Menschenmenge zu stehen.
  • The Burned - Aus irgendeinem Grund möchten sie keine neuen Klassen gründen. Wahrscheinlich empfinden sie es als zu schwierig.
  • The Time Crunched - Sie sind so beschäftigt, dass sie sich nicht die Mühe machen können, ihren Code zu reparieren.
  • Der Boss - Sie denken: "Nun, es funktioniert. Warum also die Mühe machen?"
  • The Irrational - Ok, sie sind einfach total verrückt.

Das Buch geht weiter mit einer Liste von Strategien und so weiter, aber im Falle des OP ist es eine Frage der Überzeugung. Sich mit Fakten über das Anti-Pattern zu messen, ist nicht genug.

Wenn es in Ihrem Interesse ist, die Codequalität zu verbessern, geben Sie dem betreffenden Team zumindest die Möglichkeit, sein eigenes Durcheinander zu wiederholen und zu korrigieren . Persönlich würde ich versuchen, sie zu beeinflussen, indem ich ihnen zuhöre und ihnen wichtige Fragen stelle. Lassen Sie sie ihre Geschichte erzählen:

  • Was genau macht ihre Gottesklasse?
  • Haben sie irgendwelche Probleme? Haben sie irgendwelche Fehler? Schlagen Sie vernünftige Korrekturen vor, ohne sie dazu anzuweisen.
  • Wenn Sie ein Benutzer dieser Klasse als API sind: Gibt es einfachere Möglichkeiten, den Code zu verwenden, als das Ganze zu verwenden? Schlagen Sie einfachere Beispiele vor und sehen Sie, wie sie reagieren.
  • Können Sie eine Funktion mit einer anderen austauschen, ohne die Funktion schreiben zu müssen?
  • Benötigen sie eine Ausbildung? Können Sie das Management davon überzeugen, dies zu tun, oder ein Lunch-Meeting über Muster und Praktiken abhalten?

... und so weiter. Geben Sie ihnen kleine Vorschläge, damit sie vorankommen können. Es braucht Zeit und braucht ein bisschen büropolitisches Ellbogenfett, aber Geduld und harte Arbeit sind eine Tugend, oder?

Spoike
quelle
Dies ist eine sehr aufschlussreiche Antwort. Wenn Sie ein neuer Entwickler sind, müssen Sie dies verstehen. Die meisten erfahrenen Entwickler stellen dies nach mehreren Jahren fest, manche nie.
FishySwede
6

Auf der Seite MSDN Partial Classes and Methods werden zwei Situationen für die Verwendung von Teilklassen vorgeschlagen:
1. Aufteilen einer riesigen Klasse in mehrere separate Dateien.
2. Um einen Ort zu haben, an dem automatisch generierter Quellcode abgelegt werden kann.

2 wird häufig von Visual Studio verwendet (z. B. für Aspx-Dateien und für Winforms). Dies ist eine sinnvolle Verwendung von Teilklassen.

1 ist das, was dein Team tut. Ich würde sagen, dass die Verwendung von Teilklassen eine absolut vernünftige Methode ist, um Modularität zu erreichen, wenn Sie über Riesenklassen verfügen, aber Riesenklassen selbst sind unvernünftig. Mit anderen Worten, eine Riesenklasse ist eine schlechte Idee, aber wenn Sie eine Riesenklasse haben wollen, sind Teilklassen eine gute Idee.

Wenn Sie eine Klasse auf intelligente Weise in separate Dateien für verschiedene Benutzer aufteilen können, können Sie sie stattdessen nicht einfach in separate Klassen aufteilen?

Brian
quelle
+1 für "Kannst du es nicht stattdessen in separate Klassen aufteilen?" Genau das schlagen wir vor. Es scheint ein gesunder Menschenverstand zu sein, dass es ursprünglich so hätte gemacht werden sollen.
Joshua Smith
4

Letztendlich machen sie also eine normale prozedurale Entwicklung ohne OOP. Sie haben einen globalen Namespace mit allen Methoden, Variablen und so weiter.

Entweder sie überreden, dass sie es falsch machen, oder verdammt noch mal raus.

Euphorisch
quelle
1

Eine Utility-Klasse enthält Methoden, die nicht sinnvoll mit anderen Methoden kombiniert werden können, um eine Klasse zu erstellen. Wenn Sie über 800 Methoden haben, die in 135 Dateien aufgeteilt sind, hat es wahrscheinlich jemand geschafft, einige gängige Methoden zu finden ...

Nur weil Sie eine Utility-Klasse haben, heißt das nicht, dass Sie keine andere Utility-Klasse haben können.

Selbst wenn Sie über 800 meist nicht verwandte Methoden verfügen, ist die Lösung keine große Klasse und enthält nicht viele Dateien. Die Lösung ist ein Namespace, einige Subnamespaces und viele kleine Klassen. Dies ist etwas mehr Arbeit (Sie müssen einen Namen für die Klasse sowie die Methode ausarbeiten). Aber es wird Ihnen das Leben erleichtern, wenn Sie dieses Chaos beseitigen müssen, und in der Zwischenzeit wird es die Verwendung von Intellisense vereinfachen (dh es wird einfacher, herauszufinden, wo eine Methode es verwenden soll).

Und nein, das ist nicht üblich (mehr die Anzahl der Dateien als die Anzahl der freien Funktionen).

jmoreno
quelle
0

Das mag ich überhaupt nicht. Möglicherweise machten die Teilklassen jedoch für die Entwickler während der Entwicklung Sinn, da sie die gleichzeitige Entwicklung dieser großen Anzahl von Methoden ermöglichten, insbesondere, wenn zwischen ihnen keine großen Abhängigkeiten bestehen.

Eine andere Möglichkeit besteht darin, dass diese Teilklassen erstellt wurden, um eine automatisch generierte Kernklasse zu ändern. In diesem Fall sollte man sie nicht berühren, da sonst der benutzerdefinierte Code beim erneuten Generieren ausgepeitscht wird.

Ich bin mir nicht sicher, ob jemand dies ohne etwas Studium mühelos durchhalten kann. Wenn Sie es jetzt töten, wird die Anzahl der Methoden nicht sinken. Die Anzahl der Methoden und die Komplexität sind für mich das eigentliche Problem. Wenn die Methoden wirklich zu der Klasse gehören, wird das Vorhandensein einer großen Datei Ihr Leben nicht einfacher machen, insbesondere bei der Wartung. Tatsächlich ist es möglicherweise fehleranfälliger, diesen gesamten Code für dumme Fehler wie die Suche mit Platzhaltern bereitzustellen und ersetzen.

Seien Sie also vorsichtig und begründen Sie die Tötungsentscheidung. Überlegen Sie auch, welche Tests erforderlich sind.

Keine Chance
quelle
0

Aus Sicht des praktischen Designs ist es vollkommen in Ordnung, wenn man annimmt, dass die 135 Dateien Methoden ähnlich wie bei herkömmlichen Klassen gruppieren. Es sind nur durchschnittlich 6 Methoden pro Datei. Es ist definitiv nicht die beliebteste oder traditionellste Art, ein Projekt zu entwerfen. Der Versuch, es zu ändern, wird nur eine Reihe von Problemen und einen schlechten Willen ohne wirklichen Nutzen hervorrufen. Wenn Sie das Projekt an die OO-Standards anpassen, entstehen so viele Probleme, wie es löst. Es ist eine völlig andere Sache, wenn die mehreren Dateien tatsächlich keine sinnvollen Trennungen liefern.

Ryathal
quelle
3
Das Umgestalten von Prozedurcode in OO hat im Allgemeinen dieses Problem - ich denke, dass das Beheben dieses Problems eine große Aufgabe ist und das Team lehrt, noch umfangreicher richtig zu programmieren. Außerdem wird Joshua für alles verantwortlich gemacht, was im nächsten Jahr (und darüber hinaus) passiert ), wenn er sie zum Refactor überredet. Dies ist der Grund, warum niemand zu viel Druck auf solche Refaktoren ausübt (zumindest nicht, wenn sie die Ergebnisse erst einmal gesehen haben). Auch wenn Sie der Meinung sind, dass es sich um ein gutes Design handelt, lesen Sie diese Antwort in 5 Jahren noch einmal durch und teilen Sie uns Ihre Meinung mit (anscheinend lerne ich alle 5 Jahre alles, was ich über Design weiß, neu).
Bill K
@BillK Wenn Sie zehn Jahre warten, wird das, was Sie wissen, wahrscheinlich die aktuelle "in" -Design-Philosophie sein.
Ryathal
Bei den 135-Dateien handelt es sich im Allgemeinen um gruppenbezogene Methoden, aber dies ist (für mich) immer noch keine gute Idee. Ich möchte dieses System testen, aber die 800-Methode Hydra zu stoppen oder zu verspotten wird ein hässlicher Schmerz im Arsch sein.
Joshua Smith
@Ryathal Es ist nicht das, was "in" ist, sondern das, was Sie für gutes Design halten (aus guten Gründen). Wenn Sie dann üben und verbessern, stellen Sie fest, dass es keine so gute Idee ist, wie Sie dachten. Es sieht so aus, als ob das alle fünf Jahre passiert und als ich bemerkte, dass es meine Reaktion auf die Kommentare einiger Leute beeinträchtigt, weil ich feststelle, dass sie wirklich hervorragende Designer sind, die (wie wir alle) dabei sind, unsere Praktiken für immer zu verbessern. Der einzige Programmierer, der mir Sorgen macht, ist einer, der nicht glaubt, dass er den Code verbessern kann, den er vor fünf Jahren geschrieben hat.
Bill K
0

Abgesehen von den bereits erwähnten Antworten können Teilklassen in einem mehrschichtigen Entwurf nützlich sein, in dem Sie Funktionen organisieren möchten, die Ihre Klassenhierarchie in separate schichtenspezifische Dateien aufteilen. Dies ermöglicht die Verwendung des Lösungs-Explorers zum Navigieren durch die Funktionen pro Ebene (nach Dateiorganisation) und der Klassenansicht zum Navigieren durch die Funktionen pro Klasse. Ich würde es vorziehen, eine Sprache zu verwenden, die Mixins und / oder Merkmale unterstützt, aber Teilklassen sind eine sinnvolle Alternative, wenn sie sparsam verwendet werden, und sollten keinen Ersatz für ein gutes Design der Klassenhierarchie darstellen.

Sean McDirmid
quelle