品質の悪いソフトウェアは、単にバグが多いソフトウェアではない。使う人の問題を解いていない、変更が難しい、運用で壊れやすい、判断の根拠がコードにも仕様にも残っていない。そういう状態も含めて、品質が悪いと考えている。
品質を上げるという話になると、テストを増やす、レビューを厳しくする、設計を丁寧にする、といった手段に話が寄りがちだ。もちろんそれらは必要だが、手段だけを増やしても品質は安定しない。
品質は、問題領域の理解から始まる。
人を増やす前に、流れを整える
フレデリック・ブルックスは『The Mythical Man-Month』で、よく知られたブルックスの法則を述べている。
“Adding manpower to a late software project makes it later.”
Frederick P. Brooks Jr., The Mythical Man-Month
遅れているプロジェクトに人を足せば単純に速くなる、という考えは危うい。新しく参加した人が状況を理解する時間、既存メンバーが説明する時間、コミュニケーション経路の増加、判断の同期コストが発生するからだ。
これは単に「人を増やすな」という話ではない。人を増やしても機能する開発基盤があるか、という話である。ドキュメント、設計の境界、テスト、CI、デプロイ手順、観測性が弱いまま人数だけを増やすと、開発速度ではなく混乱が増える。
何を作るべきかを間違えると、品質は上がらない
実装が正しくても、解くべき問題を間違えていれば価値は出ない。仕様通りに動くけれど現場では使いにくい、機能は揃っているけれど判断に必要な情報が見えない、という状態は珍しくない。
こうした問題は、後からテストを増やしても解決しにくい。むしろ早い段階で、利用者の業務、制約、例外、失敗時の扱いを理解する必要がある。
私はソフトウェア開発において、技術的な正しさと同じくらい、問題領域に対する理解を重視している。深く理解できていれば、作らない判断もできる。作るべきものを絞れるので、結果として速く届けられる。
ここで重要になるのがドメインモデルである。ドメインモデルは、単なるデータ構造ではない。業務上の概念、制約、言葉、状態遷移、判断基準を、ソフトウェアの中で扱える形にしたものだ。ドメインモデルの理解が浅いと、コードは一見整理されていても、業務の変化に追従できない。逆に、モデルが問題領域をよく表していれば、仕様変更は場当たり的な修正ではなく、モデルの更新として扱える。
DDDはこの理解を深めるための強力な道具である。戦略設計では、システム全体をひとつの巨大なモデルとして扱わず、境界づけられたコンテキストに分ける。どの領域がコアドメインなのか、どこは汎用的に扱えばよいのか、外部システムや別チームとの境界をどう置くのかを考える。これはアーキテクチャの話であると同時に、事業上の優先順位をソフトウェアに反映する作業でもある。
戦術設計では、境界づけられたコンテキストの内側で、エンティティ、値オブジェクト、集約、リポジトリ、ドメインサービスといったパターンを使い、業務上の不変条件をコードに閉じ込める。重要なのは、パターンを並べることではない。業務上守るべきルールが、アプリケーション層やUIの都合に流されず、ドメインモデルの中に表現されていることだ。
ドメインモデルが弱いシステムでは、ルールが画面、バッチ、API、SQLに散らばる。最初は速く見えるが、変更のたびに同じ判断を複数箇所へ反映することになる。これは品質を下げ、開発速度も下げる。DDDの価値は、複雑さを消すことではなく、複雑さに名前を与え、境界を置き、チームが同じ言葉で扱えるようにすることにある。
速度と品質は、本来は対立しない
速度を上げるために品質を落とす、品質を上げるために速度を犠牲にする。そういう言い方を聞くことがある。しかし多くの場合、速度を落としている原因は品質不足そのものである。
仕様の理解が浅ければ手戻りが増える。変更しづらい設計であれば、毎回の修正で影響範囲が広がる。テストがなければ、リリース前確認に時間がかかる。運用上の前提が曖昧であれば、障害対応は属人化する。これらはすべて品質の問題である。
品質を高めることは、遅く作ることではない。次の変更を速くするための投資である。
DevOpsとCIは品質基盤である
品質は個人の注意力だけで維持するものではない。チームが毎日同じ水準で変更を届けるには、開発からリリースまでの流れそのものを整える必要がある。
DevOpsは、開発と運用を分けて考えないための実践である。開発者が本番運用を理解し、運用上の制約が設計へ戻り、障害や変更の学びが次の開発に反映される。この循環がないと、リリース後に初めて問題が見つかり、品質は後工程の責任になってしまう。
CIはその循環を支える最小単位である。すべての変更に対して、ビルド、テスト、静的解析、型チェック、脆弱性検査、フォーマット確認を自動で実行する。人間が頑張って確認するのではなく、確認すべきことを機械に任せる。
CIで守るべきことは、単に「テストが通る」だけではない。
- mainブランチが常にリリース可能な状態に近いこと
- 失敗した変更が早く見つかること
- レビュー前に機械で検出できる問題を落とすこと
- デプロイ手順が人に依存しないこと
- 変更と結果の対応が追跡できること
この品質基盤があると、チームは品質を気合いで守らなくてよくなる。レビューでは設計や仕様の判断に集中でき、リリースはイベントではなく日常の作業になる。
逆に、この品質基盤がない状態で人数を増やすと、ブルックスが指摘した問題が起きやすくなる。ビルド手順を人が口頭で教え、テストの実行条件が環境ごとに違い、リリース判断が属人化し、障害時にログを探すところから始まる。これは開発速度の問題ではなく、組織の品質基盤の問題である。
AIによる開発自動化は、品質管理の差を広げる
今後、AIによる開発支援はさらに強くなる。コード生成、テスト生成、レビュー補助、ログ解析、障害対応の初動、リファクタリング案の提示、ドキュメント更新など、多くの作業がAIによって部分的に自動化されていく。
ただし、AIがあるから品質基盤が不要になるわけではない。むしろ逆である。CIが整い、テストがあり、ドメインモデルが明確で、設計上の境界が切られているプロジェクトほど、AIの出力を品質管理の流れに乗せやすい。AIが生成したコードが正しいかどうかを、人間の勘だけで判断するのではなく、型、テスト、静的解析、受け入れ条件、運用上の観測によって確認できるからだ。
AIは実装速度を上げるが、問題領域の理解を肩代わりするものではない。何を作るべきか、どの概念をモデルとして扱うべきか、どこに境界を置くべきか、どの不変条件を守るべきか。こうした判断は、ドメイン理解と設計の問題である。ここが曖昧なままAIに実装させると、もっともらしいコードが大量に生成されるだけで、品質の悪いソフトウェアをより速く量産することになる。
AI開発が本当に効くのは、チームが「何を正しさとするか」を明確にできているときだ。ユビキタス言語があり、ドメインモデルがあり、テストがあり、CIがあり、リリースと運用のフィードバックがある。その状態なら、AIは単なるコード補完ではなく、変更作業の一部を担う開発基盤になる。
これから重要になるのは、AIに任せる範囲を広げることだけではない。AIの出力を安全に受け止め、検証し、継続的に改善へつなげる品質基盤を作ることだ。品質の悪いソフトウェアを量産しないための基準は、AI時代にはさらに重要になる。
テストは品質を作る最後の工程ではない
テストは重要だが、テストだけで品質を作ることはできない。テストは、設計上の意図や仕様上の約束を実行可能な形で残すものである。
良いテストは、実装の誤りを検出するだけでなく、次に変更する人へ「ここは壊してはいけない」という情報を渡す。逆に、意図のないテストや壊れやすいテストは、開発速度を落とす。
重要なのは、何を保証したいのかを明確にすることだ。ビジネス上守るべき振る舞い、障害時の期待値、データの整合性、セキュリティ上の境界。これらを設計とテストの両方に反映する必要がある。
運用まで含めて設計する
ソフトウェアはリリースして終わりではない。むしろ、価値を出し始めるのは運用が始まってからである。
そのため、最初から運用上の観点を設計に含める。ログから何が起きたか追えるか。失敗時に安全に止まれるか。データの復旧手段があるか。変更の影響範囲を小さく保てるか。チーム内で判断理由を共有できるか。これらは派手な機能ではない。しかし、長く使われるシステムでは確実に効いてくる。
量産しないための基準
品質の悪いソフトウェアを量産しないためには、毎回の判断に基準が必要である。
私の場合は、いくつかの問いを置いている。これは本当に解くべき問題か。使う人の業務や制約を理解できているか。次の変更を妨げる設計になっていないか。重要な振る舞いはテストで守られているか。運用時に観測し、復旧できるか。
この問いに答えられないまま作ると、短期的には進んでいるように見えても、後で必ず負債になる。
良いソフトウェアは、単に美しいコードから生まれるわけではない。問題領域の理解、設計、実装、テスト、運用がつながって初めて、長く使えるものになる。