Qual è un buon design per consentire la retrocompatibilità dei file tra le diverse versioni del software?


14

Qual è un buon design per consentire la retrocompatibilità di un tipo di file tra diverse versioni del software?

Ad esempio, in che modo Microsoft ottiene Word 2007, 2010 e 2013 ecc ... in tutti i file docx aperti, ma diverse edizioni possono salvare più / meno dati e salvare i dati in modi leggermente diversi, tutti nello stesso tipo di file e un il file salvato in una versione può essere aperto in un'altra, ma alcuni elementi del file potrebbero non essere disponibili nelle versioni precedenti?

Voglio dire, il modo più ovvio per farlo è avere qualcosa di simile

private string openfile(string filename)
{
    File.Open(filename)

    ... some logic that gets a header from the file that will never change

    switch (fileversion)
        case 2007:
            .....
        case 2010
            .....
        case 2013
            .....
}

ma questo sembra incredibilmente monolitico, non molto estensibile e probabilmente porta a un sacco di codice copiato / incollato.

Quindi stavo pensando di utilizzare un'interfaccia di base per tutte le versioni che definisce le strutture immutabili, come l'intestazione, che devono essere presenti nel file e i metodi che devono essere disponibili per la serializzazione / deserializzazione, quindi l'ereditarietà multipla in modo che ogni la nuova classe di versione che implementa l'interfaccia eredita la vecchia versione e sovrascrive solo le cose che sono cambiate, poiché il file sarà lo stesso, per la maggior parte.

Non mi preoccupo molto della struttura del file, poiché è già deciso che useremo XML e lo schema iniziale è, in linea di massima, già deciso. Tuttavia, ci saranno senza dubbio modifiche in futuro, e voglio solo essere in grado di progettare il codice in modo da semplificare l'adattamento di queste modifiche.


6
È necessario progettare il formato del file in modo che non solo ignori le informazioni mancanti perché l'origine proviene da una versione precedente, ma anche le informazioni che non si aspetta perché l'origine proviene da una versione più recente. Se stai iniziando da zero, ti preghiamo di fare anche avanti la compatibilità . Non è quasi nessuno sforzo aggiuntivo e raddoppia l'utilità del tuo software.
Kilian Foth,

Su un open, saprai sempre in anticipo (ad esempio, dall'intestazione) con quale versione di file hai a che fare? Inoltre, per effettuare un'altra richiesta, si prega di verificare la presenza di file corrotti o dannosi e non lasciare che causino problemi. I tuoi amministratori di sistema ti ringrazieranno :).
Cxw,

1
Sì, il numero di versione sarà sempre nell'intestazione del file e il formato dell'intestazione non cambierà mai. Stiamo andando con l'idea che i file creati tra le revisioni software minori dovrebbero essere compatibili, vale a dire un file creato nella v1.1 può essere aperto nella v1.2 e viceversa, anche se alcune funzionalità dalla 1.2 potrebbero mancare in 1.1 ma revisioni importanti interromperà la compatibilità, quindi le cose scritte in v2 non si apriranno in v1, ma quelle scritte in v1 si apriranno in v2.
JJBurgess,

E per quanto riguarda la corruzione, i file contengono DSL e il programma che li apre / chiude è un IDE / compilatore interno personalizzato. Questi non andranno da nessuna parte vicino a un ambiente di produzione, quindi l'amministratore non deve preoccuparsi.
JJBurgess,

Risposte:


10

Potresti dare un'occhiata al formato di file PNG e come gestisce la compatibilità delle versioni. Ogni blocco ha un ID che descrive che tipo di blocco è, e ha alcuni flag che indicano al software cosa fare se non riesce a capire quell'ID. Ad esempio "non puoi leggere il file se non capisci questo blocco" o "puoi leggere il file ma non modificarlo" oppure "puoi modificare il file ma devi eliminare questo blocco". Per compatibilità con le versioni precedenti, il tuo software deve solo gestire la situazione quando non sono presenti dati previsti.


Grande idea! Il formato PNG si basa su funzionalità e non su versioni. Significa, tuttavia, che il formato di base non deve mai cambiare. (ovvero l'intestazione che definisce la funzione.)
Florian Margaine,

Interessante. Al momento sto leggendo le specifiche del file. Mi piace l'idea di pezzi critici e accessori, e potrei provare a lavorarci su.
JJBurgess,

3

Un modo per farlo può essere usando una classe base e un'interfaccia con le funzioni di base per la gestione dei file. Quindi utilizzare le classi per ciascuna versione che si estende dalla classe di base per gestire tutti i casi specifici della versione. Le funzioni che possono cambiare possono essere virtuali nella classe di base di abstract se sono presenti solo implementazioni specifiche della versione. Quando è necessaria una classe per gestire il file, utilizzare una factory che ottiene l'implementazione specifica della versione dell'interfaccia di gestione dei file.


Il mio unico problema con questo è che finiresti per duplicare l'implementazione specifica della versione per ogni revisione successiva. Supponiamo che tu abbia tre metodi di classe base: ReadNames (), ReadAges () e ReadAddresses () e in V2 della classe, apporti una modifica a ReadAges (). Se in V3, decidi di apportare una modifica a ReadNames (), se tutte le classi specifiche della versione ereditano dalla base, perdi le modifiche alla V2 o dovresti copiare / incollare le modifiche dalla V2 anche nell'implementazione V3.
JJBurgess,

1
L'implementazione di readages può chiamare una classe diversa che detiene l'implementazione effettiva su come leggere le età per questa versione. Fare la tua classe sarà più una configurazione di interfacce / fabbriche che una vera programmazione.
peer

2

L'ho fatto con XML e funziona bene:

Consenti semplicemente a qualsiasi elemento nel tuo documento di avere attributi e sottoelementi (e quando l'ordine non è importante - in qualsiasi ordine). A partire dalla prima versione del programma: durante la lettura del documento, ignora gli attributi e gli elementi secondari che non conosci nella versione corrente.

In futuro, quando si aggiungono nuove funzionalità alla nuova versione del programma, aggiungere l'attributo o l'elemento secondario. Le versioni precedenti lo ignoreranno. La nuova versione dovrebbe verificare la pressione dell'attributo o dell'elemento secondario e gestirla.

Ad esempio hai alcuni elementi con testi:

<item text="Hello, world!"/>

E nella versione più recente desideri aggiungere colore all'elemento in modo da aggiungere l'attributo color:

<item text="Hello, world!" color="008000"/>

La versione precedente ignorerà semplicemente l' colorattributo all'apertura del documento. Le nuove versioni verificano la pressione colordell'attributo e, se non esiste, assegna il colore predefinito.

Con questa semplice soluzione avrai compatibilità sia all'indietro che in avanti.


Il leggero problema con questa opzione "semplice" è che toglierai tutti gli attributi imprevisti (o li manterrai invariati) quando salvi il documento. Come menzionato in altre risposte, una soluzione migliore determina almeno in qualche modo agnostico se un attributo debba essere lasciato cadere, conservato o fatto in modo che il documento diventi di sola lettura per le versioni che non lo comprendono.
Mark Hurd,

@Mark Hudr: Sì, presumo silenziosamente che la compatibilità con le versioni precedenti sia obbligatoria e che la compatibilità con le versioni successive sia un bonus. Quando qualcuno apre un nuovo documento nella vecchia versione delle applicazioni, non dovrebbe essere sorpreso dal fatto che quando lo salva, ha perso qualcosa che non è già visibile nella vecchia app. Altre logiche mi sembrano troppo ingegnerizzate.
user3123061
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.