Quelle est la bonne conception pour permettre la compatibilité descendante des fichiers entre les différentes versions du logiciel?

14

Quelle est la bonne conception pour permettre la rétrocompatibilité d'un type de fichier entre différentes versions de logiciel?

Par exemple, comment Microsoft obtient-il Word 2007, 2010 et 2013, etc. dans tous les fichiers docx ouverts, mais différentes éditions peuvent enregistrer plus / moins de données et enregistrer les données de manières légèrement différentes, toutes dans le même type de fichier, et un le fichier enregistré dans une version peut être ouvert dans une autre, mais certains éléments du fichier peuvent ne pas être disponibles dans les anciennes versions?

Je veux dire, la façon vraiment évidente de le faire est d'avoir quelque chose comme

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

mais cela semble incroyablement monolithique, peu extensible et susceptible de conduire à beaucoup de code copié / collé.

Je pensais donc à utiliser une interface de base pour toutes les versions qui définit les structures immuables, telles que l'en-tête, qui doivent être présentes dans le fichier, et les méthodes qui doivent être disponibles pour la sérialisation / désérialisation, puis l'héritage multiple afin que chaque La classe de la nouvelle version qui implémente l'interface hérite de l'ancienne version et ne remplace que les éléments qui ont changé, car le fichier sera le même, pour la plupart.

Je ne suis pas vraiment dérangé par la structure du fichier, car il a déjà été décidé que nous utiliserons XML, et le schéma initial est, dans l'ensemble, déjà décidé. Cependant, il y aura sans aucun doute des modifications à l'avenir, et je veux juste être en mesure de concevoir le code d'une manière qui facilite la prise en compte de ces modifications.

JJBurgess
la source
6
Vous devez concevoir le format de fichier de manière à ce qu'il ignore non seulement les informations manquantes car la source provient d'une version antérieure, mais également les informations auxquelles il ne s'attend pas car la source provient d'une version plus récente. Si vous partez de zéro, veuillez également faire la compatibilité ascendante . Ce n'est presque pas un effort supplémentaire et double l'utilité de votre logiciel.
Kilian Foth du
Sur une ouverture, saurez-vous toujours à l'avance (par exemple, à partir de l'en-tête) quelle version de fichier vous avez affaire? De plus, pour faire une autre demande, veuillez vérifier les fichiers corrompus ou malveillants et ne pas les laisser causer de problèmes. Vos administrateurs système vous remercieront :).
cxw
1
Oui, le numéro de version sera toujours dans l'en-tête du fichier et le format de l'en-tête ne changera jamais. Nous partons de l'idée que les fichiers créés entre des révisions mineures du logiciel devraient être compatibles, c'est-à-dire qu'un fichier créé dans la v1.1 peut être ouvert dans la v1.2 et vice versa, bien que certaines fonctionnalités de 1.2 puissent être manquantes dans 1.1 mais des révisions majeures rompra la compatibilité ascendante, donc les choses écrites en v2 ne s'ouvriront pas en v1, mais les choses écrites en v1 s'ouvriront en v2.
JJBurgess
Et en ce qui concerne la corruption, les fichiers contiennent DSL, et le programme qui les ouvre / les ferme est un IDE / compilateur interne personnalisé. Ceux-ci n'iront nulle part près d'un environnement de production, donc l'administrateur n'a pas à s'inquiéter.
JJBurgess du

Réponses:

10

Vous pourriez avoir un aperçu du format de fichier PNG et de la façon dont il gère la compatibilité des versions. Chaque bloc a un identifiant décrivant de quel type de bloc il s'agit, et il a des indicateurs qui indiquent au logiciel quoi faire s'il ne peut pas comprendre cet identifiant. Par exemple, "vous ne pouvez pas lire le fichier si vous ne comprenez pas ce bloc", ou "vous pouvez lire le fichier sans le modifier" ou "vous pouvez modifier le fichier mais vous devez supprimer ce bloc". Pour une compatibilité descendante, votre logiciel a juste besoin de gérer la situation lorsque aucune donnée attendue n'est présente.

gnasher729
la source
Bonne idée! Le format PNG repose sur des fonctionnalités et non sur des versions. Cela signifie cependant que le format de base ne doit jamais changer. (c'est-à-dire l'en-tête définissant la fonctionnalité.)
Florian Margaine
C'est intéressant. Je lis la spécification du fichier en ce moment. J'aime l'idée de morceaux critiques et auxiliaires, et je pourrais essayer de travailler
dessus
3

Pour ce faire, vous pouvez utiliser une classe de base et une interface avec les fonctions de base pour la gestion de vos fichiers. Utilisez ensuite des classes pour chaque version qui s'étendent à partir de la classe de base pour gérer tous les cas spécifiques à la version. Les fonctions qui peuvent changer peuvent être virtuelles dans votre classe de base d'abstrait s'il n'y a que des implémentations spécifiques à la version. Lorsque vous avez besoin d'une classe pour gérer le fichier, utilisez une fabrique qui obtient l'implémentation spécifique à la version de l'interface de gestion des fichiers.

pair
la source
Mon seul problème avec cela est que vous finiriez par dupliquer l'implémentation spécifique à la version pour chaque révision suivante. Disons que vous avez trois méthodes de classe de base: ReadNames (), ReadAges () et ReadAddresses () et dans la V2 de la classe, vous apportez une modification à ReadAges (). Si dans la V3, vous décidez ensuite d'apporter une modification à ReadNames (), si toutes vos classes spécifiques à la version héritent de la base, vous perdriez vos modifications V2 ou vous auriez besoin de copier / coller les modifications de la V2 dans la mise en œuvre V3 ainsi.
JJBurgess
1
L'implémentation des lectures peut appeler une classe différente qui contient l'implémentation réelle sur la façon de lire les âges pour cette version. Faire votre classe sera plus une configuration d'interfaces / usines qu'une programmation réelle.
pair
2

Je l'ai fait avec XML et cela fonctionne bien:

Permettez simplement à n'importe quel élément de votre document d'avoir des attributs et des sous-éléments (et lorsque l'ordre n'est pas important - dans n'importe quel ordre). À partir de la première version du programme - lors de la lecture du document, ignorez les attributs et sous-éléments que vous ne connaissez pas dans la version actuelle.

À l'avenir, lorsque vous ajouterez une nouvelle fonctionnalité à une nouvelle version du programme, ajoutez un attribut ou un sous-élément. Les versions plus anciennes l'ignoreront. La nouvelle version doit vérifier la pression de l'attribut ou du sous-élément et gérer avec.

Par exemple, vous avez certains éléments avec des textes:

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

Et dans une version plus récente, vous souhaitez ajouter de la couleur à l'élément afin d'ajouter un attribut color:

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

La version antérieure ignorera simplement l' colorattribut lors de l'ouverture du document. Les nouvelles versions vérifient la pression de l' colorattribut et s'il n'existe pas, attribue la couleur par défaut.

Avec cette solution simple, vous aurez à la fois une compatibilité ascendante et descendante.

user3123061
la source
Le léger problème avec cette option "simple" est que vous supprimerez tous les attributs inattendus (ou les conserverez inchangés) lors de l'enregistrement du document. Comme mentionné dans d'autres réponses, une meilleure solution détermine au moins d'une manière indépendante de la version si un attribut doit être supprimé, conservé ou faire en sorte que le document devienne en lecture seule pour les versions qui ne le comprennent pas.
Mark Hurd
@Mark Hudr: Oui, je suppose silencieusement que la compatibilité descendante est indispensable et que la compatibilité descendante est un bonus. Lorsque quelqu'un ouvre un nouveau document dans une ancienne version des applications, il ne devrait pas être surpris que lorsqu'il l'enregistre, il ait perdu quelque chose qui n'est pas déjà visible dans l'ancienne application. Des logiques supplémentaires me semblent trop développées.
user3123061