決定と事故を機密のないポートフォリオに変える
한국어 원문으로 표시합니다.
한 줄 요약
ADR 은 결정을 내릴 당시의 맥락·대안·선택·결과를 보존하고, 사고 보고서는 실제 영향·타임라인·근본 원인·탐지·담당자가 있는 교정 조치를 남깁니다. 포트폴리오는 이 원본을 복사하지 않고 허용된 요약만 발행합니다.
왜 코드만으로 판단을 설명할 수 없는가
ON CONFLICT 구문은 무엇을 선택했는지는 보여 주지만 왜 클라이언트 전용 중복
제거보다 데이터베이스 경계를 택했는지 말하지 않습니다. 6개월 뒤 그 코드를 보는
사람은 두 가지 중 하나를 합니다. 이유를 몰라 그대로 두거나, 이유를 몰라 걷어냅니다.
둘 다 나쁩니다.
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 를 넘으면 재검토한다.
"되돌리는 조건" 이 있는 ADR 과 없는 ADR 은 다른 문서입니다. 조건이 있으면 나중에 그 조건을 측정해 판단할 수 있고, 없으면 영원히 남습니다.
사고 보고서가 학습 기록이 되려면
사고가 나면 설계의 가정이 실제로 맞았는지 사고 보고서로 되돌아봅니다. 비난할 사람을 찾는 문서가 아니라 시스템의 다음 안전장치를 만들기 위한 학습 기록이어야 합니다. 이 성격을 지키는 장치가 몇 가지 있습니다.
타임라인은 시간대를 포함하고, 세 시각을 구분합니다.
| 시각 | 뜻 | 이 값이 크면 |
|---|---|---|
| 시작 | 사용자 영향이 시작된 때 | — |
| 탐지 | 사람이 알아챈 때 | 관측이 부족하다 |
| 복구 | 영향이 끝난 때 | 대응 절차가 느리다 |
탐지까지 40분이 걸렸다면 근본 원인과 별개로 "왜 40분 동안 몰랐는가" 가 독립된 교정 항목입니다. 사고의 절반은 여기서 나옵니다.
근본 원인은 사람이 아니라 조건을 가리킵니다. "김 아무개가 잘못된 설정을 배포 했다" 가 아니라 "잘못된 설정이 배포까지 도달하는 경로에 검증이 없었다" 입니다. 앞의 문장은 다음 사고를 막지 못하고, 뒤의 문장은 막습니다.
교정 조치는 "주의한다" 가 아니라 소유자와 기한, 검증 가능한 완료 조건을 가집니다.
- [ ] values 스키마 검증을 CI 에 추가 (담당: 배포팀, 기한: 3/25)
완료 조건: 잘못된 replicas 값을 넣은 PR 이 CI 에서 떨어지는 것을 확인
- [ ] 에러율 경보를 백엔드별로 분리 (담당: 관측팀, 기한: 3/20)
완료 조건: 한 대만 죽였을 때 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분 중단, 영향 규모는 비공개" |
| 전체 로그 붙여넣기 | 메트릭 이름 목록과 그래프 한 장 |
스키마 버전을 고정하고 알 수 없는 필드는 거부해, 후속 도구가 원본 비밀을 실수로 추가하지 못하게 합니다.
{"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분 중단"}
]}
additionalProperties: false 로 스키마를 잠가 두면, 누군가 편의로 raw_log 필드를
추가하는 순간 검증이 실패합니다. 사람의 주의력 대신 도구가 막습니다.
실무 판단 기준
좋은 포트폴리오는 화려한 스크린샷보다 재현 가능한 계약과 판단 능력 을 보여 줍니다. 면접에서 실제로 물어보는 것도 이쪽입니다.
- 어떤 실패 반례를 테스트했는가 — 성공 경로만 테스트한 것은 테스트가 아닙니다.
- 데이터 경계와 권한 경계를 어떻게 나눴는가 — 왜 그 선을 그었는지가 설계입니다.
- 장애에서 무엇을 바꿨는가 — 원인 분석에서 멈춘 보고서는 절반입니다.
- 되돌릴 조건을 정해 두었는가 — 이것이 있으면 결정을 관리할 줄 아는 사람입니다.
이 코스의 마지막 퀴즈에서는 구현·운영·문서 증거가 하나의 이야기로 이어지는지 확인합니다.