제 친구 프리야는 34병상 규모 병동의 근무 일정을 담당하고 있는데, 지난 2년간 아무도 순서대로 읽지 않는 단체 문자로 교대 변경 요청을 처리해왔습니다. 그녀는 간호사들이 휴식 시간에 휴대폰으로 열어서, 대신 근무해줄 사람이 필요한 교대를 올리고, 수간호사가 직접 일일이 조정하기 전에 누군가 그것을 가져갈 수 있는 무언가를 원했습니다. 저는 3주간 저녁 시간을 활용해 이를 만들었습니다. 이것은 실제로 서비스가 시작된 날의 기록입니다 — 게시, 커스텀 도메인, 실제 간호사들, 실제 교대 근무 — "테스트에서는 작동한다"와 "인력이 2명 부족한 오전 7시에도 작동한다" 사이의 간극이 그 나름의 교훈이 되었기 때문입니다.
오전 6:58 — 게시
전날 밤에 배포 대상을 프리야의 자체 도메인으로 설정해뒀기 때문에, 이 부분은 싱겁게 끝났습니다: 게시 버튼을 누르고, 빌드의 검증 기록이 다음 항목들을 확인하는 것을 지켜봤습니다:
- 라우팅 정상 작동
- 교대 신청(claim) 엔드포인트가 더미가 아닌 실제 응답을 반환하는지
- SMS 알림 훅이 드라이런이 아니라 실제로 설정되어 있는지
모두 정상이었습니다. 저는 오전 6:58에 프리야에게 링크를 보냈습니다. 그녀가 딱 그 시간에 근무를 시작하러 들어갈 거란 걸 알고 있었고, 하루가 시작되기 전에 실제로 작동하는 모습을 보여주고 싶었기 때문입니다.
오전 7:15 — 첫 실제 사용자가 제가 테스트하지 않은 일을 하다
프리야는 20분 만에 그날 저녁 빈 교대 근무를 올렸습니다. 예상보다 빨랐고, 첫 실제 데이터가 생기기 전에 커피조차 다 마시지 못했다는 뜻이었죠. 그다음 데니스라는 간호사가 그 근무를 가져갔다가, 4분 뒤 취소하고, 다시 가져갔습니다. 이유는 저도 모릅니다 — 어쩌면 신청 도중 자신의 일정을 확인하다 치과 예약이 있다는 걸 깨달았을지도 모르죠. 앱은 문제없이 처리했습니다. 제가 테스트하지 않았던 것은 같은 10초 창 안에 세 명이 동시에 같은 근무를 신청하는 경우였습니다. 3주간의 단독 테스트 동안 그런 시나리오는 한 번도 떠오르지 않았거든요. 지금도 떠오르지 않았습니다. 약 5시간 뒤에 현실이 대신 떠올려줬습니다.
오전 9:40 — 조용함, 그리고 그 조용함에 불안해지다
2시간 30분 동안 아무 일도 일어나지 않았습니다. 신청도, 게시도, 로그상 오류도 없었죠. 그래도 대시보드를 네 번이나 확인했는데, 아마 고쳐야 할 습관일 겁니다 — 사용되지 않는 빌드는 고장난 게 아니라 아직 사용되지 않고 있을 뿐이며, 이 둘은 해결책이 다른 완전히 별개의 문제니까요. 저는 억지로 탭을 닫고 실제 업무로 돌아갔습니다.
오전 11:52 — 버그
신청 엔드포인트는 셋 다 받아들였습니다. "신청 완료로 표시" 로직을 락 없이 단순한 '열려 있으면 업데이트' 방식으로 작성했었기 때문인데, 일반적인 단일 사용자 테스트 상황에서는 이 경쟁 조건(race condition)이 애초에 발생할 여지가 없습니다. 서로 다른 세 대의 휴대폰에서 동시에 세 번 탭하는 상황에서는 여지가 충분히 생깁니다. 세 명의 간호사 모두 근무를 커버했다는 확인 문자를 받았습니다. 데니스도 그중 한 명이었고, 그날 두 번째로 그런 일을 겪었으며, 이번에는 짜증이 나 있었습니다.
이 문제를 어떻게 발견했는지 솔직히 말씀드리면 — 모니터링으로 잡아낸 게 아니었습니다. 프리야가 저에게 문자를 보냈습니다. 웃는 이모지와 함께요. 문자 그대로 재미있어했다고는 생각하지 않지만요. 실제로 그녀의 오후를 망친 문제였으니까요:
앱에서 같은 근무를 3명이 가져갔다고 뜸 ㅋㅋ
오후 12:10 — 빌드 채팅으로
저는 버그를 평이한 말로 설명했습니다: 여러 사람이 비슷한 시간에 탭하면 한 근무를 동시에 신청할 수 있는데, 신청은 한 건만 성사되어야 한다고요. 직접 수정 코드를 먼저 작성하려 하지 않았는데, 주차장에서 휴대폰으로 작업 중이었던 이유도 있었지만, 실패 상황을 정확히 설명하는 것이 정확히 진단하는 것보다 보통 더 빠르기 때문이기도 했습니다. 에이전트는 신청 테이블에 로우 락이 빠져 있다는 것을 찾아냈고, 원자적 조건부 업데이트로 전환하는 것을 제안했습니다 — 근무 상태가 여전히 "열림"일 때만 신청이 성공하며, 세 요청이 모두 동시에 "열림"을 보게 만드는 확인 후 쓰기(check-then-write) 방식 대신 작업 자체가 누가 이기는지를 결정하도록 하는 방식이었습니다. 한 문장으로 요약하면 그게 실제 버그였고, 말하고 나면 명백하지만 강제로 드러나기 전까지는 눈에 보이지 않는 종류의 문제였습니다.
오후 12:34 — 수정 사항 배포, 그리고 프리야를 기다리게 하다
패치는 작았습니다. 그래도 근무 중에 바로 실서비스 도메인에 푸시하지는 않았습니다 — 먼저 프리뷰 버전에 적용해서, 근무 중이 아니었던 프리야의 수간호사 동료에게 세 개의 브라우저 탭에서 동시에 세 번 탭하는 동일한 상황을 재현해 달라고 부탁했습니다. 정상적으로 처리됐습니다. 신청 하나는 성공하고, 나머지 둘은 거짓 확인 대신 "이 근무는 방금 다른 사람이 신청했습니다" 메시지를 받았습니다. 저는 오후 12:34에 이를 실서비스에 배포했습니다. 버그 발생 후 약 42분 만이었는데, 그 순간에는 느리게 느껴졌지만 돌이켜보면 빠른 편이었습니다.
오후 2:00부터 6:00까지 — 지루하지만 좋은 시간
- 11건의 근무가 추가로 게시됨
- 9건이 문제없이 신청 완료됨
- 2건은 신청되지 않은 채 만료되어 프리야가 여전히 수동으로 관리하는 게시판으로 넘어갔습니다 — 괜찮습니다. 이 도구가 첫날부터 모든 것을 해결할 필요는 없고, 고장 났던 그 특정 문제만 해결하면 되니까요
- 0건의 추가 중복 신청
저는 결과를 상상하는 대신 실제 숫자를 지켜봤습니다. 완전히 다르고 훨씬 차분한 경험이었습니다.
달리 했을 점
두 가지가 있습니다.
- 동시 요청 시나리오는 실제로 겪고 나서야 알았는데, 처음부터 빌드 프롬프트에 적어뒀어야 했습니다 — "여러 사용자가 같은 순간에 같은 동작을 한다"는 것은 어려운 요구가 아니라 한 문장으로 끝날 이야기인데, 제 테스트 방식 자체가 늘 순차적이다 보니 — 한 번에 버튼 하나씩만 누르다 보니 — 그걸 포함시켜야 한다는 생각 자체를 못 했습니다.
- 2주 차에는 아무도 불평하지 않은 확인 문자 문구를 세 번이나 다시 쓰는 등 SMS 알림 문구에 과도하게 시간을 쏟았고, 정작 휴식 시간에 간호사들이 한꺼번에 휴대폰을 들여다볼 것이 뻔했던 동시성 엣지 케이스에는 시간을 충분히 쏟지 못했습니다. 그리고 그 문제는 첫날부터 터졌습니다.
다음 출시 때는 아무도 지적하지 않을 문구를 다듬는 데 시간을 덜 쓰고, "이걸 다섯 명이 동시에 하면 어떻게 되지?"를 더 많이 물어볼 생각입니다. 실사용자가 한 명 이상인 기능이라면 언젠가는 반드시 누군가 그렇게 하기 때문입니다.



