Effectivity

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

Many facts are true only for a certain period of time. So an
obvious way to describe these facts is to mark them with a period of
time. For many that period is a pair of dates, however Range can be used here to make that date range an object.

Once defined, effectivity ranges are then used in queries to
return the appropriate objects that are effective on a certain date.

The effectivity range if often updated directly, however it
usually makes sense to provide an interface that better fits the
need of the class. A creation method can take the start date of the
effectivity period, and then use an open-ended Range to indicate there is no end date: this fits cases
where something is set to be created on a certain date and is
effective until further notice. When that further notice comes, you
can have a method that indicates that the object is no longer
effective and the date that occurs

Using the employment example suggested in the sketch, we have a
person, Wellington. On Dec 12 1999 he begins employment with India
Inc, which we represent by creating an employment object ( Figure 1). As time continues he starts a new
employment with Peninsula Inc on April 1 and ends his employment
with India Inc on May 1. Figure 2 shows
the state of the objects after these events. Notice that this means
that during April he was employed by both.

Figure 1: With a single employment

Figure 2: One employment ended, another
begun

This update mechanism handles additive updates,
that is updates that occur in the right order on the time line. In
many cases additive updates are all you need. Sometimes, however,
you need retroactive updates, effectively correcting mistakes in the
timeline. Say we discover later that Wellington actually worked for
Dublin Inc during May and didn't start with Peninsula Inc until June
1. We have to alter the effectivity on the employment for Peninsula
and add a new employment for Dublin to yield the state described in
Figure 3.

Figure 3: After adding the Dublin Inc
employment

This usually requires a more primitive
interface that allows employments have their effectivity ranges
changes directly.

Supporting retroactive changes is often important, since people
do make mistakes. We can add that by having direct access to the
effectivity date range.

Adding bi-temporal support is, in a sense, pretty simple - you
just add another date range. Of course the complexity is passed to
the users of the class who now need to use both dates all the time
in their queries and updates.

When to Use It

Effectivity dating is the most common way to indicate temporality
in modelling. It's simple and easy to understand its usage. It's
principal disadvantage is that it requires the client to be aware of
these temporal aspects and take them into account while processing.
So any query that wants to look at current information needs to add a
clause in its logic to test the effectivity range. While this is not a
very onerous requirement it does make things more tricky, particularly
when the temporal responsibility is not obvious from the domain.

It's possible to build structures that remove much of this
responsibility and thus make the temporal issues more transparent - so
that you only need to worry about them when you specifically need
to. To do this for a property at a time you can use Temporal Property. To do this for a whole object you can use
Temporal Object. Both of these more sophisticated
patterns handle much of the temporal logic, reducing the burden on the
clients of these objects.

So use Effectivity when you have a simple situation for temporal
behavior, and it makes sense in the domain that those objects should
be temporal. In an object implementation you should ensure you
actually use Range for the effectivity range, as
that is much easier than using pairs of dates.

Example: Employments (Java)

These code examples parallel the cases I talked about in the how
it works section. I'll start with simple named object classes for
person and company.

A good object designer may wonder if that
for loop should really be moved into a method on the Person
class. Indeed it should, and that's the driver for the Temporal Property pattern. Well see the consequences of such
a move there, so I'll continue to use the for loop in fragments for
this pattern.

Now let's look at the retroactive changes. For these we need some
more primitive behavior on employment and person.

Retrospective changes aren't always needed but they usually are -
after all people are known for making mistakes. Making a
retrospective change usually requires this kind of more primitive
interface than an additive change, so there's an argument that you
don't need the separate interface for an additive change. However I
prefer to include it, as it makes it easier to do the most common
additive changes. After all we're not looking for the smallest
interface, but the easiest to use. Small helps ease of use (since
there's less to learn) but it's only one factor, not the dominant
one.