最近は毎日プログラミングの日々を過ごしている。
そんな中、とあるテーブル(ドキュメント)で状態を管理しなきゃいけない場面があった。
この問題の一つの手としてはstate をint で保存し、一つ一つの数字を何かしらの状態に紐づけるやり方だ。これを実践してみたことがある方ならわかる通り、後でこれをメンテする人がいったいその数字が何なのか、をいちいちどっかのドキュメントを見て調べなければならない。これの管理がとても面倒。何かの状態が新しくできたらそのドキュメントもちゃんと更新しないと、色々崩壊する。
State Machine
State Machine はそれぞれの状態と、状態の遷移を管理する一種のデザインパターン。これにより、数値での管理をなくし、さらにある状態からある状態への遷移を限定することができる。例えば、状態として「走る」「歩く」「止まる」「寝る」があるとしよう。いきなり「走る」から[寝る」ことは不可能だ。このときにこの状態遷移をしようとしたら例外が発生するようにしたい。さらに、「走る」から「歩く」は「徐行する」という状態遷移名で呼び出せるようにすれば、ステータスを変える、というプログラムから「徐行する」ととても読みやすいコードを実現することができる。
Rails における 「AASM」
AASM は Acts as State Machine の頭文字だ。かつてのRailsプラグイン界隈の命名規則でありがちだった Act as ~ はDB操作を便利にしてくれるプラグインによく使われていた。今回もそれ系列のGemだ。 これを使えば以下のようにModelに定義できる。
class Job include AASM aasm do state :sleeping, :initial => true state :running state :cleaning event :run do transitions :from => :sleeping, :to => :running end event :clean do transitions :from => :running, :to => :cleaning end event :sleep do transitions :from => :running, :to => :sleeping, :guard => :cleaning_needed? end end def cleaning_needed? false end end job = Job.new job.run job.may_sleep? # => false job.sleep # => raises AASM::InvalidTransition
なんとわかりやすいコードだろう。状態の遷移がすぐ理解できる。
この guard ってオプションがとても良い。一定の条件を満たさないとそのstateに変われないようにチェックすることができる。それを満たさなかったらAASM::InvalidTransitionの例外が投げられる。
まとめ
読みやすくて管理しやすいコードを書くように心がけます。