¿Por qué poner la lógica de negocios en el modelo? ¿Qué sucede cuando tengo varios tipos de almacenamiento?

70

Siempre pensé que la lógica de negocios tiene que estar en el controlador y que el controlador, dado que es la parte 'intermedia', permanece estático y que el modelo / vista debe encapsularse a través de interfaces. De esa manera, podría cambiar la lógica de negocios sin afectar nada más, programar múltiples Modelos (uno para cada base de datos / tipo de almacenamiento) y una docena de vistas (para diferentes plataformas, por ejemplo).

Ahora leí en esta pregunta que siempre debe poner la lógica de negocios en el modelo y que el controlador está profundamente conectado con la vista.

Para mí, eso realmente no tiene sentido e implica que cada vez que quiero tener los medios para soportar otra base de datos / tipo de almacenamiento, tengo que reescribir todo mi modelo, incluida la lógica comercial.

Y si quiero otra vista, tengo que reescribir la vista y el controlador.

¿Alguien puede explicar por qué es eso o si me equivoqué en alguna parte?

Steffen Winkler
fuente

Respuestas:

69

La respuesta de ElYusubov es fundamental, la lógica de dominio debe ir al modelo y la lógica de la aplicación al controlador.

Dos aclaraciones:

  • El término lógica de negocios es bastante inútil aquí, porque es ambiguo. La lógica de negocios es un término general para toda la lógica que les interesa a los empresarios, separándola de meros tecnicismos como cómo almacenar cosas en una base de datos o cómo representarlas en una pantalla. Tanto la lógica de dominio ("una dirección de correo electrónico válida parece ...") como los flujos de trabajo / procesos de negocio ("cuando un usuario se registra, solicita su dirección de correo electrónico") se consideran lógica de negocios, y la primera claramente pertenece al modelo y este último es la lógica de aplicación que va en el controlador.
  • MVC es un patrón para colocar cosas en una pantalla y permitir al usuario interactuar con él, no especifica el almacenamiento en absoluto . La mayoría de los frameworks MVC son frameworks de pila completa que van más allá del mero MVC y lo ayudan a almacenar sus datos, y debido a que los datos que deben almacenarse generalmente se encuentran en el modelo, estos marcos le brindan formas convenientes de almacenar su modelo. datos en una base de datos, pero eso no tiene nada que ver con MVC. Idealmente, los modelos deberían ser independientes de la persistencia y el cambio a un tipo diferente de almacenamiento no debería afectar el código del modelo en absoluto. Las arquitecturas completas tienen una capa de persistencia para manejar esto.
Waquo
fuente
44
La mayoría de los frameworks MVC mezclan todo el material de almacenamiento / base de datos en el modelo para facilitar el almacenamiento de sus modelos (a menudo haciendo que amplíe la clase de modelo de frameworks). Esta es probablemente la fuente de confusión. Técnicamente, el código de modelo que escriba debe ser el modelo real (capa de dominio), mientras que el código proporcionado por el marco debe tratar con el almacenamiento (capa de persistencia). Por ejemplo, algo como User.find (...) (con User como modelo) funciona porque el marco implementó el patrón de repositorio como parte del Modelo.
Waquo
3
View-Controller-Model-Storage es el principio general (aunque la relación entre M, V y C debe visualizarse como un triángulo). Cuando su marco mezcla el almacenamiento en su "modelo", funciona de la siguiente manera: View-Controller- (El modelo hereda el almacenamiento del marco).
Waquo
2
View-Controller-Model-Storage es bastante tosco, porque no debería ser plano. Por ejemplo, cuando un controlador hace algo como User.find (...) para obtener un modelo, solicita la capa de almacenamiento directamente en lugar de pasar por la capa de dominio.
Waquo
2
En arquitecturas con capas más cuidadosas, sería algo así como UserRepository.find (). Por "modelo" me refería a la clase "modelo" proporcionada por el marco, de la que hereda. El objeto de usuario devuelto por User.find () es un modelo de un usuario en el sentido de que alguien modeló lo que es un usuario, cómo se comporta un usuario ...
Waquo
1
@flipdoubt la lógica de negocios es cualquier lógica que debe mantenerse igual si se transfiere desde mvc para decir una aplicación uwp.
Andy
23

Usted y grandes partes del mundo de la programación parecen malinterpretar cuáles son los roles de las partes MVC. En resumen, son:

Modelo = lógica de dominio

Ver = lógica de salida

Controlador = lógica de entrada

Esto significa que el modelo es responsable de toda la lógica de negocios: todo lo relacionado con el dibujo de widgets en una pantalla, manejar una impresora, generar datos como HTML, analizar solicitudes HTTP, etc., etc. no pertenece al modelo.

Sin embargo, muchos de los marcos de trabajo llamados "MVC" modernos realmente no hacen MVC en absoluto, o etiquetan mal sus partes. Muy a menudo, lo que se llama "modelo" es la capa de persistencia del modelo, mientras que la lógica empresarial se encuentra en lo que llaman el "controlador"; el controlador real suele ser solo un punto de entrada central con una tabla de enrutamiento y un poco de código en los "controladores" individuales para enviar la entrada que reciben a los procesos comerciales correctos. Lo que estos frameworks llaman "vista" es realmente un poco de todo: algo de lógica de presentación (Ver), un poco de manejo y validación de entrada (Controlador) y algo más de lógica de negocios (Modelo). La mayor parte de la vista real generalmente se llama "plantillas".

También es posible que desee leer sobre la arquitectura de varios niveles; donde MVC es unidireccional (el flujo es Controlador -> Modelo -> Ver), Multi-Tier es una cosa de dos vías (Presentación -> Lógica -> Datos -> Lógica -> Presentación), y bastantes Los marcos que pretenden hacer MVC en realidad hacen tres niveles, reetiquetando presentación para ver, lógica para el controlador y datos para modelar.

tdammers
fuente
2
Creo que tergiversas el Modelo ("Modelo = lógica de dominio"), en mi opinión, es más un recipiente para la población con datos, que luego se representa usando una Vista, en la forma más pura del patrón MVC. Claro, en casos de uso realmente simples, puede tratarlo como la "lógica de dominio", pero garantizo que la mayoría de los sistemas que vale la pena superarían muy rápidamente. Es mejor dividir la "lógica de dominio" en una capa / clase separada, por ejemplo, una capa de servicio.
A. Murray
@ A.Murray: Por supuesto, el Modelo no tiene que ser un bloque de código monolítico, y separarlo en persistencia, estructuras de datos y lógica de dominio generalmente tiene mucho sentido. Aún así, MVC agrupa estas tres preocupaciones en el Modelo. En cualquier caso, cuando sus controladores y vistas contienen lógica de dominio, ya no es MVC real.
tdammers
@tdammers, me gusta el orden de su respuesta y su enfoque en la lógica. En su opinión, ¿a dónde pertenecen las inquietudes de la aplicación como la persistencia y el procesamiento de transacciones? Parece que MVC debería ser un acrónimo de cuatro letras como MVCS donde el S es para servicio.
flipdoubt
15

Para aislar verdaderamente la lógica de negocios y separarla de la infraestructura de la capa de presentación, los servicios de aplicación deben encapsularla. La arquitectura MVC es una forma de implementar la capa de presentación y debe permanecer en ese ámbito, delegando toda la lógica empresarial a estos servicios de aplicación. Piense en los modelos de vista como adaptadores entre la vista y los datos que deben mostrarse o leerse. El controlador media la interacción entre los modelos de vista, las vistas y los servicios de aplicaciones que alojan la lógica empresarial.

Los servicios de aplicación implementan casos de uso de negocios y están desacoplados de la capa de presentación, ya sea MVC u otra cosa. A su vez, los servicios de aplicaciones pueden alojar scripts de transacciones o un diseño controlado por dominio .

Para el almacenamiento, el servicio de aplicación puede hacer referencia a un repositorio o cualquier abstracción de un mecanismo de persistencia. Se pueden admitir diferentes implementaciones abstrayendo el acceso a los datos en una interfaz. Por lo general, estas abstracciones tienen fugas y solo son parcialmente portátiles en las implementaciones y, a menudo, es un intento inútil de lograr la portabilidad total.

ACTUALIZAR

Mi sugerencia se basa en la arquitectura hexagonal . En una arquitectura hexagonal, su modelo de dominio (lógica de negocios) está en el centro. Este núcleo está encapsulado por servicios de aplicaciones que actúan como una fachada . Los servicios de aplicación son clases simples que tienen métodos correspondientes a casos de uso en su dominio. Para una discusión en profundidad sobre los servicios de aplicaciones, eche un vistazo a Servicios en diseño dirigido por dominio . El ejemplo de código contiene un PurchaseOrderServiceservicio de aplicación para un dominio de compras. (Tenga en cuenta que un servicio de aplicación no implica el uso de diseño controlado por dominio).

En una arquitectura hexagonal, una capa de presentación MVC es un adaptador entre su modelo de dominio (lógica de negocios) y una GUI. El modelo de dominio no conoce la capa de presentación, pero la capa de presentación sí conoce el modelo de dominio.

Esta solución ciertamente tiene partes móviles que una solución que coloca la lógica empresarial en el controlador y debe sopesar los inconvenientes y los beneficios. La razón por la que sugiero es porque prefiero mantener la lógica de negocios desacoplada de la capa de presentación para combatir la complejidad. Esto se vuelve más importante a medida que crece la aplicación.

eulerfx
fuente
Parece que estás describiendo a un bastardo de MVC y MVVM que tiene tanto controladores como modelos de vista. Además, creo que la arquitectura que está describiendo puede ser un poco pesada para las necesidades de OP.
Waquo
Para ser honesto, me gusta más la respuesta de Waquo. Principalmente porque no tengo idea de lo que quieres decir con 'servicios de aplicación'. ¿Podría explicar ese término? Mi GoogleFU no funciona aquí como parece.
Steffen Winkler
1
@Waquo Estoy de acuerdo en que la arquitectura propuesta puede ser exagerada, sin embargo, debe considerarse. No he mencionado MVVM, que es simplemente otra forma de implementar una capa de presentación. Los servicios de aplicación se aplican independientemente de si usa MVC o MVVM y nada de lo que he sugerido indica una combinación de ambos.
eulerfx
1

Depende de lo que entiendas por lógica empresarial. Cualquier "lógica" que dé significado al contenido del modelo debe estar en el modelo. En la pregunta vinculada, la respuesta más votada parece definir "lógica empresarial" como cualquier cosa relacionada con los datos; ¡Esto tiene sentido desde el punto de vista de que los datos de una empresa son su negocio!

Una vez vi un ejemplo del creador de Rails (creo) que estaba hablando exactamente sobre esto: no poner "lógica de negocios" en el modelo. Su ejemplo fue una clase de controlador y un método para el registro y el inicio de sesión de la aplicación: una contraseña suministrada en texto sin formato se cifró antes de insertarse o consultarse en el modelo (una base de datos).

No puedo pensar en un mejor ejemplo de algo que no sea la lógica del controlador y que pertenezca directamente al modelo.

El modelo podría ser una interfaz para miles de almacenes de datos, aliviando las preocupaciones de portabilidad. Es aquí donde uno podría encontrar confusión sobre si la interfaz del modelo es en realidad el "controlador".

En términos generales, el controlador vincula el modelo y la vista (que son la carne y la papa de la aplicación). En el desarrollo de Cocoa puede ser simplista hasta el punto en que el controlador se maneja a través de la GUI XCode (objetos y enlaces del controlador).

La sección "Patrones de diseño" del GoF en MVC, citada libremente:

La tríada de clases MVC se usa para construir interfaces de usuario en Smalltalk-80. El Modelo es el objeto de la aplicación, la Vista es su presentación en pantalla y el Controlador define la forma en que la IU reacciona a la entrada del usuario. MVC desacopla las vistas y los modelos al establecer un protocolo de suscripción / notificación entre ellos. El siguiente diagrama muestra un modelo y tres vistas. Hemos dejado de lado los controladores por simplicidad.

MVC tiene que ver con las interfaces de usuario. La atención se centra en el modelo y la vista: definición y visualización de datos. Tenga en cuenta el "protocolo de suscripción / notificación": aquí es donde entra su controlador. Puede crear todas las vistas que desee; siempre y cuando se adhieran al protocolo, nunca tendrá que tocar el modelo o el controlador.

Si habla específicamente de desarrollo web, en mi humilde opinión, muchos marcos web populares son rápidos y flexibles con el término MVC y sus definiciones de componentes.

Duque
fuente
Soy desarrollador de C # / Java (solo algunos proyectos allí). Parece que no entendí lo que hace el modelo. Poner la 'lógica de negocios' en el controlador realmente fue solo un efecto secundario (mi línea de pensamiento fue 'está bien, tengo el modelo de datos (léase: conexión / almacenamiento de la base de datos), por lo que mi lógica de negocios necesita entrar en el controlador porque Tengo que aplicarlo antes de almacenar los datos en la base de datos ". Solo tengo que mover todo un nivel hacia abajo desde el controlador. En realidad, eso resuelve un problema que tenía actualmente (compatible con MySQL y MSSQL en un programa)
Steffen Winkler
0

¿Por qué no introduces una capa de servicio?

Entonces su controlador será delgado y más legible, entonces todas sus funciones de controlador serán acciones puras.

Puede descomponer la lógica empresarial tanto como lo necesite dentro de la capa de servicio. La reutilización del código es mejor y no hay impacto en los modelos y repositorios.

Añil
fuente