はじめに
昨今、仕様駆動開発 (Spec-Driven Development) の名前を耳にする機会が増えてきたと感じています。MiiTel Phone チームにおいても数ヶ月ほど OpenSpec というツールを使用して仕様駆動開発を試みていました。結論として、OpenSpec の採用は取りやめることにしました。今回は OpenSpec をベースに仕様駆動開発を試してみて感じた課題や所感について共有いたします。
前提
- フロントエンド開発における採用です
- 新規開発ではなく、既存プロダクトの開発における導入です
⚠️ 注意書き
本記事は仕様駆動開発の手法や OpenSpec などのツールそのものを非難する意図はありません。
あくまで「MiiTel Phone チームでは合わなかった」というだけであり、 仕様駆動開発が有益であるかどうかは、チームの文化や開発フローなどによっても異なってくると思います。
そのため、最終的には実際にツールや手法などを試してから判断いただくことを推奨いたします。
📚 仕様駆動開発 (Spec-Driven Development) について
概ね「まず Spec を書き、それをベースに AI エージェントにコードを書いてもらう手法」のことを指すことが多いのではないかと思います。
Spec は AI エージェントと人の双方に対して信頼できる情報源として振る舞うことが想定されます。
OpenSpec について
OpenSpec は Node.js 製の仕様駆動開発のためのフレームワークです。
OpenSpec を採用したのは以下の理由からです。
- まずは既存のツールを使用して進めた方が自分達で仕組みを整備するよりも手間が少ないと考えたこと
- Node.js 製であるため、フロントエンド開発においては普段使用しているパッケージマネージャーを使用して導入・管理ができること
- シンプルであり、導入にあたっての心理的障壁が比較的低いこと
- 様々な AI エージェント (Claude Code, Gemini, Codex など) をサポートしていること
使い方
# インストール $ mise use npm:@fission-ai/openspec@latest $ openspec init # Claude Code での利用例 $ claude > /opsx:new
仕様駆動開発を試みた背景
仕様駆動開発を試みたのは、下記が目的でした。
- AI コーディングエージェントは実装や仕様の背景などに関する知識を保持していないことに加え、セッションごとに記憶がリセットされてしまう。必要なコードが削除・改変されてしまうなど、意図せぬコード生成が行なわれてしまうケースをできる限り防止したい。
- 新規メンバーでもプロジェクトのキャッチアップを行いやすくするために、暗黙知をきちんとドキュメント化する仕組みがあると便利ではないかと考えていました。
OpenSpec により仕様駆動開発を実践し、Git リポジトリ内に要求や過去の設計における意思決定の背景などが自然と蓄積されることにより、これらの課題が自然に解消されることを目論んでいました。そして、仕様駆動開発を支援してくれる特定のツールを採用することによって実践のハードルを低下させつつ、チーム内で方法を統一できるようにすることを期待して、まずは導入コストが低いと思われる OpenSpec を導入することにしました。
OpenSpec ってどうなの?
まず OpenSpec においては openspec/specs/<spec>/spec.md に信頼できる情報源としての仕様が蓄積されます。具体的には以下のようなフォーマットの Markdown によって仕様が記述されます。
# Example Specification ## Purpose This app supports a simple, reliable TODO management experience for individuals. ## Requirements ### Requirement: Creating and managing TODO items The TODO app MUST allow a user to create, view, and complete TODO items. #### Scenario: Creating a new TODO - **GIVEN** a user is signed in to the TODO app - **WHEN** the user enters a title and submits the form - **THEN** a new TODO item is created with status "Incomplete" - **AND** the new TODO item appears in the TODO list #### Scenario: Completing a TODO - **GIVEN** a TODO item exists with status "Incomplete" - **WHEN** the user marks the TODO item as completed - **THEN** the TODO item's status becomes "Completed" - **AND** the TODO item is visually distinguished as completed in the list
実装の開始時に /opsx:new コマンドを実行すると、OpenSpec は対話的にやり取りしたを内容ベースに openspec/changes/<change> ディレクトリへ以下のようなファイルを作成してくれます。
design.md- 実装予定の機能に関する設計をまとめたドキュメントproposal.md- 実装予定の機能に関するハイレベルな要約をまとめたドキュメントtasks.md- 実装時に行うべきタスクをチェックリスト形式でまとめたドキュメント<spec>/spec.md- 本実装を進めることによってopenspec/specs/<spec>/spec.mdに対して生じる仕様への差分をまとめたドキュメント
開発が完了したら、/opsx:archive コマンドを実行することで、openspec/changes/<change>/<spec>/spec.md が openspec/specs/<spec>/spec.md へマージされた後、openspec/changes/<change> の各ドキュメントが openspec/changes/archive/<change> へ移動されます。
これにより、openspec/specs/<spec>/spec.md が常に最新化されつつ、過去の実装における意思決定の背景や仕様に関する変化の過程などが openspec/changes/archive/<change> へ蓄積されてゆきます。
まず実装に取り掛かる前に design.md を作成してくれる点は良い点に感じました。事前にチーム内で design.md をレビューすることで、実装に取り掛かる前に考慮漏れがないか検討することができます。
また、OpenSpec は tasks.md のチェックリストに順次チェックをつけながら開発を進めてくれるため、途中まで開発を進めてもらった状態で一度セッションを中断し、後から新しくセッションを作り直して開発を再開してもらうような進め方などもやりやすかったです。
ただし、後述する課題により、少なくとも MiiTel Phone チームの開発においては「わざわざ OpenSpec などのツールを使ってもあまり期待した効果は得られなさそう」というのが率直な結論でした。
OpenSpec がマッチしないと感じた理由について
なぜいまいちマッチしないのか考えたところ、4 つほど要因があるのではないかと思いました。
- フロントエンド開発との相性がそこまでよろしくない
- 手間に見合うほどの効果を実感できなかった
- 他の手法によって代替可能であること
- 仕組みとしてはやや貧弱であること
1. フロントエンド開発との相性がそこまでよろしくない
フロントエンド開発における関心ごとの大半はプレゼンテーションレイヤーに偏りがちです。ドメインレイヤーの関心ごとなどと比較して、自然言語によって「何が正しいか」を形式的に定義・記述することが難しいケースが多いと感じました。
また、プレゼンテーションレイヤーはドメインレイヤーにおける制約や振る舞いなどと比べて変化しやすく、頻繁に Spec の見直しが必要となってしまうケースが多いです。結果として手間がかかると感じてしまうケースがありました。
逆にドメインに関する関心ごとの比率が高いバックエンド開発においての方が仕様駆動開発との相性は良いのではないかと感じました。
2. 手間に見合うほどの効果を実感できなかった ※
そもそも MiiTel Phone チームにおいては、OpenSpec の導入以前から、要件定義の段階で要求や制約などをあらかじめ Notion ドキュメントにまとめてから開発に取り掛かるケースが多かったです。
OpenSpec における openspec/specs/<spec>/spec.md はあらかじめフォーマットが規定されているため、一貫したフォーマットを維持できるなどのメリットもあります。しかし、使い慣れている Notion ドキュメントと比較するとどうしても表現力に制限があると感じるケースが多々ありました。また、全体的にコーディングエージェントに生成してもらった文章はやや冗長になりがちで、人が仕様や要求を理解するためのドキュメントとしてはあまり効果を実感しづらかったという事情もあります。
OpenSpec がドキュメントを生成してくれることにより事前にレビューができるなどのメリットはあるものの、逆に更なるレビューや編集の必要性が発生することにより、却って手間がかかってしまうケースがあるとも感じました。
※ ただし、この課題は OpenSpec の問題というよりは、MiiTel Phone チームにおける開発プロセスとの相性の問題であると思います。
3. 他の手法で代替可能であること
OpenSpec をベースに仕様駆動開発を進めることで、以下のようなメリットが得られます。
- 過去の設計や実装における意思決定の履歴をリポジトリに記録として残すことができる。
- 開発に取り掛かる前に OpenSpec が生成した
design.mdをチーム内でレビューすることで、考慮漏れを探すことができる。
ただし、過去の意思決定の履歴をリポジトリへ記録することは、Git のコミットメッセージをきちんと記述することによって代替可能です。そしてコミットメッセージをきちんと記述することによるコストはコーディングエージェントによって大幅に緩和されています。
また、過去の意思決定の記録は、リポジトリ内に残さずとも、ADR を Notion データベースなどで管理しておき、Notion MCP などによって検索できるように整備しておくことによって代替可能です。
そして、過去の設計や実装における意思決定の履歴がリポジトリ内にファイルとして蓄積されていく (openspec/changes/archive) ことにより、コーディングエージェントが意図せぬタイミングで古いドキュメントを参照してしまい、却ってコード生成の精度が低下してしまうというデメリットが発生する懸念もあることに気づきました。
4. 仕組みとしてはやや貧弱であること
ドキュメントはとても重要なものであるものの、仕様駆動開発における Spec はあくまで静的なドキュメントでしかありません。
そのため、AI エージェントが生成したコードが正しく仕様に則っている状況を維持し続けるためには、結局、信頼性の高いテストコードやコードレビューなどが必要です。
コストを掛けて投資をしていくのであれば、テストコードの信頼施の改善や拡充などにより力を入れ、テストコードを仕様として扱ってゆく方針で進めた方が効果が高いのではないか、という結論に至りました。
ただし、過去の意思決定の記録を残すために ADR を記述することは依然として価値があるとは感じており、このようなプラクティスは今後も実践し続ける想定です。
今後について
最終的に OpenSpec はいまいちチームにおける開発の進め方とマッチせず、メリットを活かし切ることもうまくできなかったこともあり、廃止をすることに決定しました。逆に OpenSpec が想定するやり方にチームの開発プロセスを合わせるという方法もありそうですが、そこまでして導入するメリットも薄い、との判断に至りました。
Notion で ADR や要求などをまとめたドキュメントを用意し、必要に応じて Notion MCP を活用して必要なドキュメントを参照できるようにすれば十分ではないかというのが結論です。
OpenSpec を試していく中で良かったと感じたこととしては、まず、要件や要求などをまとめたドキュメントを用意し、それに基づいて開発を進めるプロセスそのものはそこまで悪くはないと感じました。技術的な詳細はコーディングエージェントに委ねつつ、人はよりハイレベルなポイントに対して注力しやすくなります。
今後は ADR のより積極的な活用や、Notion との連携強化、テストコードの拡充や信頼性の改善などを進めていくことで、より効果的にコーディングエージェントを活用していきたいと考えています。