0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

頑張るほど悪化する? 現場でよく見る謎の現象を "システムの構造" で読み解く

0
Posted at

はじめに

「正しいことをしているのに、なぜかうまくいかない」。
開発現場にいると、この感覚に出くわすことがあります。

人を増やしたのに開発が遅くなった。
バグを直したのに別の場所が壊れた。
各チームは頑張っているのに、全体がぐちゃぐちゃになった。

個人の力量不足ではなく、
システムの構造にその原因があるとしたらどうでしょうか。
この記事では、現場でよく感じる「謎の体験」を入り口にして、
その正体を構造の視点から読み解き、
どう向き合えばいいかを整理してみます。

TL;DR

  • 入力と出力は比例しない。「もう少し増やせば」が逆効果になることがある
  • 自分が引いた分析範囲の外に根本原因があると、どれだけ頑張っても的外れになる
  • 各チームの局所的な正解が、全体の失敗を生むことがある
  • 出来事ではなく、出来事を生み出す構造を見ることで謎が解ける
  • 複雑なシステムは制御できない。観察し、可視化し、小さく試す

セクション1: 「人を増やしたのに、なぜか開発が遅くなった」

  開発速度
  ↑
  │         .........  ← 期待(人数に比例)
  │       .
  │     . ____-------  ← 現実(頭打ち → 低下)
  │   ./--
  │  /
  │ /
  │/
  └──────────────────→ チームの人数

こんな経験はありませんか。

プロジェクトの進捗が遅れていて、マネージャーが「人を増やそう」と判断した。
実際に増員した。最初はたしかに少し速くなった気がする。
しかし1〜2か月たつと、なぜか前より遅くなっている。
会議が増え、レビューの待ちが増え、「誰が何をやっているのか」が見えなくなった。

自分たちは無意識のうちに
「入力を増やせば出力も比例して増える」と考えがちです。
人を2倍にすれば生産性も2倍、
テストを増やせば品質も比例して上がる、と。

しかし現実には、ある閾値を超えると効果が頭打ちになったり、
逆効果になったりすることがあります。
これが非線形性です。

なぜ比例しないのか

チームに人を追加するとき、
コミュニケーションの組み合わせ数は n×(n-1)/2 で増えます。

  • 5人なら10通り
  • 10人なら45通り
  • 20人なら190通り

認識合わせ、レビュー、会議の時間が加速度的に増えるため、
一人当たりの生産性がむしろ下がる局面が訪れます。

「人が足りないから増やす」は直感的で正しく聞こえますが、
チームの規模がすでに閾値を超えている場合、
増員はかえってコミュニケーションコストを増大させます。
人数ではなく、チーム分割やスコープの見直しが
有効な打ち手になることがあります。

他にもある「比例しない」パターン

非線形な関係はチーム規模だけではありません。

入力 期待 現実
テストカバレッジを60%→80%に上げる 品質が改善する 改善する(ただしペースは鈍化)
テストカバレッジを90%→100%に上げる さらに品質が上がる テスト保守コストが急増し、開発速度が落ちる
APIリクエスト数が増える レスポンスタイムが少し遅くなる ある閾値を超えると一気に詰まる

共通しているのは、
少しうまくいったから、もっとやればもっとうまくいく
という期待が裏切られる点です。

入力を増やす行為がシステム内部の力学を変えてしまうからです。
少人数のときは「人が増える → タスクがさばける」
という正のループが優勢ですが、
閾値を超えると「人が増える → 調整コストが増える → タスクが滞る」
という別のループが優勢になります。

セクション2: 「バグを直したのに、また別のところが壊れる」

  ┌───────── 自分の分析範囲 ─────────────┐
  │                                    │
  │   自サービス                         │
  │   ┌────────────┐                   │
  │   │  エラー発生  │                   │
  │   │  ↓         │                   │
  │   │  修正した    │                  │
  │   │  ↓         │                   │
  │   │  でも直らない│                   │
  │   └────────────┘                   │
  │                                    │
  └────────────────────────────────────┘
                 ↑ 本当の原因はここにはない

  ┌───────── 見落としている範囲 ───────┐
  │                                 │
  │   依存サービス / インフラ          │
  │   ┌────────────────────────┐    │
  │   │ API仕様変更 / DB接続数の  │    │
  │   │ 上限到達 / 認証の遅延     │    │
  │   └────────────────────────┘    │
  │            ↑ 本当の原因           │
  └─────────────────────────────────┘

——そんな経験はありませんか。

自分のサービスでエラーが頻発している。
ログを追い、コードを修正し、デプロイした。
しかしエラーは止まらない。
結局、原因は依存先サービスのAPI仕様変更だった。
自サービスのコードには何の問題もなかったのに、
何日も自分のコードの中を探し回ってしまった。

これは境界の罠です。

境界は無意識に引いている

問題を分析するとき、
自分たちは必ず「ここからここまでが対象範囲」という境界を引いています。
多くの場合、それは無意識に行われています。
そして、その境界が狭すぎると、
本当の原因が視界に入りません。

マイクロサービスアーキテクチャでは、この罠がより深刻になります。

  • 自チームのサービスでタイムアウトが多発している
  • 自サービスのコードやインフラを調べても異常がない
  • 実は上流の認証サービスのレイテンシが増加していて、
    タイムアウトの連鎖を引き起こしていた

自チームのサービスだけを境界にしていると、
原因は永遠に見つかりません。

「副作用」という言葉に注意する

自分たちは問題を議論するとき「副作用」という言葉をよく使います。
しかし「副作用」とは本質的に、
自分が予見していなかった、あるいは考えたくない影響のことです。

システムの視点から見れば、副作用も主作用も同じ「作用」です。
「副」という言葉をつけることで、
自分の境界の外に影響を追いやっているだけかもしれません。

境界を広げればすべて解決するかというと、
広すぎてもかえって分析が発散します。
大切なのは「目的に応じて境界を引き直す柔軟性」です。
今の境界で原因が見つからないなら、
境界の設定自体を疑ってみる、というのが実践的なアプローチです。

境界を引き直すための問いかけ

行き詰まったとき、こんな問いかけが役立ちます。

  • 「この問題は、自分の分析範囲の中だけで完結しているか?」
  • 「依存先や上流に、見落としている変化はないか?」
  • 「アプリケーション層だけでなく、
    インフラ層やネットワーク層にも原因がないか?」

セクション3: 「各チームは頑張っているのに、全体がぐちゃぐちゃになる」

これも開発現場で起きがちな話です。

各チームはそれぞれのスプリントを真面目に回している。
自チームの完了ポイントも順調に伸びている。
なのに結合テストの段階で大量の手戻りが発生し、
全体のリリースが遅れる。
どのチームも「自分たちはちゃんとやった」と思っているのに、
全体としてはうまくいっていない。

これが限定合理性の罠です。

局所的な正解が全体の失敗を生む

限定合理性とは、各アクター(チーム・個人)が
自分の持っている情報の範囲内で合理的に判断する
という概念です。
全知全能ではなく、見えている範囲で最善を尽くす。

問題は、その「見えている範囲」が限定されているため、
局所的に正しい判断が全体では噛み合わないことがある、ということです。

上の図のアラート閾値の例が分かりやすいです。
各チームが「自分たちが対応しやすい基準」を選ぶのは合理的ですが、
全体で見ると障害が埋もれる結果になります。

誰も「アラートを多くして障害対応を遅らせよう」
とは思っていません。
全員が自分の範囲で合理的に動いた結果がこれです。

人を変えても構造が同じなら結果は変わらない

ここで大事なのは、
人を責めても状況は変わらないということです。

同じ情報フロー・インセンティブ・制約の中に
別の人を置いても、同じ行動をとる可能性が高いです。

「あのチームの判断がおかしい」と感じたとき、
もし自分がそのチームと同じ情報・制約・目標の中にいたら
同じ判断をしないだろうか? と考えてみてください。
もし同じ判断をしそうなら、
問題は人ではなくシステムの設計にあります。

セクション4: 出来事ではなく、構造を見る

          ┌─────────────────────────────────┐
  水面上   │  出来事                          │
          │  「本番障害が発生した」             │
          ├─────────────────────────────────┤
  水面下   │  振る舞い(時間的なパターン)        │
          │  「毎月リリース直後にエラー          │
          │   レートが跳ね上がる」              │
          ├─────────────────────────────────┤
  深層     │  構造(パターンを生む仕組み)        │
          │  「テストカバレッジの薄い領域        │
          │   +ステージング検証の形骸化」       │
          └─────────────────────────────────┘

ここまで3つの「謎の体験」を見てきました。
非線形性、境界の罠、限定合理性。
一見バラバラに見えますが、共通する視点があります。

それは、目の前の出来事ではなく、出来事を生み出す構造に目を向けることです。

3つの層で考える

出来事・振る舞い・構造の3層モデルで整理してみます。

問いかけ
出来事 「今、何が起きたか?」 本番でエラーが発生した
振る舞い 「時間軸で見ると、どんなパターンの一部か?」 毎月リリース直後にエラーが増える
構造 「このパターンを生み出している仕組みは何か?」 テスト戦略とリリースプロセスの設計

本番障害が起きたとき、
自分たちはまず「何が原因か」を調べて修正をデプロイします。
これは正しい対応です。
ただし、ここで見ているのは「出来事」の層だけです。

パターンが見えると、問いが変わる

個々のインシデントを対処し続けているだけだと、
エラーレートの長期トレンドを見落としがちです。
月次でエラーレートをグラフ化すると、
こんなパターンが浮かび上がることがあります。

  • 毎月のリリース直後にエラーレートが跳ね上がる
  • 2〜3日かけて収束するが、翌月また同じことが起きる
  • しかも跳ね上がりの幅が徐々に大きくなっている

個々のインシデントだけを見ていたら、
「今回はたまたまバグが多かった」で終わります。
時間軸で並べると「毎月繰り返されるパターン」が見えてきます。

振る舞いの層が見えると、次の問いが浮かびます。
「なぜ毎月リリース直後に障害が集中するのか?」
この問いに答えるのが「構造」の層です。

  • テストカバレッジが薄い領域が放置されている
  • リリース前のステージング検証が形骸化している
  • CI/CDパイプラインにステージング環境での
    自動テストが組み込まれていない

構造が見えると、対処の仕方が変わります。
個々のバグを直すのではなく、
CI/CDパイプラインやテスト戦略を見直す、という発想になります。

出来事レベルの分析が無駄というわけではありません。
インシデント対応では当然必要です。
ただ、それだけでは「パターンがなぜ繰り返されるのか」に到達できません。
振る舞いと構造の層まで意識的に掘り下げることで、
前半で見た3つの「謎」にも構造的に対処できるようになります。

セクション5: まず観察する

┌─────────────────────────────────────────────────────┐
│  よくあるパターン(解決策に飛びつく)                     │
│                                                     │
│  問題発生 → 「○○が足りない!」 → すぐ施策を打つ            │
│         → 思い込みで見当違いの対応 → 再発                │
│                                                     │
├─────────────────────────────────────────────────────┤
│  観察してから動くパターン                               │
│                                                     │
│  問題発生 → メトリクスの時系列を見る                     │
│         → 「何が起きているか」を事実で把握               │
│         → 原因に基づいた施策を打つ → 改善                │
└─────────────────────────────────────────────────────┘

ここからは「じゃあどうするか」の話です。

構造を見ることが大事だと分かったところで、
最初にやるべきことは介入ではなく観察です。

解決策から逆算して問題を定義していませんか

問題に遭遇すると、つい「足りないもの」で問題を定義しがちです。

  • 「キャッシュが足りない」
  • 「サーバーを増やせばいい」
  • 「エンジニアが足りない」

これらはすべて「何を追加すればいいか」を述べているだけで、
「今、何が起きているか」を説明していません。
打ち手から逆算して問題を定義すると、
本当の原因にたどり着く前に
見当違いの対応をしてしまうリスクがあります。

時系列データで事実を見る

介入の前にやるべきことがあります。
システムの振る舞いを時系列で観察する習慣です。

「レスポンスタイムが遅い」という報告があったとします。
CloudWatchやDatadogでレイテンシの時系列グラフを引いてみると、
実は特定の時間帯だけスパイクしていた
――ということは珍しくありません。

  • 「全体的に遅い」と「特定時間帯だけ遅い」では、
    打つべき施策がまったく変わる
  • 「最近悪化している」という感覚と実際のデータが
    一致しないこともある
  • デプロイ頻度と障害発生率をプロットしてみると、
    想定していた相関が見えないこともある

ダッシュボードの長期トレンドを見てから
施策を検討する習慣をつけると、
思い込みによる誤った介入を防げます。
「感覚」ではなく「データ」を起点にするのがポイントです。

動的な問いを持つ

「何が問題か?」という静的な分析に加えて、
動的な視点を持つと問題の解像度が上がります。

問い
いつからこの傾向が始まったか? エラーレートの推移を見ると、特定のデプロイ以降に急増している
放置した場合の影響は? 徐々に悪化しているトレンドなら、半年後には深刻になる可能性がある
正常に動いている部分はどこか? 正常な箇所を理解することで、原因の切り分けに役立つ

セクション6: 暗黙の前提を可視化する

┌────────────────────────┐    ┌────────────────────────┐
│  暗黙のまま              │    │  可視化された状態         │
│                        │    │                        │
│  Aさんの頭の中:          │    │  ADR / アーキテクチャ図   │
│  「DBはリードレプリカ     │    │                        │
│    で分散してるはず」     │ →  │  ・判断根拠が記録済み      │
│                        │    │  ・前提条件が明示         │
│  Bさんの頭の中:          │    │  ・不整合に気づける       │
│  「DBは1台構成の         │    │  ・チームで検証できる     │
│    はず」               │    │                        │
└────────────────────────┘    └────────────────────────┘
    認識のズレに             外部化されていれば
    気づけない                 問題を発見できる

前半のセクション3で
「各チームが合理的に動いても全体が壊れる」という話をしました。
その原因の一つが、
チーム間で暗黙の前提がズレていることです。

メンタルモデルは「滑りやすい」

メンタルモデルとは、
自分がシステムについて頭の中に持っている
「こうなっているはず」という理解の枠組みのことです。
この仮定は、意識しないと見えません。

ある設計レビューでは
「このサービスはステートレス(サーバー側に状態を持たない)だ」という前提で議論しているのに、
別の障害対応では
「ローカルにセッション情報を持っているはず」
という矛盾する前提で動いている。
こういうことは、思った以上に起こります。

見えていれば検証できる

メンタルモデルは
「正しいかどうか」より
「見えているかどうか」が重要です。
見えていれば検証できるからです。

外部化の具体的な方法をいくつか紹介します。

ADR(Architecture Decision Records)

「なぜこの技術を選んだのか」の判断根拠を記録します。
当時の前提条件(トラフィック量の見込み、チームのスキルセットなど)
も一緒に書いておくと、
前提が変わったときに見直すきっかけになります

アーキテクチャ図(C4モデルなど)

C4モデルは、システムの全体像から
コンポーネント単位まで4段階の粒度で図を描く手法です。
チームメンバーごとにシステムの理解が違うことがあるため、
図にすることで認識のズレが表面化します

設計レビューでの確認

「自分はこう理解しているが合っているか?」と確認する文化を持つことで、
暗黙の前提が共有されます

ADRに書く内容は大げさなものでなくて構いません。
「Aの案とBの案があったが、○○の理由でAを選んだ。
ただし△△の前提が変わったら再検討する」程度で十分です。
大切なのは、判断の根拠と前提条件がどこかに残っていることです。

前提は更新するもの

メンタルモデルを可視化することには、もう一つ大事な意味があります。
「更新できるようになる」ということです。

半年前に正しかったアーキテクチャの前提が、
トラフィックの変化やチーム構成の変化で
成り立たなくなることはよくあります。

ADRに「ステータス: 廃止」と書き加えて
新しいADRを起こす。
その更新の繰り返しが、
チームのシステム理解を現実に追従させます。

セクション7: 謙虚に、でも設計的に

観察し、前提を可視化した。では、その先どうするか。
ここでは「完全な制御」を手放しつつも、
設計的にシステムと付き合うアプローチを考えます。

ここまでの話を踏まえると、
一つの結論にたどり着きます。

複雑なシステムは完全には制御できない。
でも、うまく付き合うことはできる。

非線形で、境界がにじみ、
各所が限定合理的に動くシステム。
こうしたシステムと付き合うには、
完璧な予測・制御を目指すのではなく、
次のような姿勢が求められます。

  • 制御できないことを前提に、変化に対応できる仕組みを作る
  • 間違いを早く検知し、そこから学ぶサイクルを回す
  • 大きな賭けを避け、小さく試す

小さく試して、観察して、学ぶ

わからないときにすべきことは、
知ったかぶりをすることでも思考停止することでもなく、
小さく試して学ぶことです。

ソフトウェア開発では、学ぶ仕組みを設計できます。

  • フィーチャーフラグ:
    一部のユーザーにだけ新機能をリリースし、
    メトリクスを見てから全体に展開する
  • カナリアリリース:
    本番環境の一部にだけ新バージョンをデプロイし、
    問題がないことを確認してからロールアウトする

どちらも「小さく試して、観察して、判断する」
というサイクルを仕組みとして実現しています。

大きな変更を一括でデプロイすると、
障害が発生したときに原因の特定が困難になります。
小さく出して観察するほうが、
結果的にリスクもコストも小さくなることが多いです。

ブレームレス・ポストモーテムで間違いから学ぶ

間違いを受け入れる姿勢が学習の条件です。

ブレームレス・ポストモーテムは、
障害の原因を個人の責任ではなく
システムの構造に求める振り返りの手法です。
「誰が悪いか」ではなく「何がこの結果を生んだか」を分析します。

前半のセクション3で
「人を変えても構造が同じなら結果は変わらない」という話をしました。
ブレームレス・ポストモーテムは、
まさにその考え方を障害振り返りに適用したものです。

  • 障害レポートを公開し、他のチームも学べるようにする
  • 「この判断は当時の情報ではどうだったか」を検証する
  • 再発防止策は「人の注意力」ではなく「仕組み」に落とし込む

完璧な計画を立ててから動くのではなく、
小さく動いて失敗から学ぶ。
そのサイクルを回し続けることが、
複雑なシステムとの付き合い方の基本です。

おわりに

「正しいことをしているのに、なぜかうまくいかない」。
この記事では、その正体を3つの構造的な罠として読み解きました。

  • 入力と出力が比例しない(非線形性)
  • 分析範囲の外に原因がある(境界の罠)
  • 局所的な正解が全体を壊す(限定合理性)

そして、これらの罠に対処するために
「出来事ではなく構造を見る」という視点のシフトと、
3つの実践を紹介しました。

  • 介入の前にまず観察する
  • 暗黙の前提を外部化して検証可能にする
  • 完全な制御を諦め、小さく試して学ぶ

システムを完璧に予測することはできません。
でも、「驚きを減らすこと」はできます。

次に「正しいことをしているのにうまくいかない」と感じたら、
目の前の出来事から少し引いて、
構造を眺めてみてください。
「何がこの結果を生んでいるのか?」という問いが、
きっと新しい打ち手を見せてくれるはずです。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?