-
모노레포의 실패가 아닙니다, 엔지니어링 규율의 실패입니다.ANYTHING 2025. 11. 23. 08:45반응형

최근 "모노레포 절망편, 14개 레포로 부활하기까지 걸린 1년"이라는 글을 봤습니다. (링크)
한 기업이 비대해진 모노레포의 복잡성을 감당하지 못하고, 14개의 폴리레포(Polyrepo)로 서비스를 분리하며 안정성을 되찾았다는 일종의 '탈출기'입니다. 많은 분들이 이 글을 보고 "역시 모노레포는 어렵구나", "우리도 나누는 게 답인가?"라고 생각하셨을지 모릅니다.
하지만 저는 이 사례를 조금 다른 시각, 아니 더 본질적인 엔지니어링 관점에서 바라보고 싶습니다.
과연 그들이 겪은 고통의 원인이 '모노레포라는 아키텍처' 때문이었을까요? 제가 보기엔 '테스트와 경계(Boundary)라는 기본기의 부재'가 진짜 원인으로 보입니다.
1. "Product Stock Checker"가 말해주는 진실
원문에 등장하는 실패 사례 중 가장 인상적인 대목이 있습니다.
*"단순 상품 재고 조회 UI 컴포넌트에 '재주문 비즈니스 로직'이 섞이고, 심지어 '고객 만족도 조사 폼'까지 들어갔다."*
이것은 모노레포의 잘못이 아닙니다. 전형적인 관심사 분리(Separation of Concerns) 실패이자 단일 책임 원칙(SRP) 위반입니다. UI 컴포넌트가 비즈니스 로직과 섞이고, 캡슐화가 깨진 채 아무나
import해서 쓰게 만든 것은 '나쁜 코드'이지 '나쁜 저장소 전략'이 아닙니다.이런 코드는 레포지토리를 100개로 쪼개도 똑같이 문제를 일으킵니다. 단지
npm install로 얽힌 '분산된 스파게티(Distributed Spaghetti)'가 될 뿐입니다.2. 테스트 없는 코드는 시한폭탄이다
원문에서 팀이 겪은 가장 큰 공포는 "내가 수정한 코드가 어디서 터질지 모른다"는 것이었습니다. 제대로 된 모노레포 환경이었다면, 의존성 그래프에 기반한 자동화된 테스트가 변경 사항의 영향 범위를 정확히 검증해 줬어야 합니다.
하지만 그들에게는 '믿을 수 있는 테스트'가 없었습니다. 결국 그 불안감을 해소하기 위해 "물리적 분리(격리)"라는 극단적인 처방을 내린 것입니다.
3. 그럼에도 불구하고, 왜 그들은 '14개의 레포'를 선택했는가?
여기서 우리는 한 가지 중요한 질문을 던져야 합니다. "그들은 왜 테스트를 보강하고 CI를 고치는 '정공법' 대신, 레포지토리를 찢는 고단한 작업을 선택했을까?"
단순히 몰라서 그랬던 것은 아닐 것입니다. 여기엔 엔지니어링 이상론만으로는 설명할 수 없는 현실적인 이유들이 존재합니다.
- 첫째, '폭발 반경(Blast Radius)'의 물리적 차단
테스트 코드를 작성하고 커버리지를 높이는 것은 '오랜 시간'이 걸리는 투자입니다. 당장 오늘 배포가 막히고 장애가 터지는 상황에서, 레포지토리 분리는 "내 코드가 남의 서비스를 망가뜨리지 않는다"는 심리적 안정감을 즉각적으로 제공합니다. 비록 그것이 기술 부채를 미래로 미루는 것일지라도, 당장의 '심리적 안전'이 급했던 것입니다. - 둘째, 툴링(Tooling) 역량의 한계와 인지 부하
거대 모노레포를 지탱하려면 Nx, Bazel, Turborepo 같은 툴을 아주 정교하게 다룰 수 있는 '플랫폼 엔지니어링' 역량이 필수적입니다. 영향 범위를 계산하고, 캐싱을 최적화하여 빌드 속도를 방어해야 합니다. 하지만 비즈니스 기능 개발에 쫓기는 조직에게 이러한 '도구 관리 비용'은 감당하기 힘든 오버헤드였을 것입니다. 차라리 "느리더라도 확실히 분리된" 환경이 인지 부하를 낮춰준다고 판단했을 것입니다. - 셋째, 콘웨이의 법칙 (Conway's Law)
조직은 이미 여러 스쿼드로 나뉘어 있는데, 코드만 하나로 뭉쳐 있으니 배포 병목이 생깁니다. "우리 팀 배포가 저 팀 때문에 막힌다"는 불만을 해소하기 위해, 조직 구조에 맞춰 저장소를 찢는 것이 가장 정치적이고 행정적인 비용이 낮은 해결책이었을 수 있습니다.
4. 폴리레포에서 모노레포를 흉내 내는 아이러니
하지만 역설적이게도, 그들은 분리된 14개 레포지토리에서 다시 모노레포의 기능을 구현하기 시작했습니다.
- 통 버저닝(Bundle Versioning): 버전 파편화를 막기 위해 여러 패키지의 버전을 강제로 통일.
- 엄격한 레이어링 강제: 패키지 간 참조 방향 제한.
소프트웨어적 규율(Lint, Test)로 지킬 자신이 없어 물리적 장벽(Repo 분리)을 세웠지만, 결국 효율을 위해 다시금 '가상의 모노레포'를 수동으로 구축하고 있는 셈입니다.
5. 결론: 도구 탓을 하기 전에
14개의 레포로 나누는 결정은 그 당시 그 조직이 선택할 수 있었던 가장 '현실적인 생존 전략'이었음을 인정합니다. 방에 불이 났다면(장애와 배포 지연), 소화기를 찾는 것(테스트 구축)보다 일단 밖으로 뛰쳐나가는 것(분리)이 살길일 수 있으니까요.
하지만 이 사례를 "모노레포의 실패와 폴리레포의 승리"로 포장해서는 안 됩니다.
이 이야기가 우리에게 주는 진짜 교훈은 아키텍처의 우열이 아닙니다.
"소프트웨어의 복잡성은 저장소를 나눈다고 사라지지 않는다"는 사실입니다.방이 어질러졌다고 해서 집을 14채로 쪼개서 살 필요는 없습니다. 우리에게 필요한 건 집을 부수는 것이 아니라, 청소(Refactoring)와 정리 규칙(Lint/Test), 그리고 그것을 유지할 규율(Discipline)입니다.
반응형'ANYTHING' 카테고리의 다른 글
AI에게 기억을 선물하다 (0) 2025.11.08 AI 시대의 MongoDB 활용 전략 및 개발팀 주요 시사점 (0) 2025.09.03 CI만으로도 개인정보일까? (0) 2025.04.26 미국의 ‘민감국가’ 지정과 한국 (3) 2025.03.19 미국 민감국가 지정 (0) 2025.03.12 - 첫째, '폭발 반경(Blast Radius)'의 물리적 차단