소프트웨어 엔지니어 - 좋은 팀에 대한 고찰

좋은 팀이란 무엇인가

개발자로서 좋은 코드, 좋은 아키텍처에 대한 글은 정말 많이 읽었습니다. 하지만 좋은 팀에 대한 이야기는 늘 추상적이거나, "심리적 안전감"이라는 단어 하나로 끝나는 경우가 많았습니다.

저는 세 개의 회사를 경험했고, HoBom이라는 사이드 프로젝트를 4년째 운영하고 있습니다. 그 과정에서 좋은 팀과 아쉬운 경험을 가지게 한 팀을 모두 경험했습니다. 오늘은 그 경험을 바탕으로, 좋은 팀이란 무엇인가에 대한 저의 생각을 이야기해 보려 합니다.

기술이 아니라 팀이 시스템을 망가뜨린다

이전 글에서 에듀테크 회사의 FCM 마이그레이션 이야기를 한 적이 있습니다. Spring Boot 1.5로 작성된 푸시 서버, deprecated된 FCM API, 그리고 팀 내에 Spring Boot를 할 줄 아는 사람이 저 하나뿐이었던 상황.

당시 저는 이 문제를 기술부채라고 생각했습니다. 사실 도망가고 싶기도 했습니다. 하지만 돌이켜 보면, 이건 기술의 문제가 아니었을 지도 모릅니다. 어쩌면 진짜 문제는 팀이 기술을 함께 소유하지 않았던 것이 문제가 아니었을까요?

당시에는 Spring Boot 서버를 처음 만든 사람은 이미 퇴사한 뒤였고, 그 시스템의 맥락은 누구에게도 전달되지 않았습니다. 팀은 Node.js를 공통 스택으로 선택했지만, 이미 운영 중인 Spring Boot 서버에 대해서는 "그건 건드리지 말자"는 암묵적 합의가 있었습니다. 언제 터질지 모르는 폭탄을 서로 돌려막고 있는 상황이었습니다.

결국 이러한 팀의 기술 소유의 부채는 단순한 API 마이그레이션에 전면 재작성이라는 비용을 치러야 했습니다. 이러한 사례는 사실, 기술 스택의 문제가 아니라, 팀이 시스템을 함께 소유하지 않은 것이 근본 원인 이었을지도 모릅니다.

합의와 결정은 다르다

인터넷 은행에서 대출 심사 시스템을 운영하며 경험하고 배운 것이 있습니다. LoanApp 테이블의 Status와 LoanAppStep이 서로 얽혀 기술부채가 된 이야기는 이전 글에서도 다뤘습니다. 이 설계가 만들어질 당시에는 상품이 하나뿐 이었습니다. 당시 팀에서 이 구조를 선택한 것은 합리적이었을 겁니다. 하지만 문제는 당시의 그 결정이 "지금 이게 편하니까"라는 합의로 이루어졌다는 것입니다.

좋은 팀에서의 결정은 다릅니다.

  • "지금은 상품이 하나지만, 늘어나면 이 구조는 어떻게 되는가?"
  • "이 선택의 유효기간은 언제까지인가?"
  • "이 결정을 되돌리는 비용은 얼마인가?"

이런 질문을 던지는 사람이 팀에 한 명이라도 있었다면, 상황은 달라졌을 겁니다. 합의는 "다들 괜찮다고 하니까" 라는 의미고, 결정은 "이 선택의 트레이드오프를 이해하고, 그 비용을 감수한다"는 것입니다. 좋은 팀은 합의가 아니라 결정을 합니다.

"왜?"라고 물을 수 있는 팀

세 개의 회사를 경험하며 가장 크게 느낀 차이점은 기술 스택도, 아키텍처도 아니었습니다. "왜?"라고 물을 수 있는 분위기가 있느냐 없느냐였습니다.

  • "왜 이 프레임워크를 쓰나요?"
  • "왜 이 구조로 설계했나요?"
  • "왜 이 방식으로 운영하나요?"

이 질문들은 기술적 질문처럼 보이지만, 실은 팀 문화에 관련된 질문입니다.

"왜?"라고 물었을 때, "원래 그렇게 해왔으니까"라는 답이 돌아오는 팀과, "좋은 질문이다, 다시 생각해 보자"라는 답이 돌아오는 팀은 근본적으로 다릅니다.

에듀테크 회사에서 Spring Boot 서버를 "건드리지 말자"고 한 것도, 결국은 "왜 이 서버가 이렇게 되어 있는지?"라는 질문을 아무도 하지 않았기 때문이었습니다. 어쩌면 궁금하지 않았을 수도 있겠지요.

물어볼 수 없었던 건지, 물어볼 필요를 못 느낀 건지는 잘 모르겠습니다. 어느 쪽이든, 결과는 같았습니다.

코드 리뷰는 문화의 거울이다

PR 리뷰를 보면, 좋은 팀인지 아닌지 어느정도 가늠이 될지도 모릅니다. 코드 리뷰에서 "이 변수명 바꿔주세요"만 주고받는 팀이 있고, "이 책임이 여기 있는 게 맞나요?"를 주고받는 팀이 있습니다. 전자는 스타일 리뷰입니다. 후자는 설계 리뷰입니다.

스타일 리뷰만 하는 팀에서는 아키텍처가 조용히 무너집니다. 아무도 "이 Service가 너무 많은 책임을 갖고 있지 않나요?"라고 묻지 않기 때문입니다. 반대로, 설계 리뷰를 하는 팀에서는 코드가 쌓일수록 시스템이 견고해집니다.

하지만 여기에도 트레이드오프가 있습니다. 설계 리뷰를 지나치게 강조하면 속도가 느려집니다. 모든 PR에서 아키텍처 토론을 할 수는 없습니다. 좋은 팀은 "이건 스타일 리뷰로 충분하다"와 "이건 설계 논의가 필요하다"를 구분할 줄 압니다.

현업에서 5만줄 이상의 코드가 정말 많을 텐데, 설계가 없는 코드는 어쩌면 아쉬울지도 모릅니다.

장애 앞에서 팀의 본질이 드러난다

시스템 장애가 발생했을 때, 팀의 반응은 두 가지로 나뉩니다. "누가 이렇게 만들었어?" vs "왜 이런 일이 발생했고, 어떻게 방지할 수 있을까?" 전자는 사람을 탓합니다. 후자는 시스템을 개선합니다. 사람을 탓하는 팀에서는 실수를 숨기게 됩니다. 실수를 숨기면 같은 장애가 반복됩니다. 시스템을 개선하는 팀에서는 실수를 공유합니다. 공유하면 같은 장애는 한 번만 겪습니다. HoBom 시스템에 Gateway와 traceId 기반 중앙 로깅 구조를 도입한 이유도, 결국은 "에러를 투명하게 추적하고 싶었기 때문"이었습니다. 기술적 설계의 출발점이 결국 팀이 문제를 어떻게 다루느냐의 철학에서 비롯된 셈입니다.

HoBom 프로젝트에 대한 솔직한 회고

HoBom은 저와 저의 사랑하는 사람, 둘이서 4년째 운영하고 있는 사이드 프로젝트입니다. 2인 팀의 장점은 명확합니다. 방향성 정렬이 빠르고, 의사결정에 마찰이 적습니다. NestJS, Go, Spring Boot를 함께 쓰기로 한 결정도, 서로의 맥락을 완벽히 이해하고 있었기에 가능했습니다.

하지만 솔직히 말하면, 이것이 좋은 결과인지는 확신하지 못하겠습니다.

2인 팀은 반론이 부족합니다.

둘 다 비슷한 경험을 했고, 비슷한 결론에 도달하기 쉽습니다. "왜 Kafka를 써야 하는가?"라는 질문에 서로가 이미 같은 답을 가지고 있다면, 그건 검증이 아니라 확인에 불과합니다.

사이드 프로젝트에 Kafka, gRPC, 4개의 서버를 운영하는 것이 적절한 규모인가? 모놀리스로 충분하지 않았는가?

이 질문들은 팀 외부에서 와야 하는 질문입니다. 그리고 HoBom 팀에는 그 외부가 없었습니다.

이것이 제가 이 블로그를 운영하는 이유이기도 합니다. 글을 통해 외부의 시선을 빌리고 싶었습니다.

좋은 팀은 상태가 아니라 방향이다

세 개의 회사와 하나의 사이드 프로젝트를 경험하며 내린 결론은 이것입니다. 좋은 팀은 완성된 상태가 아닙니다.

  • 기술을 함께 소유하려는 팀
  • 합의가 아니라 결정을 하려는 팀
  • "왜?"라고 물을 수 있는 팀
  • 코드 리뷰에서 설계를 논의하는 팀
  • 장애 앞에서 사람이 아니라 시스템을 개선하는 팀

이 모든 것을 완벽히 해내는 팀은 존재하지 않을 겁니다. 중요한 것은 이 방향으로 나아가려는 의지가 있는가입니다.

  • 좋은 시스템이 확장 가능하고 지속 가능해야 하듯, 좋은 팀도 확장 가능하고 지속 가능해야 합니다.

시스템 설계에서 제가 던졌던 질문을 팀에도 동일하게 적용할 수 있습니다.

  • 이 팀은 사람이 바뀌어도 지속 가능한가?
  • 이 팀의 의사결정 구조는 규모가 커져도 작동하는가?
  • 이 팀은 3년 뒤에도 함께 일하고 싶은 팀인가?

이 질문에 답할 수 있는 팀이, 좋은 팀이라고 생각합니다.