Diseño: cómo evitar romper la compatibilidad con versiones anteriores debido a cambios en la base de datos

8

Este es mi escenario, tengo esta interfaz:

public interface hitTheDataBase
{
    public void insertMe(String [] values);
    public void modifyMe(String [] values);
    public DataTable selectMe();
}

Y tengo estas dos clases que implementan la interfaz:

public Class hitSqlServer implements hitTheDatabase
{
    public void insertMe(String [] values)
    {
         executes insert into table_in_sqlServerBD (col1, col2) values(values[0], values[1])
    }
    public void modifyMe(String [] values)
    {
         executes update table_in_sqlServerBD set col1 = values[0], col2 =  values[1] where rowid = values[3]
    }

    public DataTable selectMe()
    {
         executes select col1, col2 from table_in_sqlServerBD
    }
}

public Class hitSqLite implements hitTheDatabase
{
    public void insertMe(String [] values)
    {
         executes insert into table_in_sqLite (col1, col2) values(values[0], values[1])
    }
    public void modifyMe(String [] values)
    {
         executes update table_in_sqlLite set col1 = values[0], col2 =  values[1] where rowid = values[3]
    }

    public DataTable selectMe()
    {
         executes select col1, col2 from table_in_sqLite
    }
}

Esto es parte de una aplicación beta que realmente se ejecuta en entornos de prueba y producción (!), Pero se actualizará regularmente debido a las correcciones de errores no relacionadas con las operaciones de la base de datos. Las actualizaciones se realizan simplemente mediante desinstalación y reinstalación.

Ahora, tengo un nuevo requisito para una situación de esquina muy específica que necesitará agregar una nueva columna "col3" a la tabla, y también tendré que insertar, seleccionar y actualizar valores en esa columna. El problema es que no quiero romper la compatibilidad con las bases de datos existentes donde el software ya se está ejecutando.

Estaba pensando en codificar una tercera clase que implementa la interfaz HitTheDataBase, una clase auxiliar para verificar si existe "col3", y hacer algo como:

hitTheDataBase hitMe = !helperclass.col3Exists() ? new hitSqlServer() : new hitSqlServerWithCol3();

¿Es este un buen enfoque? Me parece bien, excepto porque necesitaré modificar el código en las clases que usan los que "golpean la base de datos". También tendré que verificar constantemente si el valor de col3 existe para mostrarlo en la GUI y dejar que el usuario lo modifique.

Ventana rota
fuente
2
¿Será esto un buen enfoque si necesita hacerlo 15 veces más?
Dan Pichelman
@DanPichelman no, Ben tiene razón: olor a diseño :(
Broken_Window
El código de ejemplo es tan malo que respiré bruscamente cuando lo vi.
Graham
@Graham es un seudocódigo horrendo de Java / C # hecho de esta manera para no revelar código propietario
Broken_Window

Respuestas:

11

Cuando se implementan las actualizaciones de software, ¿hay alguna razón por la que no pueda actualizar su esquema también? Un cambio en el software que requiere un cambio en el esquema de la base de datos implica que el esquema debe cambiar en el sistema de destino.

La compatibilidad con versiones anteriores de un esquema de base de datos suele ser algo que debe evitarse, y piratear su capa de acceso a datos para admitir múltiples versiones de esquema se siente como un olor de diseño.

Una solución más limpia es garantizar que su código siempre se ejecute en la versión del esquema para el que se ha escrito ese código. Esto no solo hará que el código sea más fácil de escribir, y mantendrá el código más limpio, sino que también hará que el código sea más fácil de probar. Puede incluir secuencias de comandos de migración como parte de su proceso de instalación / desinstalación para la actualización y la reversión.

¿Su esquema incluye algún tipo de tabla de versiones? De lo contrario, debe agregar una tabla de versión de esquema lo antes posible. El control de versiones del esquema es vital para las actualizaciones y reversiones.

Durante un período de tiempo más largo, probablemente terminará con una gran cantidad de scripts de actualización de esquema que deberán ejecutarse en un orden específico durante la instalación / desinstalación. Un mecanismo de control de versiones del esquema es clave para asegurarse de que las actualizaciones y las reversiones del esquema funcionen sin problemas.

Por otro lado, si no tiene un mecanismo para mantener su esquema en sintonía con su versión de software, su capa de acceso a datos puede eventualmente explotar en complejidad a medida que se enfrenta a un número creciente de "hacks" para preservar hacia atrás compatibilidad; y se verá abrumado por una sobrecarga cada vez mayor de pruebas de regresión cada vez que cambie algo en su esquema.

Ben Cottrell
fuente
1

Esto es lo que sucede si el esquema de su base de datos no coincide con una versión de la aplicación. Cualquier aplicación que obtenga el nuevo código col3, debe tener la base de datos actualizada junto con ella.

Si se va a tomar la molestia de verificar si existe una columna en una tabla, simplemente créela durante la actualización a la versión más reciente.

JeffO
fuente
Tienes razón, la aplicación y el esquema bd deben coincidir. Hice la cosita de "crear columnas perdidas" en el pasado. Solo funciona si el usuario que estoy usando para la conexión de la base de datos tiene suficientes privilegios, y este no es siempre el caso.
Broken_Window
Luego, su administrador del sistema debe ejecutar el script de actualización que les está proporcionando.
RubberDuck
@RubberDuck esa es la solución que usé. Incluí los scripts de actualización con los archivos de instalación y cómo actualizar la base de datos en el manual del usuario.
Broken_Window
1

Yo diría que no.

Este tipo de [interminable] "si, pero, tal vez, a menos que, excepto" la lógica solo lo lleve a la locura y, quizás lo más importante, ralentice su aplicación, porque todas estas "verificaciones" se realizan en tiempo de ejecución.

Sugeriría versionar sus cambios de esquema y almacenar esa versión [número] en algún lugar de la base de datos (como parte de su progreso de actualización).

Cree una versión de su clase de acceso a datos para cada versión de la base de datos.

En tiempo de ejecución, interrogue la base de datos para la versión del esquema y cree una instancia de la clase "correcta" en función de eso.

Phill W.
fuente
2
Es posible que desee mencionar que su última oración es una referencia al patrón de Estrategia .
TMN