¿Es posible que la lógica empresarial no se filtre en la vista?


31

Me he desarrollado para varios proyectos de aplicaciones web durante los últimos 3 años, tanto personales como en el trabajo, y parece que no puedo entender si es posible que al menos algo de lógica empresarial no termine en la capa de vista de la aplicación.

En la mayoría de los casos, habrá problemas como "Si el usuario ha seleccionado la opción x, entonces la aplicación debe permitirle proporcionar información para y, de lo contrario, debe proporcionar información z". O realice alguna operación AJAX que debería aplicar algunos cambios al modelo pero NO confirmarlos hasta que el usuario lo haya solicitado explícitamente. Estos son algunos de los problemas más simples que he encontrado y no puedo entender cómo es posible evitar una lógica compleja en la vista.

La mayoría de los libros que he leído que describen MVC generalmente muestran algunos ejemplos muy triviales, como las operaciones CRUD que solo actualizan los datos en el servidor y los muestran, pero CRUD no es el caso en la mayoría de las aplicaciones ricas.

¿Es posible lograr tener una vista sin lógica comercial?


2
Eche un vistazo a las derivaciones MVC MVP y MVVM (ver en.wikipedia.org/wiki/Model_View_Presenter y en.wikipedia.org/wiki/Model_View_ViewModel ), pueden ser lo que está buscando.
Doc Brown

relacionado (posiblemente un duplicado): desacoplamiento de clases de la interfaz de usuario
mosquito

2
La vista es la manifestación externa y visible de sus datos y lógica. No es posible que la vista NO presente lógica empresarial. ¿O estás diciendo que la vista no debería tener ningún código? Ciertamente, puede crear vistas solo HTML.
BobDalgleish

Puede mirar en la animación de la plantilla ; Si bien esto probablemente no erradicará toda la lógica de la capa de vista , parece que debería conducir a una separación un poco mejor de las cosas.
Paul

Creo que una mejor pregunta es si es mejor que los datos de la vista contaminen el modelo o si es mejor que la vista contenga la lógica de la vista que está relacionada con la lógica del negocio. Ese es el escenario del mundo más real. Su pregunta es esencialmente abogar por la contaminación del modelo para apoyar las opiniones, ya que esa sería la única forma de lograr lo que está pidiendo.
Dunk

Respuestas:


22

¿Es posible lograr tener una vista sin lógica comercial?

Me parece una pregunta engañosamente difícil de responder. (¡Pregunta que invita a la reflexión!)

Teóricamente, sí, dependiendo de lo que definamos como lógica empresarial. En la práctica, la separación estricta se vuelve mucho más difícil y quizás incluso indeseable.

La separación de inquietudes es una excelente manera de pensar sobre la creación de software: le brinda ideas sobre dónde colocar el código, y les da a los encargados una buena idea sobre dónde buscar el código. Argumentaré que es básicamente imposible para los humanos construir software de trabajo sin separación de preocupaciones. Necesitamos esto.

Pero, como con todas las cosas, hay compensaciones. La mejor ubicación conceptual puede no ser la mejor ubicación por otros motivos. Tal vez haya demasiada carga en su servidor web, por lo que debe agregar JavaScript a sus páginas web para detectar errores de entrada fáciles antes de que lleguen a su servidor; ahora tiene algo de lógica de negocios en su opinión.

La vista en sí misma, por sí sola, no tiene valor sin la lógica empresarial. Y para que su uso y visualización sean efectivos, implícita o explícitamente, la vista tendrá cierto conocimiento de los procesos comerciales que se desarrollan detrás de ella. Podemos limitar esa cantidad de conocimiento, y podemos acordonar partes de él, pero las consideraciones prácticas a menudo nos obligan a 'romper' la separación de las preocupaciones.


2
The best conceptual location may not be the best location for other reasons: ¡Bravo!
Magno C

8

Normalmente hago esto: si el usuario ha seleccionado la opción x, la vista llama

controller->OptionXChanged()

Luego, el controlador habilita y en la vista:

view->SetEnableInfoY(True) // suppose False=SetDisable

La vista notifica al controlador de lo que sucede sin decidir nada.


+1. Los problemas triviales de OP generalmente se manejarían de esta manera en una aplicación no trivial
dev_feed

Poner esta lógica en el controlador tiene dos problemas: 1) complica las pruebas unitarias y es imposible admitir múltiples vistas de los mismos datos.
Kevin Cline

4

Me pregunto si los ejemplos que describe son realmente lógica de negocios. Los ejemplos que describe son operaciones que se pueden realizar en el sistema. Es la forma en que elige presentar las opciones al usuario que tal vez le da la apariencia de que está haciendo lógica de negocios en la vista.

Desde el punto de vista "Ver", solo proporciona InfoY o InfoZ al sistema. El hecho de que su implementación de UI esté haciendo algunas actualizaciones dinámicas basadas en una elección del operador (es decir, habilitar InfoY o InfoZ) no hace que la funcionalidad sea lógica de negocios. Es realmente ver la lógica de implementación. Muy bien podría haberle dado al operador la opción de ingresar InfoY o InfoZ sin todo lo que lo habilita. En ese contexto, ¿aún lo consideraría una lógica de negocios? De lo contrario, lo mismo se aplica para habilitar / deshabilitar dinámicamente los campos de información.

Lo mismo ocurre con el ejemplo de confirmación. Estas son 2 operaciones separadas que el sistema requiere para funcionar correctamente. Su Vista debe poder iniciar las acciones adecuadas para realizar la funcionalidad deseada. ¿Saber cómo usar su sistema significa que la lógica comercial se está filtrando? Puedo ver cómo alguien podría decir que sí, pero si crees de esa manera, la realidad es que no existe la separación de la lógica comercial de nada. Debe saber qué está haciendo / trabajando el sistema para lograr algo significativo. De lo contrario, sería muy fácil crear una vista y un controlador genéricos únicos que funcionen con todas las aplicaciones MVC concebibles. Lo que sabemos es imposible.

En pocas palabras, creo que su definición de lógica de negocios no es la misma que la definición de otros.


1

Trabajo de esta manera (Struts2 + Hibernate):

My Struts Actions solo es responsable de mostrar información en el navegador web. Sin pensar.

Usuario -> Acción -> Servicio -> Repositorio -> Acceso a datos

O:

Quiero ver -> Cómo ver -> Qué hacer -> Cómo llegar -> Dónde obtener

Entonces, en la primera capa (la vista) tengo algo como:

public String execute ()   {
    try {
        CourseService cs = new CourseService();
        Course course = cs.getCourse(idCourse);
    } catch (NotFoundException e) {
        setMessageText("Course not found.");
    } catch (Exception e) {

    }
    return "ok";
}

Como puede ver, mi "vista" no piensa. Es pedir un servicio (para administrar cursos), un curso específico. Ese servicio puede hacer muchas cosas más, como informes, seraches, etc. Los resultados son siempre una lista o un objeto específico (como el ejemplo). Los servicios son la máquina real, aplican reglas y acceden al Repositorio (para administrar los datos).

Entonces, si pongo mis Servicios, Repositorios y DAOS en diferentes bibliotecas, puedo usarlo incluso en un programa basado en texto o en un sistema de escritorio basado en Windows sin cambiar nada.

El servicio sabe qué hacer, pero no sabe cómo mostrar. La vista sabe cómo mostrar, pero no sabe qué hacer. Lo mismo con el Servicio / Repositorio: El servicio envía y solicita los datos, pero no sabe dónde están los datos y cómo llevarlos. El repositorio "inventa" los datos en bruto para crear objetos para que el Servicio pueda trabajar.

Pero el repositorio no sabe nada sobre la base de datos. El tipo de base de datos (MySQL, PostgreSQL, ...) concierne a DAO.

Puede cambiar el DAO si desea cambiar la base de datos y no debe afectar a las capas superiores. Puede cambiar el repositorio si desea actualizar su administración de datos, pero esto no debe afectar el DAO y las capas superiores. Puede cambiar los Servicios si desea cambiar su lógica, pero esto no debe interferir con las capas superiores ni inferiores.

Y puede cambiar cualquier cosa a la vista, incluso la tecnología (web, escritorio, texto), pero esto no debe implicar en contacto nada a continuación.

La lógica empresarial es el servicio. Pero cómo interactuar con esto es ver. ¿Qué botón mostrar ahora? ¿Puede el usuario ver este enlace? ¿Piensa que su sistema es un programa basado en consola: debe negar si el usuario equivocado elige #> myprogram -CourseService -option=getCourse -idCourse=234o detiene que presione las teclas para escribir este comando?

Hablando en sistemas basados ​​en web (Struts + JavaEE) Tengo un paquete de controlador GUI separado. En vista Acción le doy al usuario registrado y la clase me da los botones (o cualquier elemento de interfaz que desee).

                <div id="userDetailSubBox">
                    <c:forEach var="actionButton" items="${actionButtons}" varStatus="id">
                        ${actionButton.buttonCode}
                    </c:forEach>
                </div>

Y

private List<ActionButton> actionButtons;

Recuerde mantener esto fuera de los servicios. Esto es VER cosas. Manténgalo en las acciones Struts. Cualquier interacción de la interfaz debe estar completamente separada del código comercial real, por lo que si transfiere su sistema, será fácil cortar lo que ya no necesitará.


1

En la mayoría de los casos, habrá problemas como "Si el usuario ha seleccionado la opción x, entonces la aplicación debe permitirle proporcionar información para y, de lo contrario, debe proporcionar información z"

Esa es la lógica del modelo, no la vista. Puede ser un "modelo de vista", creado específicamente para admitir la interfaz de usuario, pero sigue siendo la lógica del modelo. La secuencia de control es:

  • El controlador adjunta un controlador para ver eventos
  • Ver adjunta un controlador para eventos modelo
  • El usuario selecciona la opción X.
  • La vista genera un evento "Opción X seleccionada"
  • El controlador recibe el evento y llama a model.selectOptionX ()
  • El modelo genera un evento "Estado del modelo cambiado"
  • La vista recibe el evento de cambio de modelo y actualiza la vista para que coincida con el nuevo estado: inputY.enable(model.yAllowed()); inputZ.enable(model.zAllowed());

UI View Controller Model |.checkbox X checked.> | | | | | .. X selected ...>| | | | |-----> set X ------->| | | | | | |< .............state changed ............| | | | | | |-------------- Get state --------------->| | | | | | |<----------- new state ------------------| | <-- UI updates ------| Este es el patrón clásico de MVC. Es posible probar completamente la lógica del modelo por separado de la interfaz de usuario. El controlador y la vista son muy delgados y fáciles de probar.

=== En respuesta a Dunk ===

El modelo en un patrón UI MVC (generalmente) no es un modelo de objeto de negocio. Es solo el modelo para el estado de la interfaz de usuario. En una aplicación de escritorio, puede contener referencias a múltiples modelos de negocio. En una aplicación Web 2.0, es una clase Javascript que contiene el estado de la interfaz de usuario y se comunica a través de AJAX al servidor. Es muy importante poder escribir pruebas de unidad sin intervención del modelo de estado de la interfaz de usuario, ya que es donde se encuentran la mayoría de los errores de la interfaz de usuario. La vista y el controlador deben ser conectores muy delgados.


1
Supongo que todo se reduce a lo que crees que es la definición de MVC. Esta versión definitivamente se adhiere a una interpretación muy, muy estricta de MVC. El problema es que esta interpretación estricta rara vez proporciona un sistema útil o sostenible en la vida real. La razón es que casi cada vez que se te ocurre un nuevo elemento UI / forma de hacer algo, tienes que cambiar el modelo. El modelo se vuelve desordenado con propiedades inútiles solo relevantes para la interfaz de usuario. No tienen nada que ver con la aplicación que está intentando construir, sino solo con la forma en que desea presentar los datos al operador. ¡MALO!
Dunk

Kevin, por favor ponga sus respuestas aquí en el cuadro de comentarios, para que nos sea fácil responderle. Estoy de acuerdo contigo. No es posible mantener la información de la interfaz (UI) sin ningún tipo de estructura, pero la nomenclatura "MODELO" puede ser confusa. Prefiero administrar cosas de la interfaz de usuario en un paquete intercambiable diferente para que sea fácil hacer lo que @Dunk está hablando. Mira mi respuesta.
Magno C

@MagnoC: edité la respuesta en respuesta a Dunk porque pensé que el texto agregado mejoró la respuesta. De eso se trata el sitio: preguntas y respuestas. Modelo es un término bastante general, y en el patrón MVC significa "modelo de estado de la interfaz de usuario".
Kevin Cline

0

Se parece más a una lógica de negocios If X then return InfoType.Y, luego la IU mostrará los campos en función del resultado devuelto por el dominio.

// Controller method pseudocode
option changed routine

    get selected option

    get required info type from domain routine based on selected option

    display fields based on required info type

Si la interfaz de usuario requiere una lógica empresarial, delegue la elección al dominio. La IU simplemente actuará según la decisión.


0

Si el usuario ha seleccionado la opción x, entonces la aplicación debe permitirle proporcionar información para y, de lo contrario, debe proporcionar información z ".

Hay entradas que tienen valores obligatorios basados ​​en condiciones. En la mayoría de los entornos GUI, hay muchas opciones sobre cómo manejar las entradas, especialmente el tiempo. La opción seleccionada (en este caso x) necesita ser procesada, así que envíela al controlador. Envíelo cuando los usuarios abandonen el campo de entrada. Espere hasta que hagan clic en otro objeto o presione guardar No importa la lógica de negocios. De una forma u otra, el controlador tomará una decisión y necesita decirle a la vista "se requiere y".

Cómo la vista interpreta o implementa esto realmente no importa desde el punto de vista de la lógica empresarial. Haz tu campo requerido. Tenga una ventana emergente o dispare un cañón y dígale al usuario que ingrese y o que sea terco y no permita que el usuario pobre haga nada hasta que se dé cuenta.

Y solo piense, todo esto puede haber ocurrido porque el controlador intentó guardar y no puso un valor para un campo requerido en la base de datos y estaba respondiendo puramente a un error de la base de datos. No importa en lo que respecta a la vista.

Algo como un valor requerido o limitado para una entrada se puede manejar en muchos lugares. Si "solo" lo aborda en la vista, muchos desarrolladores lo verían como un problema cuando puede haber múltiples interfaces de usuario. Es por eso que la lógica de negocios se puede crear y probar sin una gran interfaz de usuario o incluso una base de datos. Ni siquiera tiene que tener un sitio web.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.