들어가면서 — 신조어 한 개

요즘 마음 속에 단어 하나가 떠나지 않아서 이름을 붙여 두려고 한다.

버저비터 증후군 (Buzzer-Beater Syndrome)

농구에서 경기 종료 직전, 어차피 끝난다는 압박 속에서 일단 던지는 슛. 들어가면 영웅, 안 들어가도 어차피 끝.

소프트웨어 팀에서 같은 자세를 자주 본다. 이미 운영에 나간 기능에 강한 반대가 들어왔을 때, 정책 검토를 건너뛰고 일단 예외부터 만들어 운영에 던지는 패턴.

이번 주 한 사이클을 정확히 24 시간 안에 다 돌아 봤다. 그 24 시간을 적어 두고, 그 안에서 들은 한 문장에 대해 정직하게 적어 두려고 한다.

24 시간 — 4 단계로 보면

타임스탬프는 흐릿하게 적었다. 결만 본다.

17 시 — “이거 안 됨”

한 정책으로 한 달 넘게 일했다. “기능 X 는 첫 진입 시 기본 선택되어야 한다.” 이걸 지키기 위해 여러 화면 — 상품 상세, 장바구니, 주문서 — 에 같은 정책을 한 칸씩 일관되게 박았다.

그런데 외부에서 “기본 선택되어 있어서 보이는 가격 자체가 문제” 라는 강한 클레임이 한꺼번에 올라왔다. 그 위에 “리더십이 보고 있다” 라는 시그널이 함께 왔다. 채널에 한 문장이 떨어진다.

“빠르게 처리해 주세요.”

18 시 — “그럼 뺍시다”

이미 한 달 동안 박힌 정책을 빼는 작업이 시작된다. 첫 단계는 단순해 보였다. “코드에서 기본 선택 로직만 제거하면 되지 않나요?”

그런데 그게 빠지면 옆에서 같이 돌고 있던 페어링 동작 (이 선택을 바꾸면 다른 영역의 선택도 같이 바뀌는 것) 이 줄줄이 깨진다. 한 줄짜리 변경이 아니다.

22 시 — “급한 대응”

밤 10 시 즈음, 사이드이펙트가 운영에서 재현된다. 이때 사이드이펙트를 다 잡는 정공법은 한 번 더 정책 리뷰를 해야 한다는 뜻이다. 그리고 그 정공법은, 그 자리에서 선택되지 않는다.

대신 한 줄이 떨어진다.

“우선 급한 대응으로, 블랙리스트로 막고 / 화이트리스트로 풀자.”

블랙리스트, 화이트리스트, 하드코딩. 눈에 보이는 사이드이펙트만 막는 패치 가 줄줄이 들어간다.

그리고 한 가지 더 — 밤 10 시는 트래픽 집중 시간대 인 걸 모두가 알지만, 일단 배포가 나간다. 유선으로 승인 받았어요. 기다리면 한 시간 더 기다려야 해요.

23 시 즈음 한 줄이 또 떨어진다. “이번 작업도 생각보다 복잡해서 대응에 오래 걸린 문제가 있기도 해서요.”

다음 날 09 시 — “정책 다시 정리할게요”

같은 채널에 같은 사람들이 다시 모인다. 어제 밤에 박은 블랙리스트 / 화이트리스트 / 하드코딩의 운명이 이 자리에서 결정되어야 한다.

“정확한 정책은 오늘 10:30 디자인팀과 논의 후 말씀드릴 예정이지만, 큰 방향성은 …”

그러니까, 어제 박힌 임시 코드는 다시 빠진다. 같은 자리에 같은 코드가 두 번 박히고, 두 번 빠진다. 그 사이의 24 시간 동안 사용자에게 보이는 정책은 두 번 바뀌었다.

가장 위험한 점 — 이건 “장애” 가 아니다

이 사이클에서 가장 까다로운 점은, 이게 모니터링에 안 잡힌다는 것이다.

  • 응답은 200 OK 다.
  • CPU 도 메모리도 평소와 같다.
  • 알람은 울리지 않는다.
  • 에러 트래커에 한 줄 안 찍힌다.

그런데 화면 한 칸의 정책이 어제와 오늘 다르다. 같이 일하는 누군가는 장애인 줄 알았다. 그게 정확한 표현이다. 알람도 안 울리는데, 화면 한 칸의 동작이 어제와 다르게 보였으니까.

이건 코드 장애가 아니라, 정책 장애다.

정책 장애는 대시보드에 안 잡힌다. 사용자 클레임으로 한 박자 늦게 잡히고, 그때는 이미 24 시간 안의 두 번째 사이클이 시작되어 있다.

“가볍게 결정한 게 아닙니다” — 라는 말의 작동 방식

이 사이클의 마무리에는 거의 항상, 한 사람이 마무리 메시지를 보낸다. 요지는 대체로 비슷하다.

“저녁에 연락드린 것은 리더십에서 빠르게 진행해 달라는 이야기가 있었기 때문입니다.” “한 달간 작업한 내용에 대해 의사결정이 변경된 부분에 고됨을 토로하시는 건 이해합니다.” “프로덕트가 잘못되라고 정책을 가볍게 고민하거나 의사결정하는 부분이 있는 것도 아닙니다.”

이 문장 자체는 진심일 것이다. 가볍게 결정하지 않으려고 한다는 말도, 우선순위가 높았다는 말도, 다 진심일 것이다. 나도 그 진심은 의심하지 않는다.

하지만 — 어제 밤 10 시에 호출되어 트래픽 집중 시간대에 화이트리스트 하드코딩을 박고, 다음 날 아침 8 시에 “정책 다시 정리할게요” 를 듣는 사람 입장에서, 이 문장이 좀 다르게 들리는 것도 사실이다.

이 자리에서는 들리는 게 진실이다. “가볍게 고민한 게 아니다” 라는 말은, 가볍게 들리지 않으려면 가볍게 보이지 않는 절차가 같이 있어야 한다.

가볍게 보이지 않는 절차란 보통 이런 것이다.

  • 정책 리뷰가 운영 패치보다 먼저 들어간다 — 적어도 순서 가 그렇다.
  • 24 시간 시계 가 의사결정 시점에 한 번 돌아간다 — “이 변경이 24 시간 안에 다시 바뀔 가능성이 있나요?”
  • 임시 코드가 들어가기 전에, 그게 며칠 안에 빠질 코드인지 같이 적힌다.

이 절차들 없이 “가볍게 고민한 게 아닙니다” 라는 한 문장만 오면, 받는 사람에게는 그 문장이 의도와 무관하게 가볍게 들린다. 문장이 진심이어도 가볍게 들린다는 점이, 이 신조어의 핵심이다.

그래서 — 버저비터에서 빠지려면

한 시즌에 한 번 들어가면 영웅인 슛을 매주 던지면, 그건 농구가 아니라 도박이다.

매주 던지는 슛을 한 박자 늦추기 위한 작은 장치 세 개.

1) “버저비터 라벨”

운영에 들어가는 변경에 임시 / 영구 라벨을 붙인다. 임시 라벨에는 언제까지 빠질 코드인지 도 같이 적는다. 안 적히면 영구 코드가 된다.

// [BUZZER-BEATER] 정책 재정리까지 한시 화이트리스트.
// 정책 확정 D+3 까지 제거 — 미제거 시 정책 부재로 간주.
const HARDCODED_ALLOWLIST = [...];

이 한 줄짜리 주석이 이상하게도 큰 일을 한다. 그 코드를 영구로 박은 사람은 자신이 영구로 박았다는 걸 의식하기 시작한다.

2) “24 시간 시계”

운영 패치가 들어갈 때, 의사결정 시점에 한 줄을 던진다.

“이 변경이 24 시간 안에 다시 바뀔 가능성이 있나요?”

가능성이 있으면, 그 자리에서 그 가능성을 모두에게 공유한다. “이건 내일 다시 빠질 수 있는 패치입니다” 라는 한 줄이, 그 자리의 모든 사람에게 두 번째 사이클을 미리 보여 준다. 두 번째 사이클이 미리 보이면, 첫 번째 사이클의 박는 깊이가 살짝 얕아진다.

3) “정책 장애” 를 장애로 친다

응답은 200 OK 인데 정책이 어제와 다른 상황 — 이걸 정책 장애 라는 이름으로 인지한다. 별도 라벨, 별도 회고.

이 라벨이 없으면 코드 장애만 회고되고, 정책 장애는 매번 “그땐 그럴 만 했지” 로 끝난다. 같은 사이클이 다음 달에 한 번 더 돈다.

마치며 — 한 줄

오늘 적어 두고 싶은 한 줄.

운영에 한 번 더 던질지 말지 결정할 때, “이게 24 시간 안에 두 번 바뀔 변경입니까?” 한 줄을 먼저 던져 본다.

버저비터는 가끔 들어가야 한다. 항상 던지면, 그건 슛이 아니라 다음 슛의 빚 이다.

이 빚을 갚는 사람은 보통, 다음 날 아침 같은 채널에서 “한 달 넘게 달렸습니다” 라고 적게 되는 사람이다.

그 사람의 자리에서 들리는 “가볍게 결정한 게 아닙니다” 가 어떻게 들리는지를, 결정하는 사람들이 한 번씩 헤아려 봤으면 한다. 이 글은 그 헤아림을 한 번 도와 보려는 글이다.