Understanding Statemachines, Part 3: Conditional Logic 1
Conditions
If you’re doing any significant amount of work with statmachines, you will most certainly encounter some conditional logic in your statemachines. Take our vending machine. When ever a coin is inserted, the invoked event will depend on whether the total amount of money inserted is sufficient to buy something. If enough money has been tendered, the display should suggest that the customer make a selection. If insufficient money has been inserted, the customer should be prompted to insert more.
Conditional logic can be accomplished by using entry actions. See the diagram below.

State Diagram with Conditional Logic
Starting in the Accept Money state, when a coin is inserted, the coin event is fired and the statemachine transitions into the Coin Inserted state. This is where it gets fun. Upon entering of the Coin Inserted state its entry event is invoked: count_amount_tendered. This method will count the money and invoke the not_paid_yet or paid event accordingly. This will cause the statemachine to transition into the appropriate state.
The Coin Inserted state is unique. You wouldn’t expect to find the statemachine in the Coin Inserted state for any reason except to make this decision. Once the decision is made, the state changes. States like this are called Decision States.
Code
require 'rubygems'
require 'statemachine'
class VendingMachineContext
attr_accessor :statemachine
def initialize
@amount_tendered = 0
end
def add_coin
@amount_tendered = @amount_tendered + 25
end
def count_amount_tendered
if @amount_tendered >= 100
@statemachine.paid
else
@statemachine.not_paid_yet
end
end
def prompt_money
puts "$.#{@amount_tendered}: more money please"
end
def prompt_selection
puts "please make a selection"
end
end
vending_machine = Statemachine.build do
trans :accept_money, :coin, :coin_inserted, :add_coin
state :coin_inserted do
event :not_paid_yet, :accept_money, :prompt_money
event :paid, :await_selection, :prompt_selection
on_entry :count_amount_tendered
end
context VendingMachineContext.new
end
vending_machine.context.statemachine = vending_machine
vending_machine.coin
vending_machine.coin
vending_machine.coin
vending_machine.coin
Output:
$.25: more money please $.50: more money please $.75: more money please please make a selection
Next lesson: Superstates
Understanding Statemachines, Part 4: Superstates
Clean as You Code 1
In my younger days I was a Line Cook at the Olive Garden. In case you’ve never worked in the food industry, Line Cooks are the guys putting meals together as fast as customers order them. At times, it’s nearly impossible to keep up.
Among the most fundamental of the Line Cook’s principles was Clean as you go. I can remember clearly the manager walking regally down the line chanting, “Clean as you go Javier. Clean as you go Micah. Clean as you go Brian.” Cooks would remind each other from time to time too, “Clean as you go!”.
As you’re realizing, it’s import to keep your station clean when you’re a cook. Keeping things clean is not easy. Food gets EVERYWHERE when you’re putting together hundreds of meals an hour. Why is it important to keep it clean? Simple. When your station is dirty, the system breaks down and it slows you down. Utensils are dirty or missing, ingredients get mixed together, cooking surfaces are soiled… Combine this with all the fire, boiling water, and sharp knives, it’s dangerous too! Worse, other cooks are not able to help out. Uncleanliness on the line is a vicious cycle with positive feedback. Every experienced cook keeps their station spotless at all times and unexperienced cooks learn fast.
Dirtiness is a sign of trouble too. Let’s say that it’s the middle of a dinner rush. You look down the line and notice that Javier’s station is becoming cluttered. It’s near certainty that in five minutes Javier’s system will break down. Food will be burnt, orders will get lost, and servers will get vocal. Don’t get servers mad! Line Cooks work as a team though. So when you see that Javier’s station is getting cluttered, you jump over and give Javier a hand every moment you can spare.
This principle, “Clean as you go”, is well applied to software, “Clean as you code”. The analogy is fairly straight forward. Although I’ve applied the principle to software for years, it was only recently that I recalled the mantra “Clean as you go”. I’m sure my teammates will soon grow tired of hearing me chant… “Clean as you code!”
Three Reasons to Use FitNesse 2
1. You find your self delivering software to your customer who says “That’s not what I asked for.”
Using FitNesse allows you to communicate with the customer up front. Before a line of code is written, you can have all the behavior expressed in an executable format. Make sure the customer helps to write these tests. Once your FitNesse test is in place, all you need to do it make it pass. Due to the cut-and-dry aspect of executable specifications (FitNesse test), one the spec is passing, you have delivered precisely what your customer asked for.
2. Bugs sneak into your system as development progresses and these bugs takes weeks to find and remove.
FitNesse is a tools to help you drive development with tests. When practices with discipline, test driven development will insure that you have a FitNesse test for each and every feature in your system. The moment a bug is introduced, you will know about it because a FitNesse test will fail.
3. It is difficult to create documentation for your system and it is constantly out of date because the system is changing.
FitNesse offers a unique documentation solution. When ever you write a FitNesse test, you are in fact describing how the system works. In other words you’re documenting it. The web/wiki based nature of FitNesse makes documentation simple and convenient. The best part is that the documentation in FitNesse can never go out of date. Since you’re keeping your test passing, and your tests are documentation, it’s impossible for them to lie.
There is an article I wrote about FitNesse for Windows Developer Power Tools. This book, just released today, includes articles on dozens of free tools that .NET developers might benefit from. If you write .NET code, check it out. If not, keep in mind that FitNesse will work for almost any language.