Microservices are organizational debt disguised as architecture.
마이크로서비스는 아키텍처로 포장한 조직 부채입니다
Martin Fowler는 새 프로젝트에서 마이크로서비스부터 시작하기보다 모놀리스로 출발한 뒤 서비스 경계를 파악하고 필요할 때 분리하자고 제안합니다. 마이크로서비스는 운영 부담이 크고 경계를 잘못 나누면 변경이 어려워지지만, 여러 팀의 독립 배포나 엄격한 검증이 필요한 환경에서는 장점도 있습니다.
- 주제
AI 요약
Martin Fowler는 2015년 글에서 마이크로서비스 도입 사례를 살펴보며 한 가지 경향을 짚습니다. 성공 사례 대부분은 먼저 모놀리스로 시작한 뒤 시스템이 커지면서 나눴지만, 처음부터 마이크로서비스로 만든 시스템은 심각한 문제에 빠지는 경우가 많았다는 관찰입니다. 그래서 새 프로젝트는 나중에 마이크로서비스로 바꿀 계획이 있더라도 모놀리스로 시작하자는 ‘Monolith First’ 전략을 제안합니다.
처음에는 피드백 속도를 우선합니다
새 제품이 사용자에게 쓸모 있을지 초기에 확신하기는 어렵습니다. Fowler는 단순한 버전을 빨리 만들어 반응을 확인하는 편이, 복잡한 시스템을 미리 설계하는 것보다 낫다고 봅니다. 마이크로서비스에는 서비스 묶음을 운영하는 비용이 따르며, 그 부담은 초기 개발과 피드백 주기를 늦춥니다. YAGNI 원칙에 따라 아직 필요가 확인되지 않은 분산 구조를 먼저 도입하지 말자는 주장입니다.
서비스 경계는 경험을 쌓으며 찾습니다
마이크로서비스가 잘 작동하려면 서비스 사이의 경계를 안정적으로 정해야 합니다. 이는 도메인 주도 설계(Domain-Driven Design)의 Bounded Context를 나누는 일과 맞닿아 있습니다. 경험이 많은 설계자도 프로젝트 초기에 올바른 경계를 찾기 어렵고, 서비스 간 기능 이동은 모놀리스 안에서 코드를 옮기는 일보다 훨씬 까다롭습니다. 먼저 모놀리스에서 기능과 데이터의 관계를 살피면 경계를 파악할 시간을 벌고, 세분화된 서비스를 운영하기 위한 기반도 마련할 수 있습니다.
다만 모놀리스라고 해서 나중에 쉽게 쪼갤 수 있는 것은 아닙니다. 모듈 사이에 의존성이 쌓이면 분해 과정이 엉킬 수 있습니다. 모듈화와 API 경계를 잘 설계한 모놀리스라면 전환이 비교적 수월하겠지만, Fowler는 그런 방식이 성공한 사례를 충분히 듣지 못했다고 덧붙입니다.
분리하는 방식도 하나로 정해져 있지 않습니다
한 가지 방법은 모놀리스의 모듈과 데이터 구조를 처음부터 신중하게 설계하는 것입니다. 또 다른 방법은 가장자리 기능부터 마이크로서비스로 떼어내고, 핵심부 모놀리스는 큰 변화 없이 유지하는 것입니다. 빠른 출시를 위해 모놀리스를 임시 구조로 만들고 나중에 통째로 교체하는 선택도 있습니다. 또는 처음에는 예상보다 큰 단위의 서비스 몇 개로 시작해, 경계가 안정되면 더 작게 나눌 수 있습니다. Fowler는 이 방식을 엄밀히는 ‘duolith’라고 부를 수도 있지만, 먼저 큰 단위에서 배우고 나중에 분리한다는 점에서 Monolith First의 취지에 맞는다고 설명합니다.
처음부터 마이크로서비스를 택할 조건
반대 의견도 있습니다. 마이크로서비스로 시작하면 팀이 서비스별 개발과 운영 방식에 일찍 익숙해지고, 서비스 경계를 기준으로 팀을 나눠 개발 인원을 늘리기 쉬워집니다. 특히 기존 시스템을 대체하는 프로젝트는 경계를 미리 파악하기 나을 수 있습니다. Fowler는 팀에 마이크로서비스 구축 경험이 충분하지 않다면 처음부터 도입하지 않는 편이 낫다고 조심스럽게 말합니다. 다만 당시 경험담이 아직 적다며, 이 조언 역시 확정적인 규칙이 아니라 잠정적인 판단이라고 선을 긋습니다.
Reddit 반응
- @u/plasticbug — 마이크로서비스는 유용할 수 있지만, 제 경험상 콘웨이의 법칙(Conway’s Law), 즉 시스템 설계가 조직 구조를 닮아가는 현상이 실제로 나타납니다. 우리 조직은 원하는 아키텍처에 맞춰 조직을 다시 짜는 ‘역콘웨이’ 방식을 시도하고 있습니다. 성공할지는 지켜봐야 합니다.
- @u/drakkie — 우리 조직에서도 재편을 겪었는데, 조직 개편이 계속 반복돼 시도가 무산되는 경우를 봤습니다. 어떻게 될지 궁금합니다.
- @u/Absolice — 도메인 주도 설계에 관한 내용을 제대로 읽지 않고 마이크로서비스를 쓰면 경계를 잘못 나누기 쉽고, 모놀리스보다 더 나쁜 분산 모놀리스가 생길 수 있습니다. 역콘웨이 방식은 팀이 나눈 방향으로 일이 진행되게 만들 수 있지만, 사람들은 필요 이상으로 복잡하게 만들기도 합니다. 성공 여부는 팀에 어떻게 설명하고 얼마나 함께 받아들이느냐에 달렸습니다. 위에서 밀어붙이기만 해서는 안 됩니다.
- @u/tanksc — 개발자 150명이 모놀리스 하나를 다뤄야 할 때까지는 누구나 모놀리스를 원합니다.
- @u/firewall245 — 지금 팀이 쓰는 아키텍처가 최악이라는 새 법칙이 필요하겠습니다. 끔찍한 마이크로서비스도 겪었지만, 사람 머리를 어지럽히는 모놀리스도 겪었습니다.
- @u/Shikadi297 — 아무도 적당한 중간 지점인 중간 크기의 서비스를 생각하지 않습니다.
- @u/wallstop-dev — 일반적으로는 단순한 모놀리스에서 시작하고, 필요해질 때 나누는 편이 좋습니다. 처음부터 복잡한 마이크로서비스로 시작하면 복잡성이 더해질 뿐입니다. 프로그램이
main함수 안에 들어간다면 우선 거기 두고, 복잡해질수록 클래스와 함수, 라이브러리로 나누는 식입니다.- @u/ChemTechGuy — 모놀리스가 실제로 분해되는 일은 거의 없습니다.
- @u/wallstop-dev — 맞습니다. 모놀리스가 분해할 만큼 다루기 힘들지 않다면 마이크로서비스가 필요하지 않다는 게 제 말입니다. 모놀리스가 감당하기 어려워졌을 때가 마이크로서비스를 고려할 때입니다.
- @u/Sammy81 — 우리 회사는 복잡한 시스템의 모듈을 네트워크 메시지로 연결하는 마이크로서비스 구조로 바꿨습니다. 수정한 모듈만 재검증할 수 있게 됐고, 버그나 장애를 늘리지 않으면서 테스트를 80% 줄였습니다. 모듈마다 C++, Rust, Python처럼 다른 언어를 써도 됩니다.
- @u/Shot-Damage-6723 — 마이크로서비스라서 테스트가 빨라진 게 아니라 테스트를 덜 하게 된 것 같습니다. 바이너리를 여러 개로 만들 수 있고, 선호하는 언어를 쓰려고 네트워크를 사이에 둘 필요도 없습니다. 실제로 도움이 된 이유를 더 설명할 수 있나요?
- @u/Sammy81 — NASA의 절차에서는 코드를 다시 컴파일하면 요구사항을 재검증해야 합니다. 서비스를 따로 빌드하면 다른 서비스를 수정해도 해당 서비스는 다시 컴파일하지 않으므로 이전 검증이 유효합니다. 네트워크 메시지로 바꾸면서 데이터 전달 속도가 훨씬 느려진 점은 가장 큰 문제입니다. 메시지의 90%는 괜찮지만, 나머지는 ZeroMQ나 RPC 같은 방식을 써야 합니다.
- @u/Think-nothing-210 — 코드베이스에 제대로 된 모듈을 만들지 않는 문제가 큽니다. 좋은 모듈이 있으면 작업을 나눌 때도 모듈 경계를 쓸 수 있어 마이크로서비스가 거의 필요하지 않습니다.
- @u/tommyTurds — 모듈이 해결하는 문제와 마이크로서비스가 해결하는 문제는 다릅니다. 여러 팀이 각자 다른 속도와 방식으로 배포하려는 상황에서는 모놀리스의 테스트와 배포를 함께 조율해야 합니다. 큰 조직에서는 그 조율이 몇 달씩 걸리기도 합니다. 마이크로서비스는 기술 문제를 해결하기보다 조직을 확장하는 방식이며, 네트워크 단계를 더한다고 성능이 좋아지지는 않습니다.
- @u/eluusive — 마이크로서비스에는 운영 부담이 크고 서비스 사이에서 컴파일 시점에 잡히던 오류도 놓치게 됩니다. 그보다는 모놀리스 안에서 모듈을 잘 나누고 하나의 서비스로 빌드하고 배포하는 편이 낫습니다. 가능하면 타입이 명확한 언어를 쓰는 게 좋습니다.
- @u/santagoo — 모든 선택에는 대가가 따릅니다. 아키텍처의 단점은 장점을 얻기 위해 감수하는 부채입니다. 어떤 대가를 감수할지는 해결하려는 문제에 달렸고, 마이크로서비스도 쓸 만한 경우가 있습니다.
원문: Martin Fowler / 번역·요약: Trawling