Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
A Modified Snapshot Pattern

I thought I'd share a solution and ideas around a problem that seems to come up from time to time in past systems I've built. I'll walk you through the implementation of a modified Snapshot Pattern in C#.

First off, what is the Snapshot pattern, and why would we use it? Put simply, a Snapshot is the concept of giving date/time context to an object, so that a current time period is factored in to any queries or commands we send to it. Here's an example of a simple problem that it can solve:

Say we have a Product object, which generically represents something that a person can purchase from an online store. A Product has both Name and Price properties. The problem is that the Price of a Product can change over time. We want to be able to ask the Product its Price for any possible date, and have it return the Price as it stood at that time. We do not want to have to pass around a DateTime parameter all over the place, however.

The following diagram shows us how we want the code to end up looking:

There are three main objects that form the backbone of our modified Snapshot pattern:

  • Master: This object is persistent, and holds any data that does not change over time. In our little example with Products, the Name property would hang off a Master class. The Master holds a list of many Details, which I explain next...
  • Detail: This object is also persistent, however it holds any data that may change over time. This is where our Price property lives. You'll notice that the Detail contains StartDate and ExpiryDate properties, which represent the time period during which it is valid.
  • Snapshot: This is a non-persistent object that holds exactly one Master, and one Detail. The Snapshot object delegates its calls to persistent data to both the Master and Detail of which it is composed. It also holds all our business logic.

Our code for the Product scenario ends up looking like so:

ProductMaster.cs

ProductDetail.cs

Product.cs

The important thing to remember is that within our domain we only want to work with the Snapshot implementation, not the master or the detail. Once we've constructed a Snapshot using the Master.CreateSnapshot(date) method, we're good to go.

Hopefully this makes sense. I've used this pattern in two projects now, and very heavily on my current project. It helps to clean up the code base by removing a whole bunch of GetPrice(date) type methods, and frees the developer from having to think about time when utilizing an object. It does require some discipline, however, to ensure you don't get business logic creeping in to the Master and Detail classes.

I've also included the code, with some unit tests that you can download.


Posted 11-16-2006 6:33 PM by Jeff Perrin
Filed under: , ,

[Advertisement]

Comments

BigJimInDC wrote re: A Modified Snapshot Pattern
on 11-17-2006 11:18 AM

Read the first book listed here:

http://www.cs.arizona.edu/~rts/publications.html

Billy McCafferty wrote re: A Modified Snapshot Pattern
on 11-17-2006 11:22 AM

Jeff,

Great post and interesting approach...I'll have to try this out against Fowler's original overview.  I'm sure you've seen this, but for others who haven't, the following is a good article for viewing the snapshot pattern from a larger context:  http://www.martinfowler.com/ap2/timeNarrative.html

Vladimir Levin wrote re: A Modified Snapshot Pattern
on 12-15-2006 3:02 PM

This looks good. I wonder if there is any way to further simplify by somehow removing the need to duplicate all of the method calls in the snapshot that delegate to the corresponding master or detail method.  I think you could do it in Ruby - which is interpreted - by catching the excepton generated by a call to a method that doesn't exist... maybe that's too obscure though...

Jeff Perrin wrote re: A Modified Snapshot Pattern
on 12-16-2006 12:15 PM

Hey Vlad!

I agree that there's lots of overhead involved in delegating all the property calls on the Snapshot to the Master and Detail. On a project like ours, you don't even notice it because there's far more business logic in our classes than property declarations. On a smaller project, the overhead may not be worth it. Needless to say, the "Ruby Way" won't work in C#, but it sure would in Ruby.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)