Per un ORM a supporto della convalida dei dati, è necessario applicare anche i vincoli nel database?


13

Ho sempre applicato vincoli a livello di database oltre ai miei modelli (ActiveRecord). Ma mi chiedevo se questo è davvero necessario?

Un piccolo sfondo

Di recente ho dovuto testare un metodo di generazione di data e ora automatizzato di base per un modello. Normalmente, il test crea un'istanza del modello e la salva senza convalida. Ma ci sono altri campi obbligatori che non sono annullabili nella definizione della tabella, il che significa che non posso salvare l'istanza anche se salto la convalida di ActiveRecord. Quindi sto pensando se dovrei rimuovere tali vincoli dal db stesso e lasciare che l'ORM li gestisca?

Possibili vantaggi se salto i vincoli in db, imo -

  • Può modificare una regola di convalida nel modello, senza dover migrare il database.
  • Può saltare la convalida nei test.

Possibile svantaggio?

Se è possibile che la convalida ORM non riesca o venga ignorata, tuttavia, il database non verifica i vincoli.

Cosa pensi?

MODIFICA In questo caso, sto usando Yii Framework , che genera il modello dal database, quindi vengono generate anche le regole del database (anche se potrei sempre scriverle anche io dopo la generazione).


3
Se i dati nel database possono essere abitualmente modificati senza utilizzare l'ORM (altre app senza ORM o, peggio, l'accesso diretto al database da parte degli utenti), la convalida deve essere realmente nel database.
Marjan Venema,

Risposte:


16

Il tuo principio guida dovrebbe essere Non ripetere te stesso :

Nell'ingegneria del software, Don't Repeat Yourself (DRY) è un principio di sviluppo del software volto a ridurre la ripetizione di informazioni di ogni tipo, particolarmente utile nelle architetture multilivello. Il principio DRY è dichiarato come "Ogni pezzo di conoscenza deve avere una rappresentazione unica, inequivocabile e autorevole all'interno di un sistema".

L'ORM è essenzialmente un livello aggiuntivo (o livello se preferisci), comodamente seduto tra la tua applicazione e i tuoi archivi di dati. I tuoi vincoli dovrebbero essere in un posto, e in un solo posto, sia esso l'ORM o l'archiviazione dei dati, altrimenti abbastanza presto finirai per mantenerne versioni diverse. È davvero non si vuole farlo.

Tuttavia, in pratica, la maggior parte degli ORM decenti genera automaticamente molti dei tuoi modelli dal tuo schema di dati. Sebbene ci sia ancora duplicazione, le possibilità di inferno di manutenzione sono minime poiché il codice ORM duplicato viene generato seguendo lo stesso schema ogni volta. Sarebbe ideale non avere un codice duplicato, ma i vincoli generati automaticamente sono la cosa migliore da fare.

Inoltre, avere i tuoi vincoli in un posto non significa necessariamente che dovresti avere tutti i tuoi vincoli nello stesso posto. Alcuni, come i vincoli di integrità referenziale, potrebbero essere più adatti per l'archiviazione dei dati (ma potrebbero andare persi se ci si sposta in un altro archivio di dati), e alcuni, principalmente quelli che riguardano una logica aziendale complessa, sono più adatti all'ORM. Sarebbe preferibile avere tutte le mele nello stesso paniere, ma ...

fallimenti

Lei parla dell'errore ORM. Questo è assolutamente irrilevante per la tua domanda, la tua applicazione dovrebbe pensare all'ORM e agli archivi di dati come un'unica entità. Se fallisce, fallisce, bypassare l'ORM per parlare direttamente con l'archiviazione dei dati non è una buona idea.

Bypassare l'ORM per qualsiasi altra cosa

Inoltre non è una buona idea. Tuttavia, può accadere per vari motivi:

  1. Parti legacy dell'applicazione che sono state create prima dell'introduzione dell'ORM.

    Questa è una situazione difficile, ed è esattamente la situazione che sto affrontando in questo momento , quindi la mia costante ripetizione di "inferno di manutenzione". O continui a mantenere le parti non ORM o le riscrivi per utilizzare l'ORM. La seconda opzione potrebbe inizialmente avere più senso, ma è una decisione che si basa esclusivamente su cosa stanno facendo esattamente quelle parti dell'applicazione e su quanto prezioso sarebbe una riscrittura completa a lungo termine.

    Prova a cambiare una chiave in una tabella MySQL 2 * 10 ^ 8 mal progettata (senza tempi di inattività) e capirai da dove vengo.

  2. Parti non legacy dell'applicazione che devono assolutamente parlare direttamente con l'archiviazione dei dati:

    Ancora più complicato. Gli ORM sono strumenti fantasiosi e si occupano di quasi tutto, ma a volte si intromettono o addirittura sono assolutamente inutili. La parola d'ordine (buzzphrase in realtà) è un'incongruenza di impedenza relazionale all'oggetto, in poche parole non è tecnicamente possibile per il tuo ORM fare tutto ciò che fa il tuo database relazionale, e per alcune delle cose che fanno, c'è una significativa penalità delle prestazioni.

Commenti

Dal punto di integrità dei dati, i vincoli DEVONO essere sul database e DOVREBBE essere sull'applicazione. Cosa succede se si accede alla propria applicazione da un Web e da applicazioni desktop, da un'app mobile o da un servizio Web? - Luiz Damim

È qui che aggiungere un ulteriore livello sarebbe estremamente utile e se parliamo di un'applicazione Web, utilizzerei un'API REST. Un design troppo semplicistico per questo sarebbe:

inserisci qui la descrizione dell'immagine

L'ORM si collocherebbe tra l'API e gli archivi dei dati e tutto ciò che sta dietro l'API (incluso esso) verrebbe considerato una singola entità dalle varie applicazioni.


Normalmente definiresti uno schema nel tuo ORM che viene quindi rispecchiato nel database in modo da avere un secondo livello di affidabilità.
Josh K,

2
@JoshK Dici il secondo livello di sicurezza, dico inferno di manutenzione. Non
sto

Ha senso. Sto seguendo questo percorso ora. Grazie!
na

1
Una volta passato il punto in cui uno o due sviluppatori stanno facendo funzionare il codice e il database, diventa un male necessario. Se usi un buon ORM genererà anche migrazioni per te. Quando cresci fino al punto di avere un DBA dedicato, non c'è modo di aggirarlo, non lasceranno che le tabelle fluttuino senza vincoli. Un modo semplice per impedire alle persone di registrarsi senza e-mail è vincolarne il livello di archiviazione.
Josh K,

1
Dal punto di integrità dei dati, i vincoli DEVONO essere sul database e DOVREBBE essere sull'applicazione. Cosa succede se si accede alla propria applicazione da un Web e da applicazioni desktop, da un'app mobile o da un servizio Web?
Luiz Damim,

20

Questa è in realtà una domanda molto difficile a cui rispondere e l'ho trovato un argomento molto controverso.

Come ha sottolineato Yannis Rizos nella sua risposta, avere la logica dei vincoli sia nel database che nel livello ORM sembrerebbe violare il DRY, che "può portare a incubi di manutenzione, cattivo factoring e contraddizioni logiche".

Tuttavia, rimuovere la logica di vincolo dal database e mantenerla solo a livello di ORM non funzionerebbe se si verifica una delle seguenti condizioni:

  1. Aggiornamenti DB manuali (sembrano accadere in ogni azienda)

  2. Aggiornamenti DB da un altro sistema che non può sempre condividere facilmente la logica del vincolo ORM (ex / uno script Perl che esegue attività di routine quando il livello ORM è implementato in Hibernate e utilizzato da un'applicazione Java per l'attività quotidiana)

Ciò suggerirebbe di aggiungere solo la logica del vincolo al DB e di rimuoverla dal proprio livello ORM al fine di prevenire una violazione DRY. Tuttavia, ciò può portare a casi in cui il codice dell'applicazione non è in grado di catturare correttamente il problema reale e inoltrarlo all'utente (anche se come sviluppatore il debug del problema, molto probabilmente è possibile). Questo potrebbe non essere accettabile per alcuni progetti.

L'ultima opzione è quella di automatizzare la creazione dei vincoli nell'ORM (e in qualsiasi altro sistema) dai vincoli del DB (o, in realtà ... viceversa). Sebbene alla fine si finiscano con due o più implementazioni dei vincoli, non si tratterà di una violazione del principio DRY come descritto in "Il programmatore pragmatico" in quanto raccomandano l'utilizzo della generazione di codice per evitare violazioni DRY. Certo, non è così semplice perché, ad esempio, ogni modifica a un vincolo DB può forzare una ricostruzione e una nuova distribuzione di tutte le applicazioni che lo utilizzano (non banale per l'automazione).

Davvero, dovrebbe essere valutato caso per caso . Posso dirti che, a questo punto, mi sono imbattuto in sguardi vuoti quando suggerisco di non ripetere la logica del vincolo.


2
Appena uscito dal lavoro e stavo pensando di espandere la mia risposta per essere più o meno quello che hai appena pubblicato. Buona risposta!
yannis,

3

Aggiungerei sicuramente i vincoli al database come opzione predefinita. Questo perché per un'azienda i dati sono fondamentali e la qualità dei dati è fondamentale. @Yannis Rizos ha portato alla discussione il principio DRY. Bene, un altro principio è la difesa in profondità. Per i dati utilizzerei questo principio.

Ho lavorato in imprese reali in cui il DB ha creato dati 30 anni fa. Era ed è ancora accessibile dall'applicazione COBOL e ora da un'applicazione .Net. Tra 10 anni potrebbe essere un'app per distributori, chi lo sa. Si è verificata una fusione e milioni di righe di dati sono state convertite e migrate dall'altra società a questo database utilizzando SQL. Nessun ORM può farlo. In conclusione, i dati rimangono, le applicazioni cambiano, il modo in cui i dati vengono generati cambia. Quindi perché non ridurre la possibilità di corruzione dei dati?


2

Penso che tu faccia entrambi in una certa misura.

  • I vincoli primari dovrebbero risiedere nell'ORM: i linguaggi di programmazione sono molto più flessibili, è più facile da testare e più facile da modificare quando cambiano i requisiti; non è necessario preoccuparsi almeno delle correzioni DDL. In genere si evitano difficili problemi di regressione dei dati.

  • Alcuni vincoli molto duri e veloci dovrebbero anche risiedere nel database. Non sto parlando di nomi non annullabili, per esempio. Sto parlando di cose come l'integrità referenziale o che richiedono alcuni identificatori assolutamente cruciali. Requisiti strutturali per cui il codice non deve occuparsi di "cosa succede se l'Ordine ha un prodotto inesistente".


1

Il database è IMO l'unico posto in cui è possibile violare DRY, perché se qualcosa ignora il tuo ORM e contiene dati errati, è tutto. Gioco finito. Avere dati corrotti è il colpo mortale.


Solo database? Posso pensare a molti casi in cui il comportamento associato ai dati dovrebbe esistere su più livelli (logici o fisici) anche se i dati non sono affatto persistenti. A volte è possibile avere un unico codice sorgente e ridurre la "duplicazione" alle DLL distribuite.
mike30,
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.