> ## Documentation Index
> Fetch the complete documentation index at: https://lib.findy.co.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# 開発チームの通知設計 — アラートを摩耗させない運用

> 検知時間が復旧時間を左右する理由、何を通知に値すると判断するか、アラートや開発フローのイベントをチャットへ流しつつチャンネルを摩耗させない方法を解説します。

## 概要

通知は、「何かが起きた」から「誰かが気づいた」までの間隔を短くする仕組みです。失敗したデプロイ、新しく現れた本番エラー、読まれていないレビュー依頼は、いずれも検知するコストが低く、見逃したときのコストが高いため、誰かが気づくまでの遅れがボトルネックになります。

本ページでは、速く気づくことがなぜ目標になるか、何を通知に値すると判断するか、アラートと自動実行の結果の扱い、開発フローのイベントの通知とリマインド、そしてチャンネルを読むに値する状態に保つ方法を解説します。

## 速く気づいて速く行動する

不具合や障害はゼロに近づけるべきであり、その努力は継続する価値があります。テスト・レビュー・段階的なロールアウトは、いずれも障害が本番に到達する確率を下げます。ただし、確率を下げることと、ゼロにすることは違います。

厳密にゼロを達成する方法は1つだけあります。コードを一切書かないことです。変更しなければ変更由来の障害は起きませんが、同時に価値も届きません。障害ゼロという目標は、何も出荷しないことと引き換えにしてはじめて成立します。

したがって目指すべきは、障害をなくすことではありません。起きてしまった障害に、いかに速く気づき、いかに速く復旧するかです。

復旧は、復旧すべき何かがあると誰かが知るまで始められません。異常が起きてから気づくまでの時間を平均検知時間（MTTD, Mean Time To Detect）、異常が起きてから復旧が完了するまでの時間を平均復旧時間（MTTR, Mean Time To Recovery）と呼びます。どちらも異常の発生を起点として数えるため、MTTDはMTTRに含まれる区間になります。

修正にかかる時間よりMTTDのほうが長い、という状況も起こります。修正に10分しかかからない不具合でも、気づくまでに2日かかれば、2日分の不利益が発生します。

この見方は、何を問題と捉えるかを変えます。障害そのものは、コストが有限のイベントです。一方、誰も気づいていない障害は、気づかれない限りコストが増え続けます。処理が失敗し続け、バッチが誤ったデータを書き続け、ユーザーが離れ続けます。

閾値の設定と通知は、この蓄積が見えていない区間を短くするために存在します。

同じ構造は障害以外にも当てはまります。レビュー依頼が気づかれずにいる間、変更のリードタイムは伸び続けます。ここでも問題はレビューが必要なことではなく、レビューが必要だと気づかれていないことです。

<Note>
  変更障害率と並べてMTTRが計測されるのも同じ理由です。障害率だけを見ているチームは、障害の起きる頻度しか把握できません。MTTRも併せて見ることで、1件あたりどれだけの損失になるかが把握できます。
</Note>

## 何を通知するかを決める

通知は、チャンネルにいる全員の注意を消費します。そのコストは、そのメッセージが結果的に重要だったかどうかに関係なく支払われます。したがって、あるイベントを流すかどうかは既定の動作ではなく、設計上の判断です。

イベントがチャンネルに属するかどうかは、次の3つの問いで決まります。

| 問い          | 答えが曖昧な場合に起きること                         |
| ----------- | -------------------------------------- |
| 誰が対応するか     | 担当者がいない通知は、全員に読まれて誰にも対応されません           |
| 何をすればよいか    | 次の行動を示さないメッセージは、流し読みされて忘れられます          |
| いつまでに効いてくるか | 1週間待てるものは、常時流れるチャンネルではなく定期のダイジェストに属します |

3つとも明確に答えられるイベントは通知に値します。それ以外、たとえば担当者のいない定型的な成功、参考情報にすぎない状態変化、1時間に何度も発火するものは、ダッシュボードやダイジェストに置きます。

<CardGroup cols={2}>
  <Card title="本番のエラーと負荷" icon="bug">
    エラートラッキングとインフラ監視がチャットへ投稿し、問題が次回のダッシュボード確認時ではなく数秒で人に届きます。
  </Card>

  <Card title="レビュー依頼" icon="code-pull-request">
    レビュー待ちのプルリクエストがレビュアーをメンションし、最初のレビューまでの待ち時間を短縮します。
  </Card>

  <Card title="リポジトリのイベント" icon="bell">
    新しいIssueやコメントなどのWebhookイベントをメンション付きで投稿し、誰かに向けられた質問がまだ意味を持つうちに見られるようにします。
  </Card>

  <Card title="信頼性とコストの推移" icon="chart-line">
    エラーバジェットの消費、クラウド利用費の変動、セキュリティチェックの結果は、障害になる前の段階で傾向として現れます。
  </Card>
</CardGroup>

## アラート

ここで扱うのは、動いているシステムが出す通知です。中心はインシデント対応で、監視ツールを配線し、問題が現れた瞬間にアラートがチャットへ届くようにします。異常時のアラートだけでなく、自動で走る処理の結果のように正常時にも出すべき通知も、この系統に含まれます。

* **エラートラッキング→チャット。** アプリケーションの例外や新しく現れたエラーの種類を専用チャンネルへ投稿します。受け取った人はスタックトレースを探し回らずにトリアージを始められます。
* **インフラ監視→チャット。** 負荷・レイテンシ・リソース逼迫の監視がシステムのストレス時に発火し、劣化が障害へ連鎖する前に表面化させます。
* **サービスレベル目標（SLO, Service Level Objective）の監視→チャット。** 目標に対して許容できる逸脱の量をエラーバジェットと呼びます。その消費状況を監視し、目標を割り込む前に気づけるようにします。
* **コストとセキュリティの検査→チャット。** クラウド利用費の急な変動や、セキュリティチェックの結果も、気づくのが遅れるほど不利益が積み上がるシグナルです。

### 重大度で通知先を分ける

同じ「異常」でも、いま人を呼ぶべきものと、翌営業日に見れば足りるものがあります。すべてを同じチャンネルへ同じ強さで流すと、緊急のものが埋もれます。

判断の基準は、その異常がサービスの継続にどう効くかです。冗長化された構成でプロセスが1つ落ちても、残りが処理を引き受け、やがて新しいプロセスが立ち上がるなら、警告として記録すれば足ります。一方、単一のプロセスしか持たないバッチが異常終了した場合は、その時点で処理が止まるため、即時の対応が要ります。

重大度が決まれば、通知先とメンションの強さもそれに従います。緊急のものは担当者を直接呼び出し、警告は記録用のチャンネルへ流します。

### 誤検知は監視の不具合として扱う

チームが無視すると決めた条件で発火するアラートは、アラートがないことより有害です。そのチャンネルを読み飛ばすことを人に学習させるからです。誤検知が出たときに直すべきは発火の条件、つまり閾値・判定に使う時間幅・同種のアラートのまとめ方であり、チャンネルのミュートではありません。

チューニングは両方向に効き、2種類の誤りは対称ではありません。誤検知が絶対に出ないほど緩い閾値は、実際の劣化も取り逃がします。目指すのは、発火したら実際に何かが起きていると信頼できる水準であり、トラフィックやアーキテクチャの変化に応じて見直します。

<Warning>
  何でもかんでも鳴るチャンネルは、人に無視することを学習させます。そして重要だったアラートも、そうでなかったものと一緒に見逃されます。繰り返し起きる誤検知は、許容すべき背景ノイズではなく監視側の不具合です。
</Warning>

### 成否のどちらも通知する

人手を介さずに走るもの、たとえば夜間バッチ・バックアップ・データ同期・CIの実行・デプロイについては、成否のどちらも通知します。

通知する理由は対象によって違います。CIの結果は自分たちの作業が進むかどうかを左右するため、チームにとって重要なものを選んで通知します。デプロイの結果はユーザーへの影響に直結するため、成否を問わず通知します。なお、CIからデプロイしているとは限らないので、この2つは別の通知として扱います。

失敗時だけ通知する設計は一見無駄がありませんが、チャンネルからは解消できない曖昧さを生みます。メッセージが来ないという状態からは、すべての実行が成功したのか、ジョブがそもそも動かなかったのか、通知の仕組み自体が壊れているのかがわかりません。しかも後ろの2つは、まさに何日も気づかれないまま放置される種類の失敗です。通知の仕組み全体が防ごうとしている状況そのものが起きてしまいます。

成功の通知はこの曖昧さを取り除きます。ジョブが動いたこと、そしてジョブからチャンネルまでの経路が機能していることの積極的な証拠になるからです。これにより沈黙自体も情報を持ちます。想定した時刻に成功の通知が来ていないこと自体が、調査に値する事実になります。

<Tip>
  この種の確認は、ジョブ名・結果・所要時間だけの簡潔なものにします。重要なのは、想定した時刻にメッセージが存在することであり、丁寧に読まれることではありません。
</Tip>

パイプラインでの具体的な設定方法は[CI/CD](/ja/development/ci-cd#パイプラインの結果を通知する)を参照してください。

## 開発フローの通知

インシデント以外で通知に値するのは、誰かが誰かを待っているイベントです。レビュー依頼、Issueのコメントでの質問、修正の依頼はいずれも、特定の人が応答するまで変更を止めます。

待ちが発生している間、変更のクリティカルパス上にあるのは、レビュアーがまだ気づいていない時間そのものです。レビュー依頼に気づくのが半日遅れれば、プルリクエストのリードタイムはそのまま半日伸びます。実装やCIをどれだけ速くしても、この区間は縮みません。

既製の連携でもこれらは扱えますが、既定の設定では上記よりはるかに多くのイベントを通知します。チャンネルが読めないほど賑やかになった場合の選択肢は、連携側のイベントとリポジトリのフィルタを絞るか、応答が必要なイベントだけを簡潔な形で投稿する独自の連携に置き換えるかのどちらかです。

対応につながるメッセージは、次の4つを含む傾向があります。

* 対応を期待される人を、文中の名前ではなく実際のメンションとして含みます。
* 何を依頼しているのかを1行で示します。
* 対応する場所をそのまま開けるリンクを含みます。
* 依頼からの経過時間など、優先度を判断できる程度の文脈を添えます。

## 通知するだけでなくリマインドする

1回の通知は、見られる機会が1回しかないということです。レビュアーの会議中に届いたレビュー依頼は、実質的に届いていないのと変わりません。だからこそ、その場かぎりの通知には、まだ対応されていないものを一覧する定期実行の相方が必要になります。

このパターンは、担当者と期限がある対象すべてに応用できます。まだ対応されていないものを一覧し、定期的に投稿し、対象がなければ何も投稿しません。そうすることで、ここでも沈黙が情報を持ちます。

<Tip>
  リマインドを発火させる時刻は、実際に対応できる時間帯に合わせます。スケジュール実行の設定はUTC基準のことが多く、現地の業務時間のつもりで指定するとずれます。
</Tip>

## チャンネルを読むに値する状態に保つ

通知の仕組みは放っておくと劣化します。監視が積み上がり、追加された連携が外されないまま残り、流量が増えて、やがてチャンネルは読まれずに流し見されるようになります。次の3つがこれを防ぎます。

* **すべてのチャンネルに持ち主と目的を持たせる。** 誰でも何でも流してよいチャンネルはそのどちらも持たず、最も速く劣化します。
* **実際に何が発火したかを振り返る。** どのアラートが発火し、どれが対応されたかを定期的に見ます。対応につながったことのない監視は、削除か再調整の候補です。
* **メンションを絞る。** チャンネル全体への一斉メンションは、最初の数回は気づかれ、その後は無視されます。対応を期待する人かグループをメンションします。

## 関連ページ

<CardGroup cols={3}>
  <Card title="CI/CD" icon="arrows-rotate" href="/ja/development/ci-cd">
    自動化された通知の多くが生まれる場所。結果をどう流すかを考える前提になります。
  </Card>

  <Card title="コードレビュー" icon="eye" href="/ja/development/code-review">
    レビュー依頼に気づいたあとレビュアーが何をするか、待ち時間の代償が大きい理由を扱います。
  </Card>

  <Card title="プルリクエスト" icon="code-pull-request" href="/ja/development/pull-request">
    気づくのが遅れたレビュー依頼が延ばすリードタイムと、粒度でそれを短く保つ方法を扱います。
  </Card>
</CardGroup>
