Snapshot

A view of an object at a point in time

07 March 2004

This is part of the Further Enterprise Application Architecture development writing that I was doing in the mid 2000’s. Sadly too many other things have claimed my attention since, so I haven’t had time to work on them further, nor do I see much time in the foreseeable future. As such this material is very much in draft form and I won’t be doing any corrections or updates until I’m able to find time to work on it again.

How it Works

A Snapshot is simply a view of an object with all the temporal aspects removed. So if the full temporal object has an accessor in the form getAddress(date) then the snapshot will have an accessor getAddress(). All questions of a snapshot are non-temporal.

When you create a snapshot, you need to supply an appropriate date. If Bi-temporality is present, then you'll need both actual and record dates.

Snapshots are a view to help accessing, so in most cases they should be immutable. An exception to this is where you might update a snapshot and then apply it back to the real object as at some date. This is not something that I'd do very often, and usually only when working with an external system that isn't aware of temporality.

When to Use It

Temporality adds a good bit of complexity to a design and there are times when you don't want to take that into account. Maybe you are in a context where the you want to do a good bit of work with respect to a particular timepoint and you don't want to keep reminding the system which timepoint you're dealing with. Or maybe you are linking to a system that doesn't understand temporality. Then you can take a snapshot for use with that system.

Further Reading

This pattern was crystalized for me when collaborating with Andy Carlson on our plop paper.

Example: Implementing Snapshot (Java)

Putting together a snapshot is really quite straightforward. The key is to use delegation so that the snapshot acts as an adaptor on the underlying object.

Figure 1: Using delegation to implement a snapshot

class Customer...

  private TemporalCollection addresses = new SingleTemporalCollection();
  public Address getAddress(MfDate date) {
    return (Address) addresses.get(date);
  }
  public Address getAddress() {
    return getAddress(MfDate.today());
  }
  public void putAddress(MfDate date, Address value) {
    addresses.put(date, value);
  }

class CustomerSnapshot...

  private Customer base;
  private MfDate validDate;
  public CustomerSnapshot (Customer base, MfDate validDate) {
    this.base = base;
    this.validDate = validDate;
  }
  public Address getAddress() {
    return base.getAddress(validDate);
  }

Notice in this case that you create a snapshot by calling the constructor on the CustomerSnapshot supplying the customer and the actual date. You can also do this by calling a createSnapshot(Date) method on the Customer. Using the constructor allows you to avoid a dependency from the Customer to its snapshot.