Skip to content
This repository has been archived by the owner on Nov 3, 2018. It is now read-only.

Practical Application Guidance

Matt Johnson edited this page Jan 26, 2013 · 3 revisions

Temporal Versioning is a great tool to have in your toolbox, but it is not a panacea. It is best applied to entities where there is meaningful business value to tracking changes - beyond just an audit trail. If all you need is an audit trail, use RavenDB's standard versioning bundle instead.

An easy use case to understand is for tracking changes in a payroll system.

public class Employee
{
    public string Id { get; set; }
    public string Name { get; set; }
    public decimal PayRate { get; set; }
}

The employee's name could change, such as often happens after a marriage. The employee's pay rate could change, such as often happens with promotion or demotion. Employee is a great candidate for Temporal Versioning, because we may need to reference the name and pay rate that were effective at a particular date - such as writing a new paycheck without invalidating a payrate from an old paycheck. With Temporal Versioning applied, we do not have to create other entities in our domain to model this changing data.

Sometimes we may have properties in our temporal entities that we don't care about tracking, either because they can't change (such as BirthDate), or because we don't care about the changes (such as FavoriteColor). If there are just a few of these, then tracking them along with the other temporal data is just fine. However, if you find there are many non-temporal properties and only a few temporal ones, then you may want to split these into separate documents.

We also don't want to forget another tried-and-true technique - point-in-time-duplication. An easy use case for this is an online ordering system.

public class Product
{
    public string Id { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
}

public class Order
{
    public string Id { get; set; }
    public DateTimeOffset OrderDate { get; set; }
    public OrderLine[] Lines { get; set; }
    public decimal Total { get; set; }
}

public class OrderLine
{
    public string ProductId { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

The only class here that should be temporal is the Product. It could have temporal changes to its price, to reflect pricing changes, or to discontinue (delete) the product.

Order and OrderLine are NOT good candidates for Temporal Versioning. Each OrderLine class gets a copy of the price that was in effect at the time the order was placed. This price never changes. Sure, we could look up the price from the Product temporally - but this would make even simple lookups much more complicated than they would need to be.

If one looks carefully at various other scenarios, a pattern emerges. Point-in-time-duplication should be used when there is some other contextual time reference. In this case - it's the OrderDate. Temporal Versioning is a way to add a time context where none exists. So if you're unsure where to use it, ask yourself if the Aggregate Entity already has its own concept of time or not.