“당연히 되겠지”가 사고로 이어질 때: 최소 안전장치로 ‘당연함의 함정’ 빠져나오기

도입부: 익숙한 작업일수록 “당연히 될 것”이라는 방심이 사고로 이어지곤 합니다. 이 글에서는 ‘당연히’를 전제로 하지 않기 위해 제가 무엇을 안전장치로 바라보게 되었는지, 그리고 가장 작은 비용으로 먼저 도입할 수 있는 실천 항목을 정리해봅니다.

1) 사고는 “실패”보다 “당연함”에서 시작됩니다

익숙한 일·동일한 환경에서는 뇌가 자동완성을 해버립니다. “전에 했으니까 이번에도 당연히 되겠지”라는 전제는 작업 속도를 올려주지만, 그 전제가 깨지는 순간엔 원인 추적이 어려운 형태의 사고로 이어지기 쉽습니다.

저도 한 번 사고를 겪고 나니 “당연히”라는 말을 하기 어려워졌고, 전반적인 불안이 커졌습니다. 그런데 이 불안을 줄이는 방법은 “더 조심하기” 같은 마음가짐보다, **당연히 동작하도록 만드는 장치(프로세스/도구/증거)**를 추가하는 쪽이 더 효과적이었습니다.

핵심 전환은 이거였습니다.

  • “당연히 된다”가 아니라 **“실패는 발생한다”**를 기본값으로 둡니다.
  • 중요한 건 실패 자체가 아니라 피해를 제한하고, 빨리 원인을 재구성하는 것입니다.

2) 최소 안전장치 1순위는 “작업 계획 + 원복/복구”일까요?

대화에서 제가 처음 떠올린 최소 안전장치는 작업 계획과 원복/복구 방법이었습니다. 이 접근이 좋은 이유는, 안전장치를 “실패 방지”가 아니라 실패했을 때의 피해 제한 관점으로 보기 때문입니다.

다만 여기엔 함정도 있습니다.

  • 원복이 준비되면 심리적으로 더 과감해질 수 있습니다(리스크 보상).
  • 특히 아래 유형은 “원복 가능”이 착시가 되기 쉽습니다.
    • 데이터 마이그레이션/스키마 변경
    • 외부 연동 변경(서드파티 API, 메시지 발행, 결제/알림 등)
    • 시간이 지나면서 상태가 계속 변하는 작업(배치/정산/동기화)

그래서 “원복”을 말하려면, 단위를 단순히 배포/서버가 아니라 데이터 + 외부효과까지 포함해 정의해야 합니다.

원복이 어려울 때의 현실적인 대안

원복이 사실상 불가능하다면, “되돌리기”보다 아래가 더 실용적일 때가 많습니다.

  • 정지(킬스위치): 기능 자체를 즉시 끕니다.
  • 격리(트래픽 차단): 문제 구간으로 들어오는 요청을 차단/우회합니다.
  • 보정(보상 트랜잭션): 이미 발생한 외부효과를 상쇄하는 후속 처리를 준비합니다.
  • 롤포워드(수정 배포): 되돌리는 대신 빠르게 고쳐서 앞으로 나아갑니다.
  • 기능 플래그/단계적 배포: 영향 범위를 작게 만든 뒤 관측하며 확장합니다.

3) “원복보다 먼저” 필요한 것: 무엇이 일어났는지 아는 능력(Observability)

대화를 하면서 더 본질적인 문제가 드러났습니다.

“추상적으로 결과가 나오기 때문에 실제 어떤 작업이 일어났는지 모르는 부분”

이 상황에서는 작업 계획서나 원복 절차보다 먼저, 증거가 남아야 합니다.
즉, 관측 가능성(observability) 부족이 사고의 핵심 원인이 될 수 있습니다.

원복/복구는 결국 “무슨 일이 있었는지”를 알아야 실행할 수 있습니다. 그런데 결과만 추상적으로 보이고, 실제로 어떤 요청이 어디로 전파됐는지(의존 시스템), 어떤 데이터가 어떻게 바뀌었는지(변경 이력)가 안 보이면 복구는 추측이 됩니다.

그래서 최소 안전장치의 우선순위는 이렇게 재정렬되는 느낌이었습니다.

  1. 증거를 남긴다(로그/트레이스/감사 로그)
  2. 실패했을 때 피해를 멈춘다(킬스위치/격리)
  3. 그 다음에야 원복/복구/보정이 실효성을 가집니다

4) 제가 제안하는 “가장 먼저 도입할 최소 안전장치”: 1줄 구조화 로그

“관측”은 거창하게 시작하면 오래 걸립니다. 그래서 저는 “최소 안전장치”라는 질문에 이렇게 답하고 싶습니다.

  • 모든 걸 남기려 하지 말고
  • 사고 시 원인을 재구성할 수 있는 ‘최소 증거 1줄’을 먼저 정합니다

대화에서 제가 꼽았던 키워드는 코드, 시간, 로그였습니다. 이를 운영에서 쓸 수 있게 바꾸면 아래 조합이 됩니다.

  • 언제: timestamp
  • 어떤 코드: version(commit sha, build number)
  • 어떤 흔적: structured log (요청/변경/외부호출의 연결고리)

예시(필드 설계의 뼈대):

{
  "timestamp": "2026-04-20T12:34:56.789Z",
  "service": "order-api",
  "env": "prod",
  "version": "git:1a2b3c4",
  "request_id": "req-9f2c...",
  "actor": "system|user:123",
  "action": "OrderConfirm",
  "target": {"type": "order", "id": "O20260420-0001"},
  "dependency_call": {"name": "payment.authorize", "status": "success", "latency_ms": 120},
  "result": "success"
}

이 1줄이 주는 효과는 명확합니다.

  • “무슨 코드가(버전)”
  • “언제”
  • “누가/무엇을 대상으로”
  • “어떤 외부 의존 호출을 했고”
  • “결과가 뭐였는지”

가 연결됩니다. “추상적 결과”가 “재구성 가능한 사건”으로 바뀝니다.

어디에 먼저 찍을까?

가장 좋은 시작점은 보통 진입점(API/배치 시작점) 또는 가장 치명적인 의존 시스템을 호출하는 지점입니다.
왜냐하면 사고는 대개 “내 서비스 안”보다 “의존 시스템과의 경계”에서 커지기 때문입니다.

5) 인사이트: ‘당연히’를 없애는 게 아니라, ‘당연히 동작하게’ 만들어야 합니다

사고 이후 불안이 커지는 건 자연스러운 반응입니다. 하지만 그 불안을 “더 조심하자”로만 풀면, 결국 사람의 집중력에 안전을 외주 주는 셈이 됩니다.

제가 얻은 결론은 이렇습니다.

  • “당연히 된다”는 믿음을 버리는 순간, 불안이 커질 수 있습니다.
  • 대신 당연히 동작하도록 만드는 장치(증거/정지/복구)를 추가하면,
  • 불안은 “막연함”에서 “통제 가능한 리스크”로 바뀝니다.

그리고 그 첫 단추는 의외로 작게 시작할 수 있습니다.
저는 작업 계획/원복도 중요하지만, 그보다 먼저 무슨 일이 일어났는지 알 수 있는 최소 로그 1줄이 가장 강력한 최소 안전장치라고 느꼈습니다.

마무리

“당연함의 함정”을 피하려면 “당연히”를 금지어로 만드는 게 목적이 아니라, 실패를 전제로도 시스템이 버티도록 만드는 게 목적입니다. 오늘 작업부터라도 코드(버전)·시간·구조화 로그로 사건을 재구성할 수 있는 최소 증거를 남겨보면, 불안은 줄고 재발방지는 훨씬 현실적으로 시작할 수 있습니다.

3 Likes

관측 가능성이 원복보다 먼저라는 주장에 전적으로 동의합니다

예시로 드신 로그 구조에 dependency_call까지 포함시키는 건 실무에서는 보통 로그보다 분산 트레이싱(OpenTelemetry 등) 영역으로 넘기는 경우가 많습니다. 로그는 이벤트 단위, 트레이스는 요청 흐름 단위로 역할을 나누면 카디널리티 관리도 훨씬 수월해지더라고요.

그리고 감사 로그와 운영 로그는 보존 기간·접근 권한·무결성 요구사항이 달라서, 같은 1줄로 통합하기보다 스키마는 공유하되 저장소를 분리하는 설계가 장기적으로 편했던 경험이 있습니다.

1 Like