ASP.NET MVC: ¿debería existir una lógica empresarial en los controladores?
asp.net-mvc design-patterns (6)
Esta es una pregunta fascinante.
Creo que es interesante que una gran cantidad de aplicaciones de MVC de muestra realmente no sigan el paradigma de MVC en el sentido de colocar verdaderamente la "lógica de negocios" completamente en el modelo. Martin Fowler ha señalado que MVC no es un patrón en el sentido de The Gang Of Four. Más bien, es un paradigma al que el programador debe agregar patrones si está creando algo más allá de una aplicación de juguetes.
Entonces, la respuesta corta es que la "lógica de negocios" no debería vivir en el controlador, ya que el controlador tiene la función adicional de tratar con la vista y las interacciones del usuario y queremos crear objetos con un solo propósito.
Una respuesta más larga es que debe pensar un poco en el diseño de su capa de modelo antes de simplemente mover la lógica del controlador al modelo. Quizás pueda manejar toda la lógica de la aplicación usando REST, en cuyo caso el diseño del modelo debería ser bastante claro. De lo contrario, debe saber qué enfoque va a utilizar para evitar que su modelo se hinche.
Derik Whitaker publicó un article un par de días que llegó a un punto sobre el que he tenido curiosidad durante algún tiempo: ¿ debería existir lógica comercial en los controladores?
Hasta ahora, todas las demos ASP.NET MVC que he visto ponen el acceso al repositorio y la lógica empresarial en el controlador. Algunos incluso arrojan validación allí también. Esto da como resultado controladores bastante grandes e hinchados. ¿Es esta realmente la forma de usar el framework MVC? Parece que esto terminará con una gran cantidad de código duplicado y lógica distribuida entre diferentes controladores.
La lógica de negocios no debe estar contenida en los controladores. Los controladores deben ser tan delgados como sea posible, idealmente siga el patrón:
- Buscar entidad de dominio
- Actuar sobre la entidad de dominio
- Preparar datos para ver / devolver resultados
Además, los controladores pueden contener cierta lógica de aplicación.
Entonces, ¿dónde pongo mi lógica comercial? En el modelo.
¿Qué es el modelo? Ahora esa es una buena pregunta. Consulte el artículo de msdn.microsoft.com/en-us/library/hh404093.aspx (felicitaciones a AlejandroR por su excelente hallazgo). Aquí hay tres categorías de modelos:
- Modelo de vista : Esta es simplemente una bolsa de datos, con una lógica mínima, si la hay, para pasar datos desde y hacia vistas, contiene validación de campo básica.
- Modelo de dominio : el modelo "gordo" con lógica comercial, opera en una o varias entidades de datos (es decir, la entidad A en un estado determinado que la acción en la entidad B)
- Modelo de datos : Modelo de almacenamiento, la lógica contenida en una sola entidad se relaciona solo con esa entidad (es decir, si el campo a es el campo b)
Por supuesto, MVC es un paradigma que viene en diferentes variedades. Lo que describo aquí es MVC ocupando la capa superior solamente, ve este artículo en Wikipedia
Hoy, MVC y modelo-vista-presentador (MVP) similar son patrones de diseño de Separación de preocupaciones que se aplican exclusivamente a la capa de presentación de un sistema más grande. En escenarios simples, MVC puede representar el diseño principal de un sistema, llegando directamente a la base de datos; sin embargo, en la mayoría de los escenarios, el Controlador y el Modelo en MVC tienen una dependencia relajada en un Servicio o Nivel / capa de Datos. Esto es todo sobre la arquitectura Cliente-Servidor
La lógica empresarial realmente debería estar en el modelo. Deberías apuntar a modelos gordos, controladores delgados.
Por ejemplo, en lugar de tener:
public interface IOrderService{
int CalculateTotal(Order order);
}
Yo preferiria tener:
public class Order{
int CalculateTotal(ITaxService service){...}
}
Esto supone que un servicio externo calcula el impuesto y requiere que su modelo conozca las interfaces con sus servicios externos.
Esto haría que su controlador se vea algo así como:
public class OrdersController{
public OrdersController(ITaxService taxService, IOrdersRepository ordersRepository){...}
public void Show(int id){
ViewData["OrderTotal"] = ordersRepository.LoadOrder(id).CalculateTotal(taxService);
}
}
O algo así.
Me gusta el diagrama presentado por Microsoft Patterns & Practices . Y creo en el refrán "Una imagen vale más que mil palabras".
Puede revisar este increíble tutorial de Stephen Walther que muestra Validación con una capa de servicio .
Aprenda a mover su lógica de validación fuera de las acciones de su controlador y en una capa de servicio separada. En este tutorial, Stephen Walther explica cómo puede mantener una separación nítida de preocupaciones al aislar la capa de servicio de la capa de su controlador.
Si usa Inyectores de Dependencia, su lógica de negocios irá a ellos y, por lo tanto, obtendrá controladores limpios y precisos.