In MVC è considerata buona prassi avere funzioni private, non di azione, in una classe di controller?


10

A volte le funzioni di azione nella classe controller possono diventare enormi e spiacevoli, con molte righe di codice per controllare semplicemente il flusso di dati dal Modello alla Vista. Ad un certo punto queste enormi funzioni perdono completamente traccia dei principi di base del buon codice, ovvero fanno solo una cosa, sono piccole, leggibili e gestibili ecc.

Sarebbe considerato una buona pratica suddividere queste enormi funzioni di azione in funzioni private più piccole nella classe del controller o la necessità di tale ottimizzazione dovrebbe significare che dovremmo piuttosto aggiungerle nel modello?

Vorrei votare per avere le funzioni più piccole come private nel controller in modo che siano relative all'azione, ma ho sentito argomentazioni secondo cui il controller dovrebbe essere preferibilmente semplice mentre il modello può diventare enorme e disordinato; e mi chiedevo quale sarebbe stato il metodo più preferito.

Risposte:


16

Potrebbe non essere la migliore analogia ma, pensa al controller nello stesso modo in cui pensi alla ragnatela. Il suo unico compito è quello di catturare le mosche (richieste) per il ragno (strati sottostanti) da digerire. Il web può catturare e contenere mosche più piccole o più grandi (modelli). Il ruolo di una ragnatela non è quello di digerire la preda, sebbene possa essere utilizzata a questo scopo. Più sottile e pulito è il web, più facile per il ragno sopravvivere.

È possibile applicare in qualche modo la stessa logica all'applicazione MVC. Le funzioni enormi e brutte che descrivi sono molto probabilmente comportamenti del modello e dovrebbero appartenere al modello (nota che il modello non è solo l'oggetto che viene visualizzato nella vista). Se il comportamento del modello cambia, è il modello che deve essere modificato e non il controller che lo gestisce.

Inoltre, tenerli come metodi privati ​​nel controller sarebbe solo ingombrante e renderebbe difficile la manutenzione. Fa anche strada a una cattiva abitudine, dal momento che altre persone coinvolte nello sviluppo sarebbero tentate di fare lo stesso, dal momento che l'hanno già visto fare nel progetto.


+1 per l'analogia creativa. :) Fai un punto interessante. Soprattutto sulla formazione di cattive abitudini. Grazie.
David "lo zenzero calvo",

8

La migliore risposta che posso dare è di citare dal grande libro di Robert Martin, "Clean Code" che consiglio vivamente a chiunque sia interessato all'argomento:

La prima regola delle funzioni è che dovrebbero essere piccole. La seconda regola è che dovrebbero essere più piccoli di così.

Non posso dire di meglio. Si applica un'altra grande citazione dello stesso libro:

Le funzioni dovrebbero fare una cosa. Dovrebbero farlo bene. Dovrebbero farlo solo.

Quando si divide il codice in più funzioni, si è costretti a dare a tali funzioni nomi significativi che possono migliorare notevolmente la leggibilità del codice. Inutile dire che tutte le funzioni non destinate all'uso al di fuori della classe dovrebbero essere private, in modo da poter riutilizzare facilmente il codice tramite ereditarietà.

Se il tuo controller ora ha troppe funzioni, è un segno che probabilmente fa troppo. Quindi puoi dividerlo in diversi pezzi indipendenti o provare a spostare alcune funzioni sui modelli come indicato nell'altra risposta. Inoltre, se segui un sapore MVC non classico, in cui le viste sono autorizzate ad avere un po 'di logica, puoi inserire alcune delle tue funzioni ogni volta che si adatta.


1
Non penso che mettere la logica di business in vista sia un "MVC non classico", è solo un "MVC negativo". Ovviamente hai bisogno di strutture di controllo di base nelle viste, ma dovrebbero essere allineate con le preoccupazioni dell'utente / dell'interfaccia utente, non delle preoccupazioni di dominio / business. Una funzione reale in una vista è piuttosto orribile.
Aaronaught,

1
@Aaronaught Sono stato vago con "un po 'di logica", quello che avevo in mente è ad esempio la libreria Backbone.js, dove hai messo eventi e funzioni dell'utente per gestirli nella tua vista. Nel MVC classico questo è il compito del controller. Tuttavia, questo può essere poco pratico in quanto è necessario regolare sia View che Controller ogni volta che cambia l'interfaccia utente. Inserendo le funzioni del gestore UI nella vista, è sufficiente regolare la vista. Questa è solo la mia visione soggettiva - mi sto perdendo qualcosa?
Dmitri Zaitsev,

1
Solo perché qualcosa viene consegnato sul lato client non significa che sia logicamente parte della vista. Collegamenti dei dati nelle viste, certo, ma Backbone è esso stesso un framework MV * (tipo di MVC, tipo di MVP, non del tutto) e gli script sul lato client dovrebbero essere organizzati di conseguenza; altrimenti, stai solo hackerando.
Aaronaught,

0

In MVC cerco di garantire che il mio controller sia il più "sottile" possibile e che i miei modelli siano il più stupidi possibile.

Le funzioni logiche e di supporto necessarie vengono inserite in classi di supporto indipendenti. Rende anche i miei test molto più facili (stai testando .. giusto ??: D) Testare i controller è notoriamente difficile, ogni volta che provi a creare un'istanza di un controller per testare devi pensare al contesto HTTP e fingere http questo e quello, ed è un dolore, ma è un dolore apposta. Hai bisogno di tutto questo perché un controller è così strettamente collegato a HTTP e al Web. È il punto di accesso alla tua app web.

Le funzioni logiche e di supporto non hanno nulla a che fare con il web. Sono completamente indipendenti dall'ambiente (o dovrebbero essere). Solo questo dovrebbe dirti che non appartengono insieme nello stesso posto. Inoltre, se colleghi tutta la logica delle tue applicazioni così strettamente al Web o a una particolare implementazione Web, non potrai mai portarla con te.

Abbiamo sviluppato il nostro sito MVC con tutte le nostre entità di database (non i nostri modelli mvc, le nostre effettive entità db), la nostra memoria, le nostre classi di supporto e la nostra logica in dll indipendenti. Abbiamo avuto solo un sito Web, ma lo abbiamo fatto comunque.

Alcuni mesi fa ci è stato chiesto di creare alcune app desktop correlate ad alcuni dei nostri sistemi marginali. Ciò è stato fatto facilmente poiché tutto il nostro codice testato potrebbe essere facilmente riutilizzato. Se avessimo inserito il nostro codice nel nostro progetto Web o inserito nei nostri controller, non saremmo mai stati in grado di farlo.


2
Il modello in MVC è l'unico livello che non dovrebbe essere stupido. Se le smart non sono nel modello e non sono nel controller, allora dove sono ... nella vista? Anche i controller non dovrebbero essere difficili da testare; la capacità di utilizzare DI e falsi / simulazioni per facilitare i test unitari è una delle estrazioni di MVC rispetto ad altri framework. La maggior parte dei test del mio controller sono sotto 5 righe.
Aaronaught,

Vorrei usare una classe "helper" con la logica anziché permeare un modello con la logica. che tipo di logica inseriresti all'interno di un modello? sa caricarsi e salvarsi? Sono d'accordo che fingere / stub è facile, ma non è una scusa per iniziare a ingrassare i controller.
astronauta

Ho la sensazione che questa risposta significhi bene ma sia formulata in modo errato .. o, forse, con una terminologia diversa.
Simon Whitehead,

3
Le classi "Helper" non sono un elemento architettonico. Fanno parte della M, della V o della C. Se non sei sicuro di quale, allora quegli aiutanti mancano di coesione . La parola "aiutante" si colloca anche lassù con "handle", "do", "perform" e il temuto Manager .
Aaronaught,

@SimonWhitehead: la maggior parte delle risposte ha un significato ma molte non sono corrette. Questo, sfortunatamente, sta promuovendo un fraintendimento del significato di "Modello" o raccomandando di escludere la logica aziendale critica. Ho avuto il dubbio piacere di mantenere i siti MVC con milioni di "aiutanti" - sono terribili.
Aaronaught,

-2

Oltre a Dmitri Zaitsev e all'astronauta grandi risposte, non so se quanto segue sia valido anche per PHP: dovresti cercare di evitare metodi privati ​​a causa della mancanza di possibilità di test automatizzati.

Sì, puoi utilizzare la metaprogrammazione o l'iniezione di dipendenza per testare anche metodi privati, ma non dovresti farlo poiché ha un impatto enorme sulla leggibilità del tuo codice.

Ricorda sempre il principio KISS: mantienilo semplice, stupido.


5
Questo non è un buon motivo per evitare metodi privati ​​e non ha nulla a che fare con l'architettura MVC. Non si tenta di testare metodi privati, dovrebbero essere coperti da test sui metodi pubblici . Se non riesci a coprirli, allora è un segno che la tua classe è troppo complessa e deve essere riformulata; non significa che non dovresti avere metodi privati ​​o (spero sinceramente che non sia quello che volevi veramente dire) che dovrebbero essere pubblici invece.
Aaronaught,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.