Help Santa Klaus Reward Only Nice Children
Once Upon A Time
It's 2016, and near the North Pole in Scotland, Santa Klaus is having his annual financial review. And it doesn't look great.
Santa realises he needs to reduce his costs from now on, and so decides to only reward children who have been nice throughout the year, as opposed to lavishly rewarding even the naughty ones as he's done for decades past.
After consulting with the senior elves, Santa decides to implement a child niceness assessment process over the year:
- In February, all parents receive a letter from Santa including a report form for them to fill in.
- The due date for the report form is the 1st of November.
- If no form has been received, the child is considered naughty.
- Each completed form is assigned to an elf for assessment (the assessment process is another story).
Santa's elves are not very enthusiastic about implementing this in Perl, with all the code required to track if the parents have filled in the forms or not and building the logic to trigger the right part of their existing code base at the right time. How do they design these processes so to minimize the mess? How will they unit test that so things don't randomly fail in the future?
'Stop panicking!' says Rudolf, head of Santa's programming sweatshop. 'I've found Schedule::LongSteps on the CPAN!'
Schedule::LongSteps is a small framework that enables you to program the future with confidence.
Let's Help Santa Implement!
For this example implementation, we'll assume we have an object
$santaHQ that represents Santa's business and all the wonderful things it can do. We're going to concentrate on creating example module that manages the process spelled out above.
In Schedule::LongSteps, the process we are modeling is simply modeled as a class that extends Schedule::LongSteps:
Each actual process model is an instance of this that maintains a state. The state of the process serves both as the place to give the process parameters and the place that stores the current work in progress. It must only contain 'pure Perl' data, so no objects.
Schedule::LongSteps stores this state between executions of the code in what is known as a Storage. This pluggable storage system allows Schedule::LongSteps to store data for you in various ways, typically in a SQL database.
Before we flesh out the My::Process::NicenessFeedback module, let's look at how we might instantiate it with the Schedule::LongSteps module:
We've passed in two hash refs. The first is the parameters that need to be passed to My::Process::NicenessFeedback when Schedule::LongSteps instantiates it - in this case the
$santaHQ that holds all of our underlying business logic. The second hashref contains the initial state we want to assign to the object.
This state will be accessible inside our object using the
state method, and while the state has to be a pure Perl data structure we can use builder methods to populate attributes with more complex objects:
The process now has a child!
We can now define what it should do first. For this, we first implement the (mandatory) method 'build_first_step' method:
This will cause Schedule::LongSteps to schedule the
do_send_form_to_parents step as the first step to be run for this instance. We also set the time when the step will become available to be executed with the
run_at parameter. We'd better implement the code for the steps in our class next...
Steps in the process are implemented as methods. The convention is to name them with the prefix 'do_', to avoid any possible conflict with future methods.
Note that each step either schedules the next step or calls
final_step to indicate we're done. Along the way we modify the state we store as we pick up new details of things we need to keep track of - like the form_id - that we need to populate our attributes again.
'Wait, wait, wait,' says one of the elves. 'This is supposed to happen in the future. How do we make sure today that this process will work?'
Well, this is where unit testing comes into play. Here's how to write a test:
'By Odin, Rudolf, this is jolly good,' Santa says enthusiastically. 'So I just need to run
$longsteps->run_due_process() from time to time?'
'That's right,' Rudolph replies. 'We'll put it in a cron job or an Event loop watcher, and we're good to go. We don't even need to worry about concurrency, so we can have as many machines as we want doing it.'
Santa looks thoughtful. 'And next year, maybe we can also use this to automate the gift-returning procedure...'
Of course there is no Santa Klaus, and this code has not been tested anywhere other than Dreamland. But what is the future, if not our dreams come true?
BPM::Engine A business process engine based on XPDL