Real-life clients often think that digital event management is akin to filling in a huge paper calendar sheet. For such a traditional paper calendar, you were the event schedule: You kept in mind when and how often an event would recur. You would find the fitting dates in the calendar, mark them for you event, and add some data. If you had to move one event date (or made a mistake adding it), you would just add an arrow from the old date to the new, correct one, and maybe highlight it. If some event detail changed, you’d cross it out, and write in the new detail next to it. Perhaps this didn’t look pretty and might even have become confusing over time with too many changes. But you could always freely move things around without thinking too much about them.
When we use digital instead of paper calendars to plan an event, it’s not enough for you to have its schedule on your mind. The computer needs to know it too, otherwise it can’t display its dates and details in the calendar. A schedule represents date-based information about an event: at the very least, it’s start date and time, duration, and how it recurs, whether that’s not at all for a one-off, on completely random dates, or according to a set interval like “every week”. We can say, one of the invariants of digital event management is that an event needs a schedule. When we develop an application to manage events or appointments, we must ensure that events always have a schedule no matter what we do with them.
When we schedule recurring events, we might also want to add information to certain dates in a series that differs from the root event data. Session titles, substitution teachers, guest DJs, or moving to a different room in the building come to mind. We call these differences “overrides”. Remember that with a paper calendar, all you had to do with “overrides” like a room change was find the concerned date, write in the room number, and highlight it to make sure people would find your event.
With a computer calendar, this is not as easy as slopping on correction fluid and writing in new details anymore. Event scheduling and changing the room number for a specific occurrence are completely different concerns. The schedule does not really care about your event happening in room 101 instead of 111 next time. Room 101 does not need to know that the event usually takes place in room 111 either.
Yet somehow both schedule and recurrence detail still need to communicate about whether they fit together. Not only does it not make much sense to move the event to a different room on a date that does not even belong to the event series. It would also render the entire event inconsistent: If you made a mistake and noted the room change for a Friday although the event runs on Thursdays, the event would suddenly have both its regular scheduled dates and an irregular date for the room change that does not fit its schedule. At the very least, this would lead to wrong calendar displays. At worst, people might book tickets for those wrong dates. Here we have a hidden invariant: Event data overrides for single dates must always match the event schedule.
If this sounds trivial to you, ask yourself: What happens if the user changes the entire event schedule with the room change for a future date already added? Let’s say they move it from Thursdays to Fridays. Now the event runs weekly on Fridays but the overriding data is for a Thursday. We have created exactly the inconsistent situation described above.
You might say, that’s easy, the room change probably doesn’t apply anymore because the event runs on a different weekday now. And this might be true. Or it might not. If we move away from the room change to a teacher change, for example a teacher substituting for the regular one who’s fallen ill, in all likelihood that teacher would replace the regular one on all days that week and needs to be kept as “overriding data”.
Evading the problem never works
You might think: Let the user solve this problem. We’ll simply flag mismatching override dates and have the UI nag the user to correct them. At some point schedule and recurrence data will eventually become consistent. The problem with this is that eventually in this case can be a very long, if not indefinite period of time. What if the user never corrects the mismatching recurrences? When do you force-delete them? And what happens with the mismatching dates in the meantime?
For every time someone queries event recurrences for a calendar or programme, you would have to filter flagged, mismatching data overrides to avoid double entries. That’s not ideal. You’d wind up writing quite complicated data-to-recurrence mappers for your representation classes1. But it isn’t really a representation’s job to correct out-of-sync aggregates that shouldn’t exist to begin with. Neither should you ever trust the front-end that it gets things right. If you develop a WordPress plug-in instead of doing client work, chances are that users would ignore your carefully filtered representations and resort to ordinary queries and WP_Post objects instead, and these know nothing about “right” and “wrong” dates.
Guesswork
As an in-between solution you might try to add some logic that tries to “guess” the new date of a teacher or room change when the event schedules changes. This seems easy enough if you simply move a weekly recurrence on Thursdays to Fridays.
It gets slightly creepy when you reverse the direction and shift the schedule from Fridays to Thursdays. Nearly all ways to calculate recurrences are forward-facing. That’s because we can live into the future but not travel back in time (bummer, I know). Technically speaking, with event series we only know the start date and either a number of recurrences or an “until” date, which is an arbitrary boundary and does not have to be consistent with schedule days. In other words, you cannot calculate backwards from the “until” date. Unless you always calculate all recurrence dates for a given event, which you should never do2, counting backwards would mean bloating whatever part of your software handles recurrence calculations with new “backwards” options — options you will likely never need again in you software. Unless you offer time travel, of course.
If this hasn’t given you goose bumps yet, think about schedules with different intervals, going from weekly to bi-weekly or changing the schedule entirely from every Friday to “the last Friday of the month”. You’d wind up with less recurrences than you have overrides. How would you decide which to keep and which to dump?
At this point this article might have tired you quite a lot and you’re thinking but Kat…
If it’s this complicated: Is it even a thing?
“Is it even a thing” is a great question to ask after pondering the “what ifs”. More often than not you might discover that you have framed a problem the wrong way and that the “what ifs” goes away, if you approach the problem with a different mindset.
Unfortunately, the answer in this case is yes, this is a thing. Schedule changes are quite rare, but they do happen. Room or staff availability as well as low attendance rates might force a provider to change an event schedule midterm.
If schedule changes can really happen, another great and valid question ensues: If its schedule changes, is an event really still the same event? Couldn’t we simply start a new event series?
The answer is: It depends on the nature of your event domain. For instance, if you have an educational course that gives certification to people who attended at least 90% of all sessions, it always has to keep its identity. You need to know the number of course sessions, not their precise dates and possible substitution teachers, to calculate eligibility for certification and to check attendance. Such a course cannot simply be ended midterm and replaced with another event because its schedule has changed.
On the other hand, if you have a series of concerts that already have bookings for each recurrence, by all means, do lock it. In case of a schedule change, the decent thing to do is cancelling the remaining recurrences, giving people their money back, creating a new event series, and notifying them to book for one of the new dates.
Implementing aggregate consistency
No matter which of the following options you choose, it is quite clear at this point that recurrence overrides must never be saved without checking their fit with the event schedule, so you can keep scheduled recurrences and data in sync. Scheduling an event and adding data overrides for specific recurrences are separate concerns but they still need to succeed or fail together. This remains an invariant.
Lock it down
If an event has been scheduled and if there are data overrides for future recurrences, the event cannot be rescheduled unless those overrides are removed first. In some cases, a user would have to re-enter many overrides even though the schedule change is comparatively simple, e.g. when extending an event series without changing its recurrence pattern or when you add new custom dates to an event with arbitrary recurrences. You would think that at the point in time at which you extend a series, most of its original recurrences have already happened. How much would there be to re-enter? But then users might simply want to correct a wrong until date and find that they have to add data for 10 recurrences again.
Warn and discard
If an event with data overrides is rescheduled, check if future overrides match the new pattern. Keep those that do, discard those that don’t. This is great for cases when a user just wants to extend an event series with a new “until” date since all event data will be preserved. After all, it still matches the recurrence pattern.
It’s quite bad though for a user who innocently changes a schedule and on reload finds that, poof, all recurrence data is just gone. In the UI, you can make it harder though not impossible to reschedule events with existing data and add appropriate warnings. But if you retrieve data from external calendar ical feeds, that’s not possible and would inevitably lead to unexpected results. The “lock it down” option might be more appropriate for automatic.
Summary
I hope that this article has shed light on the importance of really thinking through business cases and applying domain-driven design principles to implement them consistently.
What we have learnt:
We found an invariant: In digital events management as opposed to analogue calendars, events need to have schedules and always need to be saved with their schedules.
We discovered a hidden business rule: Scheduling an event and adding data overrides for specific recurrences are separate concerns but they still need to succeed or fail together. We must ensure that the date for a room or teacher change is a valid event series date.
We realised that rescheduling an event might lead to mismatching data overrides. We also found out that eventual consistency is not a good solution for handling mismatching recurrence and data override dates because it would lead to inconsistent calendar output.
We drew a transactional boundary, i.e. one big step of always creating (or changing) the event along with its schedule and data overrides. We decided to use the event entity as an aggregate root.