2009-12-29 11 views
10

Nel progetto su cui lavoro, gestiamo la fatturazione medica.Versioning di classe per supportare la retrocompatibilità

Ogni volta che lo stato apporta una modifica alla forma ufficiale (che rappresentano le nostre classi di dati), per mantenere la compatibilità con le forme precedenti, aggiungiamo le nuove proprietà ma lasciamo intatte quelle precedenti e disponiamo di una versione del documento proprietà che viene utilizzata per determinare cosa viene eseguita la convalida e le azioni dell'interfaccia utente per visualizzarlo.

Questo ha portato a classi gonfiate per tutta la durata del progetto (quasi 5 anni di modifiche imposte dallo Stato), e semplicemente non supportare i vecchi formati di documenti non è un'opzione.

Mi piacerebbe provare a creare una nuova classe per ogni versione del documento, ma anche in questo caso avremo diverse copie di codice molto simile (sebbene leggermente modificato). E i nomi delle classi come ProgressNoteV16, ProgressNoteV17 sembrano orribili.

L'ereditarietà non può essere utilizzata, perché ciò comporterebbe comunque lo stesso problema (classi con proprietà che non sono più necessarie). Le interfacce renderebbero l'interfaccia altrettanto gonfia, il che non risolverebbe il problema.

Quali sono le soluzioni e le migliori pratiche utilizzate per risolvere questo problema?

risposta

7

Questo è un problema abbastanza classico per qualsiasi agenzia che lavori con il pubblico a qualsiasi titolo, specialmente se è un ente governativo o governativo controllato.La soluzione non è banale e probabilmente richiederà un lavoro significativo da creare, oltre a mantenere in seguito.

Questo ha funzionato per me in passato quando si trattava di problemi simili per i clienti, potrebbe non funzionare per voi, tuttavia, sarà necessario redigere ciò che si sta cercando di ottenere e se ha senso farlo.

ci sono un paio di modelli di avere familiarità con (se non avevate già):

  1. Factory che è già stato in precedenza citato
  2. Composition che si spera si uscire alcuni del problemi di successione brutte
  3. Template per separare la logica di ciò che il modulo fa dalle versioni

Ci sono due libri che sono abbastanza buona per spiegare questi (e pochi altri quelli utili):

  1. Head First Design Patterns (non ricordo fuori dalla parte superiore della mia testa)
  2. Patterns of Enterprise Application Architecture (Fowler)

Ora per il processo che ho usato in passato:

  1. Inizia prendendo tutte le versioni attuali del forme, li separano in classi diverse e cercano la sovrapposizione comune. Puoi farlo in modalità bozza o come piano corrente per avere classi diverse per ciascuna versione
  2. Deriva da questa struttura di classe un numero di oggetti "base" che puoi utilizzare come radice di ereditarietà per ogni serie significativa di versioni per un modulo. Potresti avere molti di questi, ma dovrebbero essere inferiori a quelli di oggetti di forma totale.
  3. Ora in ciascuno di questi oggetti di base, raggruppare insieme le funzionalità comuni (vale a dire il nome e le strutture di indirizzo, ecc.) E estrapolarlo nella propria gerarchia di classi, reinserire questa gerarchia nelle classi di base mediante l'iniezione del costruttore.
  4. Applicare il modello di composizione alla gerarchia della classe base ora e lavorare per ottenere il più possibile la struttura di classi comuni. Idealmente le tue forme a questo punto sarebbero semplicemente la funzionalità minima che è cambiata in ogni modulo e hanno un costruttore che prende tutte le funzionalità comuni (e forse leggermente diverse).
  5. Applicare il modello di modello ora per astrarre tutte le "funzionalità" comuni dalle classi, come convalida comune e logica di persistenza, utilizzare nuovamente il constructor injection per ripristinare questa funzionalità nelle classi di base.
  6. Estrai le definizioni dell'adattatore di interfaccia dalle tue classi base e usale come base per l'applicazione per lavorare con i tuoi moduli
  7. Costruisci le tue classi di fabbrica per gestire tutto il lavoro sgangherato di configurazione.

La speranza che ti dà alcune idee su cosa fare.

+0

Grazie, stiamo avendo la possibilità di ripensare il nostro design a causa di una potenziale revisione del modo in cui il governo federale sta facendo le cose.Questo schema ti aiuterà molto ad esplorare le possibilità –

+0

NP. E buona fortuna. avere l'abilità di raggiungere qualcuno altre agenzie come DHS (Human Services) o DIS (Immigration Services) hanno questo problema su vasta scala e potrebbero essere in grado di fornirti alcune buone informazioni. – GrayWizardx

+0

Mi sono imbattuto in questo perché ho iniziato a vedere le "date" nei nostri nomi di classe, vale a dire ClassA, ClassA20100901, ClassA20101201. Mi è stato spiegato come: ClassA è valido/usato fino al 1 ° settembre, quindi verrà utilizzato Class20100901, quindi il 1 ° dicembre l'ultima classe diventa attiva. Questo è un odore ENORME che qualcosa non va. Lo digerirò e lo proporrò alla squadra. Fornirò una risposta se dovessimo trovare qualche suggerimento. Grazie! –

2

Se l'ereditarietà non può essere utilizzata "perché i campi nel documento possono essere rimossi", come lo gestisci attualmente?

A seconda dei dettagli del progetto, dovresti essere in grado di sovrascrivere i campi non utilizzati dalla versione corrente del documento (ad es. Sostituirlo in una sottoclasse per quel documento) e lanciare NotSupportedException o simile nell'implementazione di tale metodo se il modulo tenta di assegnare un valore. Con una logica simile, puoi (e probabilmente dovresti) usare le interfacce ... solo sapendo che un'implementazione concreta può generare un'eccezione per una proprietà che implementa ma che non è definita per quella versione dell'interfaccia utente.

È possibile utilizzare Factory Pattern per restituire un'istanza appropriata dell'oggetto per la versione di modulo specificata.

Se c'è un po 'di comunanza tra il codice che è leggermente cambiato ma per lo più lo stesso, si può essere in grado di ridefinire parte di quella comunanza in un metodo privato/protetto che viene utilizzato da più metodi pubblici.

Come per la denominazione della classe, se si utilizza il modello di fabbrica è possibile fare riferimento alla classe nella maggior parte del codice utilizzando l'interfaccia. Solo la fabbrica stessa avrebbe dovuto occuparsi di nomi di classi dall'aspetto strano.

+0

"Se l'ereditarietà non può essere utilizzata" perché i campi nel documento possono essere rimossi ", come lo gestisci attualmente?" Questo non riuscirebbe a risolvere il problema delle classi che hanno troppe proprietà (dalle versioni precedenti che sono lasciate in retrocompatibilità) –

+0

Il modello di fabbrica sembra una soluzione plausibile, e dal momento che l'associazione dei dati accetta stringhe non avrà una forte digitazione errori del compilatore ... –

+0

@Aequitarum: la versione specifica dell'interfaccia utente presumibilmente non si collegherà ai campi che non sono appropriati per quella versione. Avendo la sottoclasse specifica della versione lanciare una NotImplementedException se una tale proprietà è associata dall'interfaccia utente dopo tutto aiuta Prendi subito in considerazione questi problemi –

0

Vorrei implementarlo in un modo molto più strettamente accoppiato - una classe contenente due campi: una versione e un dizionario. Quando i dati cambiano così tanto diventa molto noioso cercare di tenere traccia delle proprietà che vengono perse e aggiunte. Con un dizionario puoi semplicemente testare per vedere se la chiave esiste.