Come non darsi la zappa sui piedi usando Liquibase

Non è mai successo, ed eccolo di nuovo!

Per il progetto successivo abbiamo deciso di utilizzare Liquibase fin dall'inizio per evitare problemi futuri. Come si è scoperto, non tutti i giovani membri del team sanno come usarlo correttamente. Ho fatto un workshop interno, che poi ho deciso di trasformare in un articolo.

Questo articolo include suggerimenti utili e descrizioni di tre delle trappole più ovvie in cui puoi cadere quando lavori con gli strumenti di migrazione dei database relazionali, Liquibase in particolare. Progettato per sviluppatori Java di livello Junior e Middle, per sviluppatori più esperti può essere interessante per strutturare e ripetere ciò che molto probabilmente è già noto.

Come non darsi la zappa sui piedi usando Liquibase

Liquibase e Flyway sono le principali tecnologie concorrenti per la risoluzione dei problemi di controllo di versione delle strutture relazionali nel mondo Java. Il primo è completamente gratuito, in pratica viene spesso scelto per l'uso, motivo per cui Liquibase è stato scelto come eroe della pubblicazione. Tuttavia, alcune delle pratiche descritte potrebbero essere universali, a seconda dell'architettura dell'applicazione.

Le migrazioni relazionali rappresentano un modo obbligato per gestire la debole flessibilità degli archivi dati relazionali. Nell'era della moda per l'OOP, lo stile di lavoro con il database implicava che avremmo descritto lo schema una volta e non lo avremmo più toccato. Ma la realtà è sempre che le cose cambiano e spesso sono necessarie modifiche alla struttura delle tabelle. Naturalmente, il processo stesso è doloroso e spiacevole.

Non approfondirò la descrizione della tecnologia e le istruzioni per aggiungere la libreria al tuo progetto, sono stati scritti abbastanza articoli su questo argomento:

Inoltre, c'era già un ottimo articolo sul tema dei consigli utili:

Suggerimenti

Voglio condividere i miei consigli e commenti, nati attraverso il sudore, il sangue e il dolore legati alla risoluzione dei problemi legati alla migrazione.

1. Prima di iniziare, dovresti leggere la sezione sulle migliori pratiche su sito web Liquido base

Ci Vengono descritte cose semplici ma molto importanti, senza le quali l'uso della biblioteca può complicarti la vita. Ad esempio, un approccio non strutturale alla gestione dei changeset porterà prima o poi a confusione e a migrazioni interrotte. Se non si implementano contemporaneamente modifiche reciprocamente dipendenti nella struttura del database e nella logica dei servizi, è molto probabile che ciò porti a test rossi o a un ambiente non funzionante. Inoltre, le raccomandazioni per l'utilizzo di Liquibase sul sito ufficiale contengono un paragrafo relativo allo sviluppo e alla verifica degli script di rollback insieme ai principali script di migrazione. Bene, nell'articolo https://habr.com/ru/post/178665/ sono presenti esempi di codice relativi alle migrazioni e al meccanismo di rollback.

2. Se hai iniziato a utilizzare gli strumenti di migrazione, non consentire correzioni manuali nella struttura del database

Come dice il proverbio: "Una volta Persil, sempre Persil". Se la base della tua applicazione ha iniziato a essere gestita dagli strumenti di Liquibase, qualsiasi modifica manuale porta immediatamente a uno stato incoerente e il livello di fiducia nei changeset diventa zero. Rischi potenziali: diverse ore spese per ripristinare il database e, nel peggiore dei casi, un server guasto. Se il tuo team ha un DBA Architect "vecchia scuola", spiegagli con pazienza e attenzione quanto andrebbero male le cose se modificasse il database a modo suo dallo sviluppatore SQL condizionale.

3. Se il changeset è già stato inviato al repository, evitare la modifica

Se un altro sviluppatore ha estratto e applicato un changeset che verrà modificato in seguito, ti ricorderà sicuramente con una parola gentile quando riceverà un errore all'avvio dell'applicazione. Se la modifica del changeset in qualche modo interferisce con lo sviluppo, dovrai imboccare la china scivolosa degli hotfix. L'essenza del problema risiede nella convalida delle modifiche tramite hash sum, il meccanismo principale di Liquibase. Quando si modifica il codice del changeset, la somma hash cambia. La modifica dei changeset è possibile solo quando è possibile distribuire l'intero database da zero senza perdere dati. In questo caso, il refactoring del codice SQL o XML può, al contrario, semplificarci la vita, rendere più leggibili le migrazioni. Un esempio potrebbe essere una situazione in cui, all'inizio dell'applicazione, lo schema del database di origine veniva coordinato all'interno del team.

4. Se possibile, verificare i backup del database

Qui, penso, tutto è chiaro. Se all'improvviso la migrazione non ha avuto successo, tutto può essere restituito. Liquibase dispone di uno strumento di rollback, ma anche gli script di rollback sono scritti dallo sviluppatore stesso e possono avere problemi con la stessa probabilità degli script principali del changeset. Ciò significa che andare sul sicuro con i backup è utile in ogni caso.

5. Se possibile, utilizzare backup di database verificati in fase di sviluppo

Se ciò non contraddice i contratti e la privacy, non ci sono dati personali nel database e non pesa come due soli: prima di applicarlo sui server di migrazione live, puoi controllare come funziona sulla macchina dello sviluppatore e calcolare quasi il 100% dei potenziali problemi durante la migrazione.

6. Chatta con altri sviluppatori del team

In un processo di sviluppo ben organizzato, tutti i membri del team sanno chi sta facendo cosa. In realtà, spesso questo non è il caso, quindi, se stai preparando modifiche alla struttura del database come parte del tuo compito, è consigliabile informarne ulteriormente l'intero team. Se qualcuno sta apportando modifiche in parallelo, dovresti organizzarti con attenzione. Vale la pena comunicare con i colleghi anche alla fine del lavoro, non solo all'inizio. Molti potenziali problemi con i changeset possono essere risolti nella fase di revisione del codice.

7. Pensa a cosa stai facendo!

Un consiglio apparentemente ovvio applicabile a qualsiasi situazione. Tuttavia, molti problemi avrebbero potuto essere evitati se lo sviluppatore avesse analizzato ancora una volta ciò che stava facendo e cosa avrebbe potuto influenzare. Lavorare con le migrazioni richiede sempre particolare attenzione e precisione.

trappole

Diamo ora un'occhiata alle tipiche trappole in cui puoi cadere se non segui i consigli di cui sopra, e cosa, in effetti, si dovrebbe fare?

Situazione 1. Due sviluppatori stanno tentando di aggiungere nuovi changeset contemporaneamente

Come non darsi la zappa sui piedi usando Liquibase
Vasya e Petya vogliono creare un changeset della versione 4 senza conoscersi. Hanno apportato modifiche alla struttura del database e hanno lanciato una richiesta pull con diversi file di changeset. Di seguito si propone il seguente meccanismo:

Come risolvere

  1. In qualche modo, i colleghi devono concordare l'ordine in cui dovrebbero essere applicati i loro changeset, diciamo che Petin dovrebbe essere applicato per primo.
  2. Una persona dovrebbe inserire l'altra e contrassegnare il changeset di Vasya con la versione 5. Questo può essere fatto tramite Cherry Pick o una fusione accurata.
  3. Dopo le modifiche, assicurati di verificare la validità delle azioni intraprese.
    Infatti, i meccanismi di Liquibase ti permetteranno di avere due changeset della versione 4 nel repository, quindi potrai lasciare tutto così com'è. Cioè, avrai semplicemente due revisioni della versione 4 con nomi diversi. Con questo approccio, diventa molto difficile navigare nelle versioni del database in un secondo momento.

Inoltre, Liquibase, come le case degli hobbit, conserva molti segreti. Uno di questi è la chiave validCheckSum, che è apparsa dalla versione 1.7 e consente di specificare un valore hash valido per un changeset specifico, indipendentemente da ciò che è archiviato nel database. Documentazione https://www.liquibase.org/documentation/changeset.html dice quanto segue:

Aggiungi un checksum considerato valido per questo changeSet, indipendentemente da cosa è archiviato nel database. Utilizzato principalmente quando è necessario modificare un changeSet e non si desidera che vengano generati errori sui database su cui è già stato eseguito (procedura non consigliata)

Sì, questo non è raccomandato. Ma a volte un forte mago della luce padroneggia anche le tecniche oscure.

Caso 2: migrazione basata sui dati

Come non darsi la zappa sui piedi usando Liquibase

Supponiamo che non sia possibile utilizzare i backup del database da server live. Petya ha creato un changeset, lo ha testato localmente e, con piena certezza di avere ragione, ha inviato una richiesta pull allo sviluppatore. Per ogni evenienza, il responsabile del progetto ha chiarito se Petya lo ha controllato e poi lo ha versato. Ma la distribuzione sul server di sviluppo è diminuita.

In effetti, questo è possibile e nessuno ne è immune. Ciò accade se le modifiche alla struttura della tabella sono in qualche modo legate a dati specifici del database. Ovviamente, se il database di Petya è pieno solo di dati di test, potrebbe non coprire tutti i casi problematici. Ad esempio, quando si elimina una tabella, risulta che sono presenti record in altre tabelle in base alla chiave esterna associati ai record in quella da eliminare. Oppure quando si modifica il tipo di colonna, risulta che non è possibile convertire il 100% dei dati nel nuovo tipo.

Come risolvere

  • Scrivi script speciali che verranno applicati una volta insieme alla migrazione e inserisci i dati nel formato corretto. Questo è un modo generale per risolvere il problema del trasferimento dei dati in nuove strutture dopo aver applicato le migrazioni, ma qualcosa di simile può essere applicato prima, in casi speciali. Questo percorso, ovviamente, non è sempre disponibile, perché la modifica dei dati sui server live può essere pericolosa e persino fatale.
  • Un altro modo complicato è modificare un changeset esistente. La difficoltà è che tutti i database in cui è già stato applicato nella sua forma attuale dovranno essere ripristinati. È del tutto possibile che l'intero team di backend sarà costretto a eseguire il rollup locale del database da zero.
  • E il modo più universale è trasferire il problema dei dati nell'ambiente dello sviluppatore, ricreare la stessa situazione e aggiungere un nuovo changeset, a uno danneggiato, che aggirerà il problema.
    Come non darsi la zappa sui piedi usando Liquibase

In generale, quanto più il database è simile nella composizione al database del server di produzione, tanto meno è probabile che i problemi con le migrazioni si estendano. E, naturalmente, prima di inviare il changeset al repository, dovresti pensare più volte se si romperà qualcosa.

Situazione 3. Liquibase inizia ad essere utilizzato dopo essere entrato in produzione

Supponiamo che il team leader abbia chiesto a Petya di includere Liquibase nel progetto, ma il progetto è già in produzione ed esiste una struttura di database già esistente.

Di conseguenza, il problema è che su qualsiasi nuovo server o macchina di sviluppo, i dati della tabella devono essere ricreati da zero e l'ambiente già esistente deve rimanere in uno stato coerente, pronto ad accettare nuovi changeset.

Come risolvere

Ci sono anche diversi modi:

  • Il primo e più ovvio è avere uno script separato che deve essere applicato manualmente durante l'inizializzazione di un nuovo ambiente.
  • Il secondo, meno ovvio, è avere una migrazione di Liquibase che si trovi in ​​un contesto Liquibase diverso e applicarla. Puoi leggere ulteriori informazioni sul contesto Liquibase qui: https://www.liquibase.org/documentation/contexts.html. In generale, si tratta di un meccanismo interessante che può essere applicato con successo, ad esempio, per i test.
  • Il terzo percorso è composto da diversi passaggi. Innanzitutto è necessario creare una migrazione per le tabelle esistenti. Quindi deve essere applicato su qualche ambiente e quindi si otterrà la sua somma hash. Il passo successivo è inizializzare le tabelle Liquibase vuote sul nostro server non vuoto e puoi inserire manualmente un record di un changeset "come se applicato" con le modifiche già presenti nel database nella tabella con la cronologia dell'applicazione dei changeset. Pertanto, su un server già esistente, la cronologia inizierà dalla versione 2 e tutti i nuovi ambienti si comporteranno in modo identico.
    Come non darsi la zappa sui piedi usando Liquibase

Scenario 4: le migrazioni diventano enormi e non riescono a tenere il passo

All'inizio dello sviluppo del servizio, di norma, Liquibase viene utilizzato come dipendenza esterna e tutte le migrazioni vengono elaborate all'avvio dell'applicazione. Tuttavia, nel tempo, potresti imbatterti nei seguenti casi:

  • Le migrazioni diventano enormi e richiedono molto tempo per essere completate.
  • È necessario migrare in ambienti distribuiti, ad esempio, su più istanze di server di database contemporaneamente.
    In questo caso, l'applicazione delle migrazioni per un periodo troppo lungo comporterà un timeout all'avvio dell'applicazione. Inoltre, l'applicazione delle migrazioni in base all'istanza dell'applicazione può comportare la mancata sincronizzazione di server diversi.

Come risolvere

In questi casi, il tuo progetto è già grande, forse anche adulto, e Liquibase inizia a funzionare come uno strumento esterno separato. Il fatto è che Liquibase, come libreria, è assemblato in un file jar e può funzionare come dipendenza all'interno del progetto, oltre che in modo autonomo.

Offline, puoi lasciare l'applicazione delle migrazioni al tuo ambiente CI/CD o alle forti spalle dei tuoi amministratori di sistema/deployer. Per fare ciò, è necessaria la riga di comando di Liquibase https://www.liquibase.org/documentation/command_line.html. In questa modalità diventa possibile avviare l'applicazione dopo che tutte le migrazioni necessarie sono state completate.

conclusione

In effetti, ci sono molte più insidie ​​​​quando si lavora con le migrazioni dei database e molte di esse richiedono un approccio creativo. È importante capire che se si utilizza correttamente lo strumento, è possibile evitare la maggior parte di queste trappole. Nello specifico ho dovuto affrontare tutti i problemi elencati in diverse forme, e alcuni di essi sono stati conseguenza dei miei stipiti. Fondamentalmente, ciò accade, ovviamente, a causa della disattenzione, ma a volte a causa dell'incapacità criminale di utilizzare lo strumento.

Fonte: habr.com

Aggiungi un commento