Porque NO uso las migraciones para agregar columnas #Laravel

Video thumbnail

Por aquí quiero hablar de un tema que creo que es interesante: las migraciones en Laravel.

Tipos de migraciones en Laravel
Recordemos que existen dos tipos de migraciones para entrar un poquito en contexto. Está la típica:

$ php artisan migrate

Siempre comienza así. Luego, create, indicas qué es lo que quieres crear (por ejemplo, el nombre de la tabla: payments, libros, etc. — users ya la tenemos). Y con eso ya se entiende que vas a crear una tabla. Esto lo puedes ver aquí; por ejemplo, fue lo que hicimos para la parte de payments. Si la encuentro… aquí está. Entonces, se va a crear una estructura llamada payments.

Pero ¿qué pasa cuando quieres, por ejemplo, agregar una columna y demás? Ahí tenemos una sintaxis ligeramente distinta.

$ php artisan make:migration add_nombre_columna_to_nombre_tabla_table

Esto es un poquito complicado. Yo lo hablo desde la perspectiva de que soy un desarrollador independiente. Todos los proyectos que hago los hago yo mismo, ya sea para terceros o directamente para mí.

Por lo tanto, cuando quiero hablar con alguien, hablo conmigo mismo. No es un proyecto en equipo, así que tengo ciertas limitantes… y también adapto mi forma de programar a eso.

Por ejemplo, Git lo uso siempre. A mí me pueden explotar la máquina —lo lamentaría, claro— pero mi trabajo no lo pierdo porque siempre lo tengo sincronizado. Lo sincronizo, como quien dice, conmigo mismo.

Uso Git, luego voy a otra máquina, bajo los cambios, sigo desarrollando… y así. Esto es muy diferente cuando estás desarrollando en un equipo de 10 personas en un mismo proyecto. En esos casos puede que en algún punto se solapen archivos, haya conflictos, y se tengan que resolver con merge. Yo no tengo esos problemas, porque trabajo solo.

Tampoco es que vaya a prender dos máquinas para trabajar en paralelo. Trabajo en una, sincronizo, voy a la otra, hago pull, sigo trabajando, y ya.

La mala práctica que me funciona

Esto también se aplica un poco a las migraciones. Y aquí es donde reconozco que puedo estar siguiendo una mala práctica.

Yo odio tener tablas “regadas” en múltiples migraciones. Sobre todo con entidades tan genéricas y flexibles como los pagos. Por ejemplo, al principio tenía un producto llamado “curso”. Luego quise manejar también “libros”. Como al inicio mi organización no fue la mejor, tengo cosas duplicadas.

Eso luego afecta a otras tablas, como la de usuarios. Al principio no vendía nada, pero cuando empecé a vender, tuve que agregar más campos a users. Suponte que users no fue generada por Laravel, sino por mí. Esto aplica con cualquier entidad.

Lo que quiero concluir es que seguramente en algún punto vas a querer modificar las tablas. Sobre todo para agregar columnas o usar tipos enumerados. Siempre vas a querer agregar cositas.

La forma “Laravel” es crear una nueva migración y hacer los cambios ahí. Esa sería la solución correcta... o al menos la más recomendada. Pero ¿qué pasa? Cuando busques payments, por ejemplo, te van a aparecer 20 migraciones para esa tabla: una donde agregaste una columna, otra donde quitaste un enum, otra donde cambiaste el nombre…

Eso me parece horroroso. No me gusta.

Mi alternativa

En mi caso, prefiero tener toda la estructura definida en una sola migración y no en múltiples. Pero esto trae un problema: si haces un cambio, tienes que eliminar toda la base de datos para que la migración vuelva a aplicarse. Eso no es lo ideal porque perderías todos los datos de prueba en desarrollo (y en producción ni hablar: no se puede hacer).

Además, trabajo en un servidor compartido. No tengo acceso a la terminal para ejecutar estos comandos. Tengo que dar directamente el SQL. Que yo sepa, Laravel no genera ese SQL de forma directa, pero tú ya entiendes el problema.

¿Cómo lo resuelvo?
Lo que yo hago es no generar migraciones intermedias. Y es por eso que no recuerdo bien los comandos. Cuando quiero agregar un campo nuevo —por ejemplo, retornado— lo agrego directamente en la migración original. Esto pasa mucho: a veces desarrollas módulos después, como uno de cancelaciones o disputas, y te das cuenta de que necesitas nuevas columnas.

Por ejemplo, al principio tienes cancelado, y después te das cuenta de que necesitas también un campo disputa. Luego integras MercadoPago. Y todo eso serían cinco migraciones diferentes... ¡para una sola tabla!

Es una pesadilla leerlo así. Y si un desarrollador nuevo entra al equipo, tiene que armar el rompecabezas en su cabeza para entender cómo quedó la tabla.

Entonces, lo que yo hago es modificar directamente la migración original. Pero claro, ¿cómo replico eso en la base de datos ya creada? Lo que hago es usar herramientas como DBgin, TablePlus, phpMyAdmin o el que trae Laragon.

Migraciones manuales con SQL

Estos sistemas gestores de base de datos generan el comando SQL por detrás. Yo hago el cambio desde la interfaz gráfica (por ejemplo, agregar un campo enum) y luego copio ese SQL.

Después lo ejecuto manualmente en mis otras máquinas… y también en el servidor de producción (donde no tengo acceso a la consola). En total, uso unas 4 máquinas, más producción:

ALTER TABLE `file_payments`
CHANGE `payments` `payments` enum('paypal','stripe','free','other', 'google', 'apple') NOT NULL DEFAULT 'paypal';

De esta forma, tengo todas mis migraciones organizadas. Las lees, las abres, y no tienes que estar armando rompecabezas. Además, evito tener tantas migraciones.

Lo malo es que sí es una mala práctica, porque Laravel está pensado para que manejes la base de datos desde el framework. Pero como te digo, a mí me ha servido.

Aunque reconozco que trae problemas. Por ejemplo, una vez definí un enum con un espacio al final del valor… y eso causó problemas. Aquí en la migración estaba bien definido, pero en el SQL que se generó manualmente, no. Entonces, cuando comparas valores, no coinciden (null vs. vacío, por ejemplo).

Ese tipo de errores son sutiles y difíciles de detectar. Pero bueno, son cosas que uno aprende con el tiempo.

Acepto recibir anuncios de interes sobre este Blog.

Te hablo de como hago para cuando quiero modificar una tabla en Laravel evitar crear una migración adicional para MODIFICAR la tabla.

- Andrés Cruz

In english