Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What versioning design pattern would you recommend

I have a requirement to build 'versioning' into an application and was wondering how best to approach it.

I have this general pattern:

Model A has many B's

Where on update the attributes of A need to be versioned and its associated objects (B's) also need to be versioned. So the application will display the current version of A, but it must also be possible to view previous versions of A and its associated objects.

I would like to use a document store however this is only a portion of the application and having a doc store and a relation database would introduce more complexity.

I have considered using a star schema, but before I progress I was wondering if there is a design pattern floating around tackling this problem?

This question is slanted towards resolving the issue of storing the versions of an associated object in a relational database. Where there is an inherent need to be able to effectively query the data (ie serializing object won't suffice).

Update: What I was thinking/have implemented but want to see if the is "a better way"

,---------. 1      * ,--------.
| Model A |----------| Model B|
`---------'          `--------'
|PK       |          | a_id   |
|b_version|          |version |
|version  |          `--------'
`---------'

Where I would be duplicating model A and all the associated B's and incrementing the version attribute. Then doing a select to join the B's via b_version and b.version. Just wondering if this can be done better.

like image 795
MatthewFord Avatar asked Feb 17 '09 16:02

MatthewFord


4 Answers

Martin Fowler has some good articles on time/versioning-based design patterns - definitely worth a look:

http://martinfowler.com/eaaDev/timeNarrative.html

like image 185
Martin Dow Avatar answered Nov 12 '22 11:11

Martin Dow


I don't think there is no specific GoF design pattern per se for versioning because there exists many implementations of it.

The most simple implementation of versioning is a linked list of objects. Where each node in the list is a new revision of whatever the versionable object is. To save space you also implement some kind of a diff that shows what the difference is between the revisions. That way you can store diffs in the database, but also the final version of the versionable object since the version control system should be able to derive the versions in between.

The database schema could principally look something like this (you can see this pattern in most wiki systems):

+--------------------+ 1     * +-----------------------------+
| VersionableObject  |---------| Diff                        |
+--------------------+         +-----------------------------+
| lastStateContent   |         | difference                  |
| originalAuthor     |         | revision                    |
| #dates and whatnot |         | # userId, dates and whatnot |      
+--------------------+         +-----------------------------+

If you want to go hardcore with branching and stuff you might want to consider have a look at DAG which is what modern distributed version control systems use.

Now if we talk about your example a whole slew of objects that needs to be saved in configurations. I.e. we have to pick out the revisions of objects that we want for the model. It means we have a many to many relationship (which is solved with an intermediary table), sort of like this:

+---+ 1   * +---------------+ 1   * +-----------------+ *   1 +-------+
| B |-------| Diff          |-------| ModelSelection  |-------| Model |
+---+       +---------------+       +-----------------+       +-------+
            | revisionNo    |       | {PK} configId   |
            | {FK} configId |       | {FK} modelId    |
            +---------------+       +-----------------+

I hope this helps.

like image 30
Spoike Avatar answered Nov 12 '22 12:11

Spoike


I've solved this problem in rails by using the acts_as_versioned plugin. When you apply it to a model, it assumes there is a model_name_version in addition to the model_name table. Every time a model is saved, the old version along with a timestamp is copied into the model_name_version table.

This approach keeps the size of the model table manageable while still allowing search on previous versions. I'm not sure the plugin handles the chaining you want out of the box, but it wouldn't be hard to add.

like image 2
Sarah Mei Avatar answered Nov 12 '22 12:11

Sarah Mei


A combination of the Memento pattern with the Observer pattern should fit your needs. Also have a look at the Visitor pattern for possible application in your case...

like image 1
Kosi2801 Avatar answered Nov 12 '22 10:11

Kosi2801