キャンセル済みのはずの注文が発送されていたと知らされ、画面の前で経緯を静かにたどっている開発者

AIに状態遷移の抜けを洗わせる|ステートマシンの穴の見つけ方

「キャンセルしたはずの注文が、発送されてるんですけど」

問い合わせを受けて履歴をたどると、確かに流れはこうでした。支払いが済み、倉庫で出荷準備が始まり、その数分後にお客さんがキャンセルボタンを押し、それでも出荷処理はそのまま進んでいた。

コードを読んでも、どこも間違っていません。キャンセル処理は「キャンセル済み」にする。出荷処理は「出荷準備中」なら発送する。それぞれは、仕様書に書かれたとおりに動いています。

「出荷準備中の注文がキャンセルされたら、どうするか」だけが、どこにも決められていなかったのです。

この手の穴は、正常な流れを追っているあいだは見えません。仕様書のフロー図は、たいてい「うまくいく道」を1本、上から下へ描いています。穴があるのは、その道から横に外れたところ——ある状態のときに、想定していない操作が来たときです。

この記事では、その「横に外れたところ」を状態遷移の表にして、AIに抜けを洗わせる方法を整理します。状態遷移とは、注文や申請のようなデータが「受付→処理中→完了」のように状態を移っていく決まりのこと。それを決まったルールでだけ動くように作ったものを、ステートマシンと呼びます。

結論:順番は3つです。①並べる——状態と、それを動かす操作(イベント)を、それぞれ漏れなく一覧にする。フロー図ではなく「状態×操作」の表にする。②埋める——表のすべてのマスに「どこへ移る/何もしない/エラーにする」のどれかを書く。空欄をAIに洗わせ、人が決める。③弾く——決めていない遷移を、コードとデータベースの側で止める。同時に来たときも含めて。

覚え方は 並べる → 埋める → 弾く。①がないと②のマスが作れず、③がないと決めた表がコードに届きません。

今日ぜんぶやる必要はありません。①の「状態を一覧にする」だけでも、AIに渡せる材料ができて、相談の中身が変わります。

何が起きているのか——穴は「道」ではなく「マス」にある

壁のボードにカードを縦横に並べて貼る場面、格子の空いたマスに付箋を1枚ずつ貼っていく場面、決められた通路以外に進もうとした箱を係の人が手で止める場面を並べた図
状態遷移の抜けを塞ぐ順番。並べる→埋める→弾く。道ではなく「状態×操作」のマスで見ると、空欄が穴として見えてくる

打ち手の前に、なぜ状態遷移の抜けが生まれやすいのかを整理します。原因の側を先に見ておくと、AIに何を渡せばいいかが見えてきます。

1つ目は、仕様書やフロー図が「道」で描かれていること。受付→支払い済み→出荷準備中→発送済み→完了。この1本の矢印は分かりやすい反面、それぞれの状態で「ほかの操作が来たら」がほとんど描かれません。状態が5つ、操作が5つなら、組み合わせは25マス。図に描かれているのは、そのうち4〜5本の矢印だけ、ということがよくあります。

2つ目は、状態を表す値が、コードのあちこちで直接書き換えられていること。order.status = "CANCELED" がキャンセル処理にも、管理画面にも、夜間バッチにも書かれている。どこから、どの状態へ移れるのかが、1か所に集まっていないので、全体を見渡す手段がありません。

3つ目は、フラグで状態を表していること。is_paid、is_shipped、is_canceled のような真偽値が並んでいると、「支払い済みで、発送済みで、キャンセル済み」のような、あり得ない組み合わせも表せてしまいます。フラグが3つなら組み合わせは8通り。そのうち意味があるのは半分くらい、ということも珍しくありません。

4つ目は、AIに頼むと、正常な道だけの実装が返ってきやすいこと。「注文のステータス管理を書いて」と頼めば、きれいな1本道のコードが出てきます。AIが手を抜いているのではなく、「横から来る操作」を前提として渡していないだけです(AIにコードを書かせる前に渡す前提と制約|伝え方の型)。

5つ目は、人と時間が操作に絡むこと。利用者のキャンセル、担当者の差し戻し、決済サービスからの通知、期限切れのバッチ。それぞれ別の人・別の仕組みが、別のタイミングで同じデータを動かします。遷移の表が頭の中にしかないと、誰かの操作が別の誰かの前提を崩します。

6つ目は、AIが「業務として許されるか」までは決められないこと。出荷準備中のキャンセルを受けるか断るかは、倉庫の運用、返金の手順、お客さんへの約束で決まります。AIは選択肢を並べることは得意ですが、どれを選ぶかは業務の判断です。

裏を返すと、これは腕前の問題ではなく、見る形の問題です。道ではなくマスで見ると、空欄は勝手に目に入ってきます。そしてマスを洗い出すのは、AIがいちばん得意な作業のひとつです。

具体例——つい、こうなりがちという形

どれも「まず正常な流れを動かそう」という自然な順番から生まれます。心当たりのある行があれば、そこだけ見れば十分です。

影響——矛盾したデータは、あとから説明が要る

急いで全部直さないと危ない、という話ではありません。ただ、出たときの後始末が重い種類の問題なので、書いておきます。

少し安心できる話をすると、この領域は打ち手がはっきりしています。作りを全部入れ替える必要はありません。状態を一覧にして、表の空欄を埋めるところから始められますし、その作業はAIがかなり手伝ってくれます。

明日からやること(並べる・埋める・弾く)

上から順に、小さく始められます。今日は①だけで構いません。

1. 並べる——状態と操作を、それぞれ一覧にする

ここを飛ばして「抜けを探して」と頼んでも、AIの答えは一般論になります。材料さえそろえば、残りは一気に進みます。

2. 埋める——表のすべてのマスに、答えを書く

縦に状態、横に操作を並べた表を作り、すべてのマスに次の3つのどれかを書きます。

ここでAIがよく効きます。表を渡して「空欄のマスと、決めた内容が怪しいマスを挙げて」と頼むと、人が見落としがちな組み合わせを、ほとんど機械的に拾ってくれます。

3. 弾く——決めていない遷移を、コードとデータベースで止める

表を決めても、コードに届かなければ効きません。決めた表以外の動きを、仕組みで止めるところまでやって、ひとまとまりです。

AIに相談するときのプロンプト(コピーして使えます)

前提を渡さないと、AIは正常な1本道を返してきます。表の形で出すこと、空欄を勝手に埋めないことを、先に伝えるのがコツです。

ある業務データの状態遷移について、抜けと矛盾を洗い出す手伝いをお願いします。

①下に示す状態と操作をもとに、縦に状態・横に操作を並べた表を作ってください。
②私が決めた遷移を表に書き入れ、決まっていないマスは「未定」と書いてください。未定のマスを推測で埋めないでください。
③「未定」のマスごとに、考えられる選択肢(移る/何もしない/エラーにする)を挙げ、それぞれ業務上どんな影響が出るかを一言添えてください。
④行き止まりの状態(終わりの状態以外で、どこへも移れないもの)と、たどり着けない状態があれば指摘してください。
⑤同時に来うる操作の組み合わせ(利用者の操作とバッチ、外部通知と担当者の操作など)を挙げ、どちらが先に来ても矛盾しないか点検してください。
⑥同じ操作が2回来たとき、順番が逆に来たときの扱いが決まっていないマスを挙げてください。

なお、業務として許されるかどうかは判断しなくて構いません。選択肢と影響だけ並べてください。

対象のデータ:( ) 状態の一覧:( ) 操作の一覧(誰が・何をきっかけに):( ) 決まっている遷移:( ) 終わりの状態:( )

②の一文が効きます。「未定のまま残して」と先に伝えるだけで、AIがもっともらしく埋めてしまうのを防げます。空欄が空欄のまま見えることが、この作業のいちばん大事なところです。

出てきた表は、次の3点だけ自分の目で確かめます。(1)自分が渡していない状態や操作が、いつのまにか足されていないか、(2)「未定」と書かせたマスに、推測の移り先が入っていないか、(3)外部通知やバッチのように、人以外の操作が表に入っているか。この3点は、表の形が整っていても抜けていることがあります(設計レビューの見落としをAIに洗わせる|プロンプトの型)。

状態遷移の抜けを塞ぐチェックリスト(コピーして使えます)

全部に○が要るわけではありません。気になった行だけで十分です。

① 並べる

② 埋める

③ 弾く

この記事のまとめ

状態遷移の抜けは、腕前の問題ではなく見る形の問題です。フロー図の1本道ではなく、「状態×操作」のマスで見ると、決めていなかった組み合わせが空欄として見えてきます。

やることは3つ。①並べる——状態と操作を、それぞれ漏れなく一覧にする。②埋める——すべてのマスに「移る/何もしない/エラーにする」を書き、空欄はAIに洗わせて人が決める。③弾く——状態を変える入口を1か所に集め、「今の状態」を条件にして更新し、決めていない遷移を止める。

AIに相談するときは、「未定のマスを推測で埋めないで」と先に一言添える。それだけで、穴が穴のまま見えるようになります。

朝のオフィスで、壁に貼った表のマスがすべて埋まったのを同僚と一緒に眺め、穏やかに笑い合っている開発者

キャンセルされた注文が発送されていたと知ったとき、まず自分の書いた処理を疑ったと思います。実際には、どの処理も指示どおりに動いていて、決められていないマスが1つあっただけでした。

これは、気をつけて防ぐ種類のものではありません。表にして見える形にする種類のものです。そして表は、状態を一覧にするところから作れます。

今日は、あなたのシステムで状態が変わるデータをひとつ選んで、状態の名前を縦に並べてみる。それだけで、次の「どうしてこうなったんですか」に、落ち着いて答えられる日が近づきます。

よければ、こちらも

関連用語