Wird es in MVC als bewährte Methode angesehen, private, nicht aktivierende Funktionen in einer Controller-Klasse zu haben?

10

Manchmal können Aktionsfunktionen in der Controller-Klasse sehr umfangreich und unangenehm werden, mit vielen, vielen Codezeilen, um einfach den Datenfluss vom Modell zur Ansicht zu steuern. Irgendwann verlieren diese riesigen Funktionen die Grundprinzipien eines guten Codes völlig aus den Augen, dh sie tun nur eines: klein, lesbar und verwaltbar usw.

Wäre es eine gute Praxis, diese riesigen Aktionsfunktionen in kleinere private Funktionen in der Controller-Klasse zu unterteilen, oder sollte die Notwendigkeit einer solchen Optimierung bedeuten, dass wir sie lieber in das Modell aufnehmen sollten?

Ich würde dafür stimmen, dass die kleineren Funktionen im Controller privat sind, damit sie relativ zur Aktion sind, aber ich habe Argumente gehört, dass der Controller vorzugsweise einfach sein sollte, während das Modell riesig und klumpig werden kann. und fragte mich nur, welche die am meisten bevorzugte Methode sein würde.

David 'der kahle Ingwer'
quelle

Antworten:

16

Könnte nicht die beste Analogie sein, aber denken Sie an den Controller genauso wie an ein Spinnennetz. Seine einzige Aufgabe ist es, Fliegen (Anfragen) zu fangen, damit die Spinne (darunter liegende Schichten) verdaut werden kann. Das Netz kann kleinere oder größere Fliegen (Modelle) fangen und halten. Die Rolle eines Spinnennetzes besteht nicht darin, die Beute zu verdauen, obwohl sie für diesen Zweck verwendet werden kann. Je dünner und sauberer das Netz ist, desto leichter kann die Spinne ihren Lebensunterhalt verdienen.

Sie können dieselbe Logik auf Ihre MVC-Anwendung anwenden. Die riesigen und unangenehmen Funktionen, die Sie beschreiben, sind höchstwahrscheinlich das Verhalten des Modells und sollten in das Modell gehören (beachten Sie, dass das Modell nicht nur das Objekt ist, das in der Ansicht angezeigt wird). Wenn sich das Verhalten des Modells ändert, sollte das Modell geändert werden und nicht der Controller, der es verarbeitet.

Wenn Sie sie als private Methoden im Controller behalten, wird dies nur unübersichtlich und die Wartung erschweren. Dies macht auch einer schlechten Angewohnheit Platz, da andere Personen, die an der Entwicklung beteiligt sind, versucht wären, dasselbe zu tun, da sie dies bereits im Projekt gesehen haben.

devnull
quelle
+1 für die kreative Analogie. :) Du machst einen interessanten Punkt. Besonders bei der Bildung von schlechten Gewohnheiten. Vielen Dank.
David 'der kahle Ingwer'
8

Die beste Antwort, die ich geben kann, ist ein Zitat aus dem großartigen Buch von Robert Martin, "Clean Code", das ich jedem empfehlen kann, der sich für das Thema interessiert:

Die erste Regel von Funktionen ist, dass sie klein sein sollten. Die zweite Regel ist, dass sie kleiner sein sollten.

Kann es nicht besser sagen. Ein weiteres großartiges Zitat aus demselben Buch gilt:

Funktionen sollten eines tun. Sie sollten es gut machen. Sie sollten es nur tun.

Wenn Sie Ihren Code in mehrere Funktionen aufteilen, müssen Sie diesen Funktionen aussagekräftige Namen geben, die die Lesbarkeit Ihres Codes erheblich verbessern können. Selbstverständlich sollten alle Funktionen, die nicht für die Verwendung außerhalb der Klasse vorgesehen sind, privat sein, damit Sie Ihren Code problemlos über die Vererbung wiederverwenden können.

Wenn Ihr Controller jetzt zu viele Funktionen hat, ist dies ein Zeichen dafür, dass er wahrscheinlich zu viel tut. Dann können Sie es in mehrere unabhängige Teile aufteilen oder versuchen, einige Funktionen auf Modelle zu verschieben, wie in der anderen Antwort erwähnt. Auch wenn Sie der nicht-klassischen MVC-Variante folgen, bei der Ansichten eine gewisse Logik haben dürfen, können Sie einige Ihrer Funktionen dort platzieren, wann immer dies passt.

Dmitri Zaitsev
quelle
1
Ich denke nicht, dass das Einfügen von Geschäftslogik in Ansichten "nicht klassisches MVC" ist, sondern nur "schlechtes MVC". Natürlich benötigen Sie grundlegende Kontrollstrukturen in Ansichten, diese sollten jedoch auf die Benutzer- / Benutzeroberflächenbedenken und nicht auf Domänen- / Geschäftsbedenken ausgerichtet sein. Eine tatsächliche Funktion in einer Ansicht ist ziemlich schrecklich.
Aaronaught
1
@Aaronaught Ich war vage mit "etwas Logik", was ich im Sinn hatte, ist zB die Backbone.js-Bibliothek, in der Sie Benutzerereignisse und -funktionen platzieren, um sie in Ihrer Ansicht zu behandeln. In der klassischen MVC ist dies die Aufgabe des Controllers. Dies kann jedoch unpraktisch sein, da Sie bei jeder Änderung Ihrer Benutzeroberfläche sowohl Ansicht als auch Controller anpassen müssen. Wenn Sie Ihre UI-Handlerfunktionen in die Ansicht einfügen, müssen Sie nur die Ansicht anpassen. Das ist nur meine subjektive Ansicht - vermisse ich etwas?
Dmitri Zaitsev
1
Nur weil etwas auf der Client-Seite geliefert wird, bedeutet dies nicht, dass es logisch Teil der Ansicht ist. Datenbindungen in Ansichten, klar, aber Backbone ist selbst ein MV * -Framework (Art von MVC, Art von MVP, auch nicht ganz), und Ihre clientseitigen Skripte sollten entsprechend organisiert sein. Ansonsten hackst du nur.
Aaronaught
0

In MVC versuche ich sicherzustellen, dass mein Controller so "dünn" wie möglich ist und dass meine Modelle so dumm wie möglich sind.

Die erforderlichen Logik- und Hilfsfunktionen werden in separate eigenständige Hilfsklassen eingeteilt. Es macht mein Testen auch viel einfacher (Sie testen .. richtig ??: D) Das Testen von Controllern ist notorisch schwierig. Jedes Mal, wenn Sie versuchen, eine Instanz eines Controllers zum Testen zu erstellen, müssen Sie über den HTTP-Kontext und Fälschungen nachdenken http dies und das, und es ist ein Schmerz, aber es ist ein Schmerz mit Absicht. Sie brauchen all das Zeug, weil ein Controller so eng mit HTTP und dem Web verbunden ist. Es ist der Einstiegspunkt in Ihre Web-App.

Logik- und Hilfsfunktionen haben nichts mit dem Web zu tun. Sie sind völlig umweltunabhängig (oder sollten es sein). Das allein sollte Ihnen sagen, dass sie nicht am selben Ort zusammengehören. Wenn Sie die gesamte Anwendungslogik so eng mit dem Web oder einer bestimmten Webimplementierung verknüpfen, können Sie sie niemals mitnehmen.

Wir haben unsere MVC-Site mit all unseren Datenbankentitäten (nicht unseren MVC-Modellen, unseren tatsächlichen Datenbankentitäten), unserem Speicher, unseren Hilfsklassen und unserer Logik in separaten eigenständigen DLLs entwickelt. Wir hatten nur eine Website, aber wir haben es trotzdem so gemacht.

Vor einigen Monaten wurden wir gebeten, einige Desktop-Apps zu erstellen, die sich auf einige unserer Fringe-Systeme beziehen. Dies war einfach, da unser gesamter getesteter Code problemlos wiederverwendet werden konnte. Wenn wir unseren Code in unser Webprojekt geschoben oder in unsere Controller eingefügt hätten, wären wir dazu niemals in der Lage gewesen.

Raumfahrer
quelle
2
Das Modell in MVC ist die einzige Ebene, die nicht dumm sein soll. Wenn die Smarts nicht im Modell und nicht im Controller enthalten sind, wo befinden sie sich dann ... in der Ansicht? Controller sollten auch nicht schwer zu testen sein; Die Fähigkeit, DI und Fakes / Mocks zu verwenden, um Unit-Tests zu erleichtern, ist einer der Vorteile von MVC gegenüber anderen Frameworks. Die meisten meiner Controller-Tests sind unter 5 Zeilen.
Aaronaught
Ich würde eine "Helfer" -Klasse mit Logik verwenden, anstatt ein Modell mit Logik zu durchdringen. Welche Art von Logik würden Sie in ein Modell einfügen? weiß es, wie es sich selbst laden und speichern kann? Ich bin damit einverstanden, dass Fälschen / Stubben einfach ist, aber es ist keine Entschuldigung, um Ihre Controller zu mästen.
Raumfahrer
Ich habe das Gefühl, dass diese Antwort gut bedeutet, aber falsch formuliert ist. Oder vielleicht eine andere Terminologie.
Simon Whitehead
3
"Helfer" -Klassen sind kein architektonisches Element. Sie sind entweder Teil des M, des V oder des C. Wenn Sie sich nicht sicher sind, welche, dann fehlt diesen Helfern der Zusammenhalt . Das Wort "Helfer" steht auch ganz oben mit "handle", "do", "perform" und dem gefürchteten Manager .
Aaronaught
@ SimonWhitehead: Die meisten Antworten bedeuten gut, aber viele sind nicht korrekt. Dieser fördert leider entweder ein Missverständnis der Bedeutung von "Modell" oder empfiehlt, kritische Geschäftslogik außerhalb davon zu setzen. Ich hatte das zweifelhafte Vergnügen, MVC-Sites mit zig Millionen "Helfern" zu pflegen - sie sind schrecklich.
Aaronaught
-2

Neben den großartigen Antworten von Dmitri Zaitsev und Spaceman weiß ich nicht, ob Folgendes auch für PHP gilt: Sie sollten versuchen, private Methoden zu vermeiden, da es an automatisierten Testmöglichkeiten mangelt.

Ja, Sie können Metaprogrammierung oder Abhängigkeitsinjektion auch zum Testen privater Methoden verwenden, aber Sie sollten dies nicht tun, da dies einen großen Einfluss auf die Lesbarkeit Ihres Codes hat.

Denken Sie immer an das KISS-Prinzip: Halten Sie es einfach, dumm.

cHaOs667
quelle
5
Dies ist kein guter Grund, private Methoden zu vermeiden, und hat auch nichts mit der MVC-Architektur zu tun. Sie versuchen nicht , private Methoden zu testen, sie sollten durch Tests der öffentlichen Methoden abgedeckt werden. Wenn Sie sie nicht abdecken können, ist dies ein Zeichen dafür, dass Ihre Klasse zu komplex ist und überarbeitet werden muss. Es bedeutet nicht, dass Sie keine privaten Methoden haben sollten oder (ich hoffe aufrichtig, dass dies nicht das ist, was Sie wirklich gemeint haben), dass sie stattdessen öffentlich sein sollten.
Aaronaught