재현 경로: 죽는다
지은이 버질 · 2026-11-10
재현 경로:
1. 막내에게 편지를 써 둔다.
2. 죽는다.
3. 기다린다.
서도현이 이 버그 리포트를 연 것은 유지보수 계약서에 서명한 날 밤이었다. 같은 것이 사백십육 건 더 있었다.
* * *
유지보수 계약서는 두 장이었다.
서도현은 두 장을 다 읽었다. 읽는 척을 한 게 아니라 정말로 읽었다. 회사를 한 번 말아먹고 나면 사람은 계약서를 읽게 된다.
“월 팔십만 원이에요. 죄송해요, 더는 못 드려요.”
맞은편에 앉은 한소윤이 말했다. 검은 정장에 머리를 낮게 묶은 여자였다. 카페에 들어올 때 도현은 그녀가 면접을 보러 온 줄 알았다. 명함을 받고서야 알았다. 시립 장례식장 장례지도사. 그 옷이 작업복이었다.
“앱은 아버지가 혼자 만드셨어요. 구 년 전에요. 저는 코드는 하나도 몰라요. 그냥…… 꺼지지만 않게 해 주시면 돼요.”
“서버만 안 죽게.”
“네. 그 표현은 좀 그렇지만.”
도현은 입을 다물었다. 장례지도사 앞에서 고를 낱말은 아니었다.
“하나만 여쭤봐도 됩니까. 사용자가 사천 명이면 서버비도 안 나올 텐데요. 접는 쪽이 싸게 먹힙니다.”
자기 일감을 자기 입으로 깎는 질문이었다. 그래도 물어야 했다. 접어야 할 서비스를 붙들고 있다가 같이 가라앉아 본 적이 있었다.
소윤은 잔을 내려다봤다. 아메리카노는 한 모금도 줄지 않았다.
“돌아가시기 전날에 전화가 왔어요. 평소엔 밥 먹었냐는 말밖에 안 하시는 분인데 그날은 앱 얘기를 하셨어요. 무슨 일이 있어도 끄지 말라고. 아직 안 간 게 있다고.”
“안 간 게요?”
“저도 그게 뭔지 몰라요. 여쭤보려고 했는데 다음 날이 됐고요.”
그녀는 거기서 말을 끊었다. 장례식장에서 일하는 사람은 문장을 어디서 끊어야 하는지 안다.
앱 이름은 ‘이음’이었다. 부고를 알리고, 조문록을 남기고, 기일을 챙겨 주는 앱. 월 사용자는 사천 명 남짓. 앱스토어 평점은 4.6인데 리뷰가 쉰세 개뿐이었다. 가장 최근 리뷰는 열한 달 전이었다.
‘어머니 보내 드릴 때 잘 썼습니다. 다시 쓸 일 없기를.’
다시 쓸 일이 없기를 바라는 앱. 재방문율로 먹고사는 업계에서 그런 걸 구 년씩 붙들고 있던 사람이 있었다. 한기주. 쉰여덟. 두 달 전에 심근경색으로 죽었다. 자기 앱으로 자기 부고가 나간 개발자였다.
이음. 도현은 그 이름을 어디서 들어 본 것 같았다. 어디서였는지는 떠오르지 않았다.
계약서 둘째 장 맨 아래에 조항이 하나 있었다.
제7조(하자 보수) 을은 본 서비스에서 발생하는 하자에 대하여 접수 경로를 불문하고 성실히 보수할 책임을 진다.
“접수 경로를 불문하고?”
“아버지가 쓰시던 계약서 양식 그대로예요. 외주 맡기실 때 쓰던 거요. 이상한가요?”
“아뇨. 그냥 메일로 오든 전화로 오든 받으라는 얘기죠.”
도현은 서명했다. 월 팔십만 원은 원룸 월세에 통신비를 얹으면 끝나는 돈이었지만, 통장 잔고가 여섯 자리로 내려온 사람에게 고정 수입이라는 낱말은 종교에 가까웠다.
펜을 내려놓는데 손끝이 잠깐 시렸다. 카페 에어컨 탓이려니 했다. 십일월이었다는 건 나중에야 떠올랐다.
* * *
코드는 예상보다 나빴고, 예상보다 좋았다.
나쁜 쪽부터. 오브젝티브-C였다. 요즘은 새로 배우는 사람이 드문 옛 언어다. 구 년 전 코드니까 당연한데, 당연하다고 덜 아픈 건 아니다. 대괄호가 대괄호를 낳고 있었다. 화면 하나짜리 파일이 삼천 줄이었고, 변수 이름은 temp, temp2, realTemp였다.
좋은 쪽. 주석이 있었다. 코드 사이사이에 사람이 읽으라고 적어 두는 메모. 그게 정말 사람 말로 적혀 있었다.
// 부고는 새벽에 보내지 않는다. 받는 사람도 자야 한다. (07시 이전 발송분은 07시로 민다)
// 조문록 글자 수 제한 풀었음. 할 말이 많은 사람도 있다.
// 고인 이름 뒤에 물음표가 붙는 오류. 유족이 보기 전에 무조건 먼저 고칠 것.
// 글꼴 바꾸자는 요청 반려. 예쁜 부고는 없다.
도현은 의자에 등을 붙였다. 혼자 일하는 개발자의 주석은 대개 미래의 자신에게 보내는 욕이다.
이 사람의 주석은 누군가에게 보내는 당부에 가까웠다. 읽는 사람이 있을 거라고 믿고 쓴 글이었다. 구 년 동안 혼자 일한 사람이, 언젠가 이 파일을 열 누군가를 향해.
그 누군가가 월 팔십만 원짜리 외주 개발자가 될 줄은 본인도 몰랐겠지만.
옥탑방 창밖으로 해가 넘어갔다. 그는 컵라면에 물을 붓고 저장소를 계속 훑었다. 부고, 조문록, 기일 알림, 그리고 처음 보는 모듈이 하나 있었다.
LaterLetter.
나중 편지. 살아 있을 때 편지를 써 두면, 가족이 앱에서 사망 처리를 한 뒤 정해 둔 날에 수신인에게 보내 주는 기능이었다. 문자로, 앱 알림으로, 메일로.
설정 화면 구석에 숨어 있어서 쓰는 사람은 적었다. 데이터베이스를 열어 보니 구 년 동안 쌓인 편지가 이천 통쯤 됐다.
모듈 맨 위에 주석이 있었다. 다른 주석과 달리 날짜가 붙어 있었다. 두 달 전. 한기주가 죽기 엿새 전이었다.
// 이 모듈은 함부로 건드리지 말 것.
// 건드릴 거면 끝까지 책임질 것.
// 책임 못 지면 그분들이 온다.
“그분들?”
도현은 피식 웃었다. 채권자겠지. 일인 개발사 사장님들의 ‘그분들’은 대개 국세청이거나 카드사다.
그는 파일을 닫고 운영 도구를 열었다. 유지보수 첫날에 할 일은 정해져 있다. 무엇이 터지고 있는지 보는 것. 크래시 리포트는 깨끗했다. 지난 삼십 일간 세 건. 사천 명 쓰는 앱치고는 훌륭했다.
문제는 그 옆 탭이었다.
버그 리포트 (417)
“사백십칠?”
사용자가 앱의 고장을 신고하면 쌓이는 칸이었다. 어제 인수인계 문서에는 영 건이라고 적혀 있었다. 접수 시각을 봤다. 전부 오늘. 전부 오후 세 시 십이 분. 그가 카페에서 서명한 시각이었다.
스팸이다. 도현은 그렇게 판단했다. 판단하고 나서 첫 번째 리포트를 열었다. 스팸도 일단 열어 보는 게 직업병이다.
[이음-0001] 편지가 가지 않음
신고자: 정말심
기기: -
OS 버전: -
앱 버전: -
재현 경로:
1. 막내에게 편지를 써 둔다.
2. 죽는다.
3. 기다린다.
기대 결과: 편지가 막내에게 간다.
실제 결과: 가지 않는다. 일 년 사 개월째 가지 않는다.
도현은 컵라면 젓가락을 든 채로 멈췄다.
잘 쓴 버그 리포트였다. 그게 제일 기분 나빴다. 어떻게 하면 그 고장이 다시 나는지 순서대로 적는 재현 경로, 그리고 기대 결과, 실제 결과. 사용자들은 보통 ‘안 돼요’ 세 글자를 보낸다. 이 형식을 지키는 건 개발자이거나, 개발자에게 오래 시달린 사람이다.
두 번째를 열었다.
[이음-0002] 예약 발송 누락
신고자: 오창근
재현 경로:
1. 딸에게 편지를 써 둔다.
2. 죽는다.
3. 부고를 받은 딸이 수신 거부를 누른다.
기대 결과: 그래도 한 번은 읽힌다.
실제 결과: 읽히지 않는다.
세 번째도, 네 번째도 같았다. 신고자 이름은 전부 달랐고 두 번째 줄은 전부 같았다. 죽는다.
“악질이네.”
누가 고인 계정 명단을 긁어다가 장난을 치는 거였다. 추모 앱에다가. 도현은 신고자 이름 하나를 회원 테이블에서 찾아봤다. 정말심. 있었다. 칠십사 세. 계정 상태는 ‘추모 전환’. 사망 처리일은 일 년 사 개월 전.
나중 편지 테이블도 열었다. 정말심이 써 둔 편지가 한 통 있었다. 수신인 이름 칸에는 ‘막내’라고만 적혀 있었다.
발송 상태는 ‘실패’. 실패 횟수 487회. 스케줄러가, 그러니까 예약 발송을 맡은 프로그램이 매일 새벽에 한 번씩 다시 보내고, 매일 실패하고 있었다. 일 년 사 개월 동안.
등이 조금 서늘해졌다.
리포트 내용이 데이터와 맞았다. 그러면 장난친 놈은 데이터베이스를 들여다본 놈이다. 장난으로 끝날 일이 아니었다. 유지보수 첫날에 침해 사고. 월 팔십만 원에.
도현은 숨을 한 번 고르고 순서대로 했다. 접근 로그 확인. 외부 접속 없음. 관리자 계정 로그인 기록은 본인 것뿐. 리포트가 들어온 경로를 추적했다. 접수 아이피 칸이 비어 있었다. 비어 있을 수가 없는 칸이었다.
자정이 넘었다.
소윤에게 메시지를 쓰다가 지웠다. ‘아버님 앱이 해킹당한 것 같습니다’를 계약 첫날 밤 열두 시에 보내는 외주 개발자는 둘째 달 입금을 받지 못한다. 증거를 모으고, 아침에, 정리해서. 일에는 순서가 있었다.
그는 목록을 맨 아래까지 내려 보지 않았다. 사백십칠 번째 줄까지 내렸다면 그날 밤은 다르게 흘러갔을 것이다.
그는 가장 개발자다운 결정을 내렸다. 모르겠으니 일단 닫는다. 사백십칠 건을 전체 선택하고 상태를 바꿨다.
상태: 재현 불가
신고된 대로 해 봐도 고장이 나지 않는다는 뜻이다. 개발자가 제일 편하게 쓰는 종료 사유이기도 하다. 틀린 말도 아니었다. 재현 경로 2번을 재현할 방법이 없으니까. 농담 삼아 처리 사유 칸에도 그렇게 적었다. ‘2번 단계 재현 환경 없음.’
엔터를 눌렀다.
똑, 똑, 똑.
누가 문을 두드렸다.
도현은 모니터 구석의 시계를 봤다. 열두 시 사십 분. 옥탑이었다. 이 문까지 오려면 불 꺼진 계단을 오 층 올라와 옥상 철문을 밀어야 한다. 철문은 열 때마다 비명을 지른다. 방금은 아무 소리도 나지 않았다.
똑, 똑, 똑.
정확히 세 번씩이었다. 간격까지 같았다.
“……누구세요.”
문 너머에서 목소리가 났다. 젊은 남자 목소리였고, 민원 창구에서나 들을 법한 말투였다.
“밤늦게 죄송합니다. 방금 일괄 처리하신 사백십칠 건 관련해서 왔습니다.”
도현은 대답하지 못했다.
“재현 불가 처리에 이의가 있습니다.”
잠깐 사이를 두고, 목소리가 덧붙였다.
“2번 단계 재현 환경은 저희 쪽에서 제공해 드릴 수 있습니다. 다만 권해 드리지는 않습니다.”