11장은 처음 만들어진 1판에는 없었고, 2판에서 새로 생겼다고 한다.
이게 좀 의미 있게 느껴졌는데, 마이크로서비스가 정답인 것처럼 이야기되던 시기를 한 바퀴 돌고 나서, 하나로 붙어 있는 앱을 제대로 만드는 법이 독립된 장을 받은 셈일 수도 있겠다.
자리는 레이어드 바로 옆이다. 배포 덩어리 하나인 건 똑같고, 쪼개는 기준만 다르다.
레이어드 덩어리 하나 + 기술로 쪼갬
모듈러 모놀리스 덩어리 하나 + 도메인으로 쪼갬한 칸 차이인데 결과가 꽤 다르다.
어떻게 생겼나
맨 위가 도메인별 모듈이다.
┌────────── 배포는 한 덩어리 ──────────┐
│ │
│ [주문] [배송] [결제] [고객] │
│ ↕ 공개된 통로로만 서로 부른다 │
│ │
│ DB 하나 │
└────────────────────────────────────┘모듈 하나 안에 그 도메인에 필요한 게 다 들어 있다. 화면도, 로직도, DB 접근도. 레이어드에서 세 층에 흩어져 있던 주문 코드가 주문 모듈 안에 모인다.
그리고 모듈 안에서는 여전히 층을 쓴다. 레이어드를 버리는 게 아니라 도메인 안쪽으로 밀어 넣는 쪽에 가깝다.
아무도 안 막아준다
여기가 이 스타일의 약점이다.
마이크로서비스는 경계가 저절로 지켜진다. 다른 서비스의 내부 코드를 직접 가져다 쓰는 게 애초에 불가능하니까. 네트워크가 막고 있다.
모듈러 모놀리스에는 그런 게 없다. 같은 프로그램 안에서 같은 메모리를 쓴다. 주문 모듈에서 배송 모듈 안쪽 코드를 가져다 쓰는 걸 아무것도 안 막는다. import 한 줄이면 끝이다.
그래서 이 스타일이 되냐 안 되냐는 규칙을 지키게 만드는 장치가 있느냐에 달려 있다. 없으면 아주 조용히 뒤엉킨 덩어리가 된다. 무너지는 걸 아무도 눈치채지 못한 채로.
데이터가 제일 어렵다
코드는 모듈로 나눴는데 DB는 하나다. 그러다 보면 주문 모듈이 배송 테이블을 그냥 조인해서 읽는 일이 생긴다. 코드는 나눠놨는데 데이터가 다 뚫려 있는 상태다.
책은 얼마나 엮여 있느냐에 따라 몇 단계로 나눈다.
다 같이 씀 모든 모듈이 모든 테이블 접근 — 사실상 경계 없음
주인 정하기 테이블을 도메인별로 묶고 주인 모듈만 직접 접근
아예 나누기 모듈마다 DB 분리 — 조인을 잃는 대신 떼어내기 쉬움현실적인 목표는 가운데다. 조인과 되돌리기의 편함은 그대로 두면서 주인은 정해두는 절충.
이게 중요한 이유가 하나 더 있다. 나중에 모듈을 서비스로 떼어낼 때 발목을 잡는 건 항상 코드가 아니라 데이터다. 코드 나누기는 정리 작업이지만, 같이 쓰던 테이블 나누기는 이사 작업이다.
클라우드, 위험, 규칙
클라우드에서의 성질은 레이어드와 비슷하다. 배포와 관리가 단순하고 싸지만, 필요한 모듈만 골라서 늘릴 수는 없다. 다른 점은 떠날 준비가 되어 있다는 것. 어떤 모듈만 부하가 크다는 게 드러나면 이미 선이 그어져 있으니 떼어내면 된다.
자주 생기는 문제는 대부분 경계가 조금씩 허물어지는 데서 온다. 급할 때 넣은 import 한 줄이 쌓이고, DB는 계속 같이 쓰고, 한 모듈이 비대해져서 그 안이 또 뒤엉킨다. 어디에도 안 맞는 코드가 shared/로 몰리다가 결국 모든 모듈이 거기 물리는 것도 흔하다.
그래서 규칙을 지키게 만드는 장치가 선택이 아니라 조건이다. 어떤 모듈이 어떤 모듈을 부를 수 있는지 정해두고, 각 모듈의 공개 통로와 내부 코드를 구분하고, 그걸 CI에서 자동으로 검사한다. 핵심은 이 규칙을 사람의 의지가 아니라 빌드 실패로 만드는 것이다. 코드 리뷰에서 잡겠다는 계획은 바쁜 스프린트를 못 버틴다.
팀은 도메인별로 묶는 쪽이 맞는다. 한 팀이 한 모듈을 화면부터 데이터까지 통으로 갖는다. 9장에서 본 스트림 정렬팀이다. 다만 배포는 여전히 다 같이 한다. 개발은 따로 하는데 배포는 따로 못 한다. 이 답답함을 못 견디는 순간이 나눠야 할 시점이다.
이 스타일 장단점
레이어드보다 나은 것 코드 정리 상태, 변경 속도, 유지보수, 테스트
레이어드와 똑같이 나쁜 것 따로 배포, 필요한 만큼 늘리기, 일부 장애 버티기
레이어드보다 나쁜 것 단순함 (경계를 설계하고 지켜야 하니까)덩어리가 하나라서 생기는 약점은 그대로 남는다. 쪼개는 기준을 바꿔서 고쳐지는 게 아니라 덩어리 자체를 나눠야 고쳐지는 것들이라 그렇다.
순서
책이 권하는 순서가 있다. 모듈러 모놀리스 → 서비스 기반 → 마이크로서비스.
잘 만들어두면 다음 단계는 새로 설계하는 게 아니라 이미 그어둔 선을 따라 자르는 일이 된다.
거꾸로 이 단계를 건너뛰고 바로 마이크로서비스로 가면, 경계가 맞는지 확인도 안 된 상태에서 그 선을 콘크리트로 굳히는 셈이다. 틀렸을 때 값이 완전히 다르다.
모듈러 모놀리스에서 틀렸다 폴더 옮기고 import 고친다
마이크로서비스에서 틀렸다 서비스 합치고 DB 옮기고 API 다시 짠다정리
하나로 붙어 있는 게 문제가 아니라, 안이 안 나뉘어 있는 게 문제라는 이야기였다.
그리고 실무에서 갈리는 질문은 하나인 것 같다. 지금 필요한 게 따로 배포하는 건가, 따로 개발하는 건가.
레퍼런스
- Mark Richards, Neal Ford, Fundamentals of Software Architecture, 2nd Edition — Chapter 11, Modular Monolith Architecture Style