목차
왜 다시 모듈러 모놀리스인가
회사를 운영하면서 개발도 같이 하다 보면, 아키텍처 선택이 단순한 기술 취향 문제가 아니라는 걸 자주 느낍니다. 예전에는 서비스가 커질 것 같으면 “처음부터 MSA로 나누자”는 판단을 하기 쉬웠습니다. 서비스별로 배포하고, 필요한 부분만 확장하고, 팀별로 책임을 나누는 그림이 깔끔해 보였기 때문입니다.
그런데 최근에는 개발 방식이 바뀌고 있습니다. 여러 명이 큰 팀을 이루기보다, 한 사람이 AI 코딩 도구와 함께 작은 솔루션을 빠르게 만들고 운영하는 일이 많아졌습니다. 이 상황에서 MSA는 장점보다 비용이 먼저 다가올 때가 많습니다. 서비스가 여러 개가 되면 저장소, 배포 파이프라인, 로그, 모니터링, 인증, 네트워크 장애, 데이터 정합성까지 모두 관리해야 합니다.
반대로 모듈러 모놀리스는 배포 단위는 하나로 유지하되, 내부 코드는 도메인별 모듈로 나눕니다. 운영은 단순하게 가져가면서도 코드 구조는 무너지지 않게 만드는 방식입니다.
모놀리스, 모듈러 모놀리스, MSA의 차이
모놀리스
모놀리스는 하나의 애플리케이션이 하나의 배포 단위로 움직이는 구조입니다. Microsoft의 설명처럼 보통 핵심 동작이 하나의 프로세스 안에서 실행되고, 확장이 필요하면 애플리케이션 전체를 복제합니다.
초기 개발에는 매우 편합니다. 로컬에서 실행하기 쉽고, 디버깅도 단순하며, 배포도 한 번이면 됩니다. 문제는 시간이 지나면서 경계가 흐려질 때입니다. 결제 코드가 회원 코드를 직접 건드리고, 주문 모듈이 알림 테이블을 마음대로 수정하기 시작하면 금방 “수정하기 무서운 코드”가 됩니다.
모듈러 모놀리스
모듈러 모놀리스는 모놀리스처럼 하나로 배포하지만, 내부는 명확한 모듈로 나눕니다. 핵심은 배포 단위가 아니라 내부 경계입니다. 예를 들어 회원, 주문, 결제, 알림을 각각 모듈로 나누고, 서로는 공개된 인터페이스나 이벤트를 통해서만 연결합니다.
Spring Modulith 같은 도구는 이런 모듈 구조를 문서화하고 검증하는 데 도움을 줍니다. 중요한 건 프레임워크가 아니라 습관입니다. “같은 프로젝트 안에 있으니 아무 클래스나 import해도 된다”는 생각을 버려야 합니다.
MSA / Microservices
MSA는 기능을 독립 배포 가능한 서비스들로 나누는 구조입니다. Martin Fowler와 James Lewis가 설명한 것처럼 각 서비스는 비즈니스 역량을 중심으로 구성되고, 독립 배포와 분산된 데이터 소유권을 갖는 경우가 많습니다.
장점은 분명합니다. 서비스별로 확장하고, 팀별로 소유하며, 장애를 격리할 수 있습니다. 하지만 그만큼 네트워크 호출, 분산 트랜잭션, 관측성, 배포 자동화, DevOps 문화가 필요합니다. Fowler가 “Microservice Prerequisites”에서 강조하듯, 기본 역량이 없으면 MSA는 아키텍처 개선이 아니라 운영 부담이 됩니다.
한눈에 보는 비교
| 구분 | 모놀리스 | 모듈러 모놀리스 | MSA |
|---|---|---|---|
| 배포 | 하나로 배포 | 하나로 배포 | 서비스별 독립 배포 |
| 내부 구조 | 경계가 약해지기 쉬움 | 모듈/도메인 경계를 명시 | 서비스 경계를 네트워크로 분리 |
| 운영 난이도 | 낮음 | 낮음~중간 | 높음 |
| 개발 속도 | 초기에는 빠름 | 초기와 중기 모두 균형적 | 초기에는 느릴 수 있음 |
| 확장 | 전체 애플리케이션 단위 | 전체 애플리케이션 단위 | 서비스별 확장 가능 |
| 장점 | 단순한 개발·배포 | 운영 단순성 + 코드 구조화 | 독립 배포, 독립 확장, 팀 자율성 |
| 위험 | 빅볼 오브 머드 | 경계 규칙을 지키지 않으면 일반 모놀리스화 | 분산 시스템 복잡도와 운영 비용 |
| 적합한 상황 | MVP, 작은 내부 도구 | 1인 개발, 작은 팀, AI 협업, 성장 중인 서비스 | 여러 팀, 높은 트래픽, 명확한 서비스 소유권 |
1인 개발 + AI에서는 무엇이 달라지나
AI와 같이 개발할 때 중요한 건 “컨텍스트”입니다. AI Agent나 코딩 도구는 전체 회사를 다 기억하는 것이 아니라, 현재 대화와 파일 범위 안에서 판단합니다. Anthropic 문서에서도 모델이 참고할 수 있는 정보는 context window 안에 제한된다고 설명합니다.
그래서 1인 개발자가 AI와 일할 때는 구조가 너무 흩어져 있으면 오히려 비효율적입니다. 서비스가 8개로 나뉘어 있고, 각 서비스마다 저장소와 배포 방식, 환경변수, DB 스키마가 다르면 AI에게도 설명해야 할 컨텍스트가 늘어납니다. 사람도 힘들고 AI도 자주 놓칩니다.
모듈러 모놀리스는 이 지점에서 균형이 좋습니다. 하나의 프로젝트 안에 있으니 로컬 실행과 테스트가 쉽고, 동시에 모듈 경계가 있으니 AI에게 “이번에는 주문 모듈만 보자”, “결제 모듈의 공개 인터페이스만 수정하자”라고 범위를 좁히기 쉽습니다.
모듈러 모놀리스 설계 포인트
1. 모듈은 기술 계층이 아니라 비즈니스 기능으로 나눈다
controller, service, repository 같은 기술 계층만으로 나누면 모듈러 모놀리스가 아닙니다. 회원, 주문, 결제, 정산, 알림처럼 비즈니스 기능을 기준으로 경계를 잡아야 합니다.
2. 모듈 간 직접 참조를 제한한다
같은 코드베이스 안에 있다는 이유로 다른 모듈의 내부 클래스를 직접 호출하면 경계가 무너집니다. 공개 API, application service, domain event 같은 통로를 정해두는 편이 좋습니다.
3. DB 경계도 미리 의식한다
처음부터 서비스별 DB를 나눌 필요는 없지만, 테이블 소유권은 정해두는 것이 좋습니다. 주문 모듈이 결제 테이블을 직접 수정하는 식의 구조는 나중에 서비스 추출을 어렵게 만듭니다.
4. 모듈별 테스트를 만든다
모듈 경계를 지키려면 테스트가 필요합니다. “이 모듈은 어떤 입력을 받고 어떤 결과를 내는가”가 테스트로 남아 있어야 AI가 코드를 수정할 때도 회귀를 줄일 수 있습니다.
실제로 헷갈리는 부분과 주의점
모듈러 모놀리스는 그냥 폴더 정리가 아니다
폴더만 나눠놓고 내부에서는 서로 마음대로 참조하면 일반 모놀리스와 다르지 않습니다. 중요한 건 폴더명이 아니라 의존성 방향과 공개 인터페이스입니다.
MSA는 코드 분리가 아니라 운영 분리다
MSA로 나누면 코드가 깔끔해질 것 같지만, 실제로는 운영 문제가 먼저 옵니다. 서비스 간 타임아웃, 재시도, 메시지 중복 처리, 장애 추적, 배포 순서까지 고려해야 합니다. 이 비용을 감당할 조직과 플랫폼이 있어야 MSA의 장점이 살아납니다.
처음부터 완벽한 경계를 찾으려 하지 않는다
도메인 경계는 개발하면서 바뀝니다. 그래서 초기에 MSA로 물리적으로 쪼개버리면 잘못 나눈 경계를 되돌리기 어렵습니다. 모듈러 모놀리스는 경계를 코드 안에서 조정할 수 있어 학습 비용이 낮습니다.
MSA로 가야 하는 순간
모듈러 모놀리스가 항상 정답은 아닙니다. 다음 신호가 반복된다면 일부 모듈을 서비스로 추출할 시점일 수 있습니다.
- 특정 기능만 트래픽이 크게 증가해 독립 확장이 필요하다.
- 여러 팀이 같은 배포 단위를 공유해서 릴리스 충돌이 잦다.
- 장애 격리가 중요해져 한 기능의 장애가 전체 시스템을 멈추면 안 된다.
- 도메인 경계가 충분히 안정되어 서비스 계약을 유지할 자신이 있다.
- 모니터링, 로그, 배포 자동화, 장애 대응 체계가 준비되어 있다.
이때도 전체를 한 번에 MSA로 바꾸기보다, 가장 독립 가치가 큰 모듈 하나부터 빼는 편이 안전합니다. Fowler의 “Monolith First” 관점처럼, 좋은 모듈 구조를 가진 모놀리스는 이후 서비스 분리의 출발점이 될 수 있습니다.
결론
요즘의 개발 환경에서는 “MSA냐 모놀리스냐”보다 “지금 내 팀과 운영 능력에 맞는가”가 더 중요합니다. 여러 팀이 독립적으로 움직이고, 서비스별 확장과 장애 격리가 실제로 필요하다면 MSA는 강력한 선택입니다. 하지만 혼자 개발하거나 작은 팀에서 AI와 함께 빠르게 제품을 만들고 있다면, 모듈러 모놀리스가 더 현실적인 출발점일 가능성이 큽니다.
저는 특히 1인 개발 + AI 환경에서는 모듈러 모놀리스가 맞는 경우가 많다고 생각합니다. 이 생각은 이론만 보고 정한 것이 아니라, 실제로 Claude Code, Codex, Gemini 같은 도구를 많이 써가며 개발해보면서 더 강해졌습니다.
처음에는 AI와 함께라면 MSA도 충분히 빠르게 가져갈 수 있을 거라고 생각했습니다. 서비스별로 역할을 나누고, 각 서비스의 코드를 AI에게 맡기면 오히려 더 깔끔해질 것 같았습니다. 그런데 실제로 해보면 다른 벽이 생깁니다. 토큰은 많이 쓰는데, AI가 한 번에 봐야 하는 컨텍스트는 계속 흩어집니다. 이 서비스의 API 계약, 저 서비스의 DB 스키마, 메시지 큐 이벤트 이름, 배포 환경변수, 인증 흐름, 장애 로그를 매번 다시 설명해야 합니다. 사람도 지치고, AI도 자주 놓칩니다.
특히 혼자 운영하는 입장에서는 “코드를 나누는 비용”보다 “나눠진 것들을 계속 기억하고 맞추는 비용”이 더 크게 느껴졌습니다. 서비스 하나를 고치려면 다른 서비스의 계약을 확인해야 하고, 로컬에서 전체 흐름을 재현하려면 여러 프로세스와 의존 서비스를 띄워야 합니다. AI에게 수정 요청을 해도 한 저장소 안에서는 그럴듯하게 고치지만, 다른 서비스와 맞물리는 부분에서 미묘한 불일치가 생기기 쉽습니다. 결국 많은 토큰을 쓰고도 마지막 통합 검증은 사람이 다시 붙잡게 됩니다.
그래서 저는 점점 모듈러 모놀리스 쪽으로 정착하게 됐습니다. 운영은 단순하게 유지하고, 코드는 모듈 경계로 관리합니다. AI에게도 “주문 모듈 안에서만 봐라”, “결제 모듈의 공개 인터페이스는 바꾸지 말아라”처럼 범위를 명확히 줄 수 있습니다. 로컬 실행과 테스트는 하나의 애플리케이션 안에서 끝나고, 정말 독립 배포나 독립 확장이 필요해지는 순간에만 일부 기능을 서비스로 추출하면 됩니다. 제 기준에서는 이 방식이 1인 개발자와 AI가 함께 오래 버티기 좋은 구조에 가깝습니다.
여러분은 어떻게 생각하시나요? AI와 함께 개발하는 시간이 늘어난 지금, 처음부터 MSA로 가는 것이 맞을까요, 아니면 모듈러 모놀리스로 시작하는 것이 더 현실적일까요?
참고 자료
- Microsoft Learn — Common web application architectures
- AWS — What are Microservices?
- Martin Fowler / James Lewis — Microservices
- Martin Fowler — Monolith First
- Martin Fowler — Microservice Prerequisites
- Spring Modulith Reference
- microservices.io — Monolithic Architecture
- microservices.io — Microservice Architecture
- Kamil Grzybek — Modular Monolith: A Primer
- Anthropic Docs — Context windows