Come progettare un modello imprevedibile?

6

Ho lavorato a un progetto che si occupa di semplificare, Scuole e Studenti.

Il requisito generale è che alcuni studenti possano essere assegnati a determinate scuole per svolgere uno stage.

Ma le scuole non sono solo scuole di per sé, quelle possono essere ospedali, carceri, case di cura, ecc.

Dato che sto usando un ORM e classi Entity, la mia prima idea era di usare il mapping di ereditarietà, come, per avere un genitore di classe StageProvider con particolari classi figlio ...

Tuttavia, un altro requisito è che questo dovrebbe essere fatto in modo che qualsiasi Utente in futuro possa aggiungere la nuova istanza di InternshipProvider usando un modulo AND allo stesso tempo per poter aggiungere alcune proprietà specifiche. A volte alla classe, e talvolta solo a un'istanza particolare.

Per ogni istanza, il InternshipProvider può avere o meno, un insieme di proprietà specifiche, che potrebbero essere disponibili su un modulo come campi di testo o opzioni di scelta, o una sottomaschera, ecc.

Quindi l'ho risolto in questo modo: esiste la classe InternshipProvider, tra le proprietà standard ha anche una lunga proprietà di testo. E all'interno di quella proprietà di testo (campo) sono presenti coppie chiave-valore JSON, che descrivono quei campi e valori specifici memorizzati.

C'è anche un "mostro", la funzione di generatore di moduli personalizzati, che gestisce questo abbastanza bene. Ad ogni istanza di InternshipProvider è assegnato un modulo personalizzato specifico per la modifica futura.

Ci sono due ragioni per questi requisiti:

  1. Vogliono eliminare la necessità di assumere uno sviluppatore di software in futuro.
  2. Il dominio È complesso e imprevedibile.

Hai un'idea migliore? C'è qualche concetto che copre questo? Qualche modello di progettazione o simili? Cosa diresti al Cliente?

Grazie

    
posta Đuro Mandinić 23.05.2017 - 18:15
fonte

4 risposte

5

Il modello che stai cercando si chiama EAV o Valore attributo dell'entità .

In questo schema si imposta una tabella con una riga per ogni attributo e un'altra tabella con valori per ciascuna combinazione di entità x attributo.

I valori vengono memorizzati come stringhe, ma puoi definire metadati nella tabella degli attributi per dire al sistema come analizzare la stringa, ad es. come una data o un intero. Se non disponi di metadati, rende difficile la convalida e l'ordinamento risulta errato.

EAV non è sempre il migliore in termini di prestazioni, ma funzionerà molto meglio di una gigantesca stringa JSON, soprattutto se devi ordinare o filtrare in base a questi attributi.

    
risposta data 24.05.2017 - 00:07
fonte
13

Non ho idea del perché ospedali, prigioni, case di cura, ecc. abbiano bisogno delle loro classi. Niente qui mi fa pensare che lo facciano. Perché non sono queste semplici istanze di InternshipProvider ?

Non tutto con un nome deve essere una classe. Hai bisogno di polimorfismo se un ospedale ha bisogno dello stesso metodo per avere un'implementazione diversa da una prigione. Altrimenti, queste classi sono inutili.

L'unica cosa "imprevedibile" che posso vedere qui è ciò che verrà chiamato il prossimo InternshipProvider . Mostrami un comportamento che deve essere diverso in base a quale InternshipProvider e lo ripenserò.

    
risposta data 23.05.2017 - 18:30
fonte
3

Vorrei andare per un dizionario di "Campi personalizzati"

public class InternshipProvider 
{
    public string Id {get;set;}
    public Dictionary<string,string> CustomFields {get;set;}
}

mappato alla seguente struttura di tabella

TABLE InternshipProvider
    varchar Id ('myguid')

TABLE CustomFields 
    varchar Id
    varchar ParentId ('myguid')
    varchar ParentType ('InternshipProvider')
    varchar Value
    varchar TypeToCastTo?

Puoi espandere questo ad altri tipi che richiedono campi personalizzati.

Quindi per le query puoi fare qualcosa sulla falsariga di ...

InternshipProviderList.Where(i=>i.CustomFields[keytosearch] == valuetosearchfor)

o qualche divertente sql dinamico

Ora ovviamente più complessa è la tua logica di query accettabile, più diventa complicato scrivere la query.

Puoi vedere come potresti inserire diverse funzioni per diversi comparatori e quindi magari ricorrere a loop su più clausole, magari capire come gestire AND vs OR, parentesi, occuparsi di null ecc. Ad un certo punto (abbastanza presto) hai bisogno di programmatori per scrivere la query.

Ho scoperto che di solito è più semplice assumere un programmatore per aggiungere la nuova logica richiesta in quel momento piuttosto che provare a scrivere un sistema generico in grado di gestire tutto E farlo in modo sufficientemente semplice da consentire agli utenti non è necessario essere formati nel linguaggio di meta-programmazione del sistema.

Non sono sicuro che direi al cliente che, forse, menziona il rischio, ma dai loro quello che vogliono.

    
risposta data 23.05.2017 - 18:37
fonte
2

Non c'è motivo per soluzioni contorte come il salvataggio di JSON. Hai un tavolo dove ogni riga è un fornitore di stage. Quindi disponi di una tabella con le proprietà del fornitore di stage, in cui ogni riga descrive una proprietà associata a un fornitore di stage tramite chiave esterna.

E se una proprietà a sua volta ha opzioni associate a uno specifico fornitore di stage, è sufficiente creare una tabella con le opzioni, con una chiave esterna per la proprietà del fornitore di stage.

È facile creare un modulo che aggiunge una riga a una tabella.

    
risposta data 23.05.2017 - 19:08
fonte