사다리를 놓는 사람 — 시니어 없이 배포하는 팀을 만든다는 것
· Essay · 7 min
높은 건물은 혼자 올라가지 않는다. 벽을 오르는 모든 일의 곁에는 사다리가 있었다. 그러나 준공 사진에 사다리는 없다. 나는 그것이 사다리의 실패가 아니라 사다리의 완성이라고 생각한다. 제 몸으로 남의 상승을 떠받치고, 일이 끝나면 말없이 치워지는 것. 그보다 떳떳한 퇴장을 나는 알지 못한다.
코드 리뷰는 문이 될 수도 있고 사다리가 될 수도 있다. 문은 막아선 자의 권위로 서고, 사다리는 받쳐 준 자의 등으로 선다. 문지기는 통과한 사람의 수를 세고, 사다리는 올라간 사람의 높이를 잰다. 매일 아침 열린 PR 목록을 여는 순간, 나는 같은 갈림길에 선다. 오늘 나는 문지기인가, 사다리인가.
남의 코드를 읽는다는 것
주니어의 PR을 여는 일은 남의 일기장을 건네받는 일이다. 코드에는 쓴 사람의 밤이 묻어 있다. 변수 이름 하나에 그가 무엇을 두려워했는지가 보이고, 주석의 말투에 그가 이 코드를 자랑스러워하는지 부끄러워하는지가 배어 있다. 커밋 로그를 시간순으로 짚으면 그가 어디서 헤맸고 어디서 무릎을 쳤는지, 지도에 없는 행로가 드러난다.
그래서 나는 세심하게 읽는다. 세심함은 여유가 만드는 사치가 아니다. 읽는 자가 쓰는 자에게 갖추는 최소한의 예의다. 대충 읽고 남긴 한 줄의 지적은 쓴 사람의 밤을 통째로 부정한다. 깊이 읽고 남긴 한 줄의 질문은 그가 자신의 밤을 스스로 다시 걷게 만든다. 나는 후자의 리뷰어다.
코멘트를 달 때 나는 문장을 고른다. "왜 이렇게 했나요"와 "이렇게 한 이유가 궁금해요"는 같은 물음이지만 다른 온도다. 전자는 취조실의 말이고 후자는 찻집의 말이다. 같은 값이면 찻집에서 묻는다. 코드는 논리의 산물이지만, 코드를 고치게 만드는 것은 결국 마음이다.
손대지 않는 것들
그러나 세심함이 간섭의 다른 이름이 되어서는 안 된다. 내 리뷰에는 성역이 하나 있다. 그 사람의 핵심 아이디어다.
주니어가 가져온 해법이 내 머릿속의 해법과 다를 때, 손끝이 근질거린다. 내 방식이 더 빠르고, 더 검증되었고, 더 우아해 보인다. 그러나 그 근질거림에 매번 굴복하는 순간 팀의 모든 코드는 내 코드가 된다. 백 명이 일해도 한 사람의 상상력만 남는 조직. 겉은 일사불란하고 속은 아흔아홉 개의 상상력이 시들어 가는 온실이다. 나는 그런 온실의 정원사가 될 생각이 없다.
씨앗의 품종에는 손대지 않는다. 대신 밭의 이랑은 함께 맞춘다. 컨벤션이 그 이랑이다. 이름 짓는 법, 층을 나누는 법, 에러를 흘려보내지 않는 법. 이것은 개성의 영역이 아니라 마을의 말씨다. 말씨가 같아야 서로의 밭을 대신 돌볼 수 있고, 새로 온 사람이 어느 밭에서든 김을 맬 수 있다. 그래서 나는 아이디어 앞에서는 관대하고 컨벤션 앞에서는 집요하다. 이 비대칭은 변덕이 아니라 원칙이다. 시간이 지나며 팀원들은 알아차렸다. 지켜야 할 선이 어디이고, 마음껏 달려도 되는 벌판이 어디인지.
가끔은 내가 대패를 잡는다
리뷰 코멘트로 다 하지 않는다. 어떤 날은 내가 직접 커밋을 얹는다.
옛 공방의 도제식 교육에는 묘한 순간이 있었다. 스승이 도제의 작업물을 말로 고치다가, 어느 지점에서 말을 멈추고 대패를 손수 잡는 순간. 그것은 도제의 실패 선언이 아니다. 말로는 건널 수 없는 감각의 강을 몸으로 보여 주는 다리다. 대팻밥이 얇게 말려 올라가는 것을 눈앞에서 본 도제는, 백 마디 설명으로도 닿지 못했던 곳에 단숨에 닿는다.
주니어의 브랜치에 직접 커밋을 얹을 때 나는 하나의 원칙을 지킨다. 반드시 그의 설계 위에서 고친다. 그의 집을 헐고 내 집을 짓는 것이 아니라, 그의 집에 들어가 문틀 하나를 바로잡는 것. 그리고 커밋 메시지에 왜 이렇게 다듬었는지를 적어 두는 것. 그러면 그 커밋은 수정이 아니라 시연이 된다. 이런 날 팀의 공기가 가장 좋다. 고침을 당한 사람이 풀이 죽는 것이 아니라, 어깨너머로 기술 하나를 훔친 사람의 얼굴이 된다.
채찍이 약이 되고 꿀이 독이 되는 날
여기까지만 쓰면 이 글은 절반의 진실이다. 나머지 절반은 조금 더 어둡고, 그래서 더 중요하다.
비난이 좋은 동기가 되는 순간이 있다. 나는 그것을 부정하지 않는다. 실력이 분명한데 안일함이 습관이 된 사람에게, 관대한 리뷰는 그 안일함의 공범이다. 그런 사람에게 어느 날 정색하고 건네는 차가운 한마디 — "이건 당신 실력이 아닌데요" — 는 잔인해 보이지만, 그 문장의 뼈대는 존중이다. 당신의 천장이 여기가 아님을 내가 안다는 고백. 담금질의 물이 차가운 것은 쇠를 미워해서가 아니다. 뜨겁기만 한 대장간에서는 어떤 칼도 여물지 않는다.
반대로 수용과 칭찬이 독이 되는 순간도 있다. 서툰 코드에 "고생하셨어요"만 쌓이는 리뷰 문화는 따뜻해 보이지만, 그 온기는 성장이 멈춘 자리의 미열이다. 모든 것이 받아들여지는 곳에서 사람은 자신의 위치를 잃는다. 칭찬이 화폐라면 남발은 인플레이션이다. 정작 진짜 잘한 날의 칭찬이 아무 값도 치르지 못하게 된다. 나는 칭찬을 아끼지 않되 헐값에 뿌리지 않는다. 내 "좋다"는 말이 팀 안에서 언제나 제값이기를 바라기 때문이다.
요컨대 이것은 온도의 기술이다. 불과 물을 오가는 담금질처럼, 사람을 벼리는 일에도 뜨거움과 차가움의 국면이 있다. 언제나 뜨거운 스승은 사람을 무르게 만들고, 언제나 차가운 스승은 사람을 부러뜨린다. 지혜는 온도 하나를 고르는 데 있지 않다. 지금 이 사람에게 필요한 온도를 알아보는 데 있다. 그리고 그것을 알아보는 길은 하나뿐이다. 세심하게 읽는 것. 코드가 아니라 사람을.
모두의 꿈이 서비스가 되는 것
이런 나날이 쌓여서 어디에 이르는가.
내가 두려워한 미래는 이런 것이었다. 모든 PR이 결국 시니어의 입맛대로 다듬어져 병합되는 조직. 리뷰가 취향의 관철 수단이 되고, 주니어들은 언젠가부터 "어차피 고쳐질 텐데"라며 반쪽의 마음만 담아 코드를 밀어 올리는 곳. 그런 조직의 서비스는 한 사람의 자화상이다. 정교할 수는 있어도 풍요로울 수는 없다.
내가 바란 미래는 다른 것이었다. 병합 버튼이 눌리는 순간마다 서로 다른 사람의 서로 다른 밤들이 하나의 물줄기로 합쳐지는 것. 저 화면 어딘가에는 입사 석 달째 주니어가 처음으로 끝까지 밀어붙인 설계가 흐르고, 그 옆에는 내가 대패를 잡았던 문틀이 있고, 그 아래에는 누군가 정색한 리뷰를 받고 이를 악물고 다시 쓴 쿼리가 돈다. 사용자는 그 지층을 볼 수 없지만 만든 우리는 안다. 이 서비스는 누구 한 사람의 작품이 아니라 모두의 꿈이 녹아든 합금이다. 그리고 합금이 순금보다 단단한 것은 야금학의 상식이다.
그런 팀은 어느 날부터 나 없이 배포하기 시작한다.
처음 그 광경을 보던 날을 잊지 못한다. 내가 자리를 비운 사이에 릴리스가 하나 나갔고, 아무 일도 일어나지 않았다. 서운함이 아주 없었다면 거짓말이다. 그러나 그 서운함의 밑바닥에서 올라온 것은 분명 기쁨이었다. 사다리의 보람은 사다리 위에 오래 서 있는 것이 아니다. 어느 날 아무도 사다리를 찾지 않게 되는 것이다.
떠날 준비를 하는 사람
언어들을 오가며 배운 문장 하나를 여기에 다시 적는다. 자원은 얻는 순간에 놓아줄 때를 정해 둔다. 시작할 때 이미 끝을 새겨 두는 것. 나는 그것이 코드의 예법일 뿐 아니라 리더의 예법이라고 믿는다.
좋은 시니어는 자신이 병목이 되지 않는 구조를 짓는 사람이고, 더 좋은 시니어는 자신이 없어도 무너지지 않는 구조를 짓는 사람이다. 매일의 세심한 리뷰도, 손대지 않는 성역도, 가끔 손수 잡는 대패도, 차가운 물과 뜨거운 불도, 전부 하나의 준비다. 내가 이 자리를 떠나는 날, 아무것도 멈추지 않게 하는 준비.
사다리는 제가 떠받친 사람의 이름을 기억하지 않는다. 다만 오늘도 벽에 기대어 서서 다음 발자국의 무게를 기다린다.
나는 그런 사다리이고 싶다.