Database relazionali e sviluppo iterativo


19

In molti approcci allo sviluppo del software come metodologie agili, progettazione guidata dal dominio e analisi e progettazione orientate agli oggetti, siamo incoraggiati ad adottare un approccio iterativo allo sviluppo.

Quindi non dovremmo fare il nostro modello di dominio nel modo giusto la prima volta che iniziamo a lavorare nel progetto. Invece, col passare del tempo, rielaboriamo il modello perché acquisiamo una comprensione più profonda del dominio del problema con il tempo.

A parte questo, anche se proviamo a ottenere un modello perfetto in anticipo, che sono già convinto sia molto difficile, i requisiti possono cambiare. Quindi, dopo che il software è stato distribuito alla produzione, gli utenti finali potrebbero notare che un determinato requisito non è stato completamente compreso, o peggio, un requisito mancava.

Il punto qui è che potremmo finire per dover cambiare il modello dopo che il software è stato distribuito. Se ciò accade, abbiamo un problema: il database di produzione ha i dati dell'utente che sono importanti ed è già inserito nel formato per il vecchio modello .

L'aggiornamento del codice potrebbe essere un compito difficile se il codice non è ben progettato e se il sistema è grande. Ma può essere fatto con il tempo, abbiamo strumenti come Git che ci aiutano a farlo senza danneggiare la versione pronta per la produzione.

D'altra parte, se il modello cambia, se le proprietà delle classi scompaiono o altro, anche il database dovrebbe cambiare. Ma abbiamo un problema: ci sono già dei dati che non possono essere persi, che è già formulato per il vecchio modello.

Sembra che un database relazionale qui sia una barriera che ci impedisce di fare sviluppo iterativo e persino di aggiornare il software quando richiesto dagli utenti finali.

Un approccio che ho già usato è stato quello di codificare una classe speciale che associa vecchie tabelle di database a nuove. Pertanto, queste classi raccolgono i dati nel vecchio formato, li convertono nel formato utilizzato dal nuovo modello e li salvano nelle nuove tabelle.

Questo approccio sembra non essere il migliore. La mia domanda qui è: esistono approcci noti e raccomandati per conciliare lo sviluppo iterativo con i database relazionali?


6
Per inciso, non penso che ciò abbia a che fare con i database relazionali in particolare. Ho un problema simile con un progetto a cui sto lavorando, ma lo stiamo riscontrando con lo schema per le nostre stringhe JSON che rappresentano oggetti molto non relazionali. Probabilmente colpisce ugualmente tutte le forme di persistenza.
Ixrec,

1
Lo schema del database viene modificato in modo da non perdere dati, en.wikipedia.org/wiki/Schema_migration .
RemcoGerlich,

1
Sono sicuro che questo argomento è stato ampiamente discusso da qualche parte prima, ma non riesco a trovarlo sui programmatori. Ma vedi qui martinfowler.com/articles/evodb.html o qui stackoverflow.com/questions/334059/...
Doc Brown

1
"A parte questo, anche se proviamo a ottenere un modello perfetto in anticipo, che sono già convinto che sia molto difficile, i requisiti possono cambiare." Vorrei aggiungere che non dovresti nemmeno provare a ottenere un modello (quasi perfetto) in primo piano. Ciò potrebbe legare la tua mentalità a un tipo di soluzioni invece di mantenere aperte le tue opzioni.
Piegato il

Risposte:


15

Non devono essere classi speciali, ma sì, hai bisogno di qualcosa che prenda il database nel formato precedente e lo converta in quello attuale.

La cosa qui è che è necessario sviluppare un processo per scrivere e testare questi script e discipline per non toccare mai i database di test e produzione a mano, ma sempre tramite script di migrazione.

Ogni volta che è necessario apportare una modifica al database, si scrive uno script che lo farà, sia in SQL che utilizzando il proprio livello ORM, e lo si impegna nel controllo della versione insieme alle modifiche che richiedono il nuovo schema. Quindi hai alcuni script di controllo che aggiorneranno il database applicando tutti gli script di migrazione che non sono stati ancora applicati in una sequenza.

E assicurati di modificare qualsiasi ambiente di sviluppo, test e QA condiviso solo applicando gli script e ripristinando la versione precedente se non funzionano, quindi puoi essere ragionevolmente sicuro che funzioneranno come previsto quando li rilasci sulla produzione .

La nuova installazione viene eseguita semplicemente applicando tutti gli script. Dopo un po ', potresti averne centinaia e pensare che sia molto inefficiente, ma non cadere nella trappola del tentativo di ottimizzarlo. L'installazione è un'attività una tantum e mantiene trionfi affidabili rendendola veloce.

@Doc Brown ha già collegato Martin Fowler: Evolutionary Database Design e /programming/334059/agile-development-and-database-changes , e aggiungerei Alex Papadimoulis: Database Changes Done Right , che è più breve e ha alcuni esempi.

Come esempio decente di strumento per attuare tale processo, suggerisco Alembic . Si basa sul framework Python SQLAlchemy , ma è possibile utilizzarlo con altri linguaggi e framework se non dispongono del proprio supporto per la migrazione. La pagina di Wikipedia su Schema Migration elenca altri strumenti di questo tipo .


1
@Tibo costruisci lo schema da zero eseguendo la stessa sequenza di script. Ecco come gestisci il problema. Dato che come standard è possibile passare da qualsiasi istanza del database - incluso uno che non esiste ancora - a uno schema corrente e avere la sicurezza che sia lo stesso. Non è necessario avere due modi come nel tuo esempio. (Almeno non viene fornita una linea di base coerente - il primo passo è stabilire la linea di base e una volta raggiunta la linea di base il problema scompare.)
Murph,

1
Complimenti per l'articolo di Alex; potrebbe non essere più breve, ma rende una lettura molto più orientata alla pratica e divertente.
Murphy

1
Siamo un negozio Agile e gestiamo un servizio di operatività al 100% ed entrambi si applicano anche al DB. Migriamo lo schema di produzione in media una volta al giorno e secondo me tutto ciò che Jan ha detto. Un'altra cosa che abbiamo fatto è stata preziosa è ciò che chiamiamo test di migrazione, che viene eseguito come parte del nostro processo di compilazione e distribuzione. Elimina un'istantanea dello schema dalla produzione, applica ad essa eventuali migrazioni in sospeso dal master e quindi esegue i test unitari dal codice di produzione attualmente distribuito rispetto a quello schema. L'obiettivo è verificare che l'applicazione delle migrazioni non interrompa il sistema in esecuzione.
Gordon Wrigley,

1

Stranamente, questo è il problema che il mio attuale team di sviluppo deve affrontare. La domanda contiene diverse sotto-domande, quindi verranno affrontate in modo indipendente.

Innanzitutto, un database relazionale limita troppo il modello di dati, rendendo le modifiche molto difficili?

Sicuramente , ma non necessariamente per i motivi citati. Sfortunatamente, anche la versatilità dei sistemi di gestione di database relazionali porta alla loro caduta. RDBMS è stato originariamente sviluppato per offrire una piattaforma di archiviazione dei dati relativamente semplice in grado di accettare set di dati di grandi dimensioni e ridurli a dimensioni relativamente ridotte. Ciò è stato fatto a spese della complessità del modello di dati e della potenza di calcolo richiesta. Con l'aumentare della complessità del database, sono state create procedure, viste, funzioni e trigger memorizzati per aiutare gli amministratori di database a gestire la complessità in modo coerente e scalabile.

Sfortunatamente, il modello di database relazionale non è orientato agli oggetti e non si associa naturalmente alle entità del mondo reale come dovrebbe fare un modello di dati. Questo ci porta alla necessità di strumenti di intermediari come mappatori relazionali di oggetti e simili. Sfortunatamente, mentre questi strumenti hanno chiaramente un posto nel mondo di sviluppo di oggi, il loro uso è semplicemente mirato a un sintomo del problema della complessità dei dati relazionali, piuttosto che alla causa sottostante, che è un disallineamento del modello di dati rispetto al mondo reale.

Ciò porta alla seconda parte della domanda, che era davvero un presupposto, ma dovrebbe essere vista come una domanda: dovremmo fare il nostro modello di dominio nel modo giusto la prima volta?

Sì, fino a un certo punto. Come sottolineato dalla domanda, raramente è possibile comprendere appieno il problema quando si avvia il processo di progettazione. Tuttavia, la differenza tra un modello di dati completamente errato, al contrario di uno che può essere modificato man mano che acquisiamo una maggiore comprensione del dominio, è il modello che mappa coerentemente con il mondo reale. Ciò significa che dobbiamo compiere ogni sforzo per creare un modello di dati iniziale coerente con la nostra comprensione del problema in termini di entità del mondo reale. Se iniziamo a normalizzarci su entità sbagliate, il modello di dati sarà errato in due modi e il recupero sarà difficile.

In molti modi, il passaggio alle soluzioni di database "No SQL" è il risultato dei problemi di incoerenza del modello di dati. L'uso di un approccio No SQL orientato agli oggetti ci porta a pensare di più alla mappatura tra i nostri oggetti nel codice e quelli nel mondo reale - e quando ci imbattiamo in un'incoerenza, è spesso evidente perché è impossibile implementare nel nostro Banca dati. Questo porta a un miglior design complessivo.

Ciò porta alla domanda finale: un modello di dati relazionali è incompatibile con l'approccio agile?

No, ma sono necessarie più abilità. Mentre nel mondo No-SQL è banale aggiungere un campo o convertire una proprietà in un array, non è affatto banale fare queste cose nel mondo relazionale. Prende almeno una persona in grado di comprendere sia il modello di dati relazionali che le entità del mondo reale che rappresentano. Questa persona è l'individuo che faciliterà l'aggiornamento del modello relazionale man mano che la comprensione dei modelli del mondo reale cambia. Non esiste un proiettile d'argento per risolvere questo problema.


1
Spero davvero che tu abbia sovradimensionato il problema di creare un nuovo campo nella tabella RDBMS per rendere la dichiarazione più drammatica. La tabella del database deve essere molto speciale (o il nuovo tipo di campo deve essere qualcosa di eccezionale) per creare davvero un problema per aggiungere un campo.
Alexey Zimarev,

Sì, ma non è mai solo un campo ...
theMayer,

1
Direi più spesso che è solo un campo. Cambiamenti di schema drammatici non sono così spesso. Non sono un fan dell'utilizzo di RDBMS con design OO a causa della mancata corrispondenza dell'impedenza. Tuttavia, l'aggiunta di nuovi tipi (tabelle) e proprietà (colonne) sono relativamente facili in entrambi i mondi sebbene in NoSQL sia effettivamente un po 'più semplice. Ma i cambiamenti complessi sono dolore in entrambi i casi. Ancor peggio diventa nel sistema di provenienza di eventi con istantanee, al contrario di quanto sia piacevole l'esperienza di sviluppo per tale sistema.
Alexey Zimarev,

Vedo che i database relazionali sono spesso usati come "martello universale" per risolvere le esigenze di archiviazione dei dati, quando in realtà ci sono ragioni molto specifiche per usarli. In un sistema attentamente studiato, raramente ci si deve preoccupare dei problemi di cui ho scritto nella mia risposta: mi rivolgo a un pubblico più generale che potrebbe non avere l'esperienza per arrivare in anticipo a una progettazione appropriata del sistema.
theMayer

Non vi è alcuna discrepanza tra il modello relazionale e di solito si associa al mondo reale così come a qualsiasi altro tipo di modello. Alcune operazioni saranno più facili con un tipo e altre con un altro tipo. Il problema è quando si crea un modello di un tipo (orientato agli oggetti) e si tenta di implementarlo con strumenti di un altro tipo (relazionale). Questo non funziona bene. Ma il mondo reale non è orientato agli oggetti. Lo è e lo modelli. E devono usare gli strumenti giusti per il tipo di modello selezionato.
Jan Hudec,

-1

Il punto principale non è quello di refactoring così tanto che il tuo modello cambia oltre ogni riconoscimento. Anche con lo sviluppo iterativo, dovresti davvero basarti sulle cose esistenti e non ridistribuirle.

Questo ti dà 2 opzioni principali per gestire grandi cambiamenti quando arrivano: il primo è costruire il livello DB come API, utilizzare le procedure memorizzate in modo che possano essere modificate per adattarsi al client senza cambiare lo schema di dati sottostante.

L'altro modo è sostituire le tabelle con un po 'di migrazione dei dati. Quando è richiesta una modifica su larga scala, si crea il nuovo schema e si implementa un set di script per prendere i vecchi dati e massaggiarli nel nuovo formato. Ciò richiede tempo, motivo per cui si fa maggiormente affidamento su metodi più economici per modificare l'accesso ai dati (ad esempio tramite SP) come prima scelta.

Quindi: 1. prova a pensare al design in modo da non dover cambiare le cose.

  1. Affidati a wrapper o API in modo che il cambiamento sia limitato o possa essere nascosto all'interno di un componente isolato

  2. Prenditi il ​​tempo per aggiornare correttamente se devi.

Questi passaggi si applicano a tutto, non solo ai database.


Lo schema sottostante a volte deve essere modificato. Man mano che l'applicazione accede ai test dei clienti, emergono nuovi attributi di cui non hai mai sentito parlare, attributi che pensavi fossero numeri che diventano stringhe, relazioni che ti aspettavi di essere 1: 1 dopo non essere così dopo tutto e così via. Non è possibile coprire questo tipo di cose dietro le procedure memorizzate (inoltre, le procedure memorizzate fanno parte del problema, perché, come altre cose nel database, non vivono nel controllo della versione).
Jan Hudec,

@JanHudec da quando gli SP non vivono nel controllo versione? Puoi occuparti di queste cose, cambiare l'API SP per prendere una stringa e scriverla in un campo diverso, gestendo i vecchi numeri e le nuove stringhe in un po 'di codice nel tuo SP. Non è il migliore, ma può essere meglio che andare su ogni sito del cliente per migrare i propri dati nel nuovo formato di stringa (ci sono esempi migliori, ma hai l'idea). Se la modifica risulta essere grande, allora devi migrare, ma almeno con un'API DB hai anche altre opzioni, più economiche.
gbjbaanb,

Devi ancora visitare il sito di ciascun cliente per installare l'SP e aggiungere il nuovo campo. E quando ci sei, puoi anche migrare i dati. Gli SP sono utili in quanto consentono di creare un'interfaccia compatibile con le versioni precedenti se si dispone di più applicazioni per accedere al database, quindi non è necessario aggiornarle tutte contemporaneamente. Ma non salvano alcun passaggio quando è necessario modificare lo schema a causa della modifica dei requisiti.
Jan Hudec,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.