9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

すでに一定量のコードがある既存の開発チームにOpenSpecを導入したときに行ったことと、その後、使用してみて感じたことをまとめました。

やりたかったこととOpenSpecを選んだ理由

今回OpenSpecを導入したプロジェクトは新規のプロジェクトではなく、すでにスクラムを採用して開発をしているチームで、コードもある程度の量がすでに完成しているプロジェクトです。既存の開発フローやリポジトリ構成を大まかに説明すると、次のような感じです。

  • 1週間のスプリントで開発を進めるスクラム開発
  • PBI(Product Backlog Item)ベースでタスク管理
  • スプリントごとに対応するPBIを決める
  • PBIの実装方針は開発チーム全員で合意してからWikiにまとめて実装に入る
  • 実装は個人の場合もあればペアプロやモブプロで進めることもある
  • コードレビューはPRベースで行う
  • リポジトリはmainブランチと開発時に作成するfeatureブランチの構成(developブランチはなし)

AIを使った開発(Claude CodeやGitHub Copilot、スキルやプロンプトの用意)はしていたのですが、これを強化しつつ、既存の開発フローやリポジトリのブランチ構成などを変えずに導入できるツールを探していました。
また、すでに稼働中のWebアプリケーションのコードがあるため、新規開発でなくても導入しやすいツールが望ましいと考えていました。

その条件の中でOpenSpecが良さそうだと感じた理由は、主に次の5つです。

  1. proposeからarchiveまで順番に実行していくだけと覚えることが少なく、導入ハードルが低かったこと
  2. AI駆動開発用の開発フローに変更せず、スクラム開発のスプリントの中で既存のブランチ運用やPRベースの開発フローを大きく変えずに入れられたこと
    • OpenSpecの公式ドキュメントにも「built for brownfield not just greenfield」と明記されている通り、既存リポジトリへの導入を意識した設計になっています。
  3. openspec/config.yamlに既存ドキュメントや運用ルールを寄せることで、AIに読ませたい文脈をリポジトリ側に置けること
    • OpenSpecの開発フローに乗ることで「どのコマンドを使って何を生成するか」がチーム内で揃う。個々のメンバーが独自にプロンプトを工夫しなくても同じ流れで進められるため、AIの活用レベルが個人のスキルに依存しにくくなることを期待しました。
  4. proposal.mdtasks.mdの形で、実装前の合意内容をファイルとして残せること
    • チームで実装方針を先に合意してから実装に入るフローがあったため、/opsx:proposeで生成されるproposal.mdやdesign.md、tasks.mdがその合意の場としてそのまま使えました。リポジトリに合意内容が残るのでレビュー等でも確認しやすいですし、後から見返すときも便利そうだと感じました。
  5. Claude CodeとGitHub Copilotの両方から似た流れで使えて、エージェントをまたいでも運用しやすかったこと

特に良かったのは、AI駆動開発を強めながらも、いきなりチームのやり方を全部変えなくてよかったことです。今あるスクラム開発の流れに、explore、proposal、apply、archiveのレイヤーを足す感覚で入れられたので、導入負荷が低く抑えられたと思います。

OpenSpecの概要

導入した話に入る前にOpenSpecがどういう流れで動くかだけ簡単に触れておきます。

OpenSpecは、AIにいきなり実装させるというより、まず変更内容をchangeとして切り出して、そのchangeに対して提案、実装、反映を進める形のツールです。作成したchangeは開発中のみ使用され、最終的にspec(正式な仕様)として反映されるイメージです。
ざっくりした流れは次のとおりです。

  1. /opsx:proposeでchangeを作り、proposal.mddesign.mdtasks.mdなどの計画用ファイルとこの変更によるdelta spec(specの差分)を作る
  2. 人間がその内容をレビューして、方針を固める
  3. /opsx:applyでtasksに沿って実装を進める
  4. /opsx:archiveでchangeの内容を本体のspecに反映して履歴化する

図にするとこんなイメージです。

このとき大事なのが、OpenSpecには「作業中の変更」と「現在の正式な仕様」の2層があることです。

  • openspec/changes/配下は、いま進めているchangeの作業場所
  • openspec/specs/配下は、現時点での正式な仕様

changes側にあるspecは、そのchangeで追加や変更したい内容だけを書く差分の仕様、いわゆるdelta specです。最終的に/archiveすると、その差分がopenspec/specs/側へ反映されます。

openspec/
├── changes/
│   └── <change-name>/
│       ├── proposal.md
│       ├── design.md
│       ├── tasks.md
│       └── specs/          ← delta spec(変更分の仕様)
└── specs/                  ← 正式なspec(/opsx:archiveで反映)

OpenSpecではこのspecsにコードの振る舞いを蓄積していくことで、後続の作業では「いまのコードはこういう仕様になっている」というのをAIに理解させながら進められるようになります。

既存リポジトリへの初期導入

OpenSpecを使い始めるにあたり、まずはOpenSpecをインストールして、リポジトリに初期設定を入れ、そして既存コードから仕様を切り出してopenspec/specs/に入れるところまでを行いました。

開発端末へのOpenSpecのインストールとテレメトリ設定

リポジトリにOpenSpecを入れる前に、まずは開発端末にOpenSpecをインストールする必要があります。インストール方法は公式のインストールガイドに従ってください。使い始める前に行った設定として、OpenSpecはテレメトリ収集を無効化できるので、自分たちは無効化しました。無効化時に設定する環境変数は次の2つです。

  • OPENSPEC_TELEMETRY=0
  • DO_NOT_TRACK=1

どちらかを設定すれば、OpenSpecのテレメトリを無効化できます(が、両方設定してます)。実際の設定コマンドや最新の案内は、公式リポジトリのTelemetryセクションを参照してください。

openspec initでOpenSpecの基本構成を作る

導入したいリポジトリに移動して、まずはopenspec initを実行します。これでOpenSpecが使うopenspec/ディレクトリと各AIエージェントが参照するOpenSpecのコマンドやスキルが生成されます。

openspec init

詳細は公式ドキュメントのQuick Startセクションを参照してください。

openspec/config.yamlの設定

OpenSpecは初期化しただけでも使えますが、各コマンドの挙動やAIに理解させたいプロジェクトの文脈をopenspec/config.yamlに書いていくことで、より効果的に使えるようになります。

自分たちの設定では、次のような情報を入れました。

  • 技術スタック
  • どの層がどの層に依存してよいか
  • 既存のアーキテクチャ資料やコーディング規約
  • テスト方針
  • specをどの単位で分けるか

公開用に少しぼかすと、こんなイメージです。使い始めてから徐々に更新していく形でも問題ないと思いますが、最初にある程度入れておくと、AIがプロジェクトの文脈を理解しやすくなります。

openspec/config.yamlで設定できる主な項目としてcontextrulesがあります。contextは全ての指示に共通してAIに理解させたいプロジェクトの文脈を入れる場所で、rulesはproposalやspecs、tasksなど生成するものごとに個別にルールを指定できる場所で、デフォルトではproposalspecsdesigontasksが指定できます。

schema: spec-driven

tools:
  - claude
  - github-copilot

context: |
  Tech stack: TypeScript, Next.js, Zod

  Architecture:
  - page -> usecase -> infrastructureの単方向依存

  Reference documents:
  - docs/architecture/overview.md
  - docs/guidelines/coding-guidelines.md
  - docs/guidelines/testing-guidelines.md

  Spec directory structure convention:
  - specs/<feature>/page/
  - specs/<feature>/usecase/
  - specs/<feature>/datasource/

rules:
  proposal:
    - 日本語で記述する
  design:
    - unitテスト・integrationテスト・E2Eテストの変更が必要かを判断する
  specs:
    - 画面仕様(page)は****を記述する
    - ユースケース仕様(usecase)は****を記述する
    - データソース仕様(datasource)は****を記述する
  tasks:
    - タスクは数時間で完了できる粒度に分割する
    - unitテスト・integrationテスト・E2Eテストの変更が必要かを判断する
    - ドキュメントとの整合性を確認するタスクを入れる
    - タスクの最後にはテストとフォーマッターを走らせる

specのディレクトリ構成を先に決める

OpenSpecではopenspec/specs/以下にそのリポジトリの振る舞いをガーキン記法で残していきます。このspecsの構成は、最初に決めておくと運用しやすいと思います。
何も指定しないと、フラットにspecs/配下にmdファイルが並ぶ構成になったり、1つのファイルに大量に書かれたりして管理が大変になる場合があります。

そこで、自分たちは独立したサイト(feature)ごと、さらにその中で責務ごとにディレクトリを分ける方針にしました。

openspec/specs/
└── <feature>/
    ├── page/
    ├── usecase/
    ├── datasource/
    ...
    └── e2e/

この分け方にした理由は3つあります。

  1. 画面仕様とビジネスルールと外部連携の関心事を分けて管理したかった
  2. 開発時のタスクの粒度に合わせた単位で分けたかった
  3. specのコンフリクトを減らしたかった

これがベストというよりは、チームの開発スタイルやプロジェクトの内容に合わせて決めると良いと思います。決定したら、openspec/config.yamlにルールとして書いておきます。

既存コードから初期specを起こした流れ

新規開発と違って、既存リポジトリでは最初のspecが空です。ここは少し工夫が必要でした。
自分たちは、前述のopenspec/config.yamlの設定を行った後、まず/opsx:exploreで「既存コードからspecを作りたい」と指示をしつつ、コードだけではなくWikiやマージ済みのPRなども参照するように指示に加えて、情報収集とspecの生成を行いました。

流れとしては次の4ステップです。

  1. /opsx:exploreで既存コードと既存資料の関連箇所を調査させる(過去のPRやWikiで管理している箇所を指定)
  2. /opsx:proposeでproposal.md、design.md、tasks.mdを作る
  3. 人間がproposalをレビューして修正する
  4. /opsx:applyでspecを生成し、最後に/opsx:archiveで反映する

この/opsx:explore/opsx:proposeのタイミングはできれば性能の良いモデルを使う方が良いかもしれません。また、GitHub MCPやAtlassian MCPなどを呼べるようにして調査中に必要な情報を引っ張ってこれるようにしておくと良いかもしれません。specの構造を変えやすいのはこの段階なので、生成されたものが気に入らなかったら消してやり直すのもありだと思います。

導入後に整理・改善したこと

OpenSpecを使うべき変更と、使わなくてよい変更

導入後に開発メンバーから上がった声として、軽微な変更まで全部OpenSpecに乗せるのは重いのではないか、というものがありました。
そこで、OpenSpecを使うべき変更と、そうでない変更を整理しました。

OpenSpecはガーキン記法でコードの振る舞いをspec化していくスタイルです。
このためspecで管理しない(振る舞いを変更しない)ものは、OpenSpecを使わなくても問題ありません。
整理した結果は以下です。

変更の種類 OpenSpec 備考
typo修正 任意 振る舞いに影響なし
コメント・JSDoc 任意 同上
リファクタリング(振る舞い不変) 任意 同上
ドキュメントのみ(README等) 任意 spec管理対象外
テストケースの追加・修正 任意 テストはspecを検証するもので、spec自体ではない
テスト設定変更(vitest.config等) 必要 specファイルが存在するため
E2Eヘルパー変更 必要 specファイルが存在するため
CI設定変更 必要 specファイルが存在するため
機能追加・変更 必要 振る舞いが変わるため

結局のところ、対象のコードやドキュメントに対してspecファイルが存在するかどうかと、その変更が振る舞いに影響するかどうかで判断しています。そのため、環境によっては上記の必須・任意は切り替わることもあります。また、後からspecファイルを変更に追従させることもできるので、そこまで神経質になる必要もないと思います。

specのコンフリクトはどうだったか

導入前からspecファイルのコンフリクトは懸念していました。そのため、specのディレクトリはfeatureと責務でディレクトリを分け、さらにその中でも複数ファイルに分ける構成にして、コンフリクトの可能性を減らす工夫をしました。しかし、それでも近いコードを並列で開発した場合はspecのコンフリクトは起きることもありました。ただ、OpenSpecのspecファイルは以下のようなガーキン記法で、ソースコードの複雑な衝突よりは解消しやすい印象で、あまり負担ではありませんでした。

#### Scenario: 認証情報でのログイン成功

- GIVEN ユーザーがログイン画面を開いている
- WHEN 有効なメールアドレスとパスワードを入力してログインボタンを押す
- THEN ダッシュボード画面に遷移する
- AND ヘッダーにユーザー名が表示される

#### Scenario: パスワード誤りによるログイン失敗

- GIVEN ユーザーがログイン画面を開いている
- WHEN 有効なメールアドレスと誤ったパスワードを入力してログインボタンを押す
- THEN ログイン画面に留まる
- AND 「メールアドレスまたはパスワードが正しくありません」のエラーメッセージが表示される

specのPRレビューはどうしているか

/archiveでspecが更新されると、当然PRの差分にspecファイルの変更が含まれます。ただ、自分たちのチームではこの部分のレビューは軽く目を通す程度で、コードと同じ粒度ではレビューしていません。

理由は、/archive後のspecはAIが自動生成するもので、動作に直接影響する変更ではなく、人間が参照して使用するドキュメントでもないからです。specの内容が実装と合っているかはある程度AIに任せていて、人間がしっかり見るのは/proposeの段階で生成されるproposal.mdやdesign.md、tasks.mdにしています。

とはいえ、specとコードが少しずつズレていくリスクはあります。将来的には後述する/opsx:verifyや専用のスキルを用意して、specとコードの乖離を検知できるようにしたいと考えていますが、今のところはまだできていません。

拡張ワークフローの/opsx:verifyはけっこう良さそう

チーム全体ではまだ標準化していませんが、個人で試していて良かったのが/opsx:verifyです。openspecのデフォルトでは有効化されていないコマンドですが、拡張フローを有効化すると使えるようになります。OpenSpecの拡張ワークフローでは、/opsx:applyのあとに/opsx:verifyを挟めます。公式ドキュメントを見ると、verifyは次の3つを確認する想定です。

  • Completeness
  • Correctness
  • Coherence

要するに、「tasksは完了しているか」「実装はspecの意図と合っているか」「設計の整合性は崩れていないか」を見てくれます。
全部の拡張コマンドを入れると少し重いですが、verifyだけでも入る価値はありそうでした。特に、archive前のセルフチェックとしてはかなり使いやすいです。

ブランチ戦略とarchiveのタイミング

自分たちのチームはmainから直接トピックブランチを切るGitHub Flow的な運用をしています。この場合、複数のトピックブランチが並行して進むと、specファイルのコンフリクトが起きる可能性があります。featureと責務でspecのディレクトリを細かく分けることでコンフリクトの可能性は減らせますが、同じ機能を複数人で触る場合は避けられないこともあります。

現状はまだ試していませんが、改善策として考えているのは次の2つです。

  • Git Flowのようにdevelopブランチを挟む構成(main ← develop ← topic)にして、developにマージされた後にarchiveする運用にする
  • CIを使ってmainへの取り込み後に自動でarchiveできるようにする

いずれにしても、archiveのタイミングをブランチのマージフローと合わせることでコンフリクトのリスクをさらに減らせそうだと感じています。

まとめ・導入してみて感じたこと

OpenSpecはコマンドを順番に実行するだけなので覚えることが少なく、既存のスクラム開発フローを大きく変えずにスムーズに導入できました。一方で、初期導入時のspecディレクトリ構成は後から変えにくいので、最初に設計しておくことが大切だと感じました。

良かった点をまとめると、次のとおりです。

  • openspec/config.yamlをチームで育てていく形が取れるので、スクラム開発との相性が良かった
  • 「どのコマンドを使って何を生成するか」がチーム内で揃うことで、AIの活用度が個人のスキルに依存しにくくなった
  • 提案と実装の間に人間レビューを入れやすくなり、AI実装後の手戻りが減った

小さい変更まで全部OpenSpecに乗せようとすると負荷が高くなるので、振る舞いが変わるかどうかを基準にしてOpenSpecを使う範囲をあらかじめ決めておくのはおすすめです。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?