승인한 적 없는 코드베이스의 책임
팀 리포를 새로 만들 때 .prettierrc 한 줄 길이를 80으로 할지 120으로 할지 붙잡고 있던 때가 있었다. 다들 전에 있던 팀에서 쓰던 게 있으니 쉽게 안 끝났고, 누가 근거를 대고 누가 반대하다가 어느 쪽으로든 결론이 났다. 그렇게 통과해야 규칙이 됐고, 통과했다는 것 자체가 이 건은 종결됐다는 기록이었다.
요즘 내가 일하는 코드베이스에 들어오는 규칙들은 그 과정을 하나도 안 거친다. 로그아웃이 어떻게 동작할지, 디자인 시스템과 개별 화면의 경계를 어디서 나눌지 같은 게 내가 모르는 새 규칙으로 들어와 있다. 한 줄 길이를 두고 반나절을 쓰던 사람들이 이건 아무도 안 물어보고 넘어간다.
특히 한 번짜리 처방이 그렇게 올라간다. 특정한 상황에서 한 번 터졌던 것을, 다음 사람이 또 밟지 않게 규칙으로 적는다. 적는 사람 머릿속에는 "그때 그 상황에서는"이 있는데 파일에 들어가는 문장에는 그게 안 붙는다. 그래서 읽는 쪽에서는 원칙으로 읽고, 상관없는 데까지 그대로 가져다 쓴다. 결과물이 이상한데 어디서부터 이상해졌는지는 안 보인다.
물론 예전에도 논쟁 없이 행동을 강제하는 장치는 있었으니 새로울 게 없다고 넘길 수도 있는데, lint 규칙이나 CI 게이트에는 포매팅이나 빌드 통과처럼 아무도 설득할 필요 없는 것만 걸렸고 그마저도 함부로 못 늘렸다. 만드는 데 구현 비용이 들고, 잘못 만들면 CI가 전원에게 실패로 떠서 나쁜 규칙은 금방 드러나 철회됐다. 지금은 예전 같으면 회의를 잡았을 판단이 같은 파일에 같은 서식으로 들어가는데, 한 줄 적으면 끝이고 잘못돼도 어디서도 실패로 안 잡힌다. "이건 팀이 합의한 것"과 "이건 누가 지난주에 한 번 데여서 적어둔 것"을 나누는 칸도 없다. 게다가 규칙은 대개 막 데인 직후에, 그러니까 검토가 제일 안 되는 시점에 쓰인다. 비용은 나중에 다른 사람 세션에서 토큰과 제약된 행동으로 흩어져 나가고, 만든 사람이 비용을 안 본다. 정작 치르는 사람은 그게 어느 줄 때문인지 모르니 아무도 지울 이유가 없다.
그래도 규칙 파일은 열어볼 수는 있는데, 에이전트는 적힌 규칙을 따르면서 옆에 있는 코드도 같이 모방하기 때문에 급해서 한 번 그렇게 짠 것이나 예외라 임시로 둔 것이 헌법이 된다. 규칙 파일이 아예 없는 리포에서는 이게 전부고, 이쪽은 지울 줄도 없이 그게 규칙이라는 걸 아무도 모른다. 여기까지는 아쉬운 정도다.
인시던트가 나면 다 같이 본다. 내가 승인한 코드인지, 동의한 규칙인지 아무도 묻지 않는다. 그런데 그 코드를 그렇게 만든 것 중 상당수는 내가 본 적 없는 규칙 몇 줄과, 누가 언제 왜 그렇게 짰는지 모르는 선례다. 책임은 공동이고 강제인데 동의는 아무도 안 물었다. 사람이 내린 나쁜 결정은 근거를 대고 반론을 받을 상대가 있으니 다시 설득해서 뒤집을 수 있지만, 파일에 들어간 규칙과 코드가 된 관습은 되돌릴 방법이 힘밖에 없다.
그럼 리뷰를 하면 되지 않냐고? 본의 아니게 최근 네 개 회사를 겪었는데, 어디에도 리뷰는 없었다. 흐지부지된 게 아니라 AI 시대에 맞춰 없앤 것이었다. 나는 이걸 노 리뷰 컬처라고 부르기 시작했다. 다른 회사들도 크게 다르지 않을 것이다.
AI로 아웃풋을 최대한 뽑아내는 게 모두의 목표인 판에서 모든 "잠깐"을 외치는 행위는 제일 먼저 손이 가는 항목이다. 검토 절차를 하나 더 만들자는 말은 속도를 모르는 사람, 예전 방식에 매인 사람의 말처럼 들린다. 게다가 리뷰를 잘하자는 것도 아니고 리뷰라는 게 아직 필요한지를 다시 얘기해보자는 말이라 한 발 더 늦은 말처럼 들리는데, 실제로 그렇게 들릴 것 같아서 나도 잘 못 꺼낸다.
규칙을 읽고 반론하면 되지 않냐고 할 수 있는데, 읽는 것부터가 쉽지 않다. 코드에 뭐 하나 넣을 때는 어느 계층에 둘지 무엇에 의존시킬지를 그렇게 따지면서, 정작 그 코드를 만들어내는 규칙은 한 파일에 평면으로 나열될 뿐이다. 코드베이스를 가꾸던 때에 비하면 훨씬 미개한 방식으로, 그것도 제각각 관여한다. 매 세션 전에 전부 읽는 것도 현실적이지 않다. 애초에 안 읽으려고 들인 도구다.
그래서 대부분은 코드를 제출하려다 훅에서 막히고 나서야 그런 규칙이 있었다는 걸 안다. 관습이 된 구현은 그마저도 없어서, 막히지도 않고 그냥 따라가게 된다.
논쟁이 끝난 것은 하네스에 맡기는 게 맞다. 사소해서가 아니고 이미 결론이 났기 때문이다. 커밋 메시지를 어떤 형식으로 쓰는지 같은 건 오히려 팀원들 머리에 없는 편이 낫다. 복잡하고 무거운 것이라도 한 번 결론이 났으면 마찬가지다. 그런데 지금 그 파일에는 아직 논쟁 중인 것까지 같은 자격으로 들어가 있고, 이런 건 팀이 충분히 논의하고 검토하는 과정을 거치지 않으면 아무의 머리에도 안 새겨진다. 파일에는 적혀 있고 에이전트는 매 세션 읽는데, 정작 그걸 지고 갈 사람들 머릿속에는 없다. 적혀는 있지만 아무도 자기 것으로 여기지 않는 규칙이다.
리뷰를 없애면서 아쉬운 건 결함을 못 잡는다는 것보다 그 논의가 통째로 사라졌다는 쪽이다. 리뷰는 결함을 잡는 일이기 이전에, 이걸 왜 이렇게 하는지를 두 명 이상이 알게 되는 과정이었다.1 승인 버튼을 누르는 데도 그만큼의 책임감이 담겨 있었다. 내가 승인한 코드에서 문제가 생기면 제출한 사람만 보는 게 아니라 나도 같이 들여다보는 게 당연했다.
AI 시대라고 해서 코드에 담긴 결정들이 쉬워진 것도 아니다. 승인은커녕 리뷰도 안 한 코드베이스에서 잡기 어려운 문제는 여전히 생기고, 이게 어떤 요청에서 비롯됐는지 같은 맥락을 문제를 파헤치는 도중에야 알게 되는 일이 요즘 부쩍 많다. 사후약방문으로 리뷰를 하는 셈이다. 그마저도 개인차가 있어서, 근원을 건드리는 대신 당장 덮는 쪽으로 가는 것도 많이 봤다.
내 손때가 덜 묻은 코드베이스가 (내 생각에) 중요한 문제를 일으키고 그게 근본에서 해결되지 않은 채로 남을 때, 내가 그걸 어떻게 감당해야 할지는 아직 찾는 중이다.