[PonsLink] 작업 기록을 따라가니 아직 진행형인 이유가 보였다
작업 기록을 다시 읽으며 PonsLink가 아직 진행형인 이유를 알게 됐다. 회의방 하나를 만들면 링크를 보내고 같은 화면에서 대화와 파일을 주고받을 수 있을 거라 생각했다. 연결 자체는 열렸지만 그 뒤의 순서와 상태, 실패 복구는 제품이 직접 책임져야 했다. 이 편은 시리즈의 중간 정산점으로, 커밋 로그를 다시 읽는 작업이 무엇을 보여줬는지, 그리고 "진행형"이라는 말이 왜 변명이 아니라 정확한 상태 표기인지를 정리한다.
커밋 로그 읽기라는 작업 자체에 대해 먼저 말할 것이 있다. 이건 감상의 시간이 아니라 감사(audit)의 시간이었다. 코드는 남아 있지만 결정의 이유는 사라지기 쉽다. 커밋 메시지와 그때의 맥락을 다시 읽으며 "이 결정은 왜 내려졌고, 지금도 유효한가"를 물었다. 제품이 계속 움직이는 동안 결정의 기록은 정지해 있으니, 정지한 기록과 움직인 현실의 차이가 곧 다음 작업 목록이 된다.
이 작업을 하게 된 직접적 계기도 단순했다. 시리즈를 이 시점까지 쓰고 나니, 앞선 편들의 결정들이 서로를 가리키는 화살표들을 한 곳에 모아 보고 싶었다. 요청 선별이 가리키는 것, No-Go가 가리키는 것, 피벗이 가리키는 것 — 각각은 그 편에서 닫혔지만 가리킨 방향은 아직 열려 있었다. 개별 결정은 닫혀도 결정들의 방향은 따로 관리해야 한다. 이것이 이 편이 시리즈의 "정산점"으로 자리 잡은 이유다.

로그가 보여 준 작은 결정
신호 교환과 입장 순서, 메시지 채널과 파일 채널이 조금만 어긋나도 사용자는 연결됐다고 느끼지 못했다. 내부에서는 한 단계가 늦어진 것처럼 보여도 바깥에서는 기다림과 불신으로 남았다. 문제는 특정 기술 하나보다 책임을 정하지 않은 채 다음 작업으로 넘어간 데 있었다.
이 어긋남이 사용자에게 어떻게 번역되는지를 한 장면으로 그리면 이렇다. 발신 쪽에서는 파일이 반쯤 갔다고 표시되는데, 수신 쪽 화면에는 아무 표시가 없다. 내부적으로는 채널 순서의 문제지만, 사용자 눈에는 "상대가 안 받는다"다. 기술의 한 단계 지연이 관계의 한 걸음 불신이 되는 순간이다. 실시간 제품의 상태 표시가 이렇게 중요한 이유가 여기에 있다 — 상대의 행동이 보이지 않을 때, 제품의 상태 문장이 상대를 대신해 말해주지 못하면 침묵은 부정적으로 해석된다.
커밋 로그를 시간순으로 읽으면 이 "어긋남"들이 흔적을 남긴다. 어떤 커밋은 채널 순서를 바꿨고, 어떤 커밋은 입장 조건을 더했고, 어떤 커밋은 재입장 처리를 손댔다. 각각은 그때그때 합리적인 수정이었다. 그런데 나열해 보면 공통점이 보인다 — 전부 "누가 무엇에 책임을 지는가"를 코드로 다시 정하는 커밋들이었다. 기술 추가 커밋보다 책임 재분배 커밋이 많다는 것 자체가, 이 제품의 난이도가 기능이 아니라 경계에 있었다는 증거다.
책임 재분배가 왜 이렇게 자주 일어났는지를 생각해보면, 초기 가설의 오차 범위가 크다는 것과 연결된다. "연결되면 끝"이라는 가설로 시작한 제품에서 책임의 대부분은 연결 라이브러리에 있었다. 실제 운영은 그 뒤의 무한한 책임 — 상태 유지, 복구, 권한, 이해 — 을 요구했고, 그때마다 책임을 어디에 둘지 다시 정했다. 가설의 오차가 클수록 재분배 커밋이 많아진다. 재분배 커밋의 밀도는 가설의 부정확성 지표다.

로그 읽기에서 발견한 또 하나의 패턴은, 실패의 언어가 시간이 지나며 바뀐다는 것이었다. 초기 커밋들의 실패 언어는 기술이었다 — "연결 실패", "재시도". 후반 커밋들의 실패 언어는 사용자였다 — "입장 전 안내", "재입장 흐름". 같은 제품의 기록에서 실패의 주어가 코드에서 사람으로 이동한 것은, 제품이 기술 시연에서 사람의 제품으로 이동한 흔적이었다. 이 언어 전환은 의도한 게 아니라 필요해서 일어났다. 사용자의 실패를 기술 언어로만 기술하면 대응이 화면 설계에 닿지 않았다.
언어 전환의 실무적 함의도 컸다. 실패의 언어가 사용자 중심으로 바뀌면 커밋의 검수자도 달라진다. 기술 언어의 커밋은 "동작하는가"로 검수하지만, 사용자 언어의 커밋은 "이해되는가"로 검수해야 한다. 내가 커밋 메시지를 쓰는 언어가 검수의 체크리스트를 결정한다는 것 — 커밋 메시지의 언어 선택이 사소하지 않은 이유다. 로그를 읽으며 과거의 나에게 느낀 감정이 있다면, 기술 언어로만 쓰인 시절의 커밋들은 지금 읽으면 무엇을 고쳤는지는 알지만 누구를 위해 고쳤는지는 알 수 없었다는 것. 그 공백이 이 시리즈를 쓰게 된 이유 중 하나다.
진행형으로 남긴 이유
개인정보는 최소화하고 링크 하나로 시작하되, 내부에서는 상태와 권한과 요청 흐름을 더 정확히 다뤄야 했다. 기록의 목적은 결론을 꾸미는 데 있지 않았다. 어떤 가정이 깨졌고 어떤 경계를 새로 그었는지 다음 작업자가 확인할 수 있게 하는 데 있었다.
"진행형"의 정확한 의미를 정리하면 세 가지다. 첫째, 아직 결정되지 않은 것이 있다 — 세션 접근의 권한 모델, 요청 흐름의 세부 등은 이 시점에도 열려 있었다. 둘째, 이미 결정된 것도 재검토의 대상이다 — 피벗과 No-Go가 보여줬듯, 제품의 기준은 고정돼 있어도 필드는 움직인다. 셋째, 진행형은 완성형과 달리 기록의 방향이 뒤를 향한다 — 완성형 제품의 문서는 사용법을 쓰지만, 진행형 제품의 문서는 판단 과정을 쓴다. 이 시리즈 자체가 셋째의 실천이다.
진행형이라는 표현이 갖는 매력과 위험도 함께 기록해둔다. 매력은 정직함이다 — 미완을 미완으로 부른다. 위험은 무기력이다 — "진행형이니까"가 어떤 미완의 사유가 되면 그 순간 정직함이 변명으로 타락한다. 이 변질을 막는 장치는 목록이다. 진행형이 되는 이유를 "아직"이라는 부사로 말하지 않고 "어떤 결정이 남았다"는 명사로 말하면, 진행형은 계획이 된다. 이 편의 세 목록이 그 역할을 한다.

로그 읽기가 남긴 것
커밋 로그를 다시 읽는 작업의 산출물은 감상이 아니라 목록이었다. 아직 책임 주체가 정해지지 않은 경계의 목록, 사용자 언어로 번역이 필요한 내부 상태의 목록, 재검토가 필요한 오래된 결정의 목록. 이 세 목록이 다음 시기의 작업 대기열이 됐다.
특히 첫 번째 목록 — 책임이 비어 있는 경계들 — 이 가장 값졌다. 시스템에서 책임이 비어 있는 곳은 반드시 나중에 문제가 되는 곳이기 때문이다. 요청이 어디에 속하는가, 세션 입장 권한이 누구의 판단인가, 파일 전송이 회의의 책임인가 별도의 책임인가. 이 질문들에 대한 답이 정해지지 않은 채 기능만 늘어난 것이 PonsLink가 "아직 진행형"인 근본 이유였고, 로그 읽기는 그 사실을 감이 아니라 목록으로 확인시켜 줬다.
두 번째 목록 — 번역이 필요한 내부 상태 — 도 구체적이었다. 내부적으로는 "재접속 대기", "권한 만료", "채널 불일치"로 불리던 상태들이 사용자 화면에서는 무엇이어야 하는가. 이 번역표를 만드는 작업이 이후 상태 화면 설계의 기초가 됐다. 내부 언어를 그대로 노출하면 사용자는 당황하고, 아예 숨기면 사용자는 갑갑하다. 번역표는 이 사이의 다리였다.
세 번째 목록 — 재검토 대상 결정들 — 은 조금 불편했다. 오래된 결정 중 몇몇은 이유가 사라졌는데 습관으로 남아 있었다. 로그를 읽지 않았다면 그 습관들은 영원히 원칙으로 둔갑해 있었을 것이다. 기록을 다시 읽는 것은 결정을 다시 내리는 것이 아니라, 결정의 이유가 아직 살아 있는지 확인하는 일이다.
세 목록을 나란히 놓고 보면 공통의 성질이 하나 있다. 전부 지금 바로 코드가 되지 않는 것들이다. 경계의 결정은 설계의 시간이 필요하고, 번역표는 문장의 시간이 필요하고, 재검토는 판단의 시간이 필요하다. 개발 일정에서 이런 "코드가 안 되는 작업"들은 밀리기 쉽다. 그래서 목록으로 남겨둔다 — 밀리는 것과 잊히는 것은 다르다. 이 세 목록이 이후 시리즈에서 각각 실제 작업으로 이행되는지가, 이 기록의 신뢰도를 판정하는 기준이 될 것이다.
로그 읽기가 이 시점의 제품 계획에 직접 반영된 사례 하나. 세 목록 중 "책임이 비어 있는 경계" 항목에서 파일 전송의 소속 문제가 다시 떠올랐고, 이것은 앞 편의 No-Go와 정확히 같은 질문이었다. No-Go가 문을 닫았다면 로그 읽기는 왜 닫혔는지를 확인한 것이고, 답은 같았다 — 파일 전송은 별도의 책임이다. 결정이 반복 확인을 거칠수록 결정은 견해가 아니라 사실이 된다. 이것이 기록을 다시 읽는 일의 복리다. 독자에게 유용할 수 있는 실용적 조언으로 이 편을 장식한다. 커밋 로그 감사는 반년에 한 번 정도만 해도 충분하다. 할 일은 단순하다 — 최근 결정 커밋들을 시간순으로 나열하고, 각각에 "이유가 아직 살아 있는가"를 물은 뒤, 이유가 죽은 것과 근거가 없었던 것을 구분해 적는다. 한 시간이면 충분한 이 작업이 프로젝트의 방향을 몇 주 단위로 교정한다. 도구도 필요 없다. 로그와 솔직함만 있으면 된다.
마치며
커밋 로그를 따라가면 완성된 제품보다 아직 결정해야 할 책임이 먼저 보인다. PonsLink가 진행형이라는 말은 미완성이라는 변명이 아니라 연결 뒤의 상태를 계속 제품으로 만들어 가고 있다는 뜻이다.
이 편이 시리즈에서 맡은 마지막 역할은 방향 전환의 안내다. 여기까지의 편들은 방 안의 이야기 — 연결, 피벗, 파일 전송, 출시 판단 — 였다. 로그 읽기로 확인된 세 목록이 가리킨 다음 작업은 방 밖의 이야기였다. 요청의 흐름, 운영의 화면, 그리고 언젠가 독립될 파일 전송. 시리즈는 여기서 시선을 방 안에서 방 밖으로 완전히 넘긴다. 연결을 만드는 것에서 연결이 성립되기 전후의 시간을 제품으로 만드는 것으로. 그것이 PonsLink의 다음 장이고, 이 기록의 다음 장이다.