Dove convalidare le regole del modello di dominio che dipendono dal contenuto del database?


10

Sto lavorando su un sistema che consente agli amministratori di definire moduli che contengono campi. I moduli definiti vengono quindi utilizzati per inserire dati nel sistema. A volte i moduli vengono compilati da un essere umano tramite una GUI, a volte il modulo viene compilato in base ai valori riportati da un altro sistema.

Per ciascun campo, l'amministratore può definire una regola di convalida che limiti i valori consentiti per il campo. Le Regole di convalida possono essere qualsiasi da "il valore inserito nel Campo deve essere Vero o Falso" a "il valore inserito nel Campo deve esistere nella colonna A della tabella B nel database". L'amministratore può in qualsiasi momento modificare la regola di convalida per il campo.

In questo scenario, qual è secondo te il posto più adatto per convalidare che ogni campo sia compilato correttamente? Attualmente ho in mente due approcci principali:

Opzione n. 1: convalida nel modello di dominio

Ogni oggetto Field conterrebbe la Regola di convalida specificata dall'amministratore. Gli oggetti Field avrebbero anche un riferimento a un IValidator. Quando si tenta di impostare il valore del campo, il campo passa il valore dato e la regola di convalida all'IValidator. Se il valore dato non è valido, verrebbe lanciata una ValidationException e gestita in modo appropriato nell'interfaccia grafica / GUI verso l'altro sistema.

Professionisti:

  • Forte protezione contro l'assegnazione accidentale di valori ai campi che violano la regola di convalida

Contro:

  • Il livello di accesso ai dati deve essere in grado di bypassare la convalida e costruire campi che violano l'attuale regola di convalida. Nonostante l'amministratore abbia modificato la regola di convalida per un campo, dobbiamo comunque essere in grado di costruire oggetti Field sulla base dei vecchi dati, ad esempio durante il rendering di un modulo compilato anni fa. Questo potrebbe essere potenzialmente risolto memorizzando l'attuale Regola di convalida ogni volta che memorizziamo il Campo.

  • In questo progetto, il modello Field ha un collegamento indiretto al livello / repository di accesso ai dati tramite IValidator. L'iniezione di Servizi / Archivi in ​​Modelli di Dominio sembra essere generalmente disapprovata .

Opzione n. 2: convalida in un servizio

Provare a garantire che tutti i tentativi di impostare il valore di un campo passino attraverso un servizio che garantisca la validità della regola di convalida. Se la regola di convalida viene violata, genera un'eccezione Validation.

Naturalmente, il livello di accesso ai dati non userebbe il servizio durante la creazione di oggetti Field che erano stati precedentemente persistenti nel DB.

Professionisti:

  • Non viola il pensiero "non iniettare servizi / repository nei tuoi modelli di dominio".

  • Non è necessario mantenere la Regola di convalida corrente durante la persistenza del campo. Il servizio può semplicemente cercare la regola di convalida corrente per il campo; quando si osservano i dati storici, il valore del campo non verrà modificato.

Contro:

  • Nessuna garanzia che tutta la logica che dovrebbe usare il servizio per impostare il valore del campo lo faccia effettivamente. Vedo questo come un grosso svantaggio; tutto ciò che serve è qualcuno che scrive "thisField.setValue (thatField.getValue ())" e la regola di convalida di thisField potrebbe essere violata senza che nessuno sia più saggio. Ciò potrebbe essere potenzialmente mitigato garantendo che il valore del campo corrisponda alla regola di convalida quando il livello di accesso ai dati sta per persistere nel campo.

Attualmente preferisco l'opzione n. 1 rispetto all'opzione n. 2, principalmente perché la considero una logica aziendale e ritengo che l'opzione n. 2 rappresenti un rischio maggiore di introdurre dati errati nel sistema. Quale opzione preferisci o esiste un altro design che si adatta a questo scenario meglio delle due opzioni descritte?

Modifica (complessità delle convalide)

I casi di validazione che sono emersi per ora sono relativamente semplici; il valore del campo deve essere ad es. numerico, una data, una data con un orario o essere un valore esistente in una colonna del database. Tuttavia, sospetto che la complessità aumenti gradualmente nel tempo. Ad esempio, la soluzione di convalida deve essere costruita pensando all'internazionalizzazione: elementi come Date possono essere inseriti in una sintassi specifica della locale.

Ho deciso di procedere con l'opzione n. 1 per ora, tentando di fare attenzione a non assegnare troppe responsabilità al modello di dominio. Coloro che si trovano in una situazione simile potrebbero anche voler verificare le relative domande Convalida e autorizzazione nell'architettura a più livelli e Convalida dell'input di dati - Dove? Quanto? .


La creazione del modello funziona perfettamente con tutte le convalide. Ma quando si desidera modificare o visualizzare il modulo, inizia anche la convalida. Ciò genera un'eccezione per i campi vuoti o con valori non validi, forse modificati nel database o caricati da Excel. La soluzione prevista è consentire la visualizzazione del modulo all'aggiornamento in modo che l'amministratore possa correggere quei campi.
Tunmise Fasipe,

Risposte:


4

Quanto sono complesse le convalide? Spesso le convalide richiedono una combinazione di campi e o regole aziendali che si basano su campi per una valutazione accurata.

Più complesse sono le convalide, più difficile e meno performante è l'opzione n. 2.

Ovviamente il livello dati potrebbe invocare il servizio di validazione in fase di persistenza. Ciò potrebbe aiutare la strana situazione in cui i dati sono in uno stato non valido a causa di un cambiamento nelle regole.

L'altro elemento su cui vale la pena commentare è la possibilità di modificare le regole di convalida senza un ciclo di qa di qualche tipo. Ma questo è un argomento per un thread diverso.

Date le informazioni di cui sopra, l'opzione 1 sembra la più flessibile supponendo che manteniate la disciplina, separando la convalida e la persistenza.


0

Forse ti manca un livello. Senza conoscere i dettagli dell'applicazione (requisiti, architettura, ecc.) Farei qualcosa come Client (chiunque esso sia) -> Servizio applicazione -> Modello di dominio

Il livello di servizio dell'applicazione può interagire con il repository e il modello di dominio contenente la logica aziendale. Quindi puoi avere qualcosa del tipo:

FieldUpdateService >> updateField(fieldId, newValue)
  List<FieldRule> rules = this.rulesRepository.findRulesFor(fieldId)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(rules,newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Se hai una relazione tra un Field e le sue FieldRules e usi un ORM come Hibernate in Java, farai solo:

FieldUpdateService >> updateField(fieldId, newValue)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Field >> updateValue(newValue)
  for rule in rules
     if !rule.isValid(newValue)
        throw ValueNotAllowedException
  this.value = newvalue

Perché la query ORM e crea un'istanza del grafico degli oggetti richiesti.

Per quanto riguarda il tuo dubbio sul fatto che qualcuno può fare

thisField.setValue (thatField.getValue ()) "e la Regola di convalida di thisField potrebbero essere violati senza che nessuno sia più saggio

Qualcuno potrebbe anche scrivere: FieldRule alwaysReturnTrueRule = new FieldRule {isValid (newValue) {return true; }} field.updateValue ("uncheckedValue", alwaysReturnTrueRule) È un esempio oscuro, ma ciò che sto cercando di dire è che nulla ti protegge da un cattivo uso del codice. Forse buona documentazione e comunicazione faccia a faccia. Penso che nulla ti protegga da un cattivo uso del codice.

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.