アーキテクチャドリフト検出:コードと設計の整合性を保つ
あなたの組織のどこかに、間違ったアーキテクチャ図があります。6ヶ月前に別のサービスに統合されたマイクロサービスがまだ表示されているかもしれません。本番障害時にチームがMemcachedに切り替えたのに、キャッシュレイヤーとしてRedisが記載されているかもしれません。ショートカットや回避策が蓄積してスパゲッティのようになっているサービスが、クリーンなヘキサゴナルアーキテクチャとして記述されているかもしれません。
これがアーキテクチャドリフトです。システムがどのように文書化されているかと、実際にどのように動作しているかの間で、徐々に静かに進行する乖離です。バグとは異なり、ドリフトはアラートを発生させません。パフォーマンスの低下とは異なり、モニタリングには表示されません。誰かが古いドキュメンテーションに基づいて意思決定を行い、その決定が間違っていたと判明するまで、静かに存在し続けます。
アーキテクチャドリフトは普遍的です。すべてのチームが経験します。問題は、ドキュメンテーションがドリフトするかどうかではなく、どれだけ早く検出し、それに対して何をするかです。
その後半についてのアドバイスには事欠きません。ドキュメントをコードの隣に置く。同じプルリクエストでレビューする。Definition of Done に含める。どれも良いアドバイスであり、その大半はこのページの下のほうにも登場します。そして、それらはひとつの盲点を共有しています。何をすべきかは教えてくれますが、それが機能したかどうかは教えてくれないのです。一般的なガイダンスの中で検証に最も近いものは最終更新のタイムスタンプですが、それが示すのは誰かがファイルに触れた時刻であって、そのファイルが真実かどうかではありません。
ドリフトの検出は、飛ばされがちなほうの半分です。このガイドでは、問題そのもの、検出手法の5つの系統、そして各手法に何が見えて何が見えないのかを扱います。姉妹記事が2本あり、それぞれ1つのテーマを掘り下げています。ドリフトスコアがどう計算され、その数値が何を意味するかと、モデルを手にした後にそれを真実に保つ実践です。
アーキテクチャドリフトとは何か?
アーキテクチャドリフトは、ソフトウェアシステムの実際の実装が、文書化または意図されたアーキテクチャから乖離する時に発生します。Perry と Wolf は Foundations for the Study of Software Architecture(ACM SIGSOFT Software Engineering Notes, 1992)でこの問題に名前を与え、アーキテクチャに違反することから生じる erosion(侵食)と、アーキテクチャに無頓着であることから生じる drift を区別しました。日常的な用法はその後変化しています。今日のエンジニアの多くは、ドキュメンテーションとコードの間のあらゆるギャップを指して「ドリフト」と呼んでおり、本ガイドもその意味で使います。この区別自体は保持する価値があり、後ほど専用のセクションを設けています。
ドリフトはアーキテクチャドキュメンテーションのあらゆるレベルで現れます。
構造的ドリフト
文書化された構造がコードベースと一致しなくなる場合:
- スタンドアロンコンテナとして文書化されたサービスがモノリスに吸収された
- コンポーネントの名前が変更されたが、図ではまだ古い名前が表示されている
- 新しいサービスが作成されたが、アーキテクチャモデルに追加されなかった
- データベースがMySQLからPostgreSQLに移行されたが、コンテナ図ではまだMySQLと記載されている
振る舞いのドリフト
文書化された振る舞いが現実と一致しなくなる場合:
- 同期API呼び出しが非同期メッセージに置き換えられたが、リレーションシップはまだ「REST/HTTP」と記載されている
- データフローがAPI Gatewayを通るように変更されたが、図ではサービス間の直接通信が表示されている
- システムコンテキスト図に反映されていない認証ステップが追加された
依存関係のドリフト
文書化された依存関係が実際の統合と一致しなくなる場合:
- サードパーティAPIが社内ソリューションに置き換えられた
- 新しい外部依存関係(決済プロバイダー、モニタリングサービス)が追加されたが文書化されていない
- 統合が廃止されたが、システムコンテキスト図にはまだ表示されている
意思決定のドリフト
文書化されたアーキテクチャ上の意思決定がもはや遵守されていない場合:
- ADRは「すべての永続ストレージにPostgreSQLを使用する」と述べているが、あるチームがMongoDBの使用を開始した
- 適合性ルールは「フロントエンドからのデータベース直接アクセスは不可」と述べているが、誰かがクライアントサイドのSupabase統合を追加した
- デプロイメントアーキテクチャは「単一リージョン」と述べているが、サービスが複数リージョンにデプロイされた
なぜアーキテクチャドリフトが発生するか
ドリフトの原因を理解することは、それを防ぐうえで不可欠です。ドリフトは通常、悪意によるものでも、怠慢によるものですらありません。ソフトウェアの開発のされ方から自然に生じる帰結です。
ドキュメンテーションより速度
金曜日までに機能を出荷しなければならないとき、アーキテクチャ図の更新は真っ先に切り捨てられます。コードの変更が成果物であり、ドキュメンテーションの更新はオーバーヘッドです。短期的には合理的な行動であり、長期的には破壊的です。
多数の小さな変更
ドリフトが劇的な一瞬に起きることはめったにありません。ドキュメンテーションの更新に値しないほど小さな変更が何百と積み重なることで蓄積していきます。
- ファイル名の変更
- ユーティリティパッケージの追加
- ライブラリ依存関係の切り替え
- 関数を別モジュールへ抽出
どの変更も単体ではドキュメンテーションの更新を引き起こすほど重要ではありません。しかし合わさると、アーキテクチャを作り変えてしまいます。
チームの入れ替わり
エンジニアが去るとき、暗黙知も一緒に持っていきます。新しいチームはコードベースを引き継ぎますが、なぜそのような構造になっているのかという理解は引き継ぎません。彼らはドキュメンテーションが述べていることではなく、コードで見えるものに基づいて変更を加え、ドリフトを広げていきます。
フィードバックループの欠如
ドキュメンテーションが現実と一致しているかを誰も確認しなければ、ドリフトは見えません。検出メカニズムがなければ、ドリフトが発覚するのは障害時、監査時、あるいは新しいエンジニアが図とコードの不一致を指摘したときだけです。その時点では、ドリフトはすでに大規模かもしれません。
緊急対応の変更
本番障害はしばしばアーキテクチャ上のショートカットを要求します。APIレイヤーを経由せずデータベースへ直接接続する、config サービスを使わず設定をハードコードする、一時的なキャッシュがそのまま恒久化する。こうした変更は通常のレビュープロセスを迂回し、ほとんど文書化されません。
アーキテクチャドリフトのコスト
ドリフトは単なる美観の問題ではありません。具体的で測定可能なコストがあります。
誤った意思決定
アーキテクトが古いドキュメンテーションに基づいて意思決定を行うと、その決定は誤りうるものになります。「このサービスはトラフィックが少ないから同期依存を持たせても大丈夫だ」――ただしドキュメンテーションは古く、実際のサービスは記載された10倍の負荷を処理していた、というように。
遅いオンボーディング
新しいエンジニアは、メンタルモデルを構築するためにアーキテクチャドキュメンテーションに頼ります。ドキュメンテーションが間違っていれば、間違ったメンタルモデルを構築します。実際のアーキテクチャに合わないコードを書きます。混乱を露呈する質問をし、シニアエンジニアの時間を消費します。
インシデント対応
本番障害の最中、アーキテクチャ図はチームが影響範囲と依存関係を把握する助けになるべきものです。その図が間違っていれば、チームは誤った依存の連鎖をたどったり、重要な上流システムを見落としたりして、貴重な数分を浪費します。
コンプライアンスと監査の不備
規制産業では、アーキテクチャドキュメンテーションはコンプライアンス(SOC 2、ISO 27001、HIPAA)のために必要とされることが多くあります。ドキュメンテーションが現実と一致していないと監査人が判断すれば、それは指摘事項になります――場合によっては重大な指摘です。
AIエージェントの混乱
AIコーディングエージェントが普及するにつれ、それらはコンテキストとしてアーキテクチャドキュメンテーションにますます依存するようになっています。古いC4モデルを読んだエージェントは、実際のアーキテクチャではなく文書化されたアーキテクチャに合うコードを生成します。これはドリフトを修正するどころか増幅させます。
アーキテクチャドリフトを検出する方法
一般的に使われているアプローチは5つあり、それぞれ答える問いが異なります。手動レビューは、その場にいる人たちにとって図がまだ正しく見えるかを問います。フィットネス関数と静的解析は、特定のルールが破られていないかを問います。LLMによる評価は、コードが実装していると称する設計のように読めるかを問います。ドリフトスコアリングは、文書化されたモデルのうちどれだけがまだ存在しているかを問います。今あなたにコストを課している問いはどれか、で選んでください。
手動レビュー(従来のアプローチ)
最もシンプルなアプローチは定期的な手動レビューです。チームを集め、アーキテクチャ図を一通り確認し、まだ現実と一致しているかをチェックします。
うまくいく場合:小規模チーム、シンプルなアーキテクチャ、四半期ごとのペース。
うまくいかない場合:大規模システム、速く動くチーム、あるいはコードを最もよく知る人たちにレビュー会議の時間がない場合。手動レビューは確証バイアスの影響も受けます――人は自分が見ると予期しているものを見る傾向があります。
アーキテクチャフィットネス関数
Neal Ford と書籍「Building Evolutionary Architectures」によって広まったフィットネス関数は、アーキテクチャ上の特性を検証する自動テストです。
// Example: Ensure no direct database imports in handler packages
func TestNoDatabaseImportsInHandlers(t *testing.T) {
packages := analyzeImports("./internal/handler/...")
for _, pkg := range packages {
for _, imp := range pkg.Imports {
assert.NotContains(t, imp, "database/sql",
"Handler %s imports database/sql directly", pkg.Name)
assert.NotContains(t, imp, "gorm.io",
"Handler %s imports GORM directly", pkg.Name)
}
}
}
フィットネス関数は特定のルールを強制するうえで強力ですが、記述と保守に先行投資が必要です。検証するのは制約であって、モデル全体ではありません。
静的解析ツール
ArchUnit(Java)、Deptrac(PHP)、go-arch-lint(Go)といったツールは、コード構造を解析して依存関係のルールを強制します。
// go-arch-lint configuration
components:
handler:
in: ./internal/handler/
service:
in: ./internal/service/
repository:
in: ./internal/repository/
rules:
handler:
can_depend_on: [service]
service:
can_depend_on: [repository]
repository:
can_depend_on: []
これらのツールは、単一のコードベース内でレイヤードアーキテクチャを強制するには優れています。サービス間のドリフトには対応せず、アーキテクチャモデルがコードと一致しているかの検証も行いません。
LLMを用いた評価
Thoughtworks は LLM によるアーキテクチャドリフトの低減を Technology Radar Vol. 34(2026年4月)の Assess リングに掲載しました。彼らによる問題の定式化は引用する価値があります。ベンダー以外の場所から出てきたものだからです。
Increased use of AI coding agents can accelerate drift from the intended codebase and architecture designs. Left unchecked, this drift compounds as agents and humans replicate existing patterns, including degraded ones, creating a feedback loop where poor code begets poorer code.
日本語訳:AIコーディングエージェントの利用が増えると、意図したコードベースやアーキテクチャ設計からのドリフトが加速しうる。放置すれば、エージェントと人間が既存のパターン(劣化したものも含む)を複製するにつれてこのドリフトは複利的に増大し、質の低いコードがさらに質の低いコードを生むというフィードバックループを作り出す。
彼らが説明する手法は、決定論的な解析ツール(Spectral、ArchUnit、Spring Modulith を挙げています)とLLMによる評価を組み合わせ、ルールエンジンでは表現できない意味的な違反を捉えたうえで、見つかったものの修正にもLLMを使います。彼らのチームはこれを API 品質ガイドラインへの適用や、エージェントが生成する変更を導くアーキテクチャゾーンの定義に用いています。
彼らの教訓のうち2つは、どのツールを使う場合でも持ち帰る価値があります。最初のスキャンでは誰もトリアージしきれないほどの違反が出てくるため、優先順位付けこそが本当の作業になるということ。そして、エージェントによる修正には独自の検証ループが必要だということ――「コードを変更した」と「システムを改善した」は別の主張だからです。
Assess は Thoughtworks の「見る価値はあるが、まだ推奨はしない」というリングです。そのとおりに扱ってください。これが確定させるのは、大手コンサルティング会社が書き留めるほどにはこの問題が実在するということであり、それはドリフトをめぐる大半の議論が指し示せるものより多くを意味します。
自動ドリフトスコアリング
これは Archyl が採るアプローチです。特定のルールをチェックするのではなく、アーキテクチャモデル全体をコードベースに対して検証します。
- 文書化された各システムはリポジトリと一致するか?
- 文書化された各コンテナはコードベース内のディレクトリと一致するか?
- 文書化された各コード要素は、まだ存在するファイルを参照しているか?
- 文書化された各リレーションシップの両端は、まだ有効か?
結果は0から100のスコアと、要素ごとの内訳です。一致したもの、文書化されているが消えたもの、コードには存在するが書き留められたことがないもの、が示されます。フィットネス関数が「あなたが書こうと思いついた制約」を検証するのに対し、こちらはすでに手元にあるモデル全体を検証します。
Archyl のドリフト検出における主要な設計判断は次のとおりです。
軽量。 AI呼び出しはなく、ファイル内容も取得しません。Git プロバイダーへの再帰的なツリーリクエストが1回、その後はモデルに対するパスと名前の照合だけです。計算は数秒で終わります。
決定論的。 同じコードベース、同じモデルなら、同じスコアになります。LLMの温度やプロンプトエンジニアリングによるばらつきがありません。
安価。 コストを気にせず毎回のプッシュで実行できます。1日100回の計算でも問題ありません。
実行可能。 内訳がどの要素がドリフトしたかを名指しするので、何を直せばよいかがわかります。
トレードオフは1つ目の項目にあります。コードを読む代わりにパスと名前を照合することで、スコアは高速・無料・再現可能になりますが、その分チェックは構造的なものにとどまります。ディレクトリが消えたコンテナや、ファイルが削除されたコード要素は見えます。しかし、両方のサービスが名前を保ったままRESTの呼び出しがキューのメッセージに変わったことは見えません。それが振る舞いのドリフトであり、本ガイド冒頭の分類の中で、安価なチェックでは捉えられない唯一の種類です。それに対して使えるのは、手動レビューとLLMによる評価です。
ドリフトスコアの計算方法の詳細では、計算式、分母から除外されるものとその理由、そのほかの限界を扱っています。
ループを閉じる
検出それ自体は何も変えません。誰かが一度計算して眺めるだけのスコアは、フィードバックループではなく監査です。それをループに変えるメカニズムが3つあり、加えて、どれを配線する前にも押さえておきたい区別が1つあります。それらと並ぶワークフロー上の実践――architecture as code、Definition of Done へのドキュメンテーションの組み込み、適合性ルールの導入――についてはリビングアーキテクチャドキュメンテーションで扱います。
CIでドリフト検出を自動化する
最も強い効き目を持つメカニズムは、ドリフトがしきい値を超えたときに失敗するCIゲートです。マージを止められるのはこれだけだからです。
on:
push:
branches: [main]
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: archyl-com/actions/drift-score@v1
with:
api-key: ${{ secrets.ARCHYL_API_KEY }}
organization-id: ${{ secrets.ARCHYL_ORG_ID }}
project-id: 'your-project-uuid'
threshold: '70'
ドリフトスコアが下がってビルドが失敗すれば、誰かがマージ前に直さなければなりません。ドキュメンテーションの正確さは、テストが通ることと同じくらい交渉の余地のないものになります。
しきい値は、望ましい数値ではなく現在のスコアより下に設定してください。初回の実行で失敗するゲートは、初回の実行で無効化されます。チームが習慣を作るにつれて引き上げていきましょう。
ドリフトアラートを設定する
Archyl はドリフトイベントの Webhook アラートをサポートしています。
drift.score_computed:ドリフト計算のたびに発火します。可視性のために Slack チャンネルへ投稿しましょう。drift.score_degraded:スコアが10ポイント以上下がったときに発火します。これが早期警戒システムです。
これらのアラートは、チームが見ているチャンネルに設定してください。気づくことが行動への第一歩です。
アーキテクチャレビューを実施する
月次または四半期ごとのアーキテクチャレビューは、複数の目的を果たします。
- 文書化されたアーキテクチャがまだ現実と一致していることの確認
- 自動ツールが見逃したドリフト(たとえば振る舞いのドリフト)の特定
- ドリフトしたコンポーネントをコード側とドキュメンテーション側のどちらで更新すべきかの議論
- 見直しが必要かもしれない意思決定について、ADRのレビューと更新
ドリフトと適合性を混同しない
この2つは一緒に実行されることが多いだけに、区別しておく価値があります。計算方法が異なり、失敗する理由も異なるからです。
ドリフト検出は、あなたのモデルが現実と一致しているかを問います。文書化されたアーキテクチャをリポジトリと比較し、スコアを出します。
適合性ルールは、現実があなたのルールに従っているかを問います。フロントエンドのコンテナはデータベースのコンテナに依存してはならない、公開APIはすべてゲートウェイを経由する、各サービスは自分のデータベースを保有する、といったものです。ひどくドリフトしたモデルでも適合性チェックは通りうるし、完全に正確なモデルが手持ちのルールをすべて破っていることもありえます。
必要なのは両方であり、片方の数値をもう片方であるかのように読むべきではありません。
アーキテクチャドリフト vs. アーキテクチャ侵食
これらの用語は関連していますが、区別されます。
アーキテクチャドリフトは、ドキュメンテーションと実装の間の乖離です。コードは完全に問題ないかもしれません――間違っているのはドキュメンテーションのほうです。
アーキテクチャ侵食は、アーキテクチャそのものの劣化です。コードがアーキテクチャ上の原則に違反し、技術的負債を蓄積し、保守が難しくなっていきます。侵食はコード品質の問題です。ドリフトはドキュメンテーションの正確さの問題です。
Perry と Wolf は1992年に別の場所に線を引いていました。彼らにとっては両方ともドキュメンテーションではなくシステムの性質であり、侵食はアーキテクチャに違反することによって、ドリフトはアーキテクチャに無頓着であることによって引き起こされるものでした。現代の用法はより緩やかで、実務のチームにとってはより有用ですが、アーキテクチャ侵食に関する学術文献を読む際には、用語の位置づけがこことは異なることを想定してください。
両者はしばしば同時に起こります。ドキュメンテーションがドリフトすると、チームは意図されたアーキテクチャへの意識を失います。その意識がないまま加えられる変更が、アーキテクチャを侵食していきます。ドリフトが侵食を可能にするのです。
だからこそ、ドリフト検出はドキュメンテーションの正確さを超えた意味を持ちます。正確なドキュメンテーションは、侵食を防ぐ参照点として機能します。意図されたアーキテクチャを全員が見られるなら、それが維持される可能性は高まります。
時間の経過に沿ってドリフトを測定・追跡する
1回のドリフトスコアは有用です。トレンドは強力です。
ベースラインを確立する
チームの働き方を何ひとつ変える前に、最初の計算を実行してください。返ってきた値が、あなたのベースラインです。最初の数値が低いことは、判決ではなく情報です。誰も維持を頼まれてこなかったドキュメンテーションは、失敗してきたのではありません。ただ測られてこなかっただけです。
初回の実行前に何かを直したくなる衝動には抗ってください。あなたが必要なのは、実際に置かれている状況を記述する数値であり、片付けの週末を過ごした後に出てくる数値ではありません。
トレンドを追う
単発のスコアは今日についての事実です。あなたが変えた何かが機能したかどうかを教えてくれるのは、トレンドのほうです。
- ドリフトは時間とともに良くなっているか、悪くなっているか?
- 特定のスプリントやリリースが低下を引き起こしたか?
- CIのしきい値は線を保っているか、それともみんなが下げているだけか?
Archyl はすべての計算を完全な内訳とともに保存するため、過去のレポートを開き直して要素単位で比較できます。どのツールを使うにせよ、履歴は残してください。四半期ごとにゼロから計算し直しては捨てるドリフトスコアは、また監査に戻ってしまいます。
実際に守れる目標を設定する
理想の数値ではなく、次の数値を選んでください。今日が58なら、有用な目標は65であり、有用な議論はどの5要素がそこへ連れて行くかについてのものです。四半期末までに90%に到達すると合意するチームは、たいてい何にも合意していません。
AI支援開発におけるドリフト検出の役割
ここが最近もっとも変化した部分であり、先ほど引用した項目を Thoughtworks が書いた理由でもあります。エージェントは見つけたパターンを――劣化したものも含めて――複製するため、かつては人間のコミットの速度で蓄積していたドリフトが、いまや生成されたコミットの速度で蓄積するようになりました。
AIエージェントはコンテキストとしてアーキテクチャドキュメンテーションにますます依存しています。MCPのようなプロトコルを通じて、エージェントはコード生成の前にあなたのC4モデル、ADR、適合性ルールを読めます。これによりエージェントはより効果的になります――推測する代わりに、あなたのアーキテクチャに合ったコードを生成するのです。
しかしこれはドキュメンテーションが正確な場合にのみ機能します。古いC4モデルを読み、それに基づいてコードを生成するエージェントは、間違ったアーキテクチャに合うコードを生み出します。エージェントはドリフトを防ぐどころか増幅させます。
ドリフト検出は、AIエージェントを誠実に保つフィードバックループを作ります。
- エージェントがアーキテクチャを読む(MCP経由)
- エージェントがコードを生成する(文書化されたアーキテクチャに合うもの)
- コードがマージされる(実際のアーキテクチャが変わる可能性がある)
- ドリフト検出が実行され、乖離を捉える
- CIゲートが失敗する(ドリフトがしきい値を超えた場合)
- チームがドキュメンテーションを更新し、現実を反映させる
- エージェントが更新されたアーキテクチャを読む ―― ループが閉じる
ステップ4がなければ、ループは開いたままです。ドキュメンテーションはますますフィクションになります。エージェントは空想上のアーキテクチャに合うコードをますます生成します。ギャップはコミットのたびに広がります。
ドリフト検出は、このループを閉じるメカニズムです。
ドリフト検出を始める
すでにどこかにモデルがある場合
ほかを何も変える前に、それを測ってください。これは利用できるなかで最も安価な最初の一手であり、何も約束させられません。
アーキテクチャがすでに Structurizr DSL、LikeC4、IcePanel、あるいは Backstage のカタログに存在しているなら、そのモデルを取り込んで、そのままの状態でスコアを計算してください。測っているのは、すでにあなたが書いたドキュメンテーションを、置いたままの状態で、です。ワークフローの変更も、チームの新しい習慣も、ツール選定の決断もまだ必要ありません。この数値はその決断の入力であって、結果ではありません。
正直な注意点が2つあります。インポーターはロスレスではありません。ビュー、スタイル、レイアウトは残らず、Structurizr のパーサーはデプロイメント環境とデプロイメントノードをスキップしますが、警告リストに行番号付きで名前を出します。分母を信頼する前に、そのリストとインポートされたモデルを読んでください。そして、スコアが記述するのは到着したモデルであって、あなたがエクスポートしたファイルではありません。
返ってくるのは要素ごとのリストです。スコア84は、予定に組み込める保守上の問題です。スコア41は、別のシステムを記述した文書に対して意思決定が行われ続けてきたということであり、それを知るのは次の障害の最中よりも今のほうがましです。
アーキテクチャドキュメンテーションがない場合
AIディスカバリーから始めましょう。リポジトリを接続し、ディスカバリーにC4モデルを提案させ、自分で描く代わりに提案を承認または却下します。モデルができたら、それを誠実に保つのがドリフト検出です。
すでにドリフトを追跡している場合
それをCIに入れましょう。現在のスコアより下にしきい値を設定します。低下アラートを設定します。ドリフトを、レビュー前に1人が計算する数値ではなく、チームが毎週目にするメトリクスにしてください。
どこから始めるにせよ
ドリフトは技術的負債と同じように積み上がります。放置するほど突き合わせる量は増え、その間ドキュメントを信頼する人は減っていきます。違うのは、何ひとつ直さないまま、今日の自分の位置を知ることができるという点です。
あなたのアーキテクチャドキュメンテーションは、現実を反映しているか、していないかのどちらかです。ドリフトスコアの意義は、そのどちらなのかをもう推測しなくてよくなることにあります。
さらに深く:仕組みについてはドリフトスコアの計算方法、モデルを真実に保つ実践についてはリビングアーキテクチャドキュメンテーション、ゼロから始めるならC4モデルとは何か。用語の定義はアーキテクチャドリフト、リビングドキュメンテーション、製品内の機能はドリフト検出。Developer プランは無料でカード登録も不要です。すでにあるドキュメンテーションに数値を与えたい方はこちらから:archyl.com。