AIで安くなったものを使い倒し、高いものを節約する――品質と開発速度を上げるソフトウェア開発
生成AIによって、ソフトウェア開発のコスト構造は大きく変わった。
コードを書くこと、テストを書くこと、ドキュメントを作ること、ログを調査すること。これまで人が時間をかけて行っていた多くの作業が、以前とは比較にならないほど安くなっている。
ここでいうコストは、サービス利用料などの金銭的なコストだけではない。むしろ、人がその作業に使う時間や労力を含めた開発上のコストを指している。
一方で、ほとんど安くなっていないものもある。
人が仕様を理解するコスト、人がコードをレビューするコスト、人同士が議論するコスト、人が複雑なシステムを頭の中に保持するコストである。
AIによって開発速度が上がった、というだけでは、この変化を十分に捉えられない。
ソフトウェア開発で使う各リソースの相対的なコストが変わった。
制約条件が変わったのであれば、品質の上げ方や設計の基準も、それに合わせて変える必要がある。
建築で、ある材料の価格が突然100分の1になったなら、その材料を以前と同じ量だけ使い続ける理由はない。その材料を多く使うことで、別の高価な材料を減らしたり、施工を単純にしたり、建物を強くしたりする。
ソフトウェア開発でも同じように考えられる。
高いものを節約し、安くなったものを潤沢に使う。
この基準で開発を見直すと、AIを単なるコード生成ツールとして使うのとは違った品質改善の方法が見えてくる。
まず、何が安くなって何が高いままなのか
AIによって劇的に安くなったものには、例えば次のようなものがある。
- コードの実装
- テストコードの作成
- Linterや静的チェックの作成
- AIによる自動レビュー
- 仕様書や設計書のドラフト作成
- 既存の仕様や実装の比較
- 業務フロー図や構成図の作成
- ログやトレーシングの追加
- ログを使った一次調査
- 運用スクリプトや管理UIの実装
- Infrastructure as Codeの作成
- セキュリティ設定や実装の機械的なチェック
これらは以前から実施できなかったわけではない。
ただ、人が行う場合には相応の時間が必要だった。得られる品質改善や運用改善に対して、そのために人を使うコストが見合わず、採用されないことがあった。
AIによって、その採算が大きく変わっている。
反対に、次のようなもののコストはほとんど変わっていない。
- 人がシステムを理解する時間
- 人がコードや仕様をレビューする時間
- 人同士が合意するためのコミュニケーション
- 人が大量の情報を読む時間
- 人が運用時に使える注意力
- CI/CDの実行時間や計算資源
- 本番環境のCPU、メモリ、IO
この差を無視して、AI以前と同じ開発プロセスをそのまま高速化すると、安くなっていない部分がすぐにボトルネックになる。
AI時代にも、人の理解は高価なままである
特に高価なままなのが、人の理解である。
AIを使えば、複雑な仕様をコードにすること自体が簡単になった。それだけでなく、機能を追加することそのものが以前よりはるかに簡単になった。
条件分岐を一つ増やす。例外ケースを追加する。特殊な顧客だけに適用されるルールを追加する。既存の処理にもう一つ状態を追加する。小さな要望のために新しい機能を一つ追加する。
以前なら、設計・実装・テストにかかるコストが「本当にこの機能が必要なのか」を考える一つの抑止力になっていた。現在は、その実装コストが大きく下がっている。
しかし、それを人が理解するコストはほとんど下がっていない。
コードを10倍速く書けるようになっても、人が10倍のコードを同じ時間で理解できるようになったわけではない。プロジェクトメンバーが頭の中に保持できる概念の数も増えていない。
さらに、追加した仕様はその機能だけに閉じるとは限らない。
例外条件や特殊な状態が増えれば、その後に別の機能を追加するときにも、それらと矛盾しないように考える必要がある。仕様同士の整合性を維持するコストや、既存の挙動を壊さないようにする難しさは、AIによってなくなったわけではない。
機能を追加するコストは下がっても、追加した仕様を今後ずっと抱え続けるコストは残る。
実装可能性が上がったことを、そのまま機能や仕様の複雑さを増やす方向に使えば、人の理解という高価なリソースを食い潰していく。
変更時に確認する範囲が広がる。レビューに時間がかかる。影響範囲が分からなくなる。新しい機能を追加するときに考慮すべき既存仕様が増える。障害調査にも多くの前提知識が必要になる。
その結果、AIは速くコードを書いているのに、システム全体としては開発が遅くなる。
これからの設計では、実装量を減らすこと以上に、人が一度に理解しなければならない範囲を減らすことの価値が大きくなる。
モジュールを分けるために多少コードが増えてもよい。一貫したアーキテクチャパターンを適用するために実装が長くなってもよい。
書くコストが安くなったのであれば、そのコストを人の理解を助けるために使える。
人のレビューも安くなっていない
同じことがコードレビューにも当てはまる。
AIによって実装量が増えても、人がレビューできる量はほとんど増えない。
AIが従来の5倍の速度でコードを生成し、それを従来と同じ密度で人がレビューするのであれば、レビュー待ちがボトルネックになる。
レビューをなくすのではなく、人にしか判断できないことへ、人のレビューを集中させる必要がある。
例えば、
- その仕様自体が妥当か
- 顧客や利用者にとって正しい動作か
- モジュールの境界は適切か
- システム全体を不必要に複雑にしていないか
- 将来の変更を難しくする判断ではないか
といったことには、人の判断を使う価値が高い。
一方で、命名規則、必要なバリデーション、APIの利用ルール、必要なテストの有無など、機械で確認できるものは自動チェックへ移していく。
高価な人のレビューを、機械で確認できる事項に使い続けない。
実装に使えるコストが劇的に下がった
最も分かりやすく安くなったのが、実装そのものである。
以前は、ある改善が技術的に有効でも、その改善によって得られる品質向上や運用負荷の削減より、人が実装するコストの方が高く、採用されないことがあった。
例えば、設定値の入力ミスが問題になる場合でも、専用の検証処理を作るより「手順書をよく読んで間違えないようにする」という運用が選ばれることがあった。
今ならJSON Schemaなどで設定自体を検証できるようにするコストはかなり小さい。
危険な運用操作があるなら、安全なCLIや専用UIを作る。一貫していない実装が多数あるなら、共通パターンへ寄せる。
「実装が面倒だから人間が注意する」という設計は相対的に高価になっている。人の注意力は高いままなのに、それを代替するコードは安くなったからである。
書く手間を理由に安全性を削る必要が減った
コーディングスタイルにも同じ変化がある。
例えば、ある書き方では型を細かく定義し、値を明示的に変換し、バリデーションを書く必要があるためコード量が増えるとする。
その代わり、不正な状態を表現しにくく、バグを検出しやすく、人が読んだときの挙動も予測しやすい。
以前なら「安全ではあるが、そこまで書くのは面倒」というトレードオフがあった。
書くコストが大幅に下がり、読むコストが大きく増えないのであれば、この判断も変わる。
書くのは安いが、読むのは高い。
AI時代には、記述量より人が理解するためのコストを優先する価値が高くなる。
人の指摘やAIの失敗を、次のルールに変える
品質上の指摘も、その場の修正だけで終わらせる必要はない。
人がレビューで、
「このプロジェクトではこの書き方は禁止する」
「この処理では必ずこのチェックを入れる」
と指摘したなら、そのPRだけを修正するのではなく、以降のAIが参照するルールへ反映できる。
AI自身の実装ミスがレビューやテストで見つかった場合も同じである。
さらに、このルール化自体も自動化できる。
例えばPRをマージするタイミングで、開発中のローカルAIセッションやPRレビューで発生した指摘を記録し、同種の指摘が何回発生したかを集計する。
繰り返し発生するものについて、AIに複数の具体例を一般化させ、定期的にAGENTS.mdなどへルールを追加するPull Requestを作らせる。
流れとしては、
人やAIの指摘 → 記録 → 同種の指摘を集計 → AIが一般化 → ルール追加PRを生成
となる。
一度しか起きていない特殊ケースを何でもルール化すると、ルールそのものが肥大化する。繰り返し発生しているものを抽出することにも意味がある。
既存プロジェクトなら、過去のPull Requestのレビューコメント、バグチケット、その修正コミットをAIに調査させることもできる。
過去に何度も発生した問題を探し、
- AI用ルール
- Linter
- テストパターン
- 設計ルール
として昇格できそうな候補を一覧化する。
人のレビューを、そのPRを直すためだけのコストではなく、今後のすべての変更を改善するための投資に変えられる。
テスト・レビュー・静的チェックも安くなった
テストを書くコストも大きく下がった。
正常系、異常系、境界値、過去のバグ、別観点のシナリオなどを列挙し、多数のテストを作りやすくなっている。
特に、シナリオテストやE2Eテストのように、人による作成・継続的なメンテナンスのコストが高かったものへの影響は大きい。仕様変更に合わせた修正や、失敗原因の調査にもAIを利用できる。
ただし、テストを書くコストが下がったことと、テストを実行するコストが下がったことは別である。
CIのCPUや実行時間が劇的に増えたわけではない。E2Eテストは依然として遅く、環境依存やflakyさも持つ。
そのため、
- ユニットテストは多く、網羅性を高くする
- 統合テストやシナリオテストは必要な範囲で使う
- E2Eテストは重要な経路に絞る
という基本的な戦略まで変える必要はない。
AIによって、これまで人の作成・保守コストが理由で諦めていた網羅性を上げやすくなった、と考える方がよい。
静的チェックを追加するコストも大きく下がった
Linterや静的解析などのチェックも追加しやすくなった。
チェックそのものだけでなく、開発フローに組み込む部分までAIに作らせられる。
例えば、
- AIエージェントのHookで生成直後に確認する
- Git hookでcommitやpush前に検査する
- GitHub ActionsですべてのPull Requestに適用する
- 定期ジョブでリポジトリ全体を再検査する
といった仕組みである。
以前は小さなチェック一つにも、処理を書き、CIの設定方法を調べ、実行条件を設定する細かなコストが発生した。
今なら「この条件を検査し、ローカルではHook、PRではGitHub Actionsから実行する」といった周辺部分まで含めて作りやすい。
一度作れば、そのチェックは今後のすべての変更に効く。
ある関数を人がレビューして一箇所の問題を見つけるより、その種類の問題を検出するLinter、テスト、Hook、AIレビューのルールを作れば、数百、数千の変更へ適用できる。
RPGで言えば、個別の敵への「単体攻撃」だけでなく、コードベース全体へ効く「全体攻撃」にコストを使いやすくなった。
個々のコードの品質を軽視するのではない。同じ種類の問題を人が何度も見つける必要のない環境を作るということである。
同じ考え方で、仕様と実装の定期比較、過去の問題パターンの再検査、セキュリティチェックなどもコードベース全体に対して行える。
人が定期的に実施するには採算が合わなかったチェックを、AIに広く実行させ、候補の分類や絞り込みまで行わせる。
ドキュメントを作るのは安いが、読むのは高い
ドキュメント作成も劇的に安くなった。
仕様書のドラフト、設計書、ADR、業務フロー図、状態遷移図、システム構成図などを以前より簡単に作れる。
ただし、ドキュメントを生成するコストは下がっても、人が読むコストは下がっていない。
AIに100ページの設計書を書かせても、人が100ページ読まなければならないなら、ボトルネックは解消していない。
目的はドキュメントの量を増やすことではなく、人が理解するまでの時間を減らすことである。
例えば、
- 現在の構成を一枚の図にする
- 重要な状態遷移を可視化する
- 変更時に確認すべき依存関係を示す
- 設計理由だけを短く残す
- 大量の情報から、人が判断すべき論点だけを要約する
といった使い方ができる。
設計理由を残す価値は上がっている
コードそのものの説明は、AIが実装を読んで生成できる。
一方、
- なぜこの方式を選んだのか
- なぜ別案を採用しなかったのか
- 当時どのような制約があったのか
- 何が変われば再検討すべきなのか
といった情報はコードからは復元できない。
そのため、ADR(Architecture Decision Record)のように、設計判断とその理由を短く残す仕組みとの相性がよい。
書くコストが下がった分、後から復元できない情報を残すことに使える。
観測・調査・運用も安くなった
ログや監視も、コスト構造が大きく変わった領域である。
構造化ログを追加する、トレース可能なIDを付ける、多数のメトリクスを収集する、ダッシュボードやアラートを作る、といった実装が安くなった。
さらに、観測データを見る側のコストも下げられる。
以前から大量のメトリクスを収集すること自体はできた。しかし、増やすほど人が見るグラフも増え、異常を探したり、複数の指標を関連付けたりするコストが高くなる。
AIなら広い範囲を確認して、
- 通常と異なる傾向
- 急激な増減
- 複数メトリクスをまたいだ異常
- 過去の障害と似たパターン
などを探し、人が見るべき内容をレポートにまとめられる。
人が大量のデータを見るのではなく、AIに大量のデータを見せて、人が理解できる量まで圧縮する。
構造化ログをAIに調査させる
アプリケーションの構造化ログをBigQueryやAthenaへ集約しておけば、AIエージェントに、
「この例外エラーがなぜ起きたのか、このリクエストに至る一連の処理をログから追って原因を調べて」
と依頼できる。
このとき重要なのは、エラーログだけを構造化することではない。
- サーバーが受け取ったリクエスト
- 認証・認可処理
- 外部サービスへのリクエストとレスポンス
- 非同期処理の呼び出し
- 非同期処理の開始・終了
- エラーログ
などに、request_idやtrace_id、resource_idといった共通のコンテキストを持たせ、一連の処理を追跡できるようにする。
例えば500エラーが起きた場合、AIがrequest_idを起点にログを調査し、
リクエスト受信
→ 認証成功
→ 非同期ジョブ登録
→ 別プロセスでジョブ開始
→ 外部API呼び出し
→ 外部APIからエラー
→ 最終的な例外発生
という流れを復元できる。
人が時刻やIDをコピーしながら複数のログを追っていた調査を、AIがクエリを組み立てながら実施できる。
そのためには、単にログを大量に保存するだけでなく、AIが安定してクエリできる構造化されたログを設計しておくことが重要になる。
ログ設計にも「人がgrepして読めるか」だけでなく、「AIがクエリして一連の処理を復元できるか」という観点が加わる。
エラー管理システムと組み合わせれば、通知を受けたAIが自動的にBigQueryやAthenaを調査し、原因候補をまとめて人へ渡すこともできる。
400系・500系エラーを広く見るコストも下げられる
400系や500系のエラーを継続的に見ることは、問題を早期に見つけ、品質を上げるために有効である。
しかし、件数が多いサービスで人が定期的に分類し、一件ずつ原因を確認する人的コストは高い。
そのため、重大な500エラーや件数が閾値を超えたものだけを見る運用になりやすかった。
AIを使えば、一定期間ごとにエラーを分類・調査し、
- 新しく出現したエラーパターン
- 急増しているもの
- 特定の顧客や端末に偏っているもの
- 同じ原因にまとめられそうなもの
を抽出し、人が見るべき内容だけをレポートできる。
必要なら構造化ログまで追わせ、原因候補まで調査させる。
これまで人的コストの問題で広く確認できなかったエラーまで対象にすることで、大きな障害になる前の兆候や小さな不具合を見つけやすくなる。
運用ミスを避けるための人の確認も高い
運用では、人に
「この値は間違えないでください」
「この順番で操作してください」
「本番ではこの操作をしないでください」
と覚えてもらい、その都度確認してもらうことがある。
こうした確認や注意に使う人のコストも下がっていない。
以前なら、年に数回の作業のために専用ツールを作る方が高くつく場合があった。
今は、
- 入力を検証するCLI
- dry-run
- 設定のコード化
- 危険な操作をできなくするUI
- AIによる変更差分の事前確認
などを作るコストが下がっている。
人に毎回注意してもらうより、間違いにくい仕組みを一度作る方が採算に合う範囲が広がっている。
IaCのメリットも大きくなった
Infrastructure as Codeも同様である。
例えばCDKでは、以前は「このAWSリソースをどう書くか」「どのプロパティを指定するか」を調べながらコードを書くこと自体にかなりの手間がかかった。
変更頻度の低い設定なら、AWS Consoleから直接変更する方が短期的には速い場合もあった。
今は、要件を伝えればAIにCDKのコードを作らせられる。
既存のインフラ定義がリポジトリにあれば、AIが現在の構成やプロジェクト固有の書き方を理解して変更できる。
変更後のdiffについても、意図しないリソース削除、セキュリティ設定の弱体化、不要な権限追加などをAIにレビューさせられる。
IaCは再現可能性だけでなく、AIが現状を理解し、変更し、自動チェックできる機械可読なインターフェースとしての価値も大きくなっている。
AIの作業を人が管理するコストも高い
AIによって実装や調査が安くなっても、その作業を人が細かく管理していては別の場所がボトルネックになる。
複数のAIセッションやタスクについて、人が「何を依頼したか」「どこまで進んでいるか」「どのIssueやPRに対応しているか」を追い続けるコストは高い。
Issue、AIの作業、Pull Request、CIの状態などをまとめて確認できる管理ツールを作れば、人が状況を把握するコストを減らせる。こうした小さな管理ツール自体もAIによって作りやすくなった。
さらに、人が介在しなくてもよい工程はAIに進めさせる。
例えば、問題の検知から調査、Issue作成、修正、テスト、Pull Request作成までを自動で進め、人には仕様判断やリスク判断など、本当に人の判断が必要な段階だけ確認を求める。
安いAIの作業を増やすために、高価な人をAIのタスク管理に使い続けないことも重要になる。
人のコミュニケーションもボトルネックになる
AIは大量の調査結果や設計案を作れる。
しかし、候補を100個生成するのが安くても、それを5人が30分ずつ議論すれば高価である。
AIには情報を増やすところだけではなく、
- 選択肢を洗い出す
- 明らかに不適切な案を除外する
- 比較軸を整理する
- 事実関係を確認する
- 意見が分かれる論点を絞る
ところまで行わせ、人は最後の判断に集中する。
人同士のコミュニケーションは重要だからこそ、安い調査や整理で置き換えられる部分には使わない。
「生成が安い」と「使うのが安い」は別である
安くなったものを何でも大量に作ればよいわけではない。
テストコードは安く生成できるが、1万件のテストを毎回CIで実行すれば、時間と計算資源が必要になる。
E2Eテストも生成は安いが、実行は遅く、flakyになれば調査コストが発生する。
ログも大量に追加すれば保存コストが増える。
ドキュメントも生成は安いが、人が読むのは高い。
安くなったものを増やすときには、その出力が最終的にどの高価なリソースを消費するかを見る必要がある。
生成コストだけを見て増やすと、別の場所にボトルネックを作ることになる。
非機能要件は変わらない
AIによって実装方法が変わっても、システムに求められる非機能要件そのものが緩和されるわけではない。
利用者が100万人いるなら、その負荷を処理する必要がある。
高い可用性が必要なら、その水準を満たす必要がある。
データベースのCPUやIOが不要になるわけでも、無停止デプロイが不要になるわけでもない。
性能、可用性、データ整合性、セキュリティといった要求そのものは変わらない。
一方、それらを実現するための仕組みを作るコストは下がっている。
多段階デプロイ、自動ロールバック、設定のバリデーション、IaC、セキュリティ設定のチェック、障害時の診断機能などである。
以前なら、その仕組みを作る人のコストに改善効果が見合わなかったものでも、実装コストが下がれば採用しやすくなる。
同じ非機能要件を満たすために、以前より多くの手段を使えるようになった。
AI時代には、こだわる場所を変える
AIによって実装が安くなったからといって、コードのスタイルや設計を軽視してよいわけではない。
制約なくコードを書かせれば、人には理解できないコードベースを非常に速い速度で作ることもできる。
だからこそ、
- プロジェクト全体で一貫したパターンを使う
- 独自ルールを機械的に検証する
- 特殊ケースを増やしすぎない
- モジュール境界を明確にする
- 設定や入力値をできるだけ検証する
- 人が理解しなければならない暗黙知を減らす
といったことの価値が高くなる。
一箇所のコードを人が工芸的に整えることだけにコストを使うのではなく、コードベース全体を理解可能な状態に保つルールと仕組みにコストを使う。
そして、そのルールもレビューや障害、AIの失敗から継続的に改善する。
新しいコスト構造に開発を最適化する
AI時代のソフトウェア開発で重要なのは、個別のAI活用テクニックだけではない。
各作業のコストが変わったことを前提に、開発プロセスそのものを組み直すことである。
実装、テスト、自動チェック、ドキュメント生成、ログ調査、運用ツール作成は安くなった。一方、人の理解、レビュー、コミュニケーション、注意力は高いままである。
であれば、安くなったものは品質向上のために潤沢に使い、高価な人の作業は人にしかできない判断へ集中させる。
人の指摘やAIの失敗もその場限りの修正で終わらせず、ルールや自動チェックへ変え、全体へ繰り返し適用する。
AIによってコードを書く速度が上がったこと以上に、品質を上げるために選べる手段のコストが変わったことを活用する。
高いものを節約し、安いものを使い倒す。
それが、AIを開発速度だけでなく、システム全体の品質向上にもつなげる基本戦略になる。