
制御システムの設計で「この装置は今どの状態にあるのか」が分からなくなった経験はないでしょうか。
自動販売機のボタン操作、エレベーターの動作、通信プロトコルの接続手順。
これらはすべて、ある状態から別の状態へと条件に応じて移り変わるシステムです。
もし状態の切り替わりを正しく整理できていなければ、想定外の入力で装置が誤動作し、重大な事故につながりかねません。
こうした「状態と遷移」を可視化する手法が状態遷移図です。
UML(統一モデリング言語)ではステートマシン図として標準化されており、組込みシステムからWebアプリケーションまで幅広い分野で利用されています。
本記事では、状態遷移図の基本からUMLでの書き方・読み方、状態遷移表との使い分け、テスト技法への応用、さらに設計現場で役立つ実践テクニックまでを体系的に解説します。
- 1. 状態遷移図とは
- 2. 状態遷移図を構成する基本要素
- 3. UMLステートマシン図の書き方
- 4. 状態遷移図の読み方
- 5. 状態遷移表との違いと使い分け
- 6. 複合状態と直交領域(応用記法)
- 7. 状態遷移テストへの活用
- 8. 設計ツールとPlantUMLによる自動生成
- 9. 状態遷移設計で陥りやすいアンチパターン
- 10. 実践例:通信プロトコルの状態遷移設計
- まとめ
1. 状態遷移図とは

状態遷移図(State Transition Diagram)とは、システムやオブジェクトが取り得る状態と、ある状態から別の状態へ移り変わる遷移を図式化したものです。
制御工学やソフトウェア工学において、動的な振る舞いを設計・検証するための基本ツールとして広く使われています。
状態遷移図で表現できる情報は、大きく3つに分けられます。
- 状態(State):システムがある条件を満たしている期間を表します。たとえばモーターの「停止中」「回転中」「異常停止」などがこれにあたります
- 遷移(Transition):ある状態から別の状態への変化を表します。矢印で描き、矢印の向きが変化の方向を示します
- イベント(Event):遷移を引き起こすきっかけとなる出来事です。「ボタン押下」「センサ検知」「タイマー満了」などが典型的なイベントです
たとえば自動販売機を考えてみましょう。
「待機中」の状態でコインが投入されると「金額受付中」に遷移します。
「金額受付中」で商品ボタンが押されると、投入金額が商品価格以上であれば「払い出し中」に遷移します。
一方、金額が不足していれば状態は変わらず「金額受付中」のままです。
「払い出し中」で商品が排出されると、釣銭があれば返却してから「待機中」に戻ります。
このように、日常的な装置の振る舞いも状態遷移図で明確に記述できます。
口頭で説明すると曖昧になりがちな「条件付きの動作」も、図に落とし込むことで設計者間の認識を統一できるのです。
状態遷移図の歴史は古く、1950年代の有限オートマトン理論にまで遡ります。
有限オートマトンとは、有限個の状態と遷移規則からなる数学的なモデルで、正規表現やコンパイラの字句解析など計算機科学の基礎を支えています。
1987年、デビッド・ハレルがステートチャート(Statecharts)を提唱しました。
従来の状態遷移図に階層構造(複合状態)や並行性(直交領域)を導入したもので、複雑な制御システムの表現力を飛躍的に高めた画期的な手法です。
このハレルのステートチャートがUMLに取り込まれ、現在のUMLステートマシン図の基盤となっています。
日本国内では、JIS X 0131:1995「ソフトウェアの状態遷移の構成及びその表記方法」として、状態遷移の表記法が標準化されています。
この規格はISO/IEC 11411:1995の翻訳版であり、状態遷移図と状態遷移表の両方の記法を定義しています。
状態遷移図を活用することで、設計の抜け漏れを早期に発見できます。
特に組込みシステムの開発では、すべての状態と遷移を網羅的に検証することが品質確保の鍵となります。
2. 状態遷移図を構成する基本要素

状態遷移図を正しく描くためには、UMLで定義された構成要素を理解する必要があります。
ここでは、ステートマシン図の基本記号を1つずつ解説します。
状態(State)
状態はシステムがある条件を満たしている期間を表します。
UMLでは角丸の四角形で描き、内部に状態名を記述します。
状態は単に名前を持つだけでなく、内部に3種類のアクションを定義できます。
- entry/:その状態に入るたびに1回だけ実行されるアクション。初期化処理やセンサの起動などに使います
- do/:その状態にいる間、継続的に実行されるアクティビティ。温度監視ループや通信待受けなどが該当します
- exit/:その状態から出るたびに1回だけ実行されるアクション。リソースの解放やログ記録などに使います
たとえばモーター制御の「回転中」状態であれば、次のように記述できます。
・entry/ モーター通電開始
・do/ 回転速度を監視し目標値と比較
・exit/ モーター通電停止
このようにアクションを明示することで、各状態で何が起き、状態の出入りでどんな処理が必要かを設計段階で確認できます。
遷移(Transition)
遷移は状態間の変化を表す矢印です。
ラベルには以下の形式で情報を記述します。
それぞれの要素は省略可能で、すべてを記述する必要はありません。
各要素の役割を詳しく見てみましょう。
イベント(Event)
遷移のきっかけとなる出来事です。
UMLでは4種類のイベントが定義されています。
- シグナルイベント:外部からの非同期通知(例:ボタン押下、センサ検知)
- 呼び出しイベント:オペレーションの呼び出し(例:start()、stop())
- 時間イベント:一定時間の経過(例:after(5s)、at(12:00))
- 変化イベント:条件式の値がfalseからtrueに変わった時(例:when(温度 > 80))
ガード条件(Guard Condition)
遷移が発生するための追加条件を角括弧内に記述します。
ガード条件はブール式(真偽値を返す式)でなければなりません。
たとえば [温度 > 80℃] や [在庫数 > 0] のように記述します。
イベントが発生しても、ガード条件がfalseであれば遷移は起きません。
アクション(Action)
遷移時に実行される処理をスラッシュの後に記述します。
たとえば / アラーム発報 や / カウンタ+1 のように記述します。
アクションは遷移の「途中」で瞬間的に実行されるものとして扱われます。
状態のentry/exitアクションとは異なり、遷移そのものに紐づく処理です。
初期擬似状態と終了状態
初期擬似状態は黒い塗りつぶし円で表します。
システムが生成されたときに最初にどの状態に入るかを示す起点です。
初期擬似状態は「状態」ではなく「擬似状態」であるため、システムがここに留まることはありません。
必ず1本の矢印が出ており、その先の状態がシステムの最初の状態となります。
終了状態は二重丸(内側が塗りつぶし円、外側がリング)で表します。
システムやオブジェクトのライフサイクルが完了することを示します。
終了状態に到達すると、そのステートマシンは動作を終了します。
ただし、永続的に動作するシステム(工場の制御装置など)では終了状態を置かない設計も一般的です。
選択擬似状態と接合擬似状態
選択擬似状態(Choice Pseudostate)はひし形で描き、ガード条件による動的な分岐を表します。
遷移の途中で条件を評価し、結果に応じて異なる状態に進む場合に使います。
接合擬似状態(Junction Pseudostate)は小さな黒丸で描き、複数の遷移を1つに合流させたり、1つの遷移を複数に分岐させたりする静的な接続点として使います。
選択擬似状態との違いは、接合は静的(コンパイル時に決定可能)であるのに対し、選択は動的(実行時に評価)である点です。
3. UMLステートマシン図の書き方

実際にUMLステートマシン図を描く手順を、エレベーター制御を題材に解説します。
設計現場で即実践できるよう、ステップ形式で進めましょう。
Step 1:状態の洗い出し
まず、システムが取り得るすべての状態を列挙します。
エレベーターであれば、以下の状態が考えられます。
- 停止中(Idle):いずれの階にも呼び出しがなく、ドアが閉まった状態
- ドア開放中(DoorOpen):乗客の乗降のためドアが開いている状態
- 上昇中(MovingUp):上方向に移動している状態
- 下降中(MovingDown):下方向に移動している状態
- 異常停止(Emergency):非常ボタン押下や過荷重で緊急停止した状態
漏れなく洗い出すコツは、「正常系」「異常系」「初期状態」「終了条件」の4つの視点で考えることです。
特に異常系は見落としがちなので、「何が壊れたらどうなるか」を積極的に検討します。
この段階では完璧を目指す必要はありません。
後のステップで遷移を検討する過程で、新たな状態が見つかることも多いです。
Step 2:イベントとガード条件の定義
次に、各状態間の遷移を引き起こすイベントを定義します。
- 呼びボタン押下(CallButton):各階のホールに設置されたボタンの操作
- 到着検知(ArrivalDetected):目的階にかごが到着したことをセンサが検知
- ドアタイマー満了(DoorTimeout):ドアを開放してから一定時間が経過
- 非常ボタン押下(EmergencyButton):かご内の非常停止ボタンの操作
- 過荷重検知(OverloadDetected):荷重センサが定格を超える重量を検知
- 復旧操作(ResetButton):保守員による復旧操作
ガード条件は、同じイベントでも遷移先が異なる場合に使います。
たとえば呼びボタン押下時の条件分岐は次のとおりです。
これら3つのガード条件は互いに排他的(どの条件も重複しない)かつ網羅的(すべてのケースをカバーする)でなければなりません。
Step 3:遷移の接続と図の作成
洗い出した状態とイベントを矢印で接続します。
このとき、以下の点に注意します。
- 初期擬似状態から「停止中」への矢印を描く(エレベーターは停止中からスタート)
- すべての状態から「異常停止」への遷移を確認する(非常ボタンはどの状態からでも有効)
- 遷移の矢印が交差しないようにレイアウトを工夫する
- 自己遷移(同じ状態へ戻る矢印)を見落とさない
遷移ラベルの記述例を数式で示します。
この式は「停止中にCallButtonイベントが発生し、呼び階が現在階より上なら、モーターを正転させて上昇中に遷移する」という意味です。
上昇中に目的階への到着が検知されたら、モーターを停止してドア開放中に遷移します。
ドアのタイマーが満了したら、ドアを閉鎖して停止中に戻ります。
Step 4:検証とレビュー
完成した図に対して、以下のチェック項目を確認します。
- すべての状態から少なくとも1つの遷移が出ているか(デッドロックの防止)
- 到達不能な状態(どこからも遷移できない状態)がないか
- ガード条件の排他性と網羅性が保たれているか
- 想定外のイベントに対する処理が定義されているか
- 異常系からの復旧パスが存在するか
検証は手動でも可能ですが、状態遷移表(§5で解説)を併用すると、すべての「状態×イベント」の組み合わせを漏れなく確認できます。
関連記事
4. 状態遷移図の読み方

描き方を理解したら、次は他者が描いた図を正しく読み取る力が必要です。
レビューや仕様理解の場面で、状態遷移図を効率的に読むためのポイントを解説します。
読み方の基本手順
状態遷移図を読む際は、以下の順序で進めると見落としが減ります。
(1)初期擬似状態を探す
黒い塗りつぶし円を見つけ、システムの開始点を把握します。
初期擬似状態からの矢印をたどると、最初の状態が分かります。
もし初期擬似状態が見つからなければ、図が不完全であるか、部分的なビュー(複合状態の内部図など)である可能性があります。
(2)主要な状態を確認する
すべての角丸四角形を読み、システムが取り得る状態の全体像を掴みます。
状態名だけでなく、entry/do/exitの内部アクションも確認しましょう。
このとき、状態の数が設計の複雑さの目安になります。
一般に、1つの図に描く状態は10個程度が上限とされています。
(3)遷移をたどる
各矢印のラベル(イベント[ガード条件]/アクション)を読み、状態間の因果関係を理解します。
特にガード条件は、同じイベントでも分岐先が異なる重要な判断ポイントです。
遷移をたどる際は、「正常系の主要パス」を先に読み、その後「異常系や例外パス」を確認する順序が効率的です。
(4)終了状態の有無を確認する
終了状態がある場合、どの経路でシステムが終了するのかを把握します。
終了状態がない場合は、永続的に動作する設計であることを確認します。
読み方で注意すべき3つのポイント
状態遷移図を読む際によくある誤解と、正しい解釈を整理します。
自己遷移を見落とさない
同じ状態への遷移(自分自身に戻る矢印)は、状態は変わらないがアクションは実行されることを意味します。
さらに重要なのは、自己遷移ではexitアクションとentryアクションが順番に実行される点です。
たとえば「監視中」状態でセンサ異常を検知し、アラームをリセットして再び「監視中」に戻るケースでは、exit/でログ記録、entry/でセンサ再初期化が実行されます。
一方、内部遷移(internal transition)を使えば、exit/entryを実行せずにアクションだけを実行できます。
内部遷移は状態の内部に「イベント / アクション」の形式で記述します。
ガード条件の排他性を確認する
同じイベントに対して複数の遷移が定義されている場合、ガード条件が互いに排他的であることを確認します。
排他性が不十分だと、2つ以上のガード条件が同時にtrueとなり、どちらに遷移するか不定になる設計不良が生じます。
たとえば [温度 > 50] と [温度 > 30] というガード条件が同じイベントに付いている場合、温度が60℃のとき両方ともtrueになってしまいます。
正しくは [温度 > 50] と [温度 <= 50 かつ 温度 > 30] のように排他的に記述する必要があります。
暗黙の拒否を認識する
ある状態で定義されていないイベントが発生した場合、UMLの規約ではそのイベントは暗黙的に無視されます。
「定義されていない=エラー」ではないことを理解しておきましょう。
ただし、実装レベルではこの「暗黙の無視」が意図的なのか設計漏れなのかを区別する必要があります。
状態遷移表(§5)を使えば、未定義の組み合わせを明示的に「無視」と記述できるため、設計意図が明確になります。
5. 状態遷移表との違いと使い分け

状態遷移を表現する手段には、図のほかに状態遷移表(State Transition Table)があります。
両者の特徴を理解し、目的に応じて使い分けることが重要です。
状態遷移表とは
状態遷移表は、行に現在の状態、列にイベントを配置し、セルに次の状態とアクションを記入するマトリクス形式の表現方法です。
すべての「状態×イベント」の組み合わせが強制的にセルとして現れるため、遷移の定義漏れを発見しやすいという大きな利点があります。
自動販売機の例で簡易的な状態遷移表を示します。
| 現在の状態\イベント | コイン投入 | ボタン押下 | 釣銭返却ボタン |
|---|---|---|---|
| 待機中 | 金額受付中 / 金額加算 | -(無視) | -(無視) |
| 金額受付中 | 金額受付中 / 金額加算 | 払い出し中 / 商品排出 | 待機中 / 返金処理 |
| 払い出し中 | -(無視) | -(無視) | 待機中 / 釣銭排出 |
表の「-」が示しているのは、その組み合わせでは遷移が発生しない(イベントが無視される)ことです。
この「-」の存在こそが状態遷移表の最大の価値です。
状態遷移図では描かれない「何も起きない組み合わせ」が明示的に可視化されるため、「この状態でこのイベントが来たらどうなるか」を全パターン確認できます。
状態遷移図と状態遷移表の比較
| 比較項目 | 状態遷移図 | 状態遷移表 |
|---|---|---|
| 視認性 | 全体の流れが直感的に分かる | 状態が多いと全体像が見えにくい |
| 網羅性 | 遷移の漏れに気づきにくい | すべての状態×イベントを網羅的に確認できる |
| 複雑な系への対応 | 状態が10個を超えると見づらくなる | 大規模でも行列の追加で対応可能 |
| テスト設計への活用 | シナリオの可視化に有効 | テストケースの抽出に直結する |
| 設計レビュー | 関係者間の認識共有に適する | 「抜け」の検出に適する |
| 保守性 | 変更箇所が視覚的に分かりやすい | 行列の追加・削除で変更可能 |
使い分けの指針
実務では状態遷移図と状態遷移表を併用するのが最も効果的です。
設計の初期段階では状態遷移図で全体像を共有し、詳細設計やテスト設計の段階では状態遷移表で網羅性を担保します。
目安として、状態数が5個以下の単純なシステムでは図だけで十分です。
状態数が6〜15個の中規模システムでは図と表を併用し、15個を超える大規模システムでは階層化した図と表のセットで管理します。
状態数 とイベント数
のシステムでは、状態遷移表のセル数は次のようになります。
このうち有効な遷移(「-」以外)のセル数が多いほど、システムの動的な複雑度が高いことを意味します。
有効遷移の割合を監視することで、設計の複雑さを定量的に評価できます。
6. 複合状態と直交領域(応用記法)

UMLステートマシン図の強力な特徴は、複合状態(Composite State)と直交領域(Orthogonal Region)を使って複雑なシステムを階層的に表現できることです。
従来のフラットな状態遷移図では扱いきれない大規模システムも、これらの記法で見通しよく設計できます。
複合状態(Composite State)
複合状態とは、内部にさらにサブ状態を持つ状態のことです。
外側の大きな角丸四角形の中に、複数のサブ状態と遷移を入れ子で描きます。
たとえば自動車の「運転中」という複合状態の内部に「加速中」「定速走行」「減速中」というサブ状態を持たせることができます。
外部から見ると単純な「運転中」1つの状態ですが、内部では3つのサブ状態が遷移しています。
複合状態のメリットは、抽象度を使い分けられる点にあります。
全体設計の段階では「運転中」と「停止中」の2状態で議論し、詳細設計の段階では「運転中」の内部を展開して3つのサブ状態を検討できます。
また、複合状態への遷移はデフォルト入口(複合状態の境界に矢印を向ける)と直接入口(内部のサブ状態を直接指定する)の2種類があります。
デフォルト入口では、複合状態内の初期擬似状態が示すサブ状態から開始します。
直交領域(Orthogonal Region)
直交領域は、1つの複合状態の内部を点線で分割し、複数の領域が同時に並行動作することを表現する記法です。
洗濯機の「運転中」状態を例にとります。
1つの直交領域では「洗い→すすぎ→脱水」のサイクルが進行し、もう1つの直交領域では「給水バルブ制御」が独立して動作します。
これらは互いに独立した状態遷移を持ちながら、同じ「運転中」という複合状態に包含されています。
領域間の同期が必要な場合は、シグナルイベントを使って連携させます。
並行状態の開始と終了には、専用の擬似状態を使います。
フォーク擬似状態は太い横棒から複数の矢印が出る記号で、並行処理の開始を表します。
ジョイン擬似状態は複数の矢印が太い横棒に合流する記号で、すべての領域が完了するまで待機する同期点を表します。
浅い履歴と深い履歴
複合状態には履歴擬似状態を設置できます。
これは、複合状態から一度出た後に戻ったとき、前回のサブ状態を記憶して復元する機能です。
丸の中に「H」と書かれた記号は浅い履歴(Shallow History)を表します。
直前のサブ状態のみを記憶します。そのサブ状態がさらに複合状態であれば、内部は初期状態から再開します。
丸の中に「H*」と書かれた記号は深い履歴(Deep History)を表します。
すべてのネスト階層の状態を記憶し、完全に元の位置から再開します。
履歴擬似状態は、割り込み処理後の復帰に特に有用です。
たとえば工作機械が異常検知で一時停止し、復旧後に加工の途中工程から再開するようなケースで威力を発揮します。
浅い履歴なら「加工中」の状態に戻り、深い履歴なら「加工中→穴あけ→3番目の穴」のように詳細な位置まで復元されます。
関連記事
7. 状態遷移テストへの活用
状態遷移図と状態遷移表は、ソフトウェアテスト技法としても非常に有効です。
状態遷移テストは、ISTQBやJSTQBのシラバスでも取り上げられている仕様ベースのテスト技法であり、特に組込みシステムのテストで多用されています。
状態遷移テストの目的
状態遷移テストでは、主に以下の2点を検証します。
- 有効な遷移が正しく動作すること(正常系テスト):設計上定義された正規の遷移が、期待どおりの次状態とアクションを生じるかを確認します
- 無効な遷移が適切に拒否されること(異常系テスト):状態遷移表で「-」と記された、本来発生してはならない遷移に対してシステムが正しくイベントを無視するか、エラー処理を行うかを確認します
テストケースの抽出方法
状態遷移テストのカバレッジには、主に3つのレベルがあります。
レベル1:全状態カバレッジ
すべての状態を少なくとも1回は訪問するテストケースを設計します。
最低限のカバレッジであり、遷移の正しさまでは検証できません。
状態数を とすると、必要なテストケース数の下限は次のとおりです。
レベル2:全遷移カバレッジ(0-switchカバレッジ)
すべての有効な遷移を少なくとも1回は実行するテストケースを設計します。
実務ではこのレベルが標準的な目標です。
有効遷移数を とすると、テストケース数は次のように見積もれます。
レベル3:全遷移ペアカバレッジ(1-switchカバレッジ)
すべての「遷移→遷移」のペア(2連続遷移)を少なくとも1回は実行します。
前の遷移が次の遷移に影響を与えるバグ(状態変数の初期化漏れなど)を検出でき、より高い品質保証が可能です。
テスト設計の手順
具体的なテスト設計は、以下の手順で進めます。
(1)状態遷移表を作成する
状態遷移図から状態遷移表を導出し、すべての状態×イベントの組み合わせを明示します。
この変換作業自体が、図の設計漏れを発見するきっかけになることも多いです。
(2)有効遷移のテストケースを抽出する
初期状態から開始し、すべての有効な遷移を網羅するパスを設計します。
1つのテストケースで複数の遷移を連鎖させることで、テストケース数を効率化できます。
(3)無効遷移のテストケースを抽出する
状態遷移表の「-」セルに対応するテストケースを作成します。
各無効遷移に対して、システムが適切にイベントを無視するか、エラー処理を行うかを検証します。
無効遷移のテストは軽視されがちですが、セキュリティ上の脆弱性やデータ破壊の原因が潜んでいることがあります。
特に外部入力を受け付けるシステムでは、無効遷移のテストを確実に実施すべきです。
8. 設計ツールとPlantUMLによる自動生成

状態遷移図を手描きで作成する時代は終わりつつあります。
現在は、テキストベースの記述やGUIツールで効率的に作成・管理する方法が主流です。
主要な設計ツール
状態遷移図の作成に使われる代表的なツールを紹介します。
| ツール名 | 種別 | 特徴 | 価格帯 |
|---|---|---|---|
| Enterprise Architect | 商用GUI | UML全図種対応、コード生成機能あり | 有料(年間ライセンス) |
| astah* | 商用GUI | 日本製、教育機関での利用が多い | 有料(Community版は無料) |
| PlantUML | テキストベース | 無料、バージョン管理と相性が良い | 無料(オープンソース) |
| draw.io | 無料GUI | ブラウザで利用可能、共有が容易 | 無料 |
| MATLAB Stateflow | 商用 | シミュレーション連携、Cコード自動生成 | 有料(高価格帯) |
PlantUMLによるテキスト記述
PlantUMLはテキストで状態遷移図を記述し、画像を自動生成するオープンソースツールです。
ソースコードと同じリポジトリで管理できるため、PID制御のような制御系の設計ドキュメントと一緒にバージョン管理が可能です。
基本的な記述例を示します。
@startuml
[*] --> 待機中
待機中 --> 金額受付中 : コイン投入 / 金額加算
金額受付中 --> 金額受付中 : コイン投入 / 金額加算
金額受付中 --> 払い出し中 : ボタン押下 [金額>=価格] / 商品排出
金額受付中 --> 待機中 : 返却ボタン / 返金処理
払い出し中 --> 待機中 : 排出完了 / 釣銭排出
@enduml
このテキストをPlantUMLエンジンに渡すと、自動販売機の状態遷移図が画像として生成されます。
[*] は初期擬似状態を表す特殊記法です。
PlantUMLの利点は主に3つあります。
- 差分管理:テキストなのでGitで変更履歴を追跡でき、レビュー時にdiffを確認できます
- 再現性:環境に依存せず、同じテキストから常に同じ図が生成されます
- 自動化:CI/CDパイプラインに組み込んで、仕様変更のたびに図を自動再生成できます
複合状態もPlantUMLで記述できます。
@startuml
state 運転中 {
[*] --> 加速中
加速中 --> 定速走行 : 目標速度到達
定速走行 --> 減速中 : ブレーキ操作
減速中 --> 定速走行 : ブレーキ解除
}
[*] --> 停止中
停止中 --> 運転中 : スタートボタン
運転中 --> 停止中 : 停止ボタン
@enduml
stateキーワードでブロックを定義すると、複合状態として表現されます。
ツール選定の判断基準
ツールの選定は、プロジェクトの規模と目的に応じて判断します。
個人や小規模チームでの設計ドキュメント作成にはPlantUMLやdraw.ioが適しています。
大規模プロジェクトでコード生成やシミュレーションが必要な場合は、Enterprise ArchitectやMATLAB Stateflowが選択肢に入ります。
特に自動車や航空宇宙など安全性が求められる分野では、MATLAB StateflowによるCコード自動生成とシミュレーション検証が事実上の標準となっています。
関連記事
9. 状態遷移設計で陥りやすいアンチパターン

状態遷移図の書き方を学んでも、実際の設計ではさまざまな落とし穴があります。
ここでは現場でよく見かける4つのアンチパターンと、その具体的な解決策を紹介します。
アンチパターン1:状態爆発
フラグやモードの組み合わせをすべて独立した状態として定義すると、状態数が指数関数的に増加します。
これを状態爆発(State Explosion)と呼びます。
たとえば、3つの独立した二値フラグを持つシステムでは、理論上の状態数は次のとおりです。
フラグが5個になれば 状態、10個になれば
状態にまで膨れ上がります。
一般化すると、n個の独立した二値フラグによる状態数は次の式で求められます。
対策:直交領域(§6)を活用し、独立したフラグは別の領域で管理します。
各領域がそれぞれ2状態を持つなら、直交領域を使った場合の状態数は次のようになります。
たとえばフラグ10個のシステムでは、1024状態が20状態に削減されます。
これが直交領域の最大の実用的メリットです。
アンチパターン2:神状態(God State)
1つの状態にあまりに多くの責務を持たせると、遷移が複雑化して保守が困難になります。
オブジェクト指向設計の「God Object」と同じ問題です。
たとえば「処理中」という状態に、データ受信・バリデーション・変換・保存・通知のすべてが含まれているケースです。
このような状態は、出入りする遷移が多くなりすぎて、図の可読性が著しく低下します。
対策:複合状態を使ってサブ状態に分割します。
「処理中」を複合状態とし、内部に「受信中」「検証中」「変換中」「保存中」「通知中」をサブ状態として配置することで、各状態の責務が明確になります。
分割の目安として、1つの状態から出る遷移が5本を超えたら分割を検討すべきです。
アンチパターン3:遷移ラベルの省略
急いで図を描くと、遷移ラベル(イベント・ガード条件・アクション)を省略しがちです。
しかしラベルのない矢印は「何がきっかけで、何が起きるか」が不明になり、設計情報としての価値を失います。
特に問題なのは、レビュー時に「この遷移は何で起きるのか」と質問されても、設計者本人すら思い出せないケースです。
対策:最低限イベント名は必ず記述します。
ガード条件とアクションは、設計の詳細度に応じて追記しましょう。
もし「何を書けばよいか分からない」場合、そもそもその遷移が必要かどうかを再検討すべきです。
アンチパターン4:到達不能状態とデッドロック
設計変更を重ねるうちに、どこからも遷移できない到達不能状態や、遷移が出ていない非終了状態(デッドロック)が生まれることがあります。
到達不能状態は、かつて有効だった遷移が設計変更で削除された際に残骸として残るケースが多いです。
デッドロックは、新しい状態を追加したときに遷移の定義を忘れるケースで発生します。
対策:状態遷移表を作成し、すべての状態が初期状態から到達可能であること、すべての非終了状態から少なくとも1つの遷移が出ていることを機械的に確認します。
ツールによっては自動検証機能を備えているものもあるので、積極的に活用しましょう。
アンチパターンの早期発見チェックリスト
設計レビューの際には、以下のチェックリストでアンチパターンの混入を防ぎましょう。
- 状態数が15個を超えていないか(超えていれば階層化を検討)
- 1つの状態から出る遷移が5本を超えていないか(超えていれば分割を検討)
- すべての遷移にイベント名が記述されているか
- 同じイベントに対するガード条件が排他的かつ網羅的か
- 初期状態からすべての状態に到達可能か
- すべての非終了状態から少なくとも1つの遷移が出ているか
これらを形式的にチェックするだけでも、設計品質は大幅に向上します。
Enterprise ArchitectやMATLAB Stateflowなどのツールには自動検証機能が備わっているので、大規模プロジェクトでは積極的に活用しましょう。
10. 実践例:通信プロトコルの状態遷移設計

これまでの知識を総合して、実践的な設計例を見てみましょう。
題材はTCPコネクション管理の簡略化モデルです。
TCPは信頼性のある通信を実現するプロトコルであり、その接続管理は状態遷移図の教科書的な適用事例として広く知られています。
TCP接続の状態一覧
TCPの3ウェイハンドシェイクを含む接続管理には、以下の主要な状態があります。
- CLOSED:接続なし(初期状態)。通信の開始前または完全な終了後の状態です
- LISTEN:接続要求待ち(サーバ側)。クライアントからのSYNパケットを待っています
- SYN_SENT:SYN送信済み(クライアント側)。接続要求を送信し、応答を待っています
- SYN_RECEIVED:SYN受信済み(サーバ側)。SYNを受信してSYN+ACKを返送し、最終確認を待っています
- ESTABLISHED:接続確立。データの送受信が可能な状態です
- FIN_WAIT:切断要求送信済み。FINパケットを送信し、相手の確認を待っています
- TIME_WAIT:切断後の待機。遅延パケットの到着に備えて一定時間待機します
主要な遷移:接続確立フェーズ
クライアント側の接続確立を遷移で表すと、以下のようになります。
サーバ側の接続確立は次のとおりです。
主要な遷移:切断フェーズ
接続の切断は次のように進みます。
TIME_WAITからCLOSEDへの遷移で使われる2MSL(Maximum Segment Lifetime)は、ネットワーク上の遅延パケットが消滅するのを待つための時間です。
この設計から学ぶポイント
TCP状態遷移の設計には、本記事で解説した概念がすべて含まれています。
ガード条件の活用:同じイベント(パケット受信)でもパケットの種類(SYN、ACK、FIN)によって遷移先が異なります。
ガード条件を使って [パケット種別=SYN] のように判別します。
自己遷移:ESTABLISHED状態でデータパケットを送受信しても、状態自体は変わりません。
しかし内部的にはシーケンス番号の更新やACKの送信といったアクションが実行されています。
タイムアウト遷移:TIME_WAIT状態からCLOSEDへの遷移は、一定時間経過というタイマーイベント(UMLの時間イベント)で発生します。
タイマーベースの遷移は、通信プロトコルやフィードバック制御のタイムアウト処理で頻繁に使われるパターンです。
このように、状態遷移図は通信プロトコルの設計において不可欠な表現手法です。
仕様書で文章だけで記述されているプロトコルも、状態遷移図に落とし込むことで曖昧さを排除し、実装の正確性を高めることができます。
状態遷移図が活躍するその他の分野
TCP以外にも、状態遷移図は幅広い分野で活用されています。
組込み制御:家電製品やFA機器の動作モード管理に使われます。
洗濯機の「洗い→すすぎ→脱水」サイクル、電子レンジの「待機→加熱→一時停止→完了」といった制御フローは、状態遷移図の典型的な適用先です。
ゲーム開発:キャラクターのAI(待機→巡回→追跡→攻撃→退避)やUI画面の遷移管理に使われます。
ゲームの状態管理は複雑になりがちですが、階層化した状態遷移図で整理することで保守性が大幅に向上します。
業務システム:注文処理(受注→確認→出荷→配送→完了→返品)やワークフロー管理にも有効です。
承認プロセスの分岐や差し戻しも、ガード条件付きの遷移として明確に記述できます。
このように、「状態」と「遷移」で振る舞いを記述できるシステムであれば、分野を問わず状態遷移図を適用できます。
まとめ
本記事では、状態遷移図の基本概念からUMLでの書き方と読み方、さらに実践的な設計テクニックまでを解説しました。
状態遷移図は、システムの動的な振る舞いを「状態」「遷移」「イベント」の3要素で可視化する設計手法です。
UMLではステートマシン図として標準化されており、複合状態や直交領域を使って大規模システムにも対応できます。
設計の現場では、状態遷移図で全体像を共有し、状態遷移表で網羅性を検証するという併用が最も効果的です。
テスト設計への活用も含めれば、状態遷移図は設計から品質保証まで一貫して使える強力なツールといえます。
状態爆発や神状態などのアンチパターンを避け、複合状態による階層化を適切に使いこなすことで、保守性の高い設計が実現できます。
PlantUMLのようなテキストベースのツールを活用すれば、設計ドキュメントのバージョン管理やCI連携も容易です。
本記事で解説した各要素を改めて整理します。
- 基本要素:状態(角丸四角形)、遷移(矢印)、イベント・ガード条件・アクション(遷移ラベル)、初期擬似状態(黒丸)、終了状態(二重丸)
- 応用要素:複合状態(階層化)、直交領域(並行動作)、履歴擬似状態(状態の記憶と復元)、フォーク・ジョイン(並行の開始と合流)
- 活用場面:設計ドキュメント作成、状態遷移テスト(有効遷移・無効遷移の検証)、チーム間の仕様共有
初めて状態遷移図を描くときは、状態を3〜5個程度に絞った小規模なモデルから着手するのがおすすめです。
いきなり大規模なシステムに挑戦すると状態爆発を起こしやすく、図が複雑になりすぎて設計の本来の目的を見失ってしまいます。
小さなモデルで基本要素の使い方に慣れてから、複合状態や直交領域を段階的に導入していくと、無理なく表現力を高められます。
まずは身近なシステム(自動販売機、エレベーター、信号機など)を題材に状態遷移図を描く練習から始めてみてください。
状態と遷移を整理する習慣が身につけば、どんな複雑なシステムでも「今どの状態にあり、次に何が起きるか」を明確に把握できるようになります。