I was writing some code that had to deal with calendar stuff (which is always a pain), and I came across a very subtle bug that I didn’t notice at first. It caused a lot of head scratching.
The scenario was this — I needed to write code that would schedule things daily. However, the catch was that it shouldn’t be scheduled on holidays nor weekends.
My first iteration was pseudocoded like this:
get_next_crontime(cron_sched, base_time, skip_holiday, skip_weekend):
next_time = compute_next_time(base_time, cron_sched)
while(skip_holiday and next_time is a holiday):
next_time = compute_next_time(next_time, cron_sched)
while(skip_weekend and next_time is a weekend):
next_time = compute_next_time(next_time, cron_sched)
See the issue?
It just so happened that on MLK day, I noticed that a task was scheduled when I expected it not to be. The reason for this was that, on Friday, the code executed and we’d skip the first while block, since the next day was not a holiday. We’d then go into the second while block, realize that Saturday and Sunday are weekends, and end up with Monday (MLK Day, a holiday) being the next day in line. However, in reality, these two statements needed to be combined, even though it felt like these flags should be separate. Combined, they would skip all the way until Tuesday.
Just made me think about how even if you do “everything right” (TDD, proper unit testing, succinct feature flags), and even if you’ve been writing code for a while, the simplest of bugs can sneak in. I got really lucky that the timing lined up this time, but it’s a good reminder to plan for the unexpected.