はじめに:「動くコードがある」は「正しいものを作った」ではない
AIを使えば、曖昧な指示からでも動くコードが手に入る。
これは事実だし、開発の速度は確かに上がった。
しかし、ある現場での経験が頭に引っかかって離れない。
ユーザーの要求を忠実に実装し続けた結果、システムは肥大化し、機能が乱立し、最終的に「これは正しく動いているのか」を誰も判断できなくなった。
コードは動いている。
テストも通っている。
だが、何を達成しようとしていたのかが見えない。
原因はAIではなく、仕様がなかったことだ。
この記事は、AI時代においても仕様と設計は必要だ、という個人的な考えを整理したものだ。
なぜ「仕様不要」と言われるようになったのか
前提として、開発のコスト構造が変わっている。
従来の開発では、実装コストが高かった。
だから、事前に要件や設計を固めることには経済的な合理性があった。
- 要件を固める
- 仕様を決める
- 設計を詰める
- 実装する
- 試験する
この順序は、単なる形式ではない。
手戻りのコストが大きいから、前工程に投資していた。
AIの登場で、この前提はかなり変わった。
試行錯誤のコストが下がり、「まず作ってみて、動いたものを見ながら直す」という進め方が成立しやすくなった。
結果として、仕様や設計を事前に定義することが「相対的にコストの高い行為」に見えるようになった。
ただし、ここで一つ混同が起きている。
「省略しやすくなった」と「省略してよくなった」は別の話だ。
現場で起きること
ケース1:仕様がコードに埋もれる
ユーザーから「こういう機能が欲しい」という要求が来る。
AIでコードを生成し、動いたのでリリースする。
次の要求が来る。
また実装する。
これを繰り返す。
気づいたときには、次のような状態になる。
- ファイルI/O、DB、APIの挙動をコードから追わないと把握できない
- 改修しようとすると、影響範囲が分からない
- 「このシステムは外部からどう見えるのか」を誰も説明できない
これは、外部との契約である仕様がコードに埋没している状態だと思う。
ドキュメントを更新するより、コードを直す方が早い。
その判断が積み重なると、仕様はコードの中にのみ存在することになる。
読めば分かる、はずだ。
しかし、誰も全体を把握していない。
ケース2:設計がなく、正しさを評価できない
冒頭の失敗談の本質は、ここにあった。
ユーザーの要求を字義通りに実現し続けた。
要求はすべて正当だった。
実装もできた。
しかし、システム全体として何を達成すべきかの構造が誰の頭にもなかった。
結果として起きたのは、次のようなことだった。
- 目的の重複した機能が乱立する
- 「これは仕様通りか」を判断する基準が消える
- テストが網羅的かどうかを誰も保証できない
コードは動いている。
しかし評価できない。
「動く」と「正しい」は別の問いだ。
設計がなければ、後者に答えられない。
仕様と設計をどう分けて考えるか
自分は、仕様と設計を次のように分けて考えている。
| 概念 | 何を書くものか |
|---|---|
| 要件 | 何を実現したいのか、なぜ必要なのか |
| 仕様 | 外部から見た振る舞い、入出力、制約、約束 |
| 設計 | 仕様を満たすための構造、責務、データの流れ、評価基準 |
| 実装 | 実際のコード、ライブラリの使い方、細かい処理手順 |
仕様は、外部との契約を書くものだと思う。
誰が何のために使うのか、何を入力し、何を出力し、どのような振る舞いを保証するのかを書く。
設計は、その仕様を満たすための構造と評価基準を書くものだと思う。
どの責務をどこに置くのか、データがどう流れるのか、何をテストすれば正しいと言えるのかを書く。
一方で、内部ロジックを逐一書き下す必要はない。
具体的なライブラリの使い方や細かい処理手順は、コードに任せた方がよいことも多い。
細かい内部ロジックを書かなければ開発できないなら、責務の分け方が曖昧だったり、不要な機能を先回りして設計していたりする可能性がある。
仕様がないと判断する基準
自分は、次のような状態なら「仕様がない」と判断する。
- 何を実現したいのかが明確でない
- 誰が何のために使うのかが明確でない
- 何を入力として必要とするのかが明確でない
- 何を出力するのかが明確でない
- 何が正常系なのかが未定義、または曖昧
- 異常系を想定していない
- 性能やセキュリティなどの制約が未確定
仕様がない状態では、外部から見た振る舞いを説明できない。
つまり、利用者や他システムに対して何を約束しているのかが分からない。
この状態で実装だけが進むと、後から「これは正しい挙動なのか」を判断できなくなる。
設計がないと判断する基準
自分は、次のような状態なら「設計がない」と判断する。
- 機能、DB、ファイル、外部APIとの入出力形式が未定義
- データの流れが未定義
- 責務の境界が曖昧
- 状態をどこで持つのかが決まっていない
- 何をテストすれば正しいと言えるのかが分からない
設計がない状態では、システムの内部構造を説明できない。
つまり、仕様をどう満たしているのかが分からない。
その結果、変更時の影響範囲が読めなくなる。
実際に破綻したとき、一番困ったのもここだった。
影響範囲を正確に把握できないことが、手戻りを大きくした。
AIは設計を消したのではなく、見えにくくした
ここが核心だと思っている。
AIは設計を不要にしたのではない。
設計を暗黙化した。
従来、人間が明示的に行っていたプロセス、つまり分解、抽象化、構造の選択を、AIが一部代替し始めている。
しかし、それは設計が消えたことを意味しない。
- 以前:設計書や議論の中に設計が記述されていた
- 現在:プロンプト、生成されたコード、モデルの出力傾向に設計が分散している
この変化で何が起きるか。
設計の責任者が見えにくくなる。
設計書があれば、「ここはなぜこうなっているのか」を問える。
しかし、プロンプトや生成コードの中に設計が埋まっているなら、その問いはどこに向ければよいのか。
AIに「いい感じに作って」と頼むとき、「いい感じ」の定義は誰が持っているのか。
それが明文化されていなければ、評価できない。
評価できなければ、改善もできない。
AIに任せてよいこと、任せるべきでないこと
AIに任せてよい部分はある。
むしろ、そこは積極的に任せればよいと思う。
たとえば、次のような部分だ。
- 設計を具体的なコードに落とす
- 既存コードに合わせた実装案を出す
- テストケースのたたき台を作る
- 曖昧な要求に対して、要件定義のための質問を出す
特に、AIに質問してもらいながら要件を明確化する使い方は有効だと思う。
人間が主体になり、AIを壁打ち相手として使う形だ。
一方で、任せるべきでない部分もある。
- 何を作るべきかの決定
- どの品質を保証すべきかの決定
- どの制約を優先するかの判断
- 曖昧な要求を、そのまま設計まで詳細化すること
AIは選択肢を出せる。
しかし、どの選択肢がこのシステムにとって正しいかを決めるのは人間の責任だと思う。
最低限、何を残すべきか
稠密な仕様書や詳細設計書を、全工程で作れと言いたいわけではない。
ただ、最低限これだけは残した方がよいと思っている。
最低限の仕様
- 何を目的としているのか
- 誰が何のために使うのか
- 入力は何か
- 出力は何か
- 正常系の振る舞い
- 異常系の振る舞い
- 外部API、DB、ファイルとの契約
- 性能、可用性、セキュリティなどの外せない制約
最低限の設計
- 仕様を満たすために必要な構成要素
- 各構成要素の責務
- データの流れ
- 状態をどこで持つか
- 変更時に影響を受ける範囲
- テストで何を保証するか
- あえてやらないこと
重要なのは、仕様や設計をテストに落とし込める形にすることだと思う。
「何を目的としていて、それを実現するために何が必要なのか」
「その実現をどうやって確認するのか」
この2つがつながっていれば、少なくとも「動いているが正しいか分からない」という状態は避けやすい。
逆に、書かなくてよいと思うもの
何でも書けばよいわけではない。
自分は、次のようなものまで設計書に詳しく書く必要は薄いと思っている。
- 具体的な処理内部の細かいロジック
- ライブラリの細かい使い方
- 実装時点でしか意味を持たないコーディング方法
- コードを読めばすぐ分かる局所的な分岐
こうしたものは、実装中に変わりやすい。
変わりやすいものを詳細に書きすぎると、ドキュメントがすぐ古くなる。
仕様や設計に残すべきなのは、コードより長く生きる判断だと思う。
設計には「鳥の目・虫の目・魚の目」がいる
伊藤元重氏の『経済を見る3つの目』に、「鳥の目・虫の目・魚の目」という考え方がある。1
- 鳥の目:全体を俯瞰する視点
- 虫の目:現場の細部を見る視点
- 魚の目:流れや変化を読む視点
これは経済を見るための考え方として紹介されているものだが、自分はシステム設計にもかなり近いものがあると思っている。
鳥の目:全体として何を作っているのかを見る
鳥の目は、システム全体を俯瞰する視点だ。
- このシステムは何を達成するためのものか
- どのサブシステムが、どの責務を持つのか
- サブシステム同士はどうつながるのか
- 外部から見たとき、何を約束しているのか
仕様や設計がないまま実装を積み上げると、この視点が失われやすい。
個々の機能は正しく動いていても、全体として何を作っているのかが説明できなくなる。
冒頭で書いた失敗も、まさに鳥の目を失った状態だった。
虫の目:局所の入出力と制約を見る
虫の目は、個々の機能や実装上の制約を見る視点だ。
- この機能は何を入力として受け取るのか
- 何を出力するのか
- DB、ファイル、外部APIとの境界はどうなっているのか
- どの異常系を扱う必要があるのか
- どのテストで正しさを確認するのか
AIでコードを書くと、この虫の目はむしろ強化されることが多い。
局所的な実装、テスト、リファクタリングは速くなる。
ただし、虫の目だけで進めると、局所最適に陥る。
細部はよくできているのに、全体の目的からずれていく。
魚の目:変化の流れを見る
魚の目は、流れや変化を見る視点だ。
- 要求はどちらに変わりそうか
- どの仕様は固定すべきで、どの仕様は変わる前提にすべきか
- どの技術選定は将来の制約になりそうか
- 今の設計は、次の変更に耐えられるか
AI時代には、この視点が特に重要だと思う。
実装が速くなると、要求や要望がすぐコードに反映される。
それ自体はよいことだが、変化の流れを読まずに積み上げると、いつの間にかシステム全体が歪む。
「今ある要求に答える」だけでなく、「どの方向に変わりそうか」を見ておかないと、設計はすぐ古くなる。
自分にとって仕様と設計は、この3つの視点を行き来するための道具でもある。
鳥の目で全体を見る。
虫の目で細部を見る。
魚の目で変化を見る。
そのどれか一つだけでは、システムを正しく捉えきれない。
現実的な進め方:大域と局所の挟みうち
現実には、最初から完全な仕様や設計を作るのは難しい。
だから、自分は次のように進めるのがよいと思っている。
- 大域的に、要件・仕様・設計を置く
- 局所的に、制約・要望・実装上の発見を拾う
- その間を往復しながら固める
上から「何を作るべきか」を定義する。
下から「今見えている制約や要望」を拾い上げる。
その間をAIも使いながら往復する。
片方だけでは、方向がぶれる。
要件や設計だけを固めても、実装上の制約を無視すれば机上の空論になる。
逆に、局所的な要望や制約だけを積み上げても、全体として何を作っているのかが分からなくなる。
AI時代の開発では、この往復の速度が上がった。
だからこそ、往復の軸になる仕様と設計が必要になるのだと思う。
おわりに
AIは強力なツールだ。
試行錯誤のコストを下げ、実装速度を上げ、個人の生産性を引き上げる。
それ自体を否定する気はない。
しかし、AIは「何を作るべきか」を教えてくれない。
要求を言葉にすること。
構造を選択すること。
品質を定義すること。
それは人間が担うべき判断だと思う。
仕様のないシステムは腐る。
AIは、その腐敗を見えにくくしたまま加速させることがある。
問うべきは「仕様は必要か」ではない。
「自分は今、何を作っているのかを説明できるか」
そこに答えられるようにするために、AI時代だからこそ仕様と設計が必要だと思う。
-
伊藤元重氏の『経済を見る3つの目』では、経済を見る視点として「鳥の目」「虫の目」「魚の目」が紹介されている。慶應MCCの講演レポートでもこの考え方が紹介されている。https://www.keiomcc.com/magazine/report139/ ↩