En muchos enfoques para el desarrollo de software, como las metodologías ágiles, el diseño basado en dominios y el análisis y diseño orientados a objetos, se nos alienta a adoptar un enfoque iterativo para el desarrollo.
Por lo tanto, se supone que no debemos hacer nuestro modelo de dominio correctamente la primera vez que comenzamos a trabajar en el proyecto. En cambio, a medida que pasa el tiempo, refactorizamos el modelo porque obtenemos una comprensión más profunda del dominio del problema con el tiempo.
Aparte de eso, incluso si tratamos de obtener un modelo perfecto por adelantado, que ya estoy convencido de que es muy difícil, los requisitos pueden cambiar. Entonces, después de que el software se haya implementado en producción, los usuarios finales pueden notar que cierto requisito no se entendió completamente o, lo que es peor, falta algún requisito.
El punto aquí es que podemos terminar necesitando cambiar el modelo después de que se haya implementado el software. Si esto sucede, tenemos un problema: la base de datos de producción tiene datos de usuario que son importantes y ya está ajustada en el formato del modelo anterior .
La actualización del código puede ser una tarea difícil si el código no está bien diseñado y si el sistema es grande. Pero se puede hacer con el tiempo, tenemos herramientas como Git que nos ayudan a hacerlo sin dañar la versión lista para producción.
Por otro lado, si el modelo cambia, si las propiedades de las clases desaparecen o lo que sea, la base de datos también debería cambiar. Pero tenemos un problema: ya hay datos allí que no se pueden perder, que ya están formateados para el modelo anterior.
Parece que una base de datos relacional aquí está siendo una barrera que nos impide realizar un desarrollo iterativo e incluso actualizar el software cuando lo requieren los usuarios finales.
Un enfoque que ya utilicé fue codificar una clase especial que asigna tablas de bases de datos antiguas a nuevas. Por lo tanto, estas clases recogen datos en formato antiguo, los convierten al formato utilizado por el nuevo modelo y los guardan en las nuevas tablas.
Este enfoque parece no ser el mejor. Mi pregunta aquí es: ¿existen enfoques conocidos y recomendados para conciliar el desarrollo iterativo con bases de datos relacionales?
fuente
Respuestas:
No tiene que ser clases especiales, pero sí, necesita algo que tome la base de datos en formato anterior y la convierta en la actual.
La cuestión aquí es que necesita desarrollar un proceso para escribir y probar estos scripts y disciplina para nunca tocar las bases de datos de prueba y producción a mano, sino siempre mediante scripts de migración.
Cada vez que necesita hacer un cambio en la base de datos, escribe un script que lo hará, ya sea en SQL o utilizando su capa ORM, y lo confirma en el control de su versión junto con los cambios que requieren el nuevo esquema. Luego, tiene un script de control que actualizará la base de datos aplicando todos los scripts de migración que aún no se aplicaron en una secuencia.
Y asegúrese de que solo modifique los entornos de desarrollo, prueba y control de calidad compartidos aplicando los scripts y retrocediendo a la versión anterior si no funcionan, de modo que pueda estar razonablemente seguro de que funcionarán según lo previsto cuando los desate en la producción .
La nueva instalación se realiza simplemente aplicando todos los scripts. Después de un tiempo, es posible que tenga cientos de ellos y piense que es muy ineficiente, pero no caiga en la trampa de tratar de optimizarlo. La instalación es una actividad que se realiza una sola vez y mantenerla confiable es más rápida.
@Doc Brown ya vinculó a Martin Fowler: Diseño de base de datos evolutiva y /programming/334059/agile-development-and-database-changes , y agregaría Alex Papadimoulis: Cambios de base de datos hechos a la derecha , que es más corto y tiene algunos ejemplos.
Como un buen ejemplo de herramienta para implementar dicho proceso, sugiero Alembic . Se basa en el marco Python SQLAlchemy , pero puede usarlo con otros lenguajes y marcos si no tienen su propio soporte de migración. La página de Wikipedia sobre Schema Migration enumera más herramientas de este tipo .
fuente
Por extraño que parezca, este es el verdadero problema que enfrenta mi equipo de desarrollo actual. La pregunta contiene varias subpreguntas, por lo que se abordarán de forma independiente.
En primer lugar, ¿una base de datos relacional restringe demasiado el modelo de datos y dificulta los cambios?
Ciertamente , pero no necesariamente por las razones citadas. Desafortunadamente, la versatilidad de los sistemas de gestión de bases de datos relacionales también conduce a su caída. El RDBMS se desarrolló originalmente para ofrecer una plataforma de almacenamiento de datos relativamente simple que aceptaría grandes conjuntos de datos y los reduciría a un tamaño relativamente pequeño. Esto se hizo a expensas de la complejidad en el modelo de datos y la potencia de cálculo requerida. A medida que aumentaba la complejidad de la base de datos, surgieron procedimientos almacenados, vistas, funciones y disparadores para ayudar a los administradores de bases de datos a lidiar con la complejidad de manera consistente y escalable.
Desafortunadamente, el modelo de base de datos relacional no está orientado a objetos y, naturalmente, no se asigna a entidades del mundo real como debería hacerlo un modelo de datos. Eso nos lleva a la necesidad de herramientas de intermediarios como mapeadores relacionales de objetos y similares. Desafortunadamente, si bien estas herramientas claramente tienen un lugar en el mundo del desarrollo actual, su uso se dirige simplemente a un síntoma del problema de complejidad de datos relacionales, en lugar de la causa subyacente, que es una desalineación del modelo de datos con el mundo real.
Eso lleva a la segunda parte de la pregunta, que en realidad era más una suposición, pero debería verse como una pregunta: ¿se supone que debemos hacer nuestro modelo de dominio bien la primera vez?
Sí, hasta cierto punto. Como señaló la pregunta, rara vez es posible comprender completamente el problema cuando comenzamos el proceso de diseño. Sin embargo, la diferencia entre un modelo de datos completamente incorrecto, a diferencia de uno que puede modificarse a medida que adquirimos una mayor comprensión del dominio, es el modelo que se asigna coherentemente al mundo real. Esto significa que debemos hacer todo lo posible para crear un modelo de datos inicial que sea consistente con nuestra comprensión del problema en términos de sus entidades del mundo real. Si comenzamos a normalizar las entidades incorrectas, el modelo de datos estará equivocado de dos maneras y la recuperación será difícil.
En muchos sentidos, el cambio a soluciones de base de datos "Sin SQL" es el resultado de los problemas de incoherencia del modelo de datos. La utilización de un enfoque orientado a objetos sin SQL nos hace pensar más sobre el mapeo entre nuestros objetos en código y aquellos en el mundo real, y cuando nos encontramos con una inconsistencia, a menudo es evidente porque no es factible implementarlo en nuestro base de datos. Esto conduce a un mejor diseño general.
Eso lleva a la pregunta final: ¿ es un modelo de datos relacionales inconsistente con el enfoque ágil?
No, pero se requiere más habilidad. Mientras que en el mundo sin SQL, es trivial agregar un campo o convertir una propiedad en una matriz, no es trivial hacer estas cosas en el mundo relacional. Se necesita, como mínimo, alguien que sea capaz de comprender tanto el modelo de datos relacionales como las entidades del mundo real que representan. Esta persona es la persona que facilitará la actualización del modelo relacional a medida que cambie la comprensión del modelo del mundo real. No hay una bala de plata para resolver este problema.
fuente
El punto principal no es refactorizar tanto que su modelo cambie más allá de todo reconocimiento. Incluso con el desarrollo iterativo, realmente debería construir sobre las cosas existentes y no refactorizarlas en pedazos.
Esto le brinda 2 opciones principales para manejar grandes cambios cuando se presenten: la primera es construir la capa de base de datos como API, usar procedimientos almacenados para que se puedan cambiar para adaptarse al cliente sin cambiar el esquema de datos subyacente.
La otra forma es reemplazar las tablas con un poco de migración de datos. Cuando se requiere un cambio a gran escala, crea el nuevo esquema e implementa un conjunto de scripts para tomar los datos antiguos y aplicarlos en el nuevo formato. Cuesta tiempo hacer esto, por lo que confía más en métodos más baratos para modificar el acceso a los datos (por ejemplo, a través de SP) como primera opción.
Entonces: 1. trate de pensar con anticipación con el diseño para no tener que cambiar las cosas.
Confíe en envoltorios o API para que el cambio sea limitado o pueda ocultarse dentro de un componente aislado
Tómese el tiempo para actualizar correctamente si es necesario.
Estos pasos se aplican a todo, no solo a las bases de datos.
fuente