Archive for the ‘state machine’ Category
resource lifecycle tuple
I came across this passage :
Moving from design to implementation, we need to think about the protocol in a slightly different way. In a resource-oriented distributed application, an application protocol can be thought of as a function of one or more resource life cycles and the business rules that connect these resources. Because of its resource-centric nature, the Restbucks service does not host an application protocol state machine. In other words, there’s no workflow or business logic for the application protocol as such. Rather, the service governs the life cycles of the orders and payments participating in the application protocol. Any workflows in the service implementation relate to resource life cycles, not the application protocol life cycle. While we’ve been explicit in modeling the business process as an application protocol state machine, we’ve been diligent in implementing it wholly in terms of resource state machines.
REST in practice, page 131, (emphasis mine).
I had to link that passage to this blog post :
The bottom line is that a business entity lifecycle represents some business logic that is “business process independent”. This is probably news to many of you and some of you might say that a BEL is a “long running process” but it is not. It is long running. It is a process in the sense of an operating system point of view (nearly), but it is not and will never be a “business process”. The business process is represented by the activities (human or automated) that advance the lifecycle of one or more business entities.
Lifecycle example, from Carnets de Bord
volute
Vos luttes partent en fumée
Vers des flûtes enchantées Et de cruelles espérances
Me lancent Des dagues et des lances En toute innocenceJ’cloue des clous sur des nuages Un marteau au fond du garage
J’cloue des clous sur des nuages Sans échafaudage
volutes Alain Bashung (funny auto-translation)
This started out in a notebook. I wanted to do something about ‘state’ and ‘lifecyle’, something like a state machine for multiple objects or a rule system for families of resources.
It ended up as something that feels like the subset of an aspect oriented framework. Subset because in its most vanilla usage it only cares about calls to set methods, and there is no “before” (at first glance).
This Ruby gem is named volute. Here is an example of its usage :
require 'volute' class Package include Volute attr_accessor :location attr_accessor :delivered end volute Package do # filters non Package instance out volute :delivered => true do # applies when delivered switches to true object.emit_invoice end volute :location do # filters out changes that are not for the :location attribute volute 'SFO' => :any, 'FRA' => :any do # SFO and FRA are our international hubs, for any package transiting from there, # initial 'international' tracking TrackingSystem.track_international(object) end end end
The “include Volute” reworks the attr_accessor, and triggers the evaluation of the volutes on each set.
It’s not always necessary to include Volute. Here is a example of [business] rules derived from Ruleby (volute is very dumb compared to Ruleby, the example doesn’t do justice to that project).
Here is the diagnosis example with volute :
require 'volute' class Patient attr_reader :name attr_accessor :fever attr_accessor :rash attr_accessor :spots attr_accessor :sore_throat attr_accessor :innoculated attr_accessor :diagnosis def initialize(name) @name = name @symptoms = {} @innoculated = false end def diagnose! Volute.apply(self) # trigger evalution of volutes return @diagnosis end end volute Patient do volute :fever => :high, :spots => :true, :innoculated => true do object.diagnosis = 'measles' over # prevent further evals end volute :spots => true do object.diagnosis = 'allergy (spots but no measles)' end volute :rash => true do object.diagnosis = 'allergy (rash)' end volute :sore_throat => true, :fever => :mild do object.diagnosis = 'flu' end volute :sore_throat => true, :fever => :high do object.diagnosis = 'flu' end end pat = Patient.new('alice') pat.rash = true puts "#{pat.name} : diagnosed with #{pat.diagnose!}" pat = Patient.new('bob') pat.sore_throat = true pat.fever = :high puts "#{pat.name} : diagnosed with #{pat.diagnose!}"
The readme for volute is quite extensive. There are a few examples included.
You’ve already seen the diagnosis one, it aimed at using volute for some mini rule engine (nothing fancy at all).
There is an example about a simple (kph = km/h) equation where each time an attribute is changed, other attributes get adjusted.
The light example simply keeps tracks of the last time an attribute got modified.
There is a book in a bookshop state machine example with a variation, to explore state volutes and transition volutes.
Note that state machines built with volute are incomplete, they know nothing about further transitions (could I even call them state machines ? Rather a ‘state transition system’).
Traffic could be fun : it tracks the state of two “lines” and adjust the colour of their lights according to the number of cars waiting. It’s more in line with the “multiple objects” goal I had initially (still here somehow, but examples with 1 class are smaller).
Not sure if it’s worth moving logic out of objects, but it is a fun experiment.
http://github.com/jmettraux/volute
state machine != workflow engine
update (2010) : this resource lifecycle post features two quotes that are enlightening when thinking about state and workflow.
update (2011) : a discussion between two engineers about state machines and workflow (guest post at Engine Yard)
This post is intended for Ruby developers. The idea for it came after numerous discussions with fellow programmers about state machines and workflow engines.
What motivates me for posting is the publication of the 3rd issue of the excellent Rails Magazine. It contains an article named “Workflow solutions with AASM”.
At first a word of warning, I wrote these lines with no intention of minimizing the potential of state machines vs workflow engines. I’m listing workflow engine and state machine implementations for Ruby at the end of this post.
There are a number of open questions in this post, I don’t intend to answer them now or later. There are so many different use cases in the wild.
spark
The article “Workflow solutions with AASM” starts with :
There are two main forms of workflows: sequential and
state-machine. Sequential workflows are predictable. They
utilize the rules and conditions we provide at the beginning
to progress a process forward. The workflow is in control of
the process.A state-machine workflow is the reverse. It is driven by
external events to its completion. We define the states and
required transitions between those states. The workflow sits
and waits for an external event to occur before transitioning
to one of the defined states. The decision making process hap-
pens externally outside of the workflow – there is a structure
to be followed still like a sequential workflow but control is
passed to its external environment.
I’m clearly in the “sequential workflow” faction. But I refute the ‘sequential’ label. Most of the state/transitions set out there can be qualified as “sequential”. Any workflow engine, in order to present any interest to its users, has to implement a certain number of [control flow] workflow patterns. The number 1 control-flow pattern is named Sequence, granted. But if you take a look at the pattern that immediately follows, it’s Parallel Split. I can’t adhere to the “sequential workflow” appellation.
Note that most workflow engines (you can call then “sequential workflow” engines) strive to implement a large set of those control-flow patterns. This is usually done via their ‘process definition’ language. The goal is to let users express their scenarii / pattern in a not too verbose way. We can argue that state machines may implement any of the control-flow patterns, my guess is ‘yes’, but what’s the cost in code ?
The difference between “sequential workflows” and “state machines” seems to lie not in the predictability of the former, but rather in how the flow between activities or state is weaved, especially how/where it’s concentrated.
Are “sequential workflows” and “state machines” excluding one another ?
The article states “sequential workflow are predictable. They utilize the rules and conditions we provide at the beginning”. It’s the same for state machines. The vast majority of [Ruby] state machine implementations rely on behaviour specified at implementation time (or right before the application’s [re]start).
The second paragraph I quoted up here says that “decision making process happens externally outside of the workflow (…) control is passed to its external environment”. I argue that a “sequential workflow” engine should do the same. A workflow [engine] can’t take a decision by itself, this task is usually handled by a human or a dedicated algorithm (a piece of code, a rule engine, a coin tossing engine wired to internet, whatever).
case
Wait, we’ve been using this ‘workflow’ term quite liberally until now, what is it about ? Why do state machines seem to be the perfect vessel for it, at least in the eyes of the hard-working developer ?
Let’s look at how state machines are sold, at their use cases. Here is a classical example from a [Rails-oriented] state machine library :
class Document < ActiveRecord::Base include StateFu def update_rss puts "new feed!" # ... do something here end machine( :status ) do state :draft do event :publish, :to => :published end state :published do on_entry :update_rss requires :author # a database column end event :delete, :from => :ALL, :to => :deleted do execute :destroy end end end
It attaches behaviour (state and transitions) to a resource. If you look at the example of any Ruby state machine library out there, you will see this pattern : a set of states and transitions attached to a resource in the system (a Model).
Let’s move to an adjacent example, it’s also about a document, but it’s in the “sequential workflow” faction (ruote). (The ‘cursor’ expression in the process definition allows for the flow to be rewound or skipped…) :
Ruote.process_definition :name => 'doc review', revision => '0.2' do cursor do participant '${f:author}', :step => 'finalize document' participant '${f:review_team}', :step => 'review document' rewind :unless => '${f:approved}' concurrence do participant '${f:publisher}', :step => 'publish document' participant '${f:author}', :step => 'publication notification' end end end
There is a document yes, but it could be a folder of documents. The process definition is a separate thing, meant to be turned into multiple process instances.
Workflow engines are mostly process definitions interpreters, graduating as “operating systems for business processes” (think ‘ps’ and ‘kill dash 9’ but with business processes / process instances).
As said, most of the Ruby state machine libraries out there are all about binding behaviour to resources / models. What about moving to the workflow engine camp and instead of binding to a system artefact (document, order, invoice, book, customer, …) why not attach state and transitions to a virtual artefact, a so-called “process instance” ? The state machine would move out of its shell and turn into a full workflow engine. Or is that so ?
cases
Back to the 90% of the cases : the state machine attached to a model. What if there is more than 1 “stateable” model ? Easy. But what if transition in model A provokes a transition in model B ? The “real workflow” now lies at the intersection of two models.
The workflow engine will expose a process definition while, with the state machines, we’ll have to extract it from two or more models. Another advantage of workflow engines is that they have process definition versioning. Most of them run process instances from process definition X at version 2 happily with process instances from version 4, concurrently.
On the other hand, when a process instance goes ballistic it might take some time to repair it (align it with the reality of the business process). It might be easier with state machines, a simple SQL update usually, but what if there are multiple inter-related behaviours ? Pain on both sides.
Whatever the tool, you’ll have to carefully avoid locking yourself into your private hell of a system.
nuances
Kenneth Kalmer is using a mix of state_machine and ruote in their ISP in a box product. The state machine library is in charge of the state of its various models while the workflow engine does the orchestration. “Processes that drives the provision of services”
The two techniques may co-exist. Tinier states / transitions sets, more concise process definitions. Models managing their states, process instances coordinating the states of multiple models.
It’s OK to remove the workflow engine and replace it with a “super” state machine, but then you’re entering in the real workflow territory and the mindset is a bit different and at that level, you’ll be exposed to a flavour of change that directly involves your customer / end-user. Nowhere to hide.
machines
I’ve been linking profusely to my ruote workflow engine. The only other workflow engine I’ve spotted in the wild is rbpm, but its development stopped a long time ago.
Here is a non-exhaustive list of Ruby state machine implementations, in no specific order :
- state-fu
- state_machine
- acts_as_state_machine
- ryan-allen’s workflow
- geekq’s workflow (fork of the previous)
- alter-ego
- stateful
- stonepath covered by an article in the 2009/10 pragprog magazine
- automatic-acts-as-state-machine
- micromachine
- ruby-state-machine
- dm-is-state_machine
- newflow
- state_pattern
- stateflow
- ActiveRecord::StateMachine (announced)
- transitions (what was supposed to become ActiveRecord::StateMachine)
- statemachine
- flojo
- ssm
- state_attr
- state_manager
- stately
- statesman
- finite_machine
- …
There’s a plethora of state machines versus very few (one or two) workflow engines. This could be interpreted in multiple ways.
State machines follow a well defined pattern, while workflow engines have to follow a set of patterns, and workflow engines strive to be “operating systems for business processes”. State machines are more humble.
So Rails Magazine #3 is out. Great read.