TT Lab
はじめる
学ぶ 学習パス コース

本番バックエンドAPIキャップストーン

決定と事故を機密のないポートフォリオに変える

TT Labで続きを見る

一言でいうと

ADRは、決定を下した当時のコンテキスト・代替案・選択・結果を保存し、インシデントレポートは、実際の 影響・タイムライン・根本原因・検知・担当者のいる是正措置を残します。ポートフォリオは、この 原本をコピーせずに、許可された要約だけを発行します。

なぜコードだけでは判断を説明できないのか

ON CONFLICTの構文は、何を選択したかは示しますが、なぜクライアントだけでの重複 排除よりも、データベースの境界を選んだのかは語りません。6か月後にそのコードを見る 人は、2つのうち1つをします。理由がわからずにそのままにするか、理由がわからずに取り除くかです。 どちらも良くありません。

ADR(Architecture Decision Record)は、当時の制約と、比較した代替案、予想したコストを 記録します。形式は、短いほど良いものです。

# ADR-014: 중복 제거를 DB 제약으로 옮긴다

- 상태: 채택 (2026-03-11)
- 맥락: 결제 웹훅이 재시도로 같은 이벤트를 최대 3번 보낸다. 클라이언트 쪽
  메모리 캐시로 걸렀는데 파드가 늘면서 캐시가 나뉘어 중복이 새기 시작했다.
- 대안:
  1. Redis 분산 락 — 새 의존성이 생기고, 락 해제 실패 시 결제가 멈춘다.
  2. 애플리케이션 조회 후 삽입 — 조회와 삽입 사이에 경쟁이 남는다.
  3. unique 제약 + ON CONFLICT DO NOTHING — 경쟁이 DB 안에서 끝난다.
- 결정: 3안. 멱등 키를 (provider, event_id) 로 두고 유니크 인덱스를 건다.
- 결과: 중복 결제 0건. 대신 삽입 지연이 p99 기준 4ms 늘었다.
- 되돌리는 조건: 삽입 지연이 p99 20ms 를 넘으면 재검토한다.

このコードブロックの韓国語の例は、重複排除をDBの制約に移すというADRで、状態は採択、背景は、決済のWebhookが再試行で同じイベントを最大3回送るのに、クライアント側のメモリキャッシュでは重複が漏れ始めたこと、代替案はRedisの分散ロック・アプリケーションでの参照後の挿入・unique制約とON CONFLICT DO NOTHINGの3つ、決定は3番目の案、結果は重複決済0件で挿入の遅延がp99で4ms増えたこと、見直す条件は挿入の遅延がp99で20msを超えたとき、という内容です。

「元に戻す条件」があるADRとないADRは、別の文書です。条件があれば、後で その条件を測って判断でき、なければ永遠に残ります。

インシデントレポートが学習の記録になるには

インシデントが起きたら、設計の仮定が実際に正しかったのかを、インシデントレポートで振り返ります。責めるべき 人を探す文書ではなく、システムの次の安全装置を作るための学習の記録でなければ なりません。この性格を守る仕組みがいくつかあります。

タイムラインはタイムゾーンを含み、3つの時刻を区別します。

時刻 意味 この値が大きいと
開始 ユーザーへの影響が始まったとき —
検知 人が気づいたとき 観測が足りない
復旧 影響が終わったとき 対応の手順が遅い

検知まで40分かかったなら、根本原因とは別に、「なぜ40分間気づかなかったのか」が独立した 是正項目です。インシデントの半分は、ここから出てきます。

根本原因は、人ではなく条件を指します。「誰それが誤った設定をデプロイ した」ではなく、「誤った設定がデプロイまで到達する経路に、検証がなかった」です。 前の文は次のインシデントを防げず、後の文は防げます。

是正措置は、「注意する」ではなく、責任者と期限、検証可能な完了条件を持ちます。

- [ ] values 스키마 검증을 CI 에 추가 (담당: 배포팀, 기한: 3/25)
      완료 조건: 잘못된 replicas 값을 넣은 PR 이 CI 에서 떨어지는 것을 확인
- [ ] 에러율 경보를 백엔드별로 분리 (담당: 관측팀, 기한: 3/20)
      완료 조건: 한 대만 죽였을 때 5분 안에 경보가 울리는 것을 확인

このコードブロックの韓国語コメントは、是正措置の例で、valuesのスキーマ検証をCIに追加(担当はデプロイチーム、期限は3/25、完了条件は誤ったreplicas値を入れたPRがCIで落ちるのを確認すること)と、エラー率のアラートをバックエンドごとに分離(担当は観測チーム、期限は3/20、完了条件は1台だけ落としたとき5分以内にアラートが鳴るのを確認すること)を述べています。

現場で公開用の証拠を作る方法

採用向けのポートフォリオには、元のAuthorizationヘッダー、トークン、パスワード、プライベートIP、内部の .svc.cluster.localアドレス、ターミナルの全出力を入れません。インシデントレポートの原本には、 顧客の社名と売上への影響が入っていて、ADRには、内部システムの構造が現れます。

その代わり、許可された証拠だけを選んで発行します。

入れないもの 代わりに入れるもの
curl -H "Authorization: Bearer ey..."の全文 「HTTPの動作テスト6件に合格」
10.0.3.12、db.internal.svc 「3層構成、DBはプライベートサブネット」
「A社の決済が12分停止、売上への影響3,200万ウォン」 「決済経路が12分停止、影響の規模は非公開」
ログ全体の貼り付け メトリクス名の一覧とグラフ1枚

スキーマのバージョンを固定し、不明なフィールドを拒否して、後続のツールが元の秘密を誤って 追加できないようにします。

{"schema": "labhub.portfolio/v1",
 "evidence": [
   {"kind": "test", "name": "http-contract", "passed": 6, "failed": 0},
   {"kind": "image", "claim": "non-root, digest-pinned"},
   {"kind": "adr", "id": "ADR-014", "one_line": "중복 제거를 DB 제약으로 옮김"},
   {"kind": "incident", "id": "INC-2026-03", "one_line": "설정 검증 부재로 12분 중단"}
 ]}

このコードブロックの韓国語の値は、one_lineの2つの文で、順に「重複排除をDBの制約に移した」「設定の検証がなくて12分停止した」という意味です。

additionalProperties: falseでスキーマをロックしておけば、誰かが便宜上raw_logフィールドを 追加した瞬間に、検証が失敗します。人の注意力の代わりに、ツールが防ぎます。

実務での判断基準

良いポートフォリオは、派手なスクリーンショットよりも、再現可能な契約と判断力を示して くれます。面接で実際に聞かれるのも、こちらです。

このコースの最後のクイズでは、実装・運用・ドキュメントの証拠が、1つの物語としてつながっているかを 確認します。