¿Dónde validar las reglas del modelo de dominio que dependen del contenido de la base de datos?

10

Estoy trabajando en un sistema que permite a los administradores definir formularios que contienen campos. Los formularios definidos se utilizan para ingresar datos al sistema. A veces, los formularios son completados por un humano a través de una GUI, a veces el formulario se llena en función de los valores informados por otro sistema.

Para cada campo, el administrador puede definir una regla de validación que limite los valores permitidos para el campo. Las Reglas de Validación pueden ser desde "el valor ingresado en el Campo debe ser Verdadero o Falso" hasta "el valor ingresado en el Campo debe existir en la columna A de la tabla B en la base de datos". El administrador puede en cualquier momento cambiar la regla de validación para el campo.

En este escenario, ¿cuál es, en su opinión, el lugar más adecuado para validar que cada campo se llene correctamente? Actualmente tengo dos enfoques principales en mente:

Opción n. ° 1: validar en el modelo de dominio

Cada objeto de campo contendría la regla de validación especificada por el administrador. Los objetos de campo también tendrían una referencia a un IValidator. Cuando se intenta establecer el valor del Campo, el Campo pasará el valor dado y la Regla de Validación al IValidator. Si el valor dado no es válido, se generará una ValidationException y se manejará de manera adecuada en la interfaz gráfica de usuario / interfaz con el otro sistema.

Pros:

  • Fuerte protección contra los campos que se asignan accidentalmente valores que violan la regla de validación

Contras:

  • La capa de acceso a datos debe poder omitir la validación y construir campos que violen la regla de validación actual. A pesar de que el administrador cambió la regla de validación para un campo, aún debemos ser capaces de construir objetos de campo basados ​​en los datos antiguos, por ejemplo, al representar un formulario que se completó hace años. Esto podría resolverse almacenando la regla de validación actual siempre que almacenemos el campo.

  • En este diseño, el modelo de campo tiene un enlace indirecto a la capa / depósito de acceso a datos a través del IValidator. La inyección de servicios / repositorios a los modelos de dominio parece estar mal vista en general .

Opción # 2: validar en un servicio

Intente asegurarse de que todos los intentos de establecer el valor de un Campo pasen por un Servicio que garantice que se cumple la Regla de validación. Si se infringe la Regla de validación, arroje una ValidationException.

Por supuesto, la capa de acceso a datos no usaría el servicio al crear objetos de campo que se hayan conservado previamente en la base de datos.

Pros:

  • No viola el pensamiento "no inyecte servicios / repositorios en sus modelos de dominio".

  • No es necesario persistir la regla de validación actual cuando se persiste en el campo. El Servicio simplemente puede buscar la Regla de Validación actual para el Campo; Al mirar los datos del historial, el valor del campo no cambiará.

Contras:

  • No hay garantía de que toda la lógica que debería usar el Servicio para establecer el valor de Campo lo haga realmente. Veo esto como un gran inconveniente; todo lo que parece ser necesario es que alguien escriba "thisField.setValue (thatField.getValue ())" y la Regla de Validación de thisField podría violarse sin que nadie sea más sabio. Esto podría mitigarse asegurando que el valor del campo coincida con la regla de validación cuando la capa de acceso a datos esté a punto de persistir en el campo.

Actualmente prefiero la Opción # 1 sobre la Opción # 2, principalmente porque veo esto como una lógica de negocios y siento que la Opción # 2 plantea un mayor riesgo de introducir datos incorrectos en el sistema. ¿Qué opción prefiere o hay otro diseño que se adapte mejor a este escenario que las dos opciones descritas?

Editar (Complejidad de validaciones)

Los casos de validación que han surgido por ahora son relativamente simples; El valor del campo debe ser, por ejemplo, numérico, una fecha, una fecha con una hora o ser un valor existente en una columna de la base de datos. Sin embargo, sospecho que la complejidad aumentará gradualmente con el tiempo. Por ejemplo, la solución de validación debe construirse teniendo en cuenta la internacionalización: cosas como las fechas pueden ingresarse en una sintaxis específica de la localidad.

Decidí continuar con la Opción # 1 por ahora, intentando cuidar de no asignar demasiadas responsabilidades al Modelo de dominio. Quienes enfrentan una situación similar también pueden consultar las preguntas relacionadas Validación y autorización en arquitectura en capas y validación de entrada de datos: ¿dónde? ¿Cuánto cuesta? .

Lauri Harpf
fuente
Crear el modelo funciona muy bien con todas las validaciones. Pero cuando desea editar o ver el formulario, la validación también se activa. Esto arroja una excepción para los campos que están vacíos o que tienen valores no válidos, tal vez cambiados en la base de datos o cargados desde Excel. La solución esperada es permitir que el formulario se muestre en la actualización para que el administrador pueda corregir esos campos.
tunmise fasipe

Respuestas:

4

¿Qué tan complejas son las validaciones? A menudo, las validaciones requieren una combinación de campos y / o reglas comerciales que dependen de los campos para ser evaluados con precisión.

Cuanto más complejas sean las validaciones, más difícil y menos eficiente será la opción # 2.

Por supuesto, el nivel de datos podría invocar el servicio de validación en tiempo de persistencia. Esto podría ayudar a la extraña situación en la que los datos están en un estado no válido debido a un cambio en las reglas.

El otro elemento que vale la pena comentar es la capacidad de un cambio en las reglas de validación sin un ciclo qa de algún tipo. Pero ese es un tema para un hilo diferente.

Dada la información anterior, la opción 1 parece la más flexible, suponiendo que mantenga la disciplina, separando la validación y la persistencia.

deschaefer
fuente
0

Tal vez te falta una capa. Sin conocer los detalles de su aplicación (requisitos, arquitectura, etc.), haría algo como Cliente (quien sea) -> Servicio de aplicaciones -> Modelo de dominio

La capa de servicio de la aplicación puede interactuar con el repositorio y el modelo de dominio que contiene la lógica empresarial. Entonces puedes tener algo como:

FieldUpdateService >> updateField(fieldId, newValue)
  List<FieldRule> rules = this.rulesRepository.findRulesFor(fieldId)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(rules,newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Si tiene una relación entre un campo y sus reglas de campo y usa un ORM como Hibernate en Java, solo hará:

FieldUpdateService >> updateField(fieldId, newValue)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Field >> updateValue(newValue)
  for rule in rules
     if !rule.isValid(newValue)
        throw ValueNotAllowedException
  this.value = newvalue

Porque la consulta ORM e instancia el gráfico de objetos que solicita.

En cuanto a su duda sobre el hecho de que alguien puede hacer

thisField.setValue (thatField.getValue ()) "y la Regla de Validación de thisField podría violarse sin que nadie sea más sabio

Alguien también podría escribir: FieldRule alwaysReturnTrueRule = new FieldRule {isValid (newValue) {return true; }} field.updateValue ("uncheckedValue", alwaysReturnTrueRule) Es un ejemplo oscuro pero lo que estoy tratando de decir es que nada te protege del mal uso del código. Quizás buena documentación y comunicación cara a cara. Creo que nada te protege del mal uso del código.

gabrielgiussi
fuente