내 질문이 ‘공격’이 될 때

어느 답답했던 코드 리뷰에 대한 회고

by Damon

그날, 코드 리뷰는 나에게 ‘전쟁’이었다


코드 리뷰 알림이 도착했다. 동료가 올린 코드 변경 사항에 몇 가지 의문이 보였다. 나는 시스템의 안정성을 위해, 잠재적 위험을 발견한 리뷰어로서 당연한 질문을 던졌다.


“faucet 주소 무한 대입 문제 아직 남아있는 것 같은데 문제 없나요?”


하지만 그 질문으로 시작된 대화는, 내가 상상했던 건설적인 기술 토론과 전혀 다른 방향으로 흘러갔다. 나의 질문은 끝없는 방어와 부딪혔고, 명확한 근거를 요구하는 나의 목소리는 어느새 상대의 판단에 도전하는 ‘공격’으로 취급받고 있었다. 대화는 빙빙 돌았고, 문제 해결에 쏟아야 할 나의 에너지는 답답함, 짜증, 그리고 분노라는 감정과 싸우는 데 소모되었다.


이 글은 그날의 소모적인 논쟁에 대한 나의 복기이자, 나와 같이 ‘좋은 의도’가 ‘나쁜 소통’으로 변질되는 경험을 한 모든 동료 개발자들을 위한 회고록이다.



평행선을 달린 대화의 재구성: 무엇이 우리를 지치게 만들었나


그날의 대화를 다시 복기해보면, 문제는 두 개의 다른 차원에서 동시에 발생하고 있었다.


1. 1차원적 문제: ‘근거’ 없는 대답, ‘신뢰’ 없는 질문

나의 첫 번째 좌절은 소통의 가장 기본적인 단계에서 시작되었다.

나의 요청은 명확했다: 나는 “방지할 필요 없는 이유를 알 수 있을까요?”, “코드나 설명만 봐선 근거를 모르겠습니다”라고 반복해서 물었다. 시스템의 리스크를 관리하기 위해, 동료의 판단에 대한 ‘논리적 근거’를 공유해달라는 지극히 당연한 요청이었다.


하지만 돌아온 답변은 ‘선언’이었다: 동료는 “파셋은 testnet testtoken이라 상관이 없습니다”라고 답했다. 그에게는 이 한 문장이 모든 것을 설명하는 ‘근거’였겠지만, 나에게는 어떤 맥락도, 논리도 없는 ‘결론’일 뿐이었다. 그는 “이건 도메인 이해가 부족하신 것 같은데 만약 안해봐서 모른다고 하셨으면 더 설명할 수 있었을거 같습니다”라고 말하며, 소통의 책임을 나의 ‘지식 부족’으로 돌렸다.


이 단계에서 이미 우리의 대화는 어긋나고 있었다. 나는 계속해서 ‘왜?’라는 질문을 던졌지만, 그 질문은 상대방의 방어적인 태도에 막혀 허공에 흩어졌다.


2. 2차원적 문제: 서로 다른 ‘위험’을 바라보는 시선

대화가 깊어질수록, 우리는 단순히 소통 방식만 다른 것이 아니라 ‘문제’를 바라보는 근본적인 ‘관점’ 자체가 달랐다는 것을 깨달았다.

동료가 본 위험: 그의 주장은 일관되게 ‘테스트 토큰의 무가치성’에 기반했다. 그에게 위험이란, 실제 자산 손실이나 메인넷의 보안 취약점 같은 직접적이고 심각한 것이었다. 테스트 토큰에는 그런 위험이 없으니, 그는 이것을 “감안하고 넘어갈 수 있는 문제”로 정의했다.


내가 본 위험: 하지만 나의 우려는 토큰의 가치에 있지 않았다. 나는 그로 인해 발생할 ‘사이드 이펙트’를 보고 있었다.
1. 가용성: 악의적인 무한 대입으로 “24시간동안 아무도 이 서비스를 쓸 수 없다”는 명백한 서비스 장애.
2. 신뢰도: “내가 발급하지도 않은 토큰이 내 지갑에 발급된 문제”가 주는 사용자의 혼란과 불신.
3. 시스템 건전성: 불필요한 “네트워크 트래픽의 상승”이 시스템 전반에 미칠 영향.


그에게는 ‘사소한 문제’가, 나에게는 ‘P0/P1 레벨의 심각한 이슈’였다. 우리는 같은 코드를 보며, 완전히 다른 종류의 위험을 평가하고 있었던 것이다. 이 철학적 차이를 인지하지 못하는 한, 우리의 대화는 영원히 평행선을 달릴 운명이었다.



벽을 허무는 기술: ‘나의 답답함’을 ‘우리의 과제’로 바꾸는 법

그날의 논쟁이 끝난 후, 나는 깊은 무력감에 빠졌다. 하지만 그 감정이 잦아들자 한 가지 깨달음이 찾아왔다. 이 싸움은 ‘누가 옳은가’를 가리는 논쟁이 아니라, ‘어떻게 상대방을 방어적인 태도에서 벗어나게 하고, 건설적인 대화의 장으로 이끌 것인가’ 라는 전략의 문제였다는 것이다.


나는 앞으로 비슷한 상황에서 나의 귀한 시간과 감정을 소모하지 않기 위해, 몇 가지 소통의 ‘기술’을 준비하기로 했다.


기술 1: 프레임 전환 - "제가 이해할 수 있도록 도와주세요" 직접적으로 "왜죠?"라고 묻는 대신, 나의 이해 부족을 전제로 도움을 구하는 방식이다.

"제가 이 도메인에 대한 컨텍스트가 부족해서 그러는데, 'testnet이라 괜찮다'는 것이 어떤 위험들(예를 들어 가용성 문제 같은)까지 감수할 수 있다는 의미인지 조금만 더 풀어주실 수 있을까요? 제가 더 잘 이해하고 싶어서요."


기술 2: 역할 부여 - "제가 다른 사람에게 설명해야 해서요" 상대방의 판단을 존중한다는 신호를 주면서, 정보 공유의 필요성을 자연스럽게 설득하는 방식이다.

"B님의 판단을 존중합니다. 다만 제가 나중에 이 결정의 배경을 다른 동료들에게 설명해야 할 때를 대비해서, '이러한 리스크가 있지만, 이러이러한 이유로 감수하기로 결정했다'고 명확하게 전달할 수 있도록 B님의 생각의 흐름을 조금 더 자세히 알고 싶습니다."


기술 3: 논의의 차원 격상 - '이 케이스'에서 '우리 팀의 원칙'으로 개인 간의 논쟁을 팀 전체의 건설적인 과제로 전환하는 것이다.

"이 논의를 통해 우리 팀이 '리스크를 판단하는 기준'에 대해 아직 명확한 합의가 없다는 것을 알게 된 것 같습니다. 좋은 기회이니 다음 팀 회의 때 '테스트넷 환경에서 허용 가능한 서비스 장애 수준과 범위'에 대해 다 같이 이야기해보는 건 어떨까요?"


이 기술들은 상대방을 비난하지 않으면서, 내가 원하는 ‘명확한 근거’를 얻어내고, 소모적인 논쟁을 팀의 성장을 위한 논의로 발전시킬 수 있는 강력한 도구가 될 것이다.



나의 질문은 팀을 위한 것이기에

그날의 코드 리뷰는 나에게 깊은 짜증과 분노를 남겼다. 하지만 이제 나는 안다. 나의 질문은 틀리지 않았다는 것을. 시스템의 안정성과 신뢰도를 위해 잠재적 위험을 파고드는 것은 동료 개발자로서의 당연한 책무이자 권리다.


다만, 그 당연한 책무를 이행하는 과정에서 불필요한 오해와 감정 소모로 스스로를 지치게 할 필요는 없다. 나의 질문이 ‘공격’이 아닌 ‘협력의 손길’로 상대방에게 닿을 수 있도록, 나는 더 지혜롭게 소통하는 방법을 익혀나갈 것이다.


결국 최고의 코드는 가장 뛰어난 개인이 아니라, 가장 건강하게 소통하며 공동의 목표를 향해 나아가는 팀이 만들어내는 것이므로. 나는 더 이상 동료와의 소통에서 무력감을 느끼지 않기로 다짐한다.