ポエム

設計は「最も起きてはいけないこと」から考える

AI時代に書くようなことでもないかもしれないけど、改めて自分の中にある単純だけどよくお世話になる設計思想を書き下してみます。

設計という言葉は広くて、アーキテクチャから実装まで含むものだと思います。私自身は「何を作るか」「どう作るか」の間にある思考全般を設計と呼んでいますが、その中心には「最も起きてはいけないことを防ぐ」という視点があると感じています。

もちろん、価値提供の速度や、変更のしやすさ、開発体験なども同時に大事です。ただ、設計の中で「最も起きてはいけないこと」を常に考え続けるのが、私にとって重要事項の1つです。

「最も起きてはいけないこと」から設計を始める

設計の入口を「最も起きてはいけないこと」とすると、優先順位が明確になります。ここで言う「最も起きてはいけないこと」は、発生確率ではなく「起きたときのダメージ」に寄ります。つまり「頻度は低いが、起きたら致命的」というものです。

たとえば次のような視点です。

  • 法的・契約的にアウトな状態にならないか
  • 業務が止まり、復旧不能に近い状態にならないか
  • 取り返しのつかないデータ損失が起きないか
  • 誰の責任か分からない、ボールが浮く状態が発生しないか

この種のリスクは、発生した段階で致命的になるケースがあります。だからこそ、設計の最初に「最も起きてはいけないこと」を列挙し、構造で潰す必要があると考えています。

機能的・非機能的なリスクを並べる

シンプルに、機能的なリスク非機能的なリスクを分けて洗い出すことから考えていきます[1]。機能的とは「仕様として想定する失敗」、非機能的とは「性能・運用・セキュリティなどの失敗」です。

例として「社内の申請・承認ワークフローシステム」を考えます。

  • 機能的リスクの例

    • 申請が承認されず、誰にもアサインされないまま放置される
    • 担当者が二重にアサインされる
    • 取り消し済みの申請が、誤って承認に進む
  • 非機能的リスクの例

    • 再送で重複イベントが発生し、二重処理になる
    • DB障害で整合性が崩れ、復旧に時間がかかる
    • 権限ミスで不正アクセスが成立する

この中で「最も起きてはいけないこと」を決めます。これは作るシステムの機能や、利用するインフラなどによって変わると思います。
例えば担当者が二重にアサインされても、発生確率が低くかつ担当者自身が片方の申請を自分で気づいて修正できるシステムなら、担当者にとっては気の毒ですが、絶対に起きてはいけないというレベルではないかもしれません。一方で誰にもアサインされない状態が発生している場合、申請が放置されてしまい業務が止まる可能性があるなら、こちらのほうが「最も起きてはいけないこと」に近いかもしれません。

具体例: 「誰にもアサインされない」状態を潰す

「誰にもアサインされていない状態」は絶対に避けたい、という結論になった場合。設計の打ち手は大きく2つあると思います。

1つ目は運用でカバーする。例えば、毎朝「未アサイン一覧」を担当者に通知する、一定時間アサインがない場合はアラートを飛ばすなどです。これも価値がありますが、人間に運用負荷がかかっていきます。

2つ目は構造で潰す。具体的には、DB制約や遷移制約を入れて「未アサインのまま承認ステップに進めない」「アサイン無しの状態を保存できない」などを強制します。これにより、「起きてはいけないこと」がそもそも起きない設計になります。

私は可能な限り後者を選びます。運用は最後の砦として残しつつ、仕様と制約で潰すほうが設計として強いからです。

具体例: 同時に起きてはいけないことがあるならロックする

もう1つの例として、「2つのワークフローの処理が並列で絶対に起きてはいけないこと」を考えます。

  • 同じ申請に対して「承認」と「差し戻し」が同時に走る
  • 同じ在庫を複数の出荷が同時に確保する

こう書くとRDBMSのよくある例ではありますね。発生頻度自体は低いですが、発生するとかなーり悲しいことになります。

一般論的には何らかのロック機構を入れるのが設計上の自然な選択になります。排他ロックでも良いし、楽観ロックでも良い。あるいはワークフローの状態遷移をトランザクションで保護するだけでも良い。とにかく「同時に起きてはいけないものが同時に起きない」ことを保証する仕組みが必要です。microservices architectureのパターンを調べたときに出てきたEnsure Idempotencyなんかも使えるかもしれませんね。

まとめ

システムを作る以上リスクはゼロにできません。インシデントが発生したときに、お客様に迷惑がかかる・必要以上に金銭的コスト、人的コストがかかる状態は誰も嬉しくありません。一方でが、そういった悲しき事態が発生するような最も起きてはいけないことは極限まで確率を下げ、仮に発生するような場面があってもルールが明確になった運用で対応できるようにする。システムを作る上ではそれが重要だなと思います。

AIの設計やAIの書くコードは素早く素晴らしいものがあります。一方でAIは設計通りに実装をし、裏の意図を汲み取らないケースもあります。ワークフローぐらい一般論的だと、AI側もリスクを理解して実装するかもしれません。我々の設計が「正常系の実装」のみを考えていると、AIも「正常系の実装」しかしません
結局、1日8時間例外がないか考え続け、1日8時間例外が発生したときのリスクを考え、1日8時間リスクが発生しない・した場合のことを考えた設計でないと、リリースしてから問題が多発することになります。1%でしか発生しない問題も1,000回行えば10回発生し、10回もミスが起きると信頼も消えます。
リスクを洗い出す思考労働もいずれかはAIが行うかもしれません。実際にリスクを徹底的に調べさせると一般論的なリスクは完璧に出してくれます。しかし商慣習・社内ルール・ドメイン知識、これらに踏み出すと精度は著しく落ちます。この辺のデータを入力するにも、そもそも言語化されていない・言語化する際に人間が誤る・AIのコンテキストが足りなくなる、といった問題があります。

ただ動くものを作るだけなら、AIにポン投げでいいですが、堅牢に動くシステムは一歩その先、起きてはいけないことを防いでいく設計が必要だと思います。一番最初にAI時代に書くことでもないと言いました。書いてて思ったけど、あと数年は人間がこの辺を考える必要があるのかなと思うし、AI時代一周回って大事なのかもね。


  1. ISMSなどで行うリスクアセススメントなどを通じて、より明確にしていく必要があるかもしれません。私自身は作るもの的にそこまで厳密に数値化しないことが多いです。 ↩︎