En MVC, ¿se considera una buena práctica tener funciones privadas sin acción en una clase de controlador?

10

A veces, las funciones de acción en la clase de controlador pueden volverse enormes y desagradables, con muchas líneas de código para controlar simplemente el flujo de datos del Modelo a la Vista. En algún momento, estas enormes funciones pierden por completo los principios básicos del buen código, es decir, solo hacen una cosa, son pequeñas, legibles y manejables, etc.

¿Se consideraría una buena práctica dividir estas enormes funciones de acción en funciones privadas más pequeñas en la clase de controlador o la necesidad de dicha optimización significa que deberíamos agregarlas en el modelo?

Votaría por tener las funciones más pequeñas como privadas en el controlador para que sean relativas a la acción, pero he escuchado argumentos de que el controlador debería ser preferiblemente simple mientras el modelo puede volverse enorme y desgreñado; y me preguntaba cuál sería el método más preferido.

David 'el jengibre calvo'
fuente

Respuestas:

16

Puede que no sea la mejor analogía, pero piensa en el controlador de la misma manera que pensarías en una telaraña. Su único trabajo es atrapar moscas (solicitudes) para que la araña (capas subyacentes) las digiera. La web puede atrapar y contener moscas más pequeñas o más grandes (modelos). El papel de una telaraña no es digerir a la presa, aunque puede usarse para este propósito. Cuanto más delgada y limpia sea la red, más fácil será para la araña ganarse la vida.

Podría aplicar la misma lógica a su aplicación MVC. Las funciones enormes y desagradables que describe son el comportamiento más probable del modelo y deben pertenecer al modelo (tenga en cuenta que el modelo no es solo el objeto que se muestra en la vista). Si el comportamiento del modelo cambia, se debe cambiar el modelo y no el controlador que lo maneja.

Además, mantenerlos como métodos privados en el controlador solo lo desordenaría y dificultaría su mantenimiento. También da paso a un mal hábito, ya que otras personas que están involucradas en el desarrollo estarían tentadas a hacer lo mismo, ya que lo han visto antes en el proyecto.

devnull
fuente
+1 para la analogía creativa. :) Haces un punto interesante. Especialmente en la formación de malos hábitos. Gracias.
David 'el jengibre calvo'
8

La mejor respuesta que puedo dar es citar el gran libro de Robert Martin, "Código limpio" que recomiendo encarecidamente a cualquier persona interesada en el tema:

La primera regla de funciones es que deben ser pequeñas. La segunda regla es que deberían ser más pequeños que eso.

No puedo decirlo mejor. Se aplica otra gran cita del mismo libro:

Las funciones deberían hacer una cosa. Deberían hacerlo bien. Solo deberían hacerlo.

Al dividir su código en más funciones, se ve obligado a dar a esas funciones nombres significativos que puedan mejorar enormemente la legibilidad de su código. No es necesario decir que todas las funciones que no están destinadas a usarse fuera de la clase, deben ser privadas, para que pueda reutilizar fácilmente su código a través de la herencia.

Si su controlador ahora tiene demasiadas funciones, es una señal de que probablemente hace demasiado. Luego, puede dividirlo en varias partes independientes o tratar de mover algunas funciones a modelos como se menciona en la otra respuesta. Además, si sigue el estilo MVC no clásico, donde se permite que las Vistas tengan algo de lógica, puede poner algunas de sus funciones allí cuando le convenga.

Dmitri Zaitsev
fuente
1
No creo que poner la lógica de negocios en vistas sea "MVC no clásico", es simplemente "MVC malo". Obviamente, necesita estructuras de control básicas en las vistas, pero deben estar alineadas con las preocupaciones del usuario / IU, no con las preocupaciones del dominio / negocio. Una función real en una vista es bastante horrible.
Aaronaught
1
@Aaronaught Fui vago con "algo de lógica", lo que tenía en mente es, por ejemplo, la biblioteca Backbone.js, donde pones eventos de usuario y funciones para manejarlos en tu vista. En MVC clásico, este es el trabajo del controlador. Sin embargo, esto puede ser poco práctico, ya que necesitaría ajustar tanto la Vista como el Controlador cada vez que cambie su IU. Al poner las funciones de su controlador de UI en la Vista, solo necesita ajustar la Vista. Esa es solo mi opinión subjetiva: ¿me estoy perdiendo algo?
Dmitri Zaitsev
1
El hecho de que algo se entregue en el lado del cliente no significa que sea lógicamente parte de la vista. Enlaces de datos en vistas, claro, pero Backbone es en sí mismo un marco MV * (tipo de MVC, tipo de MVP, no del todo) y sus scripts del lado del cliente deben organizarse en consecuencia; de lo contrario, solo estás pirateando.
Aaronaught
0

En MVC trato de asegurarme de que mi controlador sea lo más "delgado" posible y también de que mis modelos sean lo más tontos posible.

Las funciones lógicas y de ayuda que se necesitan se colocan en clases de ayuda independientes. También hace que mis pruebas sean mucho más fáciles (estás probando ... ¿verdad?: D) Probar controladores es notoriamente difícil, cada vez que intentas crear una instancia de un controlador para probar tienes que pensar en el contexto HTTP y la falsificación http this and that, y es un dolor, pero es un dolor a propósito. Necesita todas esas cosas porque un controlador está muy relacionado con HTTP y la web. Es el punto de entrada a su aplicación web.

Las funciones lógicas y de ayuda no tienen nada que ver con la web. Son completamente independientes del medio ambiente (o deberían serlo). Eso solo debería decirte que no pertenecen juntos en el mismo lugar. Además, si vincula toda la lógica de sus aplicaciones a la web o a una implementación web en particular, nunca podrá llevarla consigo.

Desarrollamos nuestro sitio MVC con todas nuestras entidades de bases de datos (no nuestros modelos mvc, nuestras entidades db reales), nuestro almacenamiento, nuestras clases auxiliares y nuestra lógica en dll independientes independientes. Solo hemos tenido un sitio web, pero lo hicimos así de todos modos.

Hace unos meses, se nos pidió que creáramos algunas aplicaciones de escritorio relacionadas con algunos de nuestros sistemas marginales. Esto se hizo fácilmente ya que todo nuestro código probado podría reutilizarse fácilmente. Si hubiéramos introducido nuestro código en nuestro proyecto web, o lo hubiéramos incluido en nuestros controladores, nunca hubiéramos podido hacerlo.

astronauta
fuente
2
El modelo en MVC es la única capa que no se supone que sea tonta. Si la inteligencia no está en el modelo y no está en el controlador, ¿dónde están ... en la vista? Los controladores tampoco deberían ser difíciles de probar; La capacidad de usar DI y falsificaciones / simulacros para facilitar las pruebas unitarias es uno de los atractivos de MVC sobre otros marcos. La mayoría de mis pruebas de controlador están bajo 5 líneas.
Aaronaught
usaría una clase "auxiliar" con lógica en lugar de impregnar un modelo con lógica. ¿Qué tipo de lógica pondrías dentro de un modelo? ¿sabe cómo cargarse y salvarse? Estoy de acuerdo en que falsificar / tropezar es fácil, pero no es una excusa para comenzar a engordar sus controladores.
astronauta
Tengo la sensación de que esta respuesta tiene buenas intenciones, pero está redactada incorrectamente ... o, tal vez, con una terminología diferente.
Simon Whitehead
3
Las clases "auxiliares" no son un elemento arquitectónico. Son parte de la M, la V o la C. Si no está seguro de cuál, entonces esos ayudantes carecen de cohesión . La palabra "ayudante" también se clasifica a la altura de "manejar", "hacer", "realizar" y el temido administrador .
Aaronaught
@SimonWhitehead: La mayoría de las respuestas tienen buenas intenciones, pero muchas no son correctas. Desafortunadamente, éste promueve un malentendido del significado de "Modelo" o recomienda poner fuera de él la lógica comercial crítica. He tenido el dudoso placer de mantener sitios MVC con un trillón de "ayudantes", son terribles.
Aaronaught
-2

Además de Dmitri Zaitsev y spaceman, excelentes respuestas, no sé si lo siguiente también es válido para PHP: debe intentar evitar métodos privados debido a la falta de posibilidades de pruebas automatizadas.

Sí, también puede usar metaprogramación o inyección de dependencia para probar métodos privados, pero no debe hacerlo, ya que tiene un gran impacto en la legibilidad de su código.

Recuerda siempre el principio de KISS: Hazlo simple, estúpido.

cHaOs667
fuente
55
Esa no es una buena razón para evitar métodos privados, y tampoco tiene nada que ver con la arquitectura MVC. No intente probar métodos privados, deberían estar cubiertos por pruebas en los métodos públicos . Si no puede cubrirlos, entonces esa es una señal de que su clase es demasiado compleja y necesita ser refactorizada; no significa que no deba tener métodos privados o (sinceramente espero que esto no sea lo que realmente quiso decir) que deberían ser públicos en su lugar.
Aaronaught