- Tags:
- #Reflection
- Date:
미움받을 용기
회사를 그만뒀다. 입사한 지 약 1년 만이었다. 한 회사에 들어가면 대개 3년 가까이는 다니던 나로서는 이례적인 일이었다.
나는 아직도 그곳에서의 시간을 되짚는다. 무의식적인 반추. 아마 나의 경우에는, 직장에 관한 가장 최근의 기억이 그곳에 멈춰 있기 때문일 것이다. 떠난 회사가 그립거나 지나간 일 따위로 괴롭지는 않지만, 끝내 매듭짓지 못한 일이 있었다. 과거에 오래 머무는 일은 사람을 조금씩 좀먹는다. 그러니 이대로 내버려둘 수는 없었다. 또 다른 종류의 고통이었다.
이 글은 가장 최근의 직장에서 겪은 일과, 그 안에서 내가 기울였던 노력에 대한 기록이다. 누군가를 비난하려는 뜻은 없다. 팀에 해를 끼치고 싶은 마음도 없다. 반대로 내게 상처를 준 행동에도 악의가 있었다고 믿지 않는다. 오히려 이 글은 나의 어리숙함을 드러내는 것일지도.
그렇다고 모든 일을 나의 문제로 축소하고 싶지도 않다. 내가 놓였던 환경에는 분명 결함이 있었고, 그 결함은 사람들의 판단과 관계를 오래 흔들었다. 나는 그 현상을 어떻게 읽었는지, 무엇을 고치려 했는지, 그리고 왜 끝내 더 나은 방식으로 행동하지 못했는지를 적으려 한다. 함께 일했던 동료에게는 변명처럼 들릴 수도 있지만, 그래도 괜찮다. 이 글은 그저 내 마음이 편해지고자 쓰는 글이니까.
회사·제품·팀 이름은 언급하지 않았고, 개인을 특정할 수 있는 정보도 최대한 덜어냈다. 우연히 이 글을 마주칠 가능성을 줄이기 위해 검색 엔진에서도 숨겨두었다. 이 이야기가 입에 오르내리거나 팀과 개인에 대한 억측, 부정적인 소문으로 번지는 일은 바라지 않는다. 끝에 이르러서는 분명 문제가 해결되고 있었고, 그 시간을 내가 버티지 못했을 뿐이다.
갈증
한때 나는 어느 스타트업의 창업 멤버로 일했다. 세 번째 직장이었고, 산업기능요원을 마친 뒤 온전히 내 뜻으로 고른 첫 회사였다. 남들이 빅테크를 원할 때 나는 스타트업에 끌렸다. 회사가 망하면 그때 떠나도 된다는 가벼운 마음도 있었다. 그러나 그곳에서 보낸 4년은 나를 깊게 바꾸었고, 과분할 만큼 많은 일을 겪었고, 많은 것을 배웠다. 오늘의 이야기는 그 회사에 관한 것이 아니므로 이쯤 해둔다.
갈증은 여전했다. 내가 무엇을 모르는지조차 모른다는 것, 그 미지의 영역이 궁금했다. 회사가 계획하는 변화는 정말 옳은가. 그렇게 판단하는 나 자신을 믿어도 되는가. 자신은 있었지만 확신은 없었다. 그동안 나는 환경을 이유로 늘 시행착오 속에서 직접 부딪히며 익혔기에, 마주한 눈앞의 문제는 그동안의 경험만으로 가늠하기 어려웠다. 그래서 이번만큼은, 내가 해보지 못한 일을 해내는 사람들 곁에서 배우고 싶었다. 나는 회사의 방향을 결정할 수는 없어도 리더로서 일을 벌일 수 있는 위치에는 있었는데, 여느 스타트업이 그렇듯 재정은 넉넉지 않았다. 스타트업의 파티가 끝나고 모두가 생존에 집중하던 시기였다. 실패를 경험으로 치부하기에는 대가가 컸고, 나보다 나은 전문가가 필요했다.
그래서 한동안 소홀했던 본업으로 돌아가기로 했다. 지금 와 돌이켜 보면, 더는 상황을 나아지게 할 수 없다는 무력감에서 도망친 결정이었을지도 모른다. 새 환경에서는 엔지니어링으로 기여하며 더 넓은 일을 배울 수 있다는 생각으로, 그때의 나는 그것을 준비된 제너럴리스트가 되기 위한 선택이라고 믿었다.
기대
인터뷰 과정이 인상적인 회사가 있었다. 이렇다 할 특별함은 없었지만, 다시 면접관이 되면 이를 모방하겠다는 생각이 들었던 회사. 어려운 질문들은 아니었지만 촘촘하게 설계된 인터뷰였다. 꽤나 공을 들였겠지. 이런 회사라면 인재 밀도도 높으리라 짐작했으니, 나름 신중한 선택이었다.
회사가 풀고 있는 문제도 마음에 들었다. 특히 더 깊이 알고 싶은 도메인이 둘 있었는데, 온보딩이 끝나기 전 그중 하나를 맡은 스쿼드에 배치될 것이라는 말을 들었다. 레거시라는 이야기도 스쳐 들었지만 내게는 문제가 아니었다. 오히려 잘됐다고 생각했다.
온보딩은 약 4주 동안 이어졌다. 플레이북 곳곳에는 정성 들인 흔적이 남아 있었다. 오래된 정보가 더러 섞여 있었고, 신입과 주니어를 상정한 프로세스라 내게 불필요한 것도 있었지만, 온보딩 메이트가 있어 문제는 아니었다. 오랜만의 시니어 엔지니어 채용이라 했으니 그럴 만도. 그 작은 조정 외에는 모든 일이 무난해 보였다. 그저 앞으로의 회사 생활이 기대될 뿐이었다.
절차에 따라 온보딩을 마칠 때까지, 나는 어느 스쿼드에도 속하지 않은 채 기다렸다. 그때 조금만 더 일찍 사정을 알았더라면, 혹은 다른 팀으로 갔더라면, 나는 지금도 그 회사에 남아 있었을까. 답할 수 없는 무의미한 질문이다.
교착
스쿼드에 합류했을 때 그곳에는 나의 매니저도 있었다. 첫인상은 좋았다. 구성원들은 밝았고, 분위기도 화기애애했다. 적어도 새로 들어온 내 눈에는 아무런 문제가 없어 보였고, 낯을 가리는 나만 적응하면 될 일이었다.
실상은 달랐다. 내가 들어갈 무렵 스쿼드는 거의 1년 동안 이렇다 할 성과를 내지 못하고 있었다. 회사의 많은 사람이 그 사정을 알고 있었지만, 신규 입사자인 내가 알아차릴 방법은 없었다. 온보딩 기간에 접근할 수 있는 문서 대부분을 읽었지만, 그런 갈등까지 애써 기록으로 남길 리가 만무했다. 기록을 잘 남기는 팀도 아니었으니 더욱 그랬다.
팀이 풀려던 문제는 그때는 맞았지만 지금은 틀린 의사결정들이 제품에 남긴 흔적을 걷어내는 일이었다. 서로 다른 고객의 요구를 모두 품을 수 있는 새로운 경험을 만들어야 했다. 오랜 시간 쌓인 문제를 고치는 일은 며칠이나 한두 번의 스프린트로 끝나지 않는다. 무엇을 나누고 무엇부터 바꿀지, 수없이 판단을 거쳐야 한다. 흔히 스타트업 씬이나 SNS에서 떠들어대는 빠른 MVP의 성공담과는 달리, 오래된 서비스에서는 종종 있는 일이었다. 그리고 그 계획은 끝내 실행되지 못했다.
처음 들었던 이유는 회사가 팀의 접근에 동의하지 않는다는 것이었다. 하지만 회사의 입장만이 문제는 아니었는데, 팀은 목표로 하는 완성된 그림 자체에는 대체로 동의했지만, 그곳에 도달하는 방법을 두고 의견이 갈라졌다. Product Owner는 자신의 의견을 고수하며 급진적인 변화를 원했고, 그 그림에 가까운 합의안마저 받아들이지 않았다. 그가 바라던 변화는 기존 고객의 경험을 파괴하고 거의 처음부터 다시 쓰는 수준이었음에도, 그는 데이터 마이그레이션조차 지원하지 않으려 했다. 이미 사용자가 있는 제품의 핵심 기능이었으니, 회사의 리더들이 반대하는 것도 결코 무리는 아니었다.
회의에는 타협할 수 없는 변화와 그에 대한 반대만 남았다. 이 문제를 책임지고 이끌 사람도 없었다. Disagree and Commit, 반대를 남겨둔 채 누군가의 결정에 힘을 싣는 선택이 필요했지만, 팀 안에서는 화합과 만장일치가 의사결정에서 양보할 수 없는 원칙처럼 작동했다. 모두가 동의하지 않으면 누구도 움직일 수 없었다. 모든 고객을 대상으로 배포하지 않고도 작은 실험을 시작할 방법을 찾았어야 했는데, 우리에게는 이 끝없는 갈등의 굴레에서 벗어날 장치가 없었다.
나 역시 이상함을 느꼈다. 다만 이것이 거의 1년째 이어진 교착이라는 사실을 몰랐던 나는, 새로 합류한 사람으로서 한 번은 이 팀이 몰입해서 일하는 모습을 관찰하고 싶었다. 결코 소극적인 태도로 임하지는 않았지만, 문제 현상을 인지하고도 최대한 지켜보려 했다. 다른 동료보다는 자주 그리고 강하게 개입했다고 자신하지만, 그 빈도는 의식적으로 줄이려 했다. 충분한 기다림이 있어야 문제를 이해하고 제안할 수 있다고 믿었으니, 결과적으로 오판이었다.
그 사이 나의 시선은 코드에 가 있었다. 내 커리어에서 본 레거시 가운데 세 손가락에 꼽을 수준이었기 때문이다. 나는 시급한 기술 부채부터 손보겠다고 말했고, 그동안 PO가 적어도 팀을 움직일 만큼은 방향을 정리해 오리라 믿었다. 네 일 내 일 가리지 않고 돕는 것을 선호하지만, 직업인으로서 각자 전문성을 발휘해야 할 분야는 다르므로. 더욱이 PO가 원하는 대로 제품 부채를 청산하려면, 그에 얽힌 기술 부채부터 해결해야 했다.
물론 다른 동료들도 마냥 손을 놓고 있었던 것은 아니었다. PO가 스스로의 문제에 묶여 있는 동안 다른 구성원들은 자신들이 주도할 수 있는 문제를 찾기 시작했고, 팀은 그렇게 당장 해결할 수 있는 문제라도 시도해 보기로 했다.
형식
새 문제를 찾으면서 스쿼드는 비로소 움직이기 시작했다. 나로서도 기대하던 순간이었다. 이 팀이 어떻게 일하는지 이제야 온전히 이해할 수 있을 테니. 어쩌면 앞으로 나아가는 경험을 통한 자신감이 오래된 교착도 풀어낼지 모를 일이었다.
하지만 일이 시작되자 문제가 나타났는데, 무엇을 만들지 이야기한 뒤에 팀은 곧바로 구현을 서둘렀다. 정확히는 근거가 없었다. 왜 지금 이 문제를 풀어야 하는지, 어떤 이유로 이 아이디어를 골랐는지, 무엇을 보면 성공과 실패를 가를 수 있는지 충분히 묻지 않았다. 검증 계획도, 구현 뒤 실제로 검증하는 과정도 희미했다. 기능은 늘었지만 다음 판단에 쓸 만한 것은 남지 않았고, 이는 PO의 공백이 여실히 드러나는 순간이었다. Feature Creep, 오늘날의 AI Slop과도 닮아 있었다.
형식은 이미 갖추고 있었다. 스프린트라는 이름이 있었고, 그에 딸린 회의와 도구도 있었다. 그러나 정작 왜 그런 주기로 일하고, 각각의 회의에서 무엇을 얻어야 하는지는 충분히 공유되지 않은 듯했다. 이를 분명히 알게 된 계기가 있었는데, 어느 날 한 동료가 스프린트가 무엇인지 설명하는 자리를 마련했다. 정확한 이유는 기억나지 않지만, 스프린트를 진행하는 과정에서 어떤 문제를 겪었던 것은 확실하다. 설명을 들은 동료들은 이제야 왜 스프린트를 하는지 알겠다는 후기를 남겼으니, 미팅 자체는 성공적이었다. 그래서 더 당황스러웠다. 그동안 이들이 반복해 온 것은 무엇이었을까.
그제야 머릿속의 퍼즐이 맞춰졌다. 흩어져 있던 현상들이 하나의 위험 신호로 보이기 시작했다. 합류한 지 이미 수개월이 지난 뒤였다.
나는 이 스쿼드가 지금 겪는 문제를 해결하고 자생할 수 없는 팀이라고 결론지었다.
생존
이곳은 내가 찾아다니던 환경이 아니었다. 이전 직장을 떠나 얻은 것이 단순히 연봉 하나만은 아니어야 했다. 그러나 문제가 보인다고 곧장 도망치고 싶지도 않았다. 팀을 계몽해서라도 어떻게든 살아남게 해야 했다. ‘계몽’이라는 단어를 떠올린 순간부터 내 태도는 이미 틀어진 것이었는지도 모른다.
나는 우선 멈춰야 한다고 주장했다. 근거도 검증도 없이 기능을 더하는 일은 전진이 아니었다. 과거의 결정이 남긴 흔적을 걷어내겠다면서, 옳은지조차 확인할 수 없는 기능을 그 위에 다시 쌓는 일은 모순이었다. 더 만들기 전에 무엇이 어긋났는지 돌아보고 바로잡아야 했다.
그러나 전혀 동의를 얻지 못했다. 이미 오래 성과를 내지 못한 팀이었고, 구성원들은 저마다의 압박 속에 있었다. 멈추자는 말은 유일하게 붙들고 있던 진척마저 포기하자는 말처럼 들렸을 것이다. 나에게는 고작 몇 달이지만, 그들은 더 이상 견디기 어려울 만큼 충분히 절박했다. 더욱이 이 회사에서는 ‘빠른 기능 구현’ 외의 일을 주장하는 것만으로도 부정적인 반응을 사기 쉬웠는데, 그러니 이들의 사전에는 ‘멈추자’는 말이 없었을 것이다. 앞서 기술 부채를 해결하겠다고 나섰을 때도 마찬가지였다. 같은 직무의 매니저조차 줄곧 반대했었으니. 물론 매니저의 반대는 그 결이 다르지만, 그와의 갈등은 뒤에서 다시 이야기하는 걸로.
다음으로 PO와 따로 이야기를 나누었다. 동료들이 그의 의견에 생각만큼 힘을 실어주지 않는 것 같다고 말했다. 물론 그의 방향에 전부 동의해서는 아니었지만, 내 말은 진심이었다. 누구도 결정을 내리지 못하는 가운데, 적어도 한 사람은 같은 편에 서야 한다고 생각했기 때문이다. 예상과 달리 그는 동료들에게 실망하지 않았다고 했다. 어쩌면 함께한 시간도 얼마 되지 않은 내가 섣불리 단정했는지도. 다만 PO가 너무 많은 책임과 부담을 혼자 지고 있다는 점은 분명해 보였다. UX 디자이너도 나와 같은 생각이었다.
그래서 우리는 워크숍을 열었다. 내가 주도했다. 명목은 앞으로 나아갈 길을 찾는 일이었지만, 내게는 팀을 잠시 멈춰 세우고 지나온 길을 돌아보게 하려는 시도였다. 그동안의 회고는 대개 서로를 격려하는 데서 그쳤는데, 지금 팀에 필요한 것은 무엇이 잘못됐는지를 함께 직시하는 회고였다. 멈추자고 직접 말하는 대신 며칠을 워크숍에 쓰자고 제안하면 거부감도 덜할 터였다. 우회는 효과적이었고 제안은 받아들여졌다. 그러나 무엇 하나 끝까지 내 뜻대로 흘러가는 일이 없었다.
동료들이 원한 것은 아이디어 탐색(Product Discovery)이었다. 물론 그것도 일정에 넣어 두었지만, 아이디어를 찾는 일에 모두가 참여할 필요는 없다는 동료들의 말이 뒤따랐다. 왜 하필 지금일까. 모두의 참여와 화합, 만장일치가 원칙과도 같은 팀이었는데. 사실 이 원칙은 어떤 개인으로부터 시작된 무언의 압박이었고, 동료들은 나와 있을 때만큼은 각자 할 수 있는 일을 하길 원한다며 솔직해졌다. 내게는 몹시 난감한 일이었다. 그들의 주장이 틀리지 않았으니까. 적절한 분업이야말로 효과적인 협업이며, 모든 일에 모두가 참여해 온 기존의 방식이야말로 우직하다 못해 무식했다. 그러나 이 워크숍만큼은 팀 전체가 함께해야 했는데. 이미 같은 논의를 수 차례 반복해온 동료들은 자신이 더 보탤 것이 없다고 느꼈을지도 모른다.
이젠 내가 무엇을 어디서부터 설명해야 하는지도 모를 만큼 지쳐버렸다. 내가 너무 늦었는지, 아니면 반대로 성급했는지. 노련한 조직이었다면. 아니, 그랬다면 처음부터 이런 일은 없었을지도. 정말 상황만이 이들을 이렇게 만든 것일까? 내가 겪은 시간은 그들에 비할 바가 아니었지만, 몇 달째 진척이 없는 상황은 내게도 큰 피로를 안겼고, 바닥난 인내심은 사고를 차단하기 시작했다. 전부 갈아엎고 싶었다. 목적을 위해 한 명씩 대화하며 발품팔이로 신뢰를 쌓는 것은 내게 어렵지 않다. 그러나 그런 느린 방법으로 해결하기에는 더 두고 볼 문제가 아니었다. 문제를 직설적으로 짚고 변화를 요구할 만큼의 신뢰가 있었다면 좋았을 텐데, 그럼 앞서 같은 논의를 수십 번 되풀이하는 것을 지적했을 때, 또는 팀이 멈춰야 한다고 주장했을 때 이미 문제가 해결됐을지도. 이때만큼은 지시형 리더십이 간절했지만, 이 팀에 그런 권한을 가진 사람은 없었다. 차라리 내가 리더로 합류했더라면. 리더십은 한 가지 유형과 태도를 고수하는 것이 아니라 상황에 맞는 방식을 선택하는 것이니, 애초에 멈춰 있던 팀 하나의 일하는 방식을 강제로 바꾸는 일쯤은 오히려 정당하다고 봐야 했다.
이제 와 제안을 무를 수도 없었다. 워크숍은 해야만 했고, 이제는 팀의 회고보다 아이디어 탐색의 결과를 만들어야 했다. 물론 PO가 혼자 들고 있던 짐을 덜어내는 것도 바라던 목적이었으니, 이 일만큼은 해내야 했다. 참여자는 Product Owner와 UX 디자이너, 그리고 프로덕트 엔지니어인 나까지 셋이었다. 다른 이들이 무엇을 했는지는 기억나지 않는다. 그들도 미뤄 두었던 해야 할 일이 있었겠지.
우리는 우선, 기존 제품의 흐름을 모두 시각화했다. 그리고 PO가 붙들고 있던 큰 문제를 잘게 나누며, 무엇부터 검증할 것인지 정리해 나갔다. PO가 원하는 그림은 한 번에 도달할 수 있는 크기가 아니므로, 이를 PO 자신과 동료들이 납득할 수 있는 단위로 만들어야 했다. 처음에는 잘 풀리는 듯했다. 혼자 감당하던 생각을 밖으로 꺼내어 함께 고민하기 시작했다는 것만으로도 이전과는 달랐다. 그러나 시간이 갈수록 PO는 의욕을 잃어가는 듯했는데, 그 이유를 내가 단정할 수는 없다. 워크숍은 끝까지 이어졌지만 마무리는 어딘가 개운하지 않았고, 우리가 다음으로 나아갈 발판을 만든 것인지, 끝내지 못한 일을 하나 더 남긴 것인지 알기 어려웠다.
그리고 머지않아 그는 퇴사했다. 마지막 회식 자리에서 그는, 자신이 고집을 부렸다며 그간의 행동을 사과했다. 그는 떠나기 전에 자신의 잘못을 인정했고, 그것만으로도 나보다는 나았다. 나는 나중에 내가 저지를 잘못에 대해 그러지 못했으니까.
나의 시도는 결실을 맺지 못한 채 멈추었다. 곧이어 조직 개편이 예고됐다. 구체적인 날짜는 정하지 않았으나, 나는 이곳을 떠나기로 마음먹었다.
균열
아마도 이때쯤부터, 나는 냉소적으로 변하기 시작했다. 스쿼드만으로도 충분히 지쳐 있었는데, 동시에 나를 집요하게 괴롭혀 온 문제가 하나 더 있었기 때문이다. 때는 다시, 내가 스쿼드의 교착을 알지 못했던 때로 돌아간다.
매니저와의 갈등은 코드 리뷰에서 먼저 드러났다. 내가 그의 코드에 리뷰를 남기면 대화는 대개 서로의 논리를 반박하는 댓글로 이어졌다. 그 자체는 잘못이 아니다. 코드 리뷰는 다른 판단을 드러내고 더 나은 결론을 찾아 상호 학습하는 자리이기도 하다. 하나의 리뷰에서 지나치게 긴 토론을 벌여 병목을 만든 일도 손에 꼽았다. 기억하기로는 세 번 남짓. 그렇게 겉보기에는 괜찮아 보였던 이유는, 그가 답변 없이 PR을 병합하거나, 이미 구현했으니 다음에 개선하자며 내가 먼저 대화를 마무리했기 때문이었다.
그래서 문제는 토론의 길이가 아니라 반복이었다. 전에 남긴 것과 같은 리뷰를 남기고, 전에 내세운 것과 같은 논리로 거절했다. 이는 나와 매니저만의 갈등이 아니었던지라, 이 패턴은 팀의 회의에서도 반복됐다. 논의의 주제는 늘 같았고, 되풀이되는 과정은 우리에게 아무런 이득도 가져다주지 않았다. 철저한 대립이 있을 때면 끝내 반박하지 못하고 떠나는 것은 항상 그였는데, 이는 자명한 사실이지만 내가 옳았다는 반증은 결코 아니다. 그러나 나로서는 더 이상의 논리가 없음에도 의견을 꺾지 않는 태도를 이해할 수 없었다. 만약 그가 일부러 말을 아꼈다면, 그가 먼저 같은 논리를 펼치며 부딪히는 일은 없어야 했다. 나에게 의사결정은 일종의 스포츠와 같다고 생각하기에. 지금의 코드에서 볼 수 있는 나쁜 결과는 사실 그와 팀이 기존의 방식만을 고수해서 얻은 결과였는데, 그는 원인을 비즈니스의 복잡성이나 다른 데에서 찾는 모습을 보였다. 그에게는 처음부터 코드가 원인이 아니었으니, 어쩌면 이 대화는 성립조차 할 수 없었을지도. 그렇게 팀의 갈등은 지속되었고, 이 갈등이 스쿼드에서까지 수면 위로 올라온 것은 내가 기술 부채를 해결하겠다고 선언하면서부터였다.
우리가 맡은 제품에는 오래된 결함이 있었다. 스쿼드의 이름과도 같은 핵심 개념—이 글에서는 ‘별’이라 부르겠다—하나를 보여주기 위해 고객사의 모든 별을 가져왔고, 별 하나를 수정해도 모든 별을 다시 불러왔다. 고객사에 따라 별의 수는 많게는 수만 개에 달했다. 여기서 파생된 문제로 브라우저가 멈추는 일은 반복됐고, 고객에게는 별을 여러 묶음으로 나누어 관리하라고 안내하고 있었다. 물론 모든 고객이 그 안내를 납득한 것은 아니었다.
처음부터 잘못된 설계였다고 말할 수는 없다. 과거에는 고객사별로 관리할 별의 수가 많지 않으리라 예상했다고 들었고, 제품 초기에는 완성도보다 빠른 구현이 중요했을 테니 합리적인 결정이었다. 문제는 수요를 검증해 전제가 달라진 뒤에도 수년이 지나도록 같은 구조를 유지했다는 데 있었다.
데이터의 형태와 쓰임은 더욱 심각했다. 전체 별 목록을 보여주기 위해 만든 API 하나로 모든 기능을 구현하면서, 이를 사용하는 코드에는 응답값을 용도별로 가공하는 수백 줄짜리 계산 함수가 여럿 생겨났다. 그리고 이 함수와 타입들은 무엇을 위한 데이터인지 이름만으로는 알기 어려웠고, 그동안 의도를 잃은 수백 줄의 함수가 여기저기 쓰이며 새로운 프로퍼티가 덧붙여지면서, 데이터가 어디에서 오고 어디로 흐르는지 이해할 수 없게 되었다. 진작 API를 용도별로 나누고, 각 계산을 어느 쪽에서 맡을지 책임을 구분했어야 했다. 그러나 문제를 알리지 않았으니 동료들은 아무런 문제가 없는 줄 알았고, 훗날 조직 개편을 거치며 이 사실을 알게 된 백엔드 엔지니어들조차 왜 프론트엔드 엔지니어가 말없이 그렇게 구현했는지 납득하지 못했다.
보통의 나쁜 코드는 해당 기능을 고칠 때 함께 손보면 그만이다. 문제없이 동작한다면 굳이 건드릴 이유도 없다. 하지만 이 구조는 달랐다. 별은 우리가 맡은 도메인 그 자체였고, 그 결함은 이미 존재하는, 그리고 앞으로 만들 모든 기능에 심각한 영향을 줬다. 작은 변경도 거의 모든 페이지에 영향을 줬다.
엔지니어로서 외면할 수 없는 문제다. 직업인이라면 자신이 지켜야 한다고 믿는 가치를 주장하되, 필요하면 이를 포기하고 팀에 가장 도움이 되는 방향으로 결정해야 한다. 그러니 반드시 지금 고치자는 의도는 아니었다. 해결을 미루더라도 문제가 있다는 사실은 모두가 알아야 팀이 우선순위를 판단하고 적절한 때에 해결할 수 있으니까. 돈이 되는 것만 좇으며 모르는 척하는 것은 판단이 아니라 방관이었다. 나보다 한 달쯤 늦게 들어온 주니어 엔지니어도 같은 문제를 느끼고 있었다.
그러나 매니저는 반대했다. 이유를 분명히 듣지는 못했다. 진심으로 궁금해져 그에게, 시니어 엔지니어에게 무엇을 기대하는지, 직무를 떠나 내게 어떤 역할을 기대하는지 물었다. 그는 잠시 생각했지만 기능을 빠르게 만드는 것 이상의 답을 내놓지 못했다.
그의 답변만으로 그의 생각을 단정할 수는 없다. 그저 미리 생각해 두지 않았던 것일 수도 있지만, 당시 스쿼드의 사정을 신규 입사자에게 솔직하게 말하기 어려웠을지도 모른다. 이미 무너져가는 것을 알고 있던 팀에 굳이 신규 채용으로 나를 배치한 이유가 분명 있었을 테니까. 내 가정이 맞다면, 그에게는 내가 제품보다 코드 품질에 집착하는 사람처럼 보였을지도 모른다. 설령 내가 몰랐다고 하더라도.
어쨌든 이번만큼은 강하게 밀어붙인 끝에 동의를 얻었다. 그래야만 했다. 나는 팀이 요구한 제품 개선을 실행했고, 그 경험을 근거로 다시 주장했으니까. 문제를 모르는 다른 직무의 동료들에게는 내가 제품을 두고 다른 일로 빠지는 사람처럼 보였겠지만, 나 역시 이런 갈등 속에서 맥락을 나누지 못하는 나름의 고충이 있었다. 그렇게 일주일을 온전히 리팩터링에 쏟았던 것으로 기억한다. 그리고 이를 마지막으로 그가 내 주장에 물러선 적은 단 한 번도 없었다.
단절
매니저와 부딪히던 사람은 나만이 아니었다. 다른 시니어 엔지니어도 챕터 미팅과 긴 토론 스레드에서 그와 반복해 충돌하고 있었다. 나는 그 동료를 본받아, 이번 리팩터링의 진행 과정과 매 순간의 판단을 커밋 단위로 정리해 발표했다. 혼자 코드를 고치는 데서 끝내지 않고 무엇을 왜 바꾸었는지, 그 사고 과정을 챕터에 남기고 싶었다.
예상과 달리 반응은 미지근했다. 평소 같았다면 여기서도 충돌이 일어났어야 했지만, 그는 듣기만 하다 별다른 의견 없이 자리를 떠났다. 이전부터 품고 있던 의심이 확신에 가까워졌다. 어떤 이유로든 그는, 지금의 문제를 나와 같은 수준으로 보고 있지 않았다.
기술적인 문제는 우리 스쿼드에만 있지 않았다. 우리가 맡은 영역이 특히 심각한 레거시였을 뿐, 제품 전체의 코드베이스도 좋은 상태와는 거리가 멀었다. 나쁜 코드가 있다는 사실 자체는 괜찮다. 과거의 판단이 남긴 부채도, 당시에는 합리적인 이유로 미뤄 둔 부채도 있을 수밖에 없다. 개인의 역량 부족도 당연히 죄가 아니다. 문제는 같은 현상이 반복되는데도 피드백을 거부하고, 이를 누구도 막지 못한다는 데 있었다. 어지르는 사람 따로, 치우는 사람 따로. 우리에게는 합의된 기준도, 이견을 판정할 경로도, 피드백을 돌려줄 장치도 없었다.
개인이 뒤따라다니며 수습하고 변화를 이끌어내는 것보다 리더가 개입하는 편이 빨랐다. 그러나 그 역할을 맡아야 할 챕터 리드이자 매니저는 애초에 이를 문제로 여기지 않았고, 동료들의 요구에 대체로 반대했다. 코드 리뷰에서도, 챕터 미팅에서도, 기술 부채를 말할 때도 그랬다. 그는 나를 앞장서서 막는 동시에 시니어라면 문제 해결을 주도하고 사람들을 이끌어야 한다고 말했는데, 매니저의 반대가 힘들다는 내 말에도 자신이 줄곧 반대해왔다는 사실조차 인지하지 못하는 듯했다. 오히려 내게 unlearning을 요구했고, 나는 억울함을 참지 못해 원온원에서 언성을 높였다. 그와 아무리 더 이야기한들 서로에게 닿지 않으리라는 생각이 들었다.
나는 결국 그를 포기했다. 어차피 서로가 피드백을 받아들이지 못하니, 그냥 무시하기로 했다. 상황은 전혀 나아지지 않았지만 적어도 내 정신 건강에는 그편이 이로웠다. 주기적으로 있던 원온원도 바쁘다는 이유로 미루거나, 아무 문제도 없다며 말을 줄였다. 손가락 마디만 한 원형 탈모는 덤이었다.
시간이 지나 그는 갑자기 다른 스쿼드로 떠났다. PO가 퇴사한 것과 비슷한 시기였다. 그가 떠난 뒤 나와 주니어 엔지니어는 비로소 스쿼드의 기술 부채를 어떻게 다룰지 함께 고민하기 시작했다. 당장 모든 것을 고치겠다는 계획은 아니었다. 지금까지 쌓아온 문제를 팀이 제어할 수 있도록, 어떤 순서와 전략으로 풀어 갈지를 계획하는 일이었다.
그 시도는 결과적으로 성공했지만, 나는 스쿼드와 챕터 어디에서도 소속감이나 안정감을 얻지 못했다. 나 외에 유일한 시니어 엔지니어였던 동료도 곧 회사를 떠났다.
전환
이상 신호는 회사 밖에서도 나타났다. 회사는 오랫동안 ‘빠른 기능 구현’을 좋은 성과와 같은 말로 여겼다. 제품 품질은 날이 갈수록 떨어지면서 결국 고객의 날 선 비판을 들어야 했는데, 구체적인 내용은 적을 수 없지만 이는 회사가 결코 지나칠 수 없는 것이었다. B2B 고객이 이토록 거친 피드백을 주는 일은 드물다는 것을 생각하면 더더욱.
처음에는 몇 사람의 태도에서 비롯된 일이라고 생각했다. 그러나 분명 회사의 문화였다. 왜 이런 분위기가 형성되었는지는 누구도 알지 못했다. 메이커의 존재 의의는 무언가를 구현하는 데 있지만, 그것이 전부는 아니어야 하는데. 안타깝게도 도입기에 통했던 성공 방식이 지금의 조직에서 철칙으로 굳어졌으리라, 그렇게 추정했다.
조직 개편 전후로 나쁜 결과가 잇따르고 나서야 회사도 방향을 바꿨다. 슬랙에는 전략 변경이 공지됐고, 앞으로 스쿼드와 메이커의 행동 양식도 달라질 것이라는 설명이 붙었다. 돌이킬 수 없을 만큼 늦지는 않았지만, 분명 늦은 변화였다.
사실 나는 전부터 비슷한 문제를 주장해 왔다. 이제는 사라져버린 스쿼드의 경험에서 시작된 문제의식. 대체로 받아들여지지 않았지만 동의하는 리더도 있었으니, 내가 모르는 곳에서 변화를 준비하는 데 시간이 필요했으리라 생각한다. 내 판단이 여전히 옳다면 이번에는 설득을 위한 더 많은 근거가 필요했고, 영역을 넓혀 다른 직무를 가진 동료들의 이야기를 듣고 문제를 분석하고 있었다. 수집한 현상들의 인과 관계를 연결해 악순환을 찾고, 시스템 원형과 인과 루프 다이어그램으로 정리했다.
그러나 일은 이미 벌어졌다. 충분히 준비할 틈도 없이, 고객의 피드백에 이어 전략 변경 공지가 올라왔다. 나는 정리하던 자료를 곧바로 답글에 붙였다. 아쉽게도 예견했던 결과를 막을 수는 없었으나, 그 결정이 왜 필요했는지, 우리가 막지 못한 결과를 두고 무엇을 바꿔야 하는지 논의할 근거는 될 수 있었다. 여러 미팅과 원온원이 뒤따랐고, 비로소 대화가 시작됐다.
다시 스쿼드로 돌아와서, 조직 개편이 끝났다고 모든 문제가 곧바로 풀리지는 않았다. 맡은 일은 그대로였지만 스쿼드 구성원의 절반 이상이 바뀌었고, 우리는 처음부터 다시 합을 맞춰야 했다. 이는 오랜 시간이 필요한 일이고, 나는 이미 지독하게 지쳐 있었다. 그래도 이번 스쿼드는 문제가 생기면 함께 들여다보려는 태도를 가지고 있었기에, 그것이 긍정적인 신호라는 사실만은 분명했다.
재건
전략은 바뀌었고 팀 빌딩도 필요했지만, 우선 급한 불부터 꺼야 했다. 내가 합류하기 전을 포함해 이전 스쿼드가 2년 가까이 표류하는 동안 쌓인 고객의 요구는 적지 않았고, 그 탓에 풀어야 할 문제와 접근도 어느 정도 정해져 있었다. 이는 내가 바라던 형태의 일이 아니지만, 대충 할 이유는 없었다.
이 일을 진행하며 발견한 팀의 문제는, 계획을 실행한 다음에야 결정하지 않은 사항이 계속 나타났다는 점이다. 해보기 전에는 모든 것을 알 수 없으니 당연한 현상이지만, 그 정도가 심했다. 아무 일도 하지 못했던 팀에 있었던 나로서는 과거의 모습들이 겹쳐 보였다.
다행히도 이번에는 팀이 그 현상을 그냥 두지 않았다. 우리는 구현을 시작하기 전에 해결하려는 문제와 기대 효과, 다른 작업과의 의존성을 먼저 확인하기로 했다. 어디까지 만들면 완료한 것으로 볼지 인수 기준을 맞추고, 누가 무엇을 실행할지도 미리 정했다. 우리에게 맞는 준비의 정의(Definition of Ready)를 만들어 나갔다. 분명 내가 주도한 일이었고 없는 것보다는 나았지만, 내게는 애초에 이런 상황이 벌어진다는 사실부터 만족스럽지 않았다. 나는 과거의 그들처럼, 점차 조급해지고 있었다.
급한 작업을 모두 마친 뒤에야 비로소 제품·기술 부채를 다룰 시간이 생겼다. 전략 변경에 따른 새로 온 PO의 제안이었다. 스쿼드 구성원 모두가 동의한 채 이런 일을 하는 것은 처음이었다. 이전에 동료 엔지니어와 세운 계획은 일종의 타협이었는데, Layered Architecture를 설계해 레거시와 격리된 틀을 만들고, 기능을 구현하다 레거시 코드를 건드려야 할 때, 비로소 개선해 옮기는 방식이었다. 그런데 갑자기 부채만 해결할 시간이 생기다니. 부채가 얼마나 있든지는 중요하지 않고, 그저 팀이 이런 결정을 내릴 수 있다는 것 자체로 묵은 체증이 내려가는 듯했다.
조직 개편 전에 별—스쿼드의 핵심 개념—의 데이터 형태와 가공 함수를 분류하고 개선해 둔 덕분에, 이번에는 API를 용도에 맞게 나눌 수 있었다. 다음으로 대량의 별을 처리하는 가공 함수의 알고리즘을 고쳐 병목을 걷어냈고, 모든 별을 보여주는 UI의 렌더링 시간은 정상 범위 안으로 들어왔다. 브라우저가 멈추는 상황을 피하려고 고객에게 별을 여러 묶음으로 나누어 사용하라는 안내도 필요 없어졌고, 별을 한 묶음으로 관리하고 싶어 하던 꽤나 큰 고객사의 계약 연장 조건도 받아들일 수 있게 됐다. 나에게는 이 회사에서, 기존 기능의 기술적인 문제를 해결해 비즈니스에 영향을 준 첫 사례였다.
그러나 기쁘지는 않았다. 새로운 경험으로 모든 문제를 한 번에 해결하려던 고집과 부채를 문제로 보지 않던 무지함이 고객을 오랫동안 불편하게 만든 것이니까. 내게 이 모든 상황은, 별일도 아닌 걸 질질 끌다가 이제야 해결한다는 생각뿐이었다.
더는 마음의 여유가 없었다. 그런 생각을 하는 내가 싫어서, 나는 퇴사를 결정했다.
매듭
퇴사일은 석 달 뒤로 잡았다. 나는 원래 퇴사일을 넉넉히 정하는 편인데, 마음을 준비하기에는 충분히 길고, 생각이 달라진다면 결정을 되돌리기에도 늦지 않은 시간이다. 회사에는 두 달 뒤 알리기로 했다. 재직한 지 정확히 1년이 되던 때였다.
떠날 날짜를 정하니 오히려 마음은 차분해졌다. 회사에 대한 기대는 더 이상 찾아볼 수 없지만, 그렇다고 동료들을 포기한 건 아니었다. 떠나기 전 무엇을 남겨야 회사에 도움이 될지를 고민했다.
마지막으로 붙들고 있던 일은 크게 두 가지였다. 하나는 직업인으로서 동료들이 외부 도움 없이도 코드를 제어하고 관리할 수 있는 기반을 남기는 것. 다른 하나는 리더십으로 회사의 구조적 문제를 분석해 해결의 실마리를 남기는 것. 후자는 앞서 말한 그것이다. 구조적인 문제가 풀리면 스쿼드 내부, 그리고 스쿼드와 이해관계자 사이의 문제는 알아서 풀 수 있으리라 생각했다.
그래서 통합·인수 테스트 환경을 만들었다. 내가 떠난 뒤에도 동료들은 이 낡은 코드 위에서 계속 제품을 만들어야 했고, 변경의 영향 범위는 넓고 예측하기도 어려워 동작이 망가졌는지 즉시 확인할 수 있는 방법이 필요했다. E2E 테스트는 있었지만 우리의 빠른 작업 흐름에는 맞지 않아 방치돼 있었다—E2E 테스트는 전략과 프로세스가 수반되지 않으면 대체로 안착에 실패한다—. 이미 있던 단위 테스트 환경을 그대로 쓸 수 있었다면 좋았겠지만, 소스코드가 여러 페이지에 걸친 동작을 테스트할 수 있도록 작성되지 않아, 스쿼드의 업무가 끝난 뒤 남는 시간마다 하나씩 리팩터링해야 했다. 그 탓에 정작 인수 테스트는 몇 개 작성하지 못했다.
전략 변경은 챕터에도 영향을 미쳤다. 기술 부채를 해결하라는 지시와 여러 과업이 내려왔고, 나는 스쿼드에 새 아키텍처를 도입한 경험이 있다는 이유로 챕터의 코드 작성 패턴과 규칙을 통일할 기준을 만드는 TF를 맡았다. 계획에 없던 일이었고 이미 바빴지만, 무리해서라도 팀에 더 도움이 되고 싶었다. 그 과정에서 매니저는 다른 TF에 참여하려던 동료 한 명을 의사결정의 균형을 맞춘다는 이유로 우리 TF에 옮겼다. 그 동료는 신중한 성격으로 반대를 자주 하는 동시에 자신이 블로커가 될까 봐 걱정하던 사람이었는데, 당시의 나는 매니저가 나를 믿지 못해 자기 편을 붙였다고 의심했다. 지금은 그런 의도가 아니었다고 생각하지만, 당시에는 사실인지 확인할 방법도, 그럴 생각도 없었다. 이미 그를 불신하던 당시의 내게는 불쾌한 경험이었다. 의도가 무엇이었든, 우리는 아무런 문제없이 챕터가 오랫동안 합의하지 못했던 좋은 코드와 설계의 기준, 이를 적용하는 방법과 해결 사례를 문서로 남겼다.
이를 계기로 내가 스쿼드에서 해 온 개선도 알려졌다. 사실 진작에 공유했었지만, TF의 결과물 덕분에 확실히 이목을 끌었다. 매니저는 설계 의도와 효과를 발표해 달라고 요청했다. 다른 동료들도 원했고, 예전의 나였다면 기대했을 반응이었다. 그러나 나는 반가움보다 ‘이제 와서 왜?’라는 생각이 먼저 들었다. 지금까지 반대만 했었는데. 나는 이미 칭찬조차도 곧이곧대로 받아들이지 못하는 사람이 되어 있었고, 그런 나를 혐오하며 반드시 떠나야겠다고 다짐했다.
용기
그렇게 두 달이 흘렀다. 나는 예정대로 퇴사 의사를 알렸다. 그동안의 갈등과 노력을 알아준 한 리더는 부서 이동을 권하며 나를 회유했으나, 마음은 바뀌지 않았다. 그때의 내게 지난 경험은 한 것도 배운 것도 없이 버려진 시간으로 느껴졌고, 무언가 만들고 싶다는 억눌린 욕구를, 회사를 떠나 1인 창업으로 풀고 싶었다. 그것이 현실 도피를 위한 자기합리화였는지도 모른다. 계획이 있다고 스스로를 속여야 떠날 수 있었으니까.
그때는 마침 인사평가 기간이었다. 퇴사까지 일주일도 남지 않았을 무렵, 한 동료에게서 내가 무섭게 말한다는 피드백을 받았다. 이미 알고 있어 놀랍지는 않았다. 표현은 전보다 거칠어졌고, 표정에서는 냉소를 감추지 못했다. 동료가 같은 실수를 반복하면 필요 이상으로 날을 세웠고, 회고에서는 동료들이 감당할 이유 없는 감정을 드러냈다. 바깥의 동료들은 몰랐겠지만, 적어도 스쿼드 안에서의 나는 생각을 편하게 나누기 어려운 사람이 되어 있었다.
그런 행동을 하는 나와 이를 지켜보는 내가 분리되고 있었다. 처음 겪는 현상이었다. 모든 일에 항상 진심이 필요하다고 생각하지는 않지만, 결코 내 방식은 아니었다. 나는 일정 초대 메일로 장문의 편지까지 쓰던 사람이었으니까. 아마 그때의 나는 회사와 동료들로부터 존중받기는커녕 핍박받고 있다고 느꼈던 것 같다.
이미 알고 있었다는 사실은 잘못을 가볍게 하지 않는다. 나는 문제를 해결해야 한다는 조급함을 이유로, 그 문제를 만들지도 않은 동료들에게까지 쌓인 감정을 떠넘겼다. 문제를 함께 풀어나갈 사람을 설득의 대상이나 잘못을 통제해야 할 대상으로만 대했다. 더 이상 내 태도를 조절하지 못했고, 서로를 위해서라도 회사를 제 발로 떠나야 했다.
그러나 최악인 것은 피드백을 받고도 떠나기 전에 사과하지 않은 것이다. 애초에 깊은 관계를 맺지도 못했지만, 회복할 기회마저 놓쳤다. 퇴사가 얼마 남지 않았다는 사실 뒤에 숨은 채 도망치듯 회사를 떠났고, 먼저 자기 잘못을 사과하고 떠난 Product Owner가 부러웠다.
그리고 매니저는 고객 가까이에서 요구사항을 빠르게 구현하는 데 강점이 있는 사람이었다. 그 지점에선 분명 나보다 뛰어났고, 그와의 갈등은 그저 인사 배치의 실패에 불과했다. 누구도 직접 맡겨보기 전에는 그가 역할을 잘 해낼지 알 수 없으니까. 회사는 그의 강점을 살리는 방향으로 역할을 조정하거나, 지금의 포지션을 그대로 유지한다면 기대에 맞게 성장하도록 적절히 피드백을 제공해야 했다. 그랬다면 서로 좋은 동료가 되었을지도. 그러므로 문제는 누가 더 나은 엔지니어였는지가 아니다. 결과는 실패가 맞지만, 이를 회사의 잘못이나 개인의 악의라고 말하고 싶지도 않다. 나는 이제 그를 원망하지 않는다. 지금까지 내 매니저를 나쁘게만 적은 듯해 글을 덧붙인다.
물론 결과는 내 문제의식이 틀리지 않았음을 보여주었다. 내 주장은 고객의 반응이 되어 돌아왔고, 회사는 방향을 바꿨다. 받아들여지지 않던 문제들은 뒤늦게 회사의 과제가 됐다. 인정받지 못하는 일을 하려면 용기가 필요하다. 누구도 듣고 싶어 하지 않는 말을 하고, 반대 속에서도 해야 한다고 믿는 일을 주장해야 하니까. 그렇다고 해서 내가 동료들에게 보인 태도가 달라지지는 않는다. 옳았다는 사실이 그릇된 행동을 정당화해서는 안 된다.
이 글이 그때 하지 못한 사과를 대신할 수는 없다는 건 안다. 나는 반대 속에서 주장할 용기도, 회사를 떠날 용기도 있었지만, 그 과정에서 잘못한 일을 인정하고 사과할 용기는 없었다. 그러므로 내가 옳았다는 기억만 남기지 않기 위해, 반성의 의미로 내 잘못들을 비겁하게나마 이곳에 기록하며 글을 마무리한다.