2026年におけるソフトウェアの品質
この記事はClaude Codeと議論しながら書いた。アイデアの骨子は僕のもので、論理構造の整理や具体的な技術例の提案、文章の推敲にClaude Codeの力をだいぶ借りている。
AIエージェントやバイブコーディングの台頭を受けて、ソースコードの品質を保証すべきかという議論をよく見かける。僕の考えを整理してみる。
コード品質の目的
コードの品質を高める目的は、コードの振る舞いについての判断が容易であることだと思う。ここでいう判断には、変更が正しいかの検証だけでなく、そもそもどこを変えるべきかの理解も含む。込み入ったコードでは変更箇所の特定自体を間違えるし、検証以前の問題が起きる。
裏を返せば、品質を高めなくても振る舞いの判断が十分にできるなら、品質にこだわる必要はない。
品質が要らないとき・要るとき
変更するつもりがないワンショットのスクリプトで、失敗しても検知とやり直しが簡単なら、品質はどうでもいい。さっさと作ってさっさと試せばいい。
一方で、たとえワンショットであっても、失敗すると人命に関わるようなものなら正しさの担保が必要だ。つまり品質への投資が割に合うかどうかは、正しさの検証にかかるコストと、誤りがもたらす被害の大きさで決まる。
なぜ品質が判断の助けになるか
コードの振る舞いを判断する方法にはテスト、形式手法、コードレビューなどがある。いずれの方法でも、コードがシンプルに目的を表現していれば正しいと判断しやすいし、実際に正しいことが多い。逆に込み入った書き方だと自信を持てなくなるし、誤解も増える。
数学のエレガントな証明が、一見難しそうな命題に対してみんなが腑に落ちる説明を与えるように、品質の高いコードはその振る舞いを自然に伝える。判断の手法を問わず、品質は振る舞いの理解に有効だ。
どこに投資すべきか
以上から、すべてのコードの品質を高める必要はない。変更を誤ったときの回復コストが高い箇所に集中して投資すべきだ。
回復コストはものによって異なる。コードの内部実装は、インターフェースが適切に切られていれば書き直しやすいので投資は少なくていい。モジュール間のインターフェースは変更時に認知すべき範囲が広がるので投資すべきだ。データスキーマや永続化形式は過去の全データの移行が必要になるので特に慎重さが求められる。
ただし回復コストが高いからといって品質投資を増やすだけでは受け身だ。回復コスト自体を下げる仕組みを設計することで、品質投資の負担を減らせる。
回復コストを下げる
大きな変更を小さなステップの連鎖に分解して、各ステップで問題を検知・修正できるようにすることが基本的な考え方だ。
データスキーマ
フィールドは追加のみで削除やリネームを禁止する、いわゆるAdditive-onlyなスキーマ変更が代表的な手法だ。Protocol Buffersはフィールド番号を保持することで新旧フォーマットの共存を保証するし、Avroはスキーマレジストリで互換性を管理する。
Expand-and-Contractパターンも有効だ。新カラム追加、新旧両方への書き込み、既存データ移行、旧カラム削除と段階を踏む。各ステップを独立してデプロイ・検証でき、途中で問題が起きても巻き戻せる。
Event Sourcingは現在の状態ではなくイベント履歴を保存する手法で、スキーマ変更が「過去データの移行」ではなく「読み取りロジックの変更」になる。現在の状態を直接マイグレーションするよりは回復コストが下がるだろう。ただしイベントスキーマ自体の変更にはupcasting等の仕組みが必要で、万能ではない。
インターフェース
型システムはインターフェースの変更が影響するすべての箇所をコンパイラが列挙してくれる。認知範囲を人間の注意力に頼らず機械的に限定できるのが強い。型による表現力が高いコードは前述の「振る舞いの判断が容易なコード」でもあるので、品質投資と回復コスト低減の両方に効く。
APIバージョニングは新旧インターフェースを共存させて一斉変更を避ける手法で、Expand-and-Contractのインターフェース版と考えていい。
デプロイ
Feature flagsはデプロイとリリースを分離する仕組みだ。コードは本番にあるが機能は無効にできる。問題があればフラグを切るだけで止められるので回復が速いし、段階的にリリースすることで問題の発生自体を予防できる。
Canary deployは全ユーザーに影響する前に一部で検証して、被害範囲を限定する。
ソフトウェア設計の目的
品質を高めるべき箇所とそうでない箇所を切り分けて、誤りからの回復コストを下げる仕組みを用意すること。これがソフトウェア設計の目的だと思う。設計によって次のことを実現したい。
- 不適切な変更をしても被害が限定されること
- 適切な変更が大きなインパクトをもたらせること
- そもそも不適切な変更が起きにくいこと
AI時代にどう変わるか
ここまでの議論はAI以前から成り立つ普遍的な話だ。では冒頭の問いに戻って、AIエージェントやバイブコーディングの台頭は何を変えるのか。
人間とAIには能力の優劣があるわけではなく、特性の違いがある。人間は長大なコンテキストを保持して長期にわたってセッションを続けられる。プロジェクトの歴史、ステークホルダーとの関係、過去の設計判断の背景といった蓄積されたコンテキストを活かすのが得意だ。一方でAIはコンテキストウィンドウが溢れない範囲で完結する短い実行単位(以下セッションと呼ぶ)の中で、与えられたコンテキスト内の仕事を高速にこなすのが得意だ。
この特性の違いを品質投資の議論に当てはめると、タスクの性質によって適性が分かれることがわかる。
内部実装はモジュールの境界内で完結する仕事であり、一回のセッションに収まるコンテキストで判断できる。AIが得意な領域だ。書き直しコストが劇的に下がるので品質への投資の優先度を下げられる。品質にばらつきがあっても、インターフェースさえ正しければ作り直せばいい。
インターフェースは利用者やシステム間の長期的な合意に基づくもので、その設計判断には過去の経緯や将来の方向性といったセッションをまたぐコンテキストが必要になることが多い。AIエージェントのオーケストレーションによって影響範囲の認知と調整のコストもある程度は下がるだろうが、セッションをまたぐコンテキストの蓄積が必要な分、内部実装ほど劇的には下がりにくい。
データ永続化フォーマットは設計判断の影響がセッションどころかプロジェクトの寿命を超えて残る。AIによってスキーマを変更する頻度が上がると、誤りに気づく前により多くのコードがそのスキーマに依存してしまう。コードはAIで書き直せても、本番に蓄積されたデータは書き直せない。だからといってここで慎重になってしまうとデータ永続化の設計がボトルネックになり、開発速度を活かせない。慎重にならずに済むようにするには、前述の回復コストを下げる仕組み、Additive-onlyなスキーマ変更やExpand-and-Contractをあらかじめ整えておくことが重要になる。Event Sourcingも状態マイグレーションよりは回復コストを下げられるが、イベントスキーマ自体の設計には注意が必要だ。いずれにせよスキーマの変更が日常的に安全に行える仕組みがあれば、最初の設計判断を間違えることを恐れずに済む。
つまりAI時代にはコード品質への投資の濃淡がより極端になる。セッション内で完結する仕事の品質への投資の優先度は下げられるが、セッションをまたぐ判断が関わる領域、インターフェースやデータ永続化では、回復コストを下げる仕組みへの投資がこれまで以上に重要になる。
今後の課題
この記事では品質投資の考え方と回復コストを下げる仕組みについて議論したが、既存の組織やプロダクトに対してこれらをどのように適用していくかという問題が残っている。すでに動いているシステムには歴史的な設計判断の蓄積があるし、回復コストを下げる仕組みを後から導入すること自体にもコストがかかる。この辺りはまた別の機会に考えたい。