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? .