Hacer referencia a los valores de la base de datos en la lógica de negocios

42

Supongo que esta es otra pregunta sobre codificación dura y mejores prácticas. Supongamos que tengo una lista de valores, digamos fruta, almacenada en la base de datos (debe estar en la base de datos, ya que la tabla se utiliza para otros fines, como los informes SSRS), con un ID:

1 Apple 
2 Banana 
3 Grapes

Puedo presentarlos al usuario, él selecciona uno, se almacena en su perfil como FavouriteFruit y la ID almacenada en su registro en la base de datos.

Cuando se trata de reglas de negocio / lógica de dominio, ¿cuáles son las recomendaciones para asignar lógica a valores específicos? Diga si el usuario ha seleccionado Grapes. Quiero realizar alguna tarea adicional, ¿cuál es la mejor manera de hacer referencia al valor de Uvas?

// Hard coded name
if (user.FavouriteFruit.Name == "Grapes")

// Hard coded ID
if (user.FavoriteFruit.ID == 3) // Grapes

// Duplicate the list of fruits in an enum
if (user.FavouriteFruit.ID == (int)Fruits.Grapes)

o algo mas?

Debido a que, por supuesto, FavouriteFruit se utilizará en toda la aplicación, la lista se puede agregar o editar.

Alguien puede decidir que quiere que se cambie el nombre de 'Grapes' a 'Grape' y esto, por supuesto, rompería la opción de cadena codificada.

La ID codificada no está completamente clara, aunque, como se muestra, puedes agregar un comentario para identificar rápidamente qué elemento es.

La opción de enumeración implica duplicar los datos de la base de datos, lo que parece incorrecto, ya que puede perder la sincronización.

De todos modos, gracias de antemano por cualquier comentario o sugerencia.

    
pregunta Kate 03.12.2015 - 13:26

7 respuestas

30

Evita las cadenas y las constantes mágicas a toda costa. Están completamente fuera de cuestión, ni siquiera deberían considerarse como opciones. Esto parece dejarte con una sola opción viable: identificadores, es decir, enumeraciones. Sin embargo, también hay una opción más, que en mi opinión es la mejor. Llamemos a esta opción "Objetos precargados". Con los objetos precargados, puede hacer lo siguiente:

if( user.FavouriteFruit.ID == MyApplication.Grape.ID )

Lo que acaba de suceder aquí es que obviamente he cargado la fila completa de Grape en la memoria, así que tengo su ID lista para usar en las comparaciones. Si por casualidad está utilizando Mapeo Relacional de Objetos (ORM), se ve aún mejor:

if( user.FavouriteFruit == MyApplication.Grape )

(Por eso lo llamo "Objetos precargados".)

Entonces, lo que hago es que durante el inicio cargo todas mis tablas de "enumeración" (tablas pequeñas como los días de la semana, los meses del año, los géneros, etc.) en la clase de dominio de la aplicación principal. Los cargo por nombre, porque obviamente, MyApplication.Grape debe recibir la fila llamada "Uva", y afirmo que se encuentran todos y cada uno de ellos. De lo contrario, tenemos un error de tiempo de ejecución garantizado durante el inicio, que es el menos maligno de todos los errores de tiempo de ejecución.

    
respondido por el Mike Nakis 03.12.2015 - 15:22
6

La verificación contra la cadena es la más legible, pero cumple una doble función: se usa tanto como un identificador como una descripción (que puede cambiar por razones no relacionadas).

Por lo general, divido ambas tareas en campos separados:

id  code    description
 1  grape   Grapes
 2  apple   Apple

Donde la descripción puede cambiar (pero no "Uvas" a "Banana"), pero el código no puede cambiar nunca.

Aunque esto se debe principalmente a que nuestros identificadores casi siempre se generan automáticamente y, por lo tanto, no son adecuados. Si puedes elegir los ID libremente, quizás puedas garantizar que siempre son correctos y usarlos.

Además, ¿con qué frecuencia alguien realmente edita "Uvas" a "Uva"? Tal vez nada de esto sea necesario.

    
respondido por el RemcoGerlich 03.12.2015 - 14:44
3

Lo que espera aquí es que la lógica de programación se adapte automáticamente a los datos cambiantes. Las opciones estáticas simples como Enum no funcionan aquí porque no es posible agregar enumeraciones adicionales en el tiempo de ejecución.

Algunos patrones que he visto:

  • Enums + default para proteger contra una nueva entrada de base de datos que arruina el día de su programa.
  • Codificación de acciones a realizar (lógica de biz) en la propia base de datos. En muchos casos esto es muy posible porque muchas lógicas se reutilizan. La implementación de la lógica debe estar en el programa.
  • Atributos / columnas adicionales en la base de datos para marcar el nuevo valor como 'para ser ignorado' en el programa hasta que el programa se despliegue correctamente.
  • Falla los mecanismos rápidos alrededor de la ruta del código que carga / recarga los valores de la base de datos. (Si la acción correspondiente no está en el programa Y no está marcada para ser ignorada, no tome la actualización).

En general, me gusta que los datos estén completos en términos de referirse a las acciones que implica, incluso aunque las acciones en sí puedan implementarse en otros lugares. Cualquier código que sea determinante de acciones independientes de los datos acaba de fragmentar su representación de datos que probablemente divergirá y dará lugar a errores.

    
respondido por el Subu Sankara Subramanian 03.12.2015 - 15:03
3

Almacenarlos en ambos lugares (en una tabla y en un ENUM) no es tan malo. El razonamiento es el siguiente:

Al almacenarlos en una tabla de base de datos, podemos imponer la integridad referencial en la base de datos mediante claves externas. Entonces, cuando asocia una persona o cualquier entidad a una fruta, es solo una fruta que existe en la tabla de la base de datos.

Almacenarlos como un ENUM también tiene sentido porque podemos escribir código sin cadenas mágicas y hace que el código sea más legible. Sí, tienen que estar sincronizados, pero en realidad lo difícil sería agregar una línea al ENUM y una nueva declaración de inserción a la base de datos.

Una cosa, una vez que se define un ENUM, no cambie su valor. Por ejemplo, si tuvieras:

  • Apple
  • uva

NO cambie el nombre de Uva a Uva. Simplemente agrega un nuevo ENUM.

  • Apple
  • uva
  • uvas

Si necesita migrar datos, aplique una actualización para mover todas las uvas a las uvas.

    
respondido por el Jon Raynor 03.12.2015 - 15:36
1

Tienes razón al hacer esta pregunta, en realidad es una buena pregunta, ya que estás intentando defenderte contra la evaluación de condiciones imprecisas.

Dicho esto, la evaluación (sus condiciones if ) no necesariamente tiene que ser el enfoque de cómo lo hace. En su lugar, preste atención a la forma en que propaga los cambios que podrían causar un problema de "desincronización".

Enfoque de cadena

Si debe usar cadenas, ¿por qué no exponer la funcionalidad de cambiar la lista a través de la interfaz de usuario? Diseñe el sistema para que, al cambiar Grape a Grapes , por ejemplo, actualice todos los registros que actualmente hacen referencia a Grape .

Enfoque de ID

Siempre prefiero hacer referencia a una identificación, a pesar del compromiso de cierta legibilidad. The list may be added to puede volver a ser algo de lo que se le notificaría si expusiera dicha función de UI. Si está preocupado por la reordenación de los elementos que cambian la identificación, propague nuevamente ese cambio a todos los registros dependientes. De manera similar a lo anterior. Otra opción (siguiendo la convención de normalización adecuada, sería tener una columna enum / id, y hacer referencia a una tabla FruitDetail más detallada, que tiene una columna de 'Orden' que puede consultar).

De cualquier manera, puedes ver que estoy sugiriendo controlar la modificación o la actualización de tu lista. Lo específico de su tecnología determina si lo hace mediante el uso de un ORM o algún otro acceso a los datos. Lo que estás haciendo, esencialmente, es exigir a las personas que se alejen del DB para tales cambios, lo que creo que está bien. La mayoría de los CRM principales harán el mismo requisito.

    
respondido por el JᴀʏMᴇᴇ 03.12.2015 - 14:09
0

Un problema muy común. Si bien parece que duplicar el lado del cliente de datos viola los principios de DRY , en realidad se debe a la diferencia de paradigma entre el capas.

Tener la enumeración (o lo que sea) fuera de sintonía con la base de datos tampoco es tan infrecuente. Es posible que haya enviado otro valor a una tabla de metadatos para admitir una nueva función de informes que aún no se usa en el código del lado del cliente.

A veces sucede de otra manera también. Un nuevo valor de enumeración se agrega al lado del cliente, pero la actualización de la base de datos no puede suceder hasta que el DBA pueda aplicar los cambios.

    
respondido por el Robbie Dee 03.12.2015 - 13:51
0

Suponiendo que estamos hablando de lo que es esencialmente una búsqueda estática, la tercera opción, la enumeración, es básicamente la única opción sensata. Es lo que harías si la base de datos no estuviera involucrada, así que tiene sentido.

La pregunta se convierte en la que trata sobre cómo mantener sincronizados los enums y las tablas estáticas / de búsqueda en la base de datos y, lamentablemente, no es un problema al que todavía tenga una respuesta completa.

Por elección, hago todo el mantenimiento de mi esquema en el código y, por lo tanto, puedo mantener una relación entre una compilación de la aplicación y una versión del esquema esperada, por lo que es sencillo mantener la búsqueda y la enumeración sincronizadas, pero es algo que uno tiene recordar hacer Sería mejor si fuera más automatizado (y también una prueba de integración automatizada para garantizar que las referencias y las búsquedas coincidan), pero eso no es algo que haya implementado nunca.

    
respondido por el Murph 03.12.2015 - 14:16

Lea otras preguntas en las etiquetas