[System Design] Modular Monolith
๐งฉ Module
๋๊ท๋ชจ ์์คํ ์ ๊ตฌ์ถํ ๋ ํํ ์ ์ง๋ฅด๋ ์ค์๋ ๋ชจ๋์ ๋จ์ํ โ๊ธฐ๋ฅ๋ณ๋ก ๋ถ๋ฅ๋ ํด๋โ๋ก ์ทจ๊ธํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ์์ง๋์ด๋ง ๊ด์ ์์ ๋ชจ๋์ ์ถ์ํ์ ๋ฒฝ(Abstraction Wall)์ ๋๋ค. ๋ด๋ถ์ ๋ณต์ก์ฑ์ ์ธ๋ถ๋ก ์ ์ถํ์ง ์์ผ๋ฉด์๋, ์์คํ ์ ์ ์ฒด์ ์ธ ์ ํฉ์ฑ์ ์ ์งํ๊ธฐ ์ํ ๋ ผ๋ฆฌ์ ์์์ฌ์ผ ํฉ๋๋ค. ๋ชจ๋ํ๊ฐ ์คํจํ ๋ชจ๋๋ฆฌ์ค๋ ๊ฒฐ๊ตญ ๋ชจ๋ ๊ฐ์ฒด๊ฐ ์๋ก๋ฅผ ์ฐธ์กฐํ๋ โ์ปค๋ค๋ ์งํ ๋ฉ์ด๋ฆฌ(Big Ball of Mud)โ๋ก ์ ๋ฝํ๋ฉฐ, ์ด๋ ๊ณง ์์ ํ๋๊ฐ ์์คํ ์ ์ฒด์ ํ๊ท ํ ์คํธ๋ฅผ ๊ฐ์ ํ๋ ์ฌ์์ผ๋ก ์ด์ด์ง๋๋ค.
Encapsulation
์ง์ ํ ์๋ฏธ์ ๋ชจ๋ํ๋ ์บก์ํ์์ ์์๋ฉ๋๋ค. ์บก์ํ๋ ๋จ์ํ ํ๋๋ฅผ private์ผ๋ก ์ ์ธํ๋ ํ์๋ฅผ ๋์ด, ๋ชจ๋ ๋ด๋ถ์ ๋ถ๋ณ์ฑ(Invariants)์ ๋ณดํธํ๊ณ ๊ตฌํ ์ธ๋ถ ์ฌํญ์ ์จ๊ธฐ๋ ์ ๋ต์ ์ ํ์
๋๋ค. ๋ชจ๋ ๋ด๋ถ์ ๋๋ฉ์ธ ๋ก์ง์ด๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๊ฐ ์ธ๋ถ๋ก ๋
ธ์ถ๋๋ ์๊ฐ, ๊ทธ ๋ชจ๋์ ๋ ์ด์ ๋
๋ฆฝ์ ์ผ๋ก ๋ณ๊ฒฝ๋ ์ ์์ต๋๋ค. ์ธ๋ถ์ ์๋ง์ ์ฐธ์กฐ์๊ฐ ํด๋น ๊ตฌ์กฐ์ ์์กดํ๊ฒ ๋๊ธฐ ๋๋ฌธ์
๋๋ค.
์ฐ๋ฆฌ๋ ๋ชจ๋ ๋ด๋ถ๋ฅผ โBlack Boxโ๋ก ์ ์งํด์ผ ํฉ๋๋ค. ์ธ๋ถ์์๋ ๋ชจ๋์ด ์ด๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๋์ง, ์ด๋ค ๋ณต์กํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๊ฒฐ๊ณผ๊ฐ์ ๋์ถํ๋์ง ์ ํ์๊ฐ ์์ต๋๋ค. ์ค์ง ์ฝ์๋ ์ธํฐํ์ด์ค๋ฅผ ํตํด์๋ง ์ํธ์์ฉํด์ผ ํฉ๋๋ค. ์ด๋ฌํ ์๊ฒฉํ ์บก์ํ๋ ๊ฐ๋ฐ์๊ฐ ๋ชจ๋ ๋ด๋ถ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ ๋ โ์ธ๋ถ์ ๋ฏธ์น ์ํฅโ์ ๊ณ ๋ฏผํ์ง ์๊ฒ ํจ์ผ๋ก์จ ๊ฐ๋ฐ ์๋๋ฅผ ๋น์ฝ์ ์ผ๋ก ํฅ์์ํต๋๋ค.
Public API
๋ชจ๋์ Public API๋ ํด๋น ๋ชจ๋์ด ์ธ์๊ณผ ์ํตํ๋ ์ ์ผํ ์ฐฝ๊ตฌ์
๋๋ค. ์ด ์ฐฝ๊ตฌ๋ ์ต๋ํ ์ข๊ณ ๊ฒฌ๊ณ ํ๊ฒ ์ค๊ณ๋์ด์ผ ํฉ๋๋ค. Java ์ง์์์๋ ํจํค์ง ๊ฐ์์ฑ(Package Visibility)์ ํ์ฉํ๊ฑฐ๋ Java 9+์ Module System์ ํตํด ๋ช
์์ ์ผ๋ก exportsํ ๋์์ ์ง์ ํ ์ ์์ต๋๋ค. Spring Modulith ๊ฐ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ฉด ํน์ ํจํค์ง(์: .internal) ํ์์ ํด๋์ค๋ค์ ์ธ๋ถ ๋ชจ๋์์ ์ฐธ์กฐํ ๊ฒฝ์ฐ ํ
์คํธ ๋จ๊ณ์์ ์คํจ๋ฅผ ๋ฐ์์์ผ ๋ฌผ๋ฆฌ์ ์ธ ๊ฒฉ๋ฆฌ๋ฅผ ๊ฐ์ ํ ์๋ ์์ต๋๋ค.
์ข์ API ์ค๊ณ๋ ์ฌ์ฉํ๊ธฐ ์ฝ๊ณ , ์ค์ฉํ๊ธฐ ์ด๋ ค์์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํด ๋ชจ๋ ๊ฐ ํต์ ์๋ ๋ด๋ถ ์ํฐํฐ(Entity)๋ฅผ ๊ทธ๋๋ก ๋ ธ์ถํ์ง ์๊ณ , ์ค์ง ํต์ ์ ์ํ ์์ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ธ DTO(Data Transfer Object)๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์์น์ ๋๋ค. ์ํฐํฐ์ ๋ณ๊ฒฝ์ด API ์คํ์ ๋ณ๊ฒฝ์ผ๋ก ์ ์ด๋๋ ๊ฒ์ ์ฐจ๋จํ๋ ๋ฐฉํ๋ฒฝ ์ญํ ์ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. ์ฃผ๋ฌธ ๋ชจ๋์ ๊ณต๊ฐ API (์ธ๋ถ ๋ชจ๋์์ ์ฐธ์กฐ ๊ฐ๋ฅ)
package com.example.order;
import lombok.Value;
public interface OrderService {
void placeOrder(OrderRequest request);
}
@Value
public class OrderRequest {
String productId;
int quantity;
}
// 2. ์ฃผ๋ฌธ ๋ชจ๋์ ๋ด๋ถ ๊ตฌํ (์ธ๋ถ ๋ชจ๋์์ ์ฐธ์กฐ ๋ถ๊ฐ - ์บก์ํ)
package com.example.order.internal;
import com.example.order.OrderRequest;
import org.springframework.stereotype.Service;
@Service
class OrderProcessor { // package-private์ผ๋ก ์ ์ธํ์ฌ ์ธ๋ถ ์ ๊ทผ ์ฐจ๋จ
public void validate(OrderRequest request) {
// ๋ณต์กํ ๋ด๋ถ ๊ฒ์ฆ ๋ก์ง
}
}
Domain Autonomy
๊ฐ ๋ชจ๋์ ์์ ์ ๋๋ฉ์ธ ์์ญ์ ๋ํด ์ ๋์ ์ธ ์์จ์ฑ์ ๊ฐ์ง๋๋ค. ์ด๋ ๋ชจ๋์ด ์ค์ค๋ก์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ณ , ์์ ์ ๋น์ฆ๋์ค ๊ท์น์ ์๊ฒฐ์ฑ ์๊ฒ ์ฒ๋ฆฌํจ์ ์๋ฏธํฉ๋๋ค. ์๋ฅผ ๋ค์ด โ์ฃผ๋ฌธ(Order)โ ๋ชจ๋์ โ์ฌ๊ณ (Inventory)โ ๋ชจ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ง์ ์กฐํํด์๋ ์ ๋ฉ๋๋ค. ์ฌ๊ณ ํ์ธ์ด ํ์ํ๋ค๋ฉด ์ฌ๊ณ ๋ชจ๋์ด ์ ๊ณตํ๋ API๋ฅผ ํธ์ถํ๊ฑฐ๋, ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ํตํด ์ํ ๋ณํ๋ฅผ ํต์ง๋ฐ์์ผ ํฉ๋๋ค.
์ด๋ฌํ ์์จ์ฑ์ ํ ๋จ์์ ๋ณ๋ ฌ ๊ฐ๋ฐ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ํต์ฌ ๋๋ ฅ์ ๋๋ค. ๊ฐ ํ์ ์์ ์ด ๋งก์ ๋ชจ๋์ ๊ฒฝ๊ณ ์์์ ์์ ๋กญ๊ฒ ๊ธฐ์ ์คํ์ ์ต์ ํํ๊ฑฐ๋ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ๋ชจ๋์ด ์์จ์ ์ผ์๋ก, ์์คํ ์ ๋ง์น ๋ ๊ณ ๋ธ๋ก์ฒ๋ผ ์ ์ฐํ๊ฒ ์กฐ๋ฆฝ๋๊ณ ํ์ฅ๋ ์ ์๋ ์ ๊ธฐ์ฒด๋ก ๊ฑฐ๋ญ๋ฉ๋๋ค.
๋ชจ๋ํ์ ๋น์ฉ๊ณผ ๊ฐ์น
๋ชจ๋ ์ฝ๋ ๋ญ์น๋ฅผ ๋ชจ๋๋ก ์ชผ๊ฐ๋ ๊ฒ์ ๊ณผ์ ์์ง๋์ด๋ง์ผ ์ ์์ต๋๋ค. ๋ชจ๋ํ๋ ์ธํฐํ์ด์ค ์ค๊ณ์ ๋ฐ์ดํฐ ๋ณํ์ด๋ผ๋ ์ถ๊ฐ์ ์ธ ๋น์ฉ์ ์๋ฐํฉ๋๋ค.
ํ์ง๋ง ์์คํ ์ ๋ณต์ก๋๊ฐ ์ง์์ ์ผ๋ก ์ฆ๊ฐํ๋ ์์ ์์, ์ด โ๊ตฌ์กฐ์ ๋น์ฉโ์ โ์ ์ง๋ณด์ ์ฌ์โ์ ๋ง๊ธฐ ์ํ ๊ฐ์ฅ ์ ๋ ดํ ๋ณดํ๋ฃ๊ฐ ๋ฉ๋๋ค.
๐งฉ Monolith
๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค ์ํคํ ์ฒ์์ Monolith๋ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ถ๋ฆฌ๋ ๋ชจ๋๋ค์ด โ๋ฌผ๋ฆฌ์ ์ผ๋ก๋ ํ๋๋ก ํตํฉ๋์ด ๋ฐฐํฌ๋จโ์ ์๋ฏธํฉ๋๋ค. ์ด๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ(MSA)๊ฐ ๊ฐ์ ํ๋ ๋คํธ์ํฌ ๊ฒฝ๊ณ(Network Boundary) ๋์ , ํ๋ก์ธ์ค ๋ด ํต์ (In-process Communication)์ ์ ํํจ์ผ๋ก์จ ์ด์ ๋ณต์ก๋๋ฅผ ์ ์ดํ๋ ์ ๋ต์ ๊ฒฐ์ ์ ๋๋ค. ๋ชจ๋ํ๋ ์ฝ๋๊ฐ ํ๋์ ์คํ ๋จ์๋ก ๋ฌถ์ผ ๋, ์์คํ ์ ๋ถ์ฐ ์์คํ ์ ๊ณ ์ง์ ์ธ ๋ฌธ์ ์ธ ๋คํธ์ํฌ ์ง์ฐ(Latency)๊ณผ ๋ถ๋ถ ์คํจ(Partial Failure)์ ๊ณตํฌ์์ ํด๋ฐฉ๋ฉ๋๋ค.
Deployment Unit
๋ชจ๋ ธ๋ฆฌ์ค์ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋ฌด๊ธฐ๋ ๋จ์ผ ๋ฐฐํฌ ์ ๋(Single Deployment Unit)์ด ์ฃผ๋ ๋จ์ํจ์ ๋๋ค. ๋ชจ๋ ๋๋ฉ์ธ ๋ก์ง์ด ํ๋์ ๋ฐ์ด๋๋ฆฌ ํน์ ์ํฐํฉํธ๋ก ๋น๋๋์ด ๋ฐฐํฌ๋๋ฏ๋ก, ์ง์์ ํตํฉ ๋ฐ ๋ฐฐํฌ(CI/CD) ํ์ดํ๋ผ์ธ์ด ๊ทน๋๋ก ๊ฐ๊ฒฐํด์ง๋๋ค. ์๋น์ค ๊ฐ ๋ฒ์ ๋ถ์ผ์น๋ก ์ธํ โ์์กด์ฑ ์ง์ฅโ์ด๋ ๋ณต์กํ ์๋น์ค ๋ฉ์(Service Mesh) ์ค์ ์์ด๋ ์์คํ ์ ์์ ์ ์ผ๋ก ์ด์ํ ์ ์์ต๋๋ค.
๋ํ, ๋ชจ๋ ๊ฐ ํธ์ถ์ด ์ธ๋ฉ๋ชจ๋ฆฌ ํจ์ ํธ์ถ(In-memory call)๋ก ์ด๋ฃจ์ด์ง๊ธฐ ๋๋ฌธ์ ์ง๋ ฌํ/์ญ์ง๋ ฌํ์ ๋ฐ๋ฅธ CPU ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค. ์ด๋ ๊ณ ์ฑ๋ฅ์ด ์๊ตฌ๋๋ ๋ฐ์ดํฐ ์ง์ฝ์ ์์ ์์ ์๋์ ์ธ ํจ์จ์ฑ์ ์ ๊ณตํฉ๋๋ค. ๊ฐ๋ฐ์๋ ๋ถ์ฐ ํธ๋์ญ์ ์ ๋ณต์ก์ฑ์ ๊ณ ๋ฏผํ๋ ๋์ , ๋จ์ผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์ ๋ด์์ ๋ชจ๋ ๊ฐ ๋ฐ์ดํฐ ์ ํฉ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ์ง์คํ ์ ์์ต๋๋ค.
Resource Contention
๋จ์ผ ํ๋ก์ธ์ค ๊ตฌ์กฐ๋ ํจ์จ์ ์ด์ง๋ง, ์์ ๊ฒฝํฉ(Resource Contention)์ด๋ผ๋ ์น๋ช ์ ์ธ ํธ๋ ์ด๋์คํ๋ฅผ ์๋ฐํฉ๋๋ค. ๋ชจ๋ ๋ชจ๋์ด ๋์ผํ ํ ๋ฉ๋ชจ๋ฆฌ(Heap Memory)์ CPU ์ฝ์ด๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์, ํน์ ๋ชจ๋์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ ๋ฌด๊ฑฐ์ด ์ฐ์ฐ์ด ์์คํ ์ ์ฒด์ ๊ฐ์ฉ์ฑ์ ์ํํ ์ ์์ต๋๋ค. ์ด๋ฅผ โํญ๋ฐ ๋ฐ๊ฒฝ(Blast Radius)โ ๋ฌธ์ ๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
๋ง์ดํฌ๋ก์๋น์ค์๋ค๋ฉด ํน์ ์๋น์ค๋ง ํฌ๋์๊ฐ ๋ฐ์ํ๊ณ ๋๋ ์ผ์ด, ๋ชจ๋ ธ๋ฆฌ์ค์์๋ ๋จ ํ๋์ ์๋ชป๋ ๋ชจ๋๋ก ์ธํด ์ ์ฒด ์์คํ ์ด ๋ค์ด๋๋ ์ฐ์ ๋ฐ์์ ์ผ์ผํต๋๋ค. ๋ฐ๋ผ์ ๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค๋ฅผ ์งํฑํ๊ธฐ ์ํด์๋ ๋ชจ๋๋ณ ๋ฆฌ์์ค ์ฌ์ฉ๋์ ๋ํ ์ ๋ฐํ ๋ชจ๋ํฐ๋ง๊ณผ, ํน์ ๋ชจ๋์ด ์ ์ฒด ์ค๋ ๋ ํ์ ์ ์ ํ์ง ๋ชปํ๋๋ก ์ฐจ๋จํ๋ ์ํท ๋ธ๋ ์ด์ปค(Circuit Breaker) ํน์ ๋ฒํฌํค๋(Bulkhead) ํจํด์ ์ ์ฉ์ด ํ์์ ์ ๋๋ค.
๋จ์ผ์ฑ์ธ๊ฐ, ๊ฒฉ๋ฆฌ์ธ๊ฐ?
๋ชจ๋ ธ๋ฆฌ์ค๋ฅผ ์ ํํ๋ค๋ ๊ฒ์ โ์ด์์ ํธ์์ฑโ์ ์ํด โ๋ฌผ๋ฆฌ์ ๊ฒฉ๋ฆฌโ๋ฅผ ํฌ๊ธฐํ๋ ์ ํ์ ๋๋ค.
๋ง์ฝ ํน์ ๋ชจ๋์ ํธ๋ํฝ์ด ๋ค๋ฅธ ๋ชจ๋๋ณด๋ค ์๋ง ๋ฐฐ ์ด์ ๋๊ฑฐ๋, ๋ ์์ ์ธ ์ค์ผ์ผ๋ง ์ ์ฑ ์ด ์ ์คํ๋ค๋ฉด ๊ทธ ์ง์ ์ด ๋ฐ๋ก ๋ชจ๋ ธ๋ฆฌ์ค์ ๊ฒฝ๊ณ๊ฐ ๋ฌด๋์ง๊ณ MSA๋ก์ ์ ํ์ ๊ณ ๋ คํด์ผ ํ ์์ ์ ๋๋ค.
๐งฉ Boundary
๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค์ ์ฑํจ๋ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ๋๋๋๋๊ฐ ์๋๋ผ, ๋๋ ์ฝ๋ ์ฌ์ด์ ์ผ๋ง๋ ๊ฒฌ๊ณ ํ ๊ฒฝ๊ณ(Boundary)๋ฅผ ์ธ์ฐ๋๋์ ๋ฌ๋ ค ์์ต๋๋ค. ๊ฒฝ๊ณ๊ฐ ๋ชจํธํ ๋ชจ๋ํ๋ ๊ฒฐ๊ตญ ์ฝ๋๋ง ๋ณต์กํด์ง โ์คํ๊ฒํฐ ๋ชจ๋ ธ๋ฆฌ์คโ๋ก ํ๊ทํ ๋ฟ์ ๋๋ค. ์์ง๋์ด๋ง ๊ด์ ์์ ๊ฒฝ๊ณ๋ ๋๋ฉ์ธ์ ์๋ฏธ๋ก ์ ํ๊ณ์ ์ธ ๋์์, ๋ฌผ๋ฆฌ์ ์ธ ์ฝ๋ ์ฐธ์กฐ๋ฅผ ์ฐจ๋จํ๋ ๊ธฐ์ ์ ์ฅ๋ฒฝ์ ๋๋ค.
Bounded Context
๋ชจ๋์ ๊ฒฝ๊ณ๋ฅผ ์ค์ ํ๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๊ธฐ์ค์ ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ(DDD)์ Bounded Context์ ๋๋ค. ๋์ผํ ์ฉ์ด๋ผ๋ ๋งฅ๋ฝ์ ๋ฐ๋ผ ๊ทธ ์๋ฏธ๊ฐ ์์ ํ ๋ฌ๋ผ์ง ์ ์์์ ์ธ์ ํ๋ ๊ฒ์ด ํต์ฌ์ ๋๋ค. ์๋ฅผ ๋ค์ด, โ์ฌ์ฉ์(User)โ๋ผ๋ ๊ฐ์ฒด๋ ๊ฒฐ์ ๋ชจ๋์์๋ โ๊ฒฐ์ ์๋จ์ ๊ฐ์ง ๊ตฌ๋งค์โ์ด์ง๋ง, ๋ฐฐ์ก ๋ชจ๋์์๋ โ์์ทจ ์ฃผ์๋ฅผ ๊ฐ์ง ์๋ น์ธโ์ ๋๋ค.
ํ๋์ ๊ฑฐ๋ํ ์ ์ญ ๋ชจ๋ธ์ ๋ง๋ค๋ ค๊ณ ์๋ํ๋ ์๊ฐ ๊ฒฝ๊ณ๋ ๋ถ๊ดด๋ฉ๋๋ค. ๋์ , ๊ฐ ๋ชจ๋ ๋ด๋ถ์ ํด๋น ์ปจํ ์คํธ์๋ง ์ต์ ํ๋ ๋ชจ๋ธ์ ๊ตฌ์ถํ๊ณ , ๋ชจ๋ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ๋๋ง ์ต์ํ์ ์ ๋ณด๋ก ๋งคํํ๋ ์ ๋ต์ด ํ์ํฉ๋๋ค. ๊ฐ ๋ชจ๋์ด ์์ ๋ง์ ์ธ์ด์ ๊ท์น์ ๊ฐ์ง ๋ ๋ฆฝ๋ ์ํ ์์ ์ธ์ ํ ๋, ๋น๋ก์ ์ง์ ํ ์๋ฏธ์ ๋๋ฉ์ธ ์์จ์ฑ์ด ํ๋ณด๋ฉ๋๋ค.
Package Visibility
์ค๊ณ์์ผ๋ก ๊ฒฝ๊ณ๋ฅผ ํ์ ํ๋ค๋ฉด, ์ด๋ฅผ ์ฝ๋๋ก ๊ฐ์ ํด์ผ ํฉ๋๋ค. ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ ํจํค์ง ๊ฐ์์ฑ(Package Visibility) ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ๋ชจ๋ ์ธ๋ถ์์ ์ ๊ทผ ๊ฐ๋ฅํ ํด๋์ค๋ฅผ ์ ํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, Java์ public ํค์๋๋ฅผ ๋จ๋ฐํ์ง ์๊ณ package-private์ ํ์ฉํ์ฌ ๋ชจ๋ ๋ด๋ถ์ ๊ตฌํ์ฒด๋ค์ ์จ๊ธฐ๋ ๊ฒ์ด ๊ทธ ์์์
๋๋ค.
์ต๊ทผ์ ๋ชจ๋ ํ๋ ์์ํฌ๋ค์ ์ฌ๊ธฐ์ ํ ๋ฐ ๋ ๋์๊ฐ ์ํคํ ์ฒ ๊ท์น์ ํ ์คํธ ์ฝ๋๋ก ๊ฒ์ฆํฉ๋๋ค. ํน์ ํจํค์ง๊ฐ ํ์ฉ๋์ง ์์ ๋ค๋ฅธ ํจํค์ง์ ํด๋์ค๋ฅผ ์ง์ ํธ์ถํ๊ฑฐ๋ ์์๋ฐ๋ ํ์๋ฅผ ๋น๋ ๋จ๊ณ์์ ์ฐจ๋จํ๋ ๊ฒ์ ๋๋ค. ์ด๋ ์๋์ด ๊ฐ๋ฐ์๊ฐ ์ฝ๋ ๋ฆฌ๋ทฐ๋ก ์ผ์ผ์ด ํ์ธํ๋ โ๊ฒฝ๊ณ ์นจ๋ฒโ์ ์์คํ ์ด ์๋์ผ๋ก ๊ฐ์งํ๊ฒ ํจ์ผ๋ก์จ, ์๊ฐ์ด ํ๋ฆ์ ๋ฐ๋ผ ์ํคํ ์ฒ๊ฐ ๋ถ์(Erosion)๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๊ฐ๋ ฅํ ๊ฐ๋๋ ์ผ์ด ๋ฉ๋๋ค.
๋์๋๋ ์ถ์ํ์ ์ํ
๊ฒฝ๊ณ๊ฐ ๋ฌด๋์ง๋ ๊ฐ์ฅ ํํ ์งํ๋ ๋ชจ๋ ๋ด๋ถ์ ์์ธ(Exception) ํด๋์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง์ ๋ฐ์ ํ๊ฒ ์ฐ๊ด๋ ๊ฐ์ฒด๊ฐ ์ธ๋ถ๋ก ๋ ธ์ถ๋๋ ๊ฒ์ ๋๋ค.
์ธ๋ถ ๋ชจ๋์ด ๋ด๋ถ์ ์์ธ๋ฅผ
catchํด์ผ ํ๊ฑฐ๋ ๋ด๋ถ ์ํฐํฐ์ ํ๋ ๊ตฌ์กฐ๋ฅผ ์์์ผ ํ๋ค๋ฉด, ์ด๋ฏธ ๊ทธ ๊ฒฝ๊ณ๋ ์ ๊ธฐ๋ฅ์ ์์คํ ์ํ์ ๋๋ค.
๐งฉ Interface
๋ชจ๋ ๊ฐ์ ๊ฒฐํฉ์ ๋์จํ๊ฒ ์ ์งํ๋ฉด์๋ ํ์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ์ ์ผํ ์๋จ์ ์ธํฐํ์ด์ค(Interface)์ ๋๋ค. ๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค์์ ์ธํฐํ์ด์ค๋ ๋จ์ํ โ๋ฉ์๋ ์๊ทธ๋์ฒ์ ์งํฉโ์ด ์๋๋ผ, ๋ ๋๋ฉ์ธ์ด ์๋ก์๊ฒ ๋์ํ ๋ช ์์ ๊ณ์ฝ(Explicit Contract)์ ๋๋ค. ์ด ๊ณ์ฝ์ด ์ ๊ตํ ์๋ก ์์คํ ์ ๊ฑฐ๋ํ ์งํ ๋ฉ์ด๋ฆฌ๊ฐ ์๋, ์กฐ๋ฆฝ ๊ฐ๋ฅํ ๋ถํ๋ค์ ์งํฉ์ฒด๋ก ๋จ์ ์ ์์ต๋๋ค.
Dependency Inversion
๋ชจ๋ ๊ฐ์ ์์กด์ฑ ๋ฐฉํฅ์ ์ํคํ ์ฒ์ ๊ฑด์ ์ฑ์ ๊ฒฐ์ ํฉ๋๋ค. ํํ ์ ์ง๋ฅด๋ ์ค์๋ ์์ ์์ค์ ์ ์ฑ ๋ชจ๋(์: ์ฃผ๋ฌธ)์ด ํ์ ์์ค์ ์์ธ ๋ชจ๋(์: ์๋ฆผ)์ ์ง์ ์์กดํ๋ ๊ฒ์ ๋๋ค. ์ด๋ ์๋ฆผ ๋ชจ๋์ ์์ ๋ณ๊ฒฝ์ด ์ฃผ๋ฌธ ๋ชจ๋์ ์ฌ๋น๋์ ์ฌ๋ฐฐํฌ๋ฅผ ๊ฐ์ ํ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ณ์ต๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๋ ๊ฒ์ด ์์กด์ฑ ์ญ์ ์์น(DIP)์ ๋๋ค. ์ฃผ๋ฌธ ๋ชจ๋์ ์์ ์ด ํ์ํ ๊ธฐ๋ฅ์ ์ธํฐํ์ด์ค๋ก ์ ์ํ๊ณ , ์๋ฆผ ๋ชจ๋์ ์ด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํฉ๋๋ค. ์ด๋ก์จ ์์กด์ฑ์ ๋ฐฉํฅ์ ์ ์ด ํ๋ฆ๊ณผ ๋ฐ๋๋ก ์ญ์ ๋๋ฉฐ, ์ฃผ๋ฌธ ๋ชจ๋์ ์๋ฆผ ๋ชจ๋์ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ(SMS์ธ์ง, ์ด๋ฉ์ผ์ธ์ง)์ผ๋ก๋ถํฐ ์๋ฒฝํ๊ฒ ์์ ๋ก์์ง๋๋ค. ๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค์์ DIP๋ ๋ฌผ๋ฆฌ์ ์ธ ํ๋ก์ ํธ ๋ถ๋ฆฌ ์์ด๋ ๋ฐํ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ๋๊ตฌ์ ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// [Order Module] - ๋๋ฉ์ธ ๊ณ์ธต์ ์์นํ ์ธํฐํ์ด์ค
package com.example.order.domain;
public interface NotificationPort {
void send(String message, String recipient);
}
// [Order Module] - ์๋น์ค ๋ก์ง์ ์ธํฐํ์ด์ค์๋ง ์์กด
package com.example.order.application;
import com.example.order.domain.NotificationPort;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class OrderService {
private final NotificationPort notificationPort;
public void completeOrder(String orderId) {
// ... ์ฃผ๋ฌธ ์ฒ๋ฆฌ ...
notificationPort.send("์ฃผ๋ฌธ์ด ์๋ฃ๋์์ต๋๋ค.", "user@example.com");
}
}
// [Notification Module] - ์ธํฐํ์ด์ค์ ์ค์ ๊ตฌํ์ฒด
package com.example.notification.infrastructure;
import com.example.order.domain.NotificationPort;
import org.springframework.stereotype.Component;
@Component
public class EmailNotificationAdapter implements NotificationPort {
@Override
public void send(String message, String recipient) {
// ์ค์ ์ด๋ฉ์ผ ๋ฐ์ก SMTP ๋ก์ง
}
}
DTO Mapping
๋ชจ๋ ๊ฒฝ๊ณ๋ฅผ ๋๋๋๋ ๋ฐ์ดํฐ๋ ๋ฐ๋์ ๊ทธ ํํ๊ฐ ๋ณํ๋์ด์ผ ํฉ๋๋ค. ๋ชจ๋ ๋ด๋ถ์์ ์ฌ์ฉํ๋ ํ๋ถํ ๋๋ฉ์ธ ์ํฐํฐ(Entity)๋ฅผ ์ธ๋ถ ๋ชจ๋์ ์ง์ ๋ ธ์ถํ๋ ๊ฒ์ ์ํคํ ์ฒ์ ์์ด ํ์์ ๊ฐ์ต๋๋ค. ์ํฐํฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง๋ ๋น์ฆ๋์ค ๊ท์น์ ๊ฐํ๊ฒ ๊ฒฐํฉ๋์ด ์์ด, ์ด๋ฅผ ์ธ๋ถ์์ ์ฐธ์กฐํ๋ ์๊ฐ ํด๋น ์ํฐํฐ๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ๋ชจ๋์ด ํ๋์ ๊ฑฐ๋ํ ์ ์ญ ์ํ๋ฅผ ๊ณต์ ํ๊ฒ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ฐ๋ผ์ ์ธํฐํ์ด์ค๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ๋๋ ์ค์ง ๋ฐ์ดํฐ ์ ๋ฌ๋ง์ ๋ชฉ์ ์ผ๋ก ํ๋ DTO(Data Transfer Object)๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ๊ฐ ๋ชจ๋์ ์ธํฐํ์ด์ค ํธ์ถ ์ง์ ์ ์์ ์ ๋ด๋ถ ๋ชจ๋ธ์ DTO๋ก ๋ณํ(Mapping)ํ๊ณ , ๋ฐ๋ ์ชฝ ์ญ์ DTO๋ฅผ ์์ ์ ๋ด๋ถ ๋ชจ๋ธ๋ก ๋ค์ ๋ณํํฉ๋๋ค. ์ด ๋ณํ ๊ณผ์ ์ ๋ฒ๊ฑฐ๋ก์ ๋ณด์ผ ์ ์์ง๋ง, ๊ฐ ๋ชจ๋์ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ์งํ์ํฌ ์ ์๊ฒ ํด์ฃผ๋ โ๋์ปคํ๋ง ๋น์ฉโ์ผ๋ก์ ์ถฉ๋ถํ ๊ฐ์น๋ฅผ ๊ฐ์ง๋๋ค.
๊ณต์ ์ปค๋์ ์ ํน
์ฌ๋ฌ ๋ชจ๋์์ ๊ณตํต์ผ๋ก ์ฐ์ด๋
Money๋Address๊ฐ์ ๊ฐ ๊ฐ์ฒด(Value Object)๋ฅผ โCommonโ ํจํค์ง์ ๋ชฐ์๋ฃ๊ณ ์ถ์ ์ ํน์ด ์๊น๋๋ค.ํ์ง๋ง ์ด โCommonโ ํจํค์ง๊ฐ ๋น๋ํด์ง์๋ก ๋ชจ๋ ๋ชจ๋์ด ์ด ํจํค์ง์ ์์กดํ๊ฒ ๋์ด, ๊ฒฐ๊ตญ ๋ ๋ค๋ฅธ ํํ์ ๊ฐ๊ฒฐํฉ์ ์ ๋ฐํฉ๋๋ค. ์ ๋ง ๊ณตํต์ ์ธ ์ ํธ๋ฆฌํฐ๊ฐ ์๋๋ผ๋ฉด, ์ฐจ๋ผ๋ฆฌ ๊ฐ ๋ชจ๋์ด ํ์ํ ์ ๋ณด๋ฅผ ์ค๋ณตํด์ ์ ์ํ๋ ๊ฒ์ด ์ํคํ ์ฒ ๊ด์ ์์๋ ๋ ์์ ํฉ๋๋ค.
๐งฉ Dependency Management
๋ชจ๋ํ๋ ์์คํ ์ ์๋ช ์ ๊ฒฐ์ ํ๋ ๊ฐ์ฅ ๊ฒฐ์ ์ ์ธ ์งํ๋ ์์กด์ฑ์ ๋ณต์ก๋์ ๋๋ค. ์๋ฌด๋ฆฌ ๋๋ฉ์ธ์ ์ ๋๋๊ณ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ตํ๊ฒ ์ค๊ณํ๋๋ผ๋, ๋ชจ๋ ๊ฐ์ ์์กด์ฑ ํ๋ฆ์ด ๋ฌด์ง์ํ๊ฒ ์ํค๊ธฐ ์์ํ๋ฉด ์์คํ ์ ๊ฑฐ๋ํ ์คํ๊ฒํฐ๋ก ํ๊ทํฉ๋๋ค. ์์ง๋์ด๋ง ์ค๋ฌด์์ ์์กด์ฑ ๊ด๋ฆฌ๋ ๋จ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ ํ์๊ฐ ์๋๋ผ, ์์คํ ์ ๋น์ํ ๋ฐฉํฅ์ฑ ๊ทธ๋ํ(DAG)๋ฅผ ์ ์งํ๊ธฐ ์ํ ๋์์๋ ํฌ์์ ๋๋ค.
Cyclic Dependency
์ํ ์ฐธ์กฐ(Cyclic Dependency)๋ ๋ชจ๋ํ์ ๊ฐ์ฅ ํฐ ์ ์ ๋๋ค. ๋ชจ๋ A๊ฐ B์ ์์กดํ๊ณ , B๊ฐ ๋ค์ A์ ์์กดํ๋ ๊ตฌ์กฐ๊ฐ ํ์ฑ๋๋ ์๊ฐ, ๋ ๋ชจ๋์ ๋ ผ๋ฆฌ์ ์ผ๋ก ํ๋๊ฐ ๋์ด๋ฒ๋ฆฝ๋๋ค. ์ด๋ฅผ โ์ํ ์ฐธ์กฐ์ ์ ์ฃผโ๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ์ด ์ํ์์๋ ํน์ ๋ชจ๋๋ง ๋ผ์ด๋ด์ด ํ ์คํธํ๊ฑฐ๋ ์ฌ์ฌ์ฉํ๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํด์ง๋ฉฐ, ์ฝ๋ ๋ณ๊ฒฝ์ ์ํฅ ๋ฒ์๊ฐ ์์ ํ๊ณ ๋ฌดํํ ํ์ฅ๋ฉ๋๋ค.
์ํ ์ฐธ์กฐ๋ฅผ ๋์ด๋ด๋ ๊ฐ์ฅ ํ์ค์ ์ธ ๋ฐฉ๋ฒ์ ์์ ์ธ๊ธํ ์์กด์ฑ ์ญ์ (DIP)์ ํ์ฉํ๊ฑฐ๋, ๊ณตํต๋ ๋ก์ง์ ์ 3์ ๋ชจ๋๋ก ์ถ์ถํ๋ ๊ฒ์ ๋๋ค. ํ์ง๋ง ๋ ์ค์ํ ๊ฒ์ ์ํ ์ฐธ์กฐ๊ฐ ๋ฐ์ํ๊ธฐ ์ ์ ์ด๋ฅผ ๊ฐ์งํ๊ณ ์ฐจ๋จํ๋ ์์คํ ์ ์ฅ์น์ ๋๋ค. ๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค์์๋ ์ปดํ์ผ ํ์ ํน์ ๋น๋ ํ์์ ์์กด์ฑ ๊ทธ๋ํ๋ฅผ ๋ถ์ํ์ฌ ์ํ ๊ตฌ์กฐ๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ์ฆ์ ๋น๋๋ฅผ ์คํจ์ํค๋ ์๊ฒฉํ ์ ์ฑ ์ด ํ์ํฉ๋๋ค.
Architecture Guardrail (ArchUnit)
์ฌ๋์ ์์ง๋ ๋ฏฟ์ ๋์์ด ์๋๋๋ค. ํ๋ก์ ํธ์ ์๋ก ํฉ๋ฅํ ๊ฐ๋ฐ์๊ฐ ์ค์๋ก ๊ฒฝ๊ณ๋ฅผ ์นจ๋ฒํ๊ฑฐ๋ ํธ๋ฆฌํจ์ ์ํด ์๋ชป๋ ์์กด์ฑ์ ์ถ๊ฐํ๋ ๊ฒ์ ํํ ์ผ์ ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ ์ํคํ ์ฒ ๊ฐ๋๋ ์ผ(Architecture Guardrail)์ ์๋ํํด์ผ ํฉ๋๋ค.
Java ์ง์์ ArchUnit์ ์ํคํ ์ฒ ๊ท์น์ ์ ๋ ํ ์คํธ ์ฝ๋๋ก ์์ฑํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค. โ์ฃผ๋ฌธ ๋ชจ๋์ ๋ฐฐ์ก ๋ชจ๋์ ๋ด๋ถ ๊ตฌํ์ฒด์ ์์กดํด์๋ ์ ๋๋คโ๋ผ๊ฑฐ๋ โ๋ชจ๋ Controller๋ Service ๊ณ์ธต๋ง ํธ์ถํด์ผ ํ๋คโ์ ๊ฐ์ ๊ท์น์ ์ฝ๋๋ก ๋ช ์ํฉ๋๋ค. ์ด๋ฌํ โArchitecture as Codeโ ์ ๊ทผ ๋ฐฉ์์ ์ฝ๋ ๋ฆฌ๋ทฐ์ ์์๋๋ ์๋์ง๋ฅผ ๋น์ฆ๋์ค ๋ก์ง์ ์ง์ค์ํค๊ณ , ์ํคํ ์ฒ์ ๋ถ์์ ์์ฒ ์ฐจ๋จํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.architecture;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packages = "com.example")
public class ModuleBoundaryTest {
// ๊ท์น: ์ฃผ๋ฌธ(Order) ๋ชจ๋์ ๊ฒฐ์ (Payment) ๋ชจ๋์ 'internal' ํจํค์ง๋ฅผ ์ง์ ์ฐธ์กฐํ ์ ์์
@ArchTest
static final ArchRule order_should_not_depend_on_payment_internal =
noClasses().that().resideInAPackage("..order..")
.should().dependOnClassesThat().resideInAPackage("..payment.internal..");
// ๊ท์น: ๋ชจ๋ ๋ชจ๋์ ์๋ก์ 'internal' ํจํค์ง๋ฅผ ์ฐธ์กฐํด์๋ ์ ๋จ (Public API๋ง ํ์ฉ)
@ArchTest
static final ArchRule modules_should_respect_internal_encapsulation =
noClasses().that().resideInAPackage("..internal..")
.should().beAccessed().byAnyPackage("..internal..");
}
์์กด์ฑ ๊ทธ๋ํ์ ๋จ์ํ
๋ชจ๋์ ๊ฐ์๊ฐ ๋์ด๋ ์๋ก ์์กด์ฑ ๊ด๋ฆฌ๋ ๊ธฐํ๊ธ์์ ์ผ๋ก ์ด๋ ค์์ง๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์์ ๋ชจ๋์ด ํ์ ๋ชจ๋์ ์กด์ฌ๋ฅผ ์์ง ๋ชปํ๊ฒ ํ๋ โ์ด๋ฒคํธ ์ฃผ๋ ํต์ (Event-driven Communication)โ์ ์ ๊ทน์ ์ผ๋ก ๋์ ํ์ญ์์ค. ์ง์ ์ ์ธ ๋ฉ์๋ ํธ์ถ ๋์ ๋ฐํ-๊ตฌ๋ (Pub-Sub) ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉด ์์กด์ฑ ๊ทธ๋ํ์ ์ฐ๊ฒฐ์ ์ ํ๊ธฐ์ ์ผ๋ก ์ค์ผ ์ ์์ต๋๋ค.
Logical Isolation in Shared Database
๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค ์ํคํ ์ฒ์์ ๊ฐ์ฅ ํด๊ฒฐํ๊ธฐ ๊น๋ค๋ก์ด ์ง์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๋ค. ์ฝ๋๋ ๊น๋ํ๊ฒ ๋๋ด๋๋ผ๋, ๋ชจ๋ ๋ชจ๋์ด ํ๋์ ๊ฑฐ๋ํ ๊ณต์ ๋ฐ์ดํฐ๋ฒ ์ด์ค(Shared Database)์์ ์๋ก์ ํ ์ด๋ธ์ ๋ง๊ตฌ์ก์ด๋ก ์กฐ์ธ(Join)ํ๊ณ ์๋ค๋ฉด, ๊ทธ๊ฒ์ โ๋ถ์ฐ๋ ์ฝ๋โ๋ฅผ ๊ฐ์ง โ๊ฑฐ๋ํ ๋ฐ์ดํฐ ๋ฉ์ด๋ฆฌโ์ผ ๋ฟ์ ๋๋ค. ์ง์ ํ ๊ฒฉ๋ฆฌ๋ ์คํ ๋ฆฌ์ง ๊ณ์ธต์์๋ ๋ ผ๋ฆฌ์ ์ธ ๋ฒฝ์ ์ธ์ธ ๋ ์์ฑ๋ฉ๋๋ค.
Schema Isolation
๋ฐ์ดํฐ ๊ฒฉ๋ฆฌ์ ์ฒซ๊ฑธ์์ ๋ฌผ๋ฆฌ์ ์ผ๋ก๋ ํ๋์ DB ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ๋, ๋
ผ๋ฆฌ์ ์ผ๋ก๋ ๊ฐ ๋ชจ๋๋ง์ด ์์ ์ ํ
์ด๋ธ์ ์ ๊ทผํ ์ ์๋๋ก ๊ถํ์ ์ ํํ๋ ๊ฒ์
๋๋ค. ๊ฐ์ฅ ๋จ์ํ ๋ฐฉ๋ฒ์ ํ
์ด๋ธ ์ด๋ฆ์ ์ ๋์ด(e.g., ord_, inv_)๋ฅผ ๋ถ์ด๋ ๊ฒ์ด์ง๋ง, ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์คํค๋ง(Schema) ๊ธฐ๋ฅ์ ํ์ฉํ๋ ๊ฒ์
๋๋ค.
๊ฐ ๋ชจ๋์ ์์ ๋ง์ ์ ์ฉ ์คํค๋ง๋ฅผ ๊ฐ์ง๋ฉฐ, ํ ๋ชจ๋์ ์คํค๋ง์ ์๋ ํ ์ด๋ธ์ ์ง์ ์กฐํํ ์ ์์ต๋๋ค. ๋ง์ฝ ๋ค๋ฅธ ๋ชจ๋์ ๋ฐ์ดํฐ๊ฐ ํ์ํ๋ค๋ฉด, ๋ฐ๋์ ํด๋น ๋ชจ๋์ด ๋ ธ์ถํ ์ธํฐํ์ด์ค(Public API)๋ฅผ ํตํด ์์ฒญํด์ผ ํฉ๋๋ค. ์ด๋ฌํ ์ ์ฝ์ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ์ด, ํ๋ ํน์ ๋ชจ๋์ ๋ง์ดํฌ๋ก์๋น์ค๋ก ๋ถ๋ฆฌํด์ผ ํ ๋ ๋ฐ์ดํฐ ์ด๊ด ์์ ์ ๋์ด๋๋ฅผ ํ๊ธฐ์ ์ผ๋ก ๋ฎ์ถฐ์ค๋๋ค.
Transactional Consistency
๊ณต์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ์ฅ ํฐ ์ถ๋ณต์ ACID ํธ๋์ญ์ ์ ๋๋ค. ์ฌ๋ฌ ๋ชจ๋์ ๊ฑธ์น ์์ ์ ์ํํ ๋, ๋ณต์กํ 2PC(Two-Phase Commit)๋ Saga ํจํด ์์ด๋ ๋ฐ์ดํฐ ์ ํฉ์ฑ์ ์๋ฒฝํ๊ฒ ๋ณด์ฅํ ์ ์์ต๋๋ค. ํ์ง๋ง ์ด๋ ์๋ ์ ๊ฒ์ ๋๋ค.
ํธ๋ฆฌํจ์ ์ทจํด ์ฌ๋ฌ ๋ชจ๋์ ๋ก์ง์ ํ๋์ ๊ฑฐ๋ํ ํธ๋์ญ์ ์ผ๋ก ๋ฌถ์ด๋ฒ๋ฆฌ๋ฉด, ํน์ ๋ชจ๋์ ์ง์ฐ์ด ์ ์ฒด ์์คํ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ๊ณ ๊ฐ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค์์๋ โํธ๋์ญ์ ์ ๋ฒ์โ๋ ์ต๋ํ ์ข๊ฒ ์ ์งํด์ผ ํฉ๋๋ค. ์ด์์ ์ธ ๊ตฌ์กฐ๋ ์ฃผ ๋๋ฉ์ธ ๋ก์ง์ ๋ก์ปฌ ํธ๋์ญ์ ์ผ๋ก ์ฆ์ ์ฒ๋ฆฌํ๊ณ , ๋ถ์์ ์ธ ์์ (e.g., ์๋ฆผ ๋ฐ์ก, ํต๊ณ ์ ๋ฐ์ดํธ)์ ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ํตํด ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌํ์ฌ ํธ๋์ญ์ ์ ์ ์ผ์ ๋ง๋ ๊ฒ์ ๋๋ค.
Cross-Module Joins: The Anti-pattern
์์ง๋์ด๋ค์ด ๊ฐ์ฅ ์์ฃผ ์ ์ง๋ฅด๋ ์ ํน์ ์ฑ๋ฅ์ ์ด์ ๋ก ์ํํ๋ ๊ต์ฐจ ๋ชจ๋ ์กฐ์ธ(Cross-Module Join)์ ๋๋ค. โAPI๋ฅผ ๋ ๋ฒ ํธ์ถํ๋ ๊ฒ๋ณด๋ค ํ ๋ฒ์ SQL ์กฐ์ธ์ด ํจ์ฌ ๋น ๋ฅด๋คโ๋ ๋ ผ๋ฆฌ๋ ๋จ๊ธฐ์ ์ผ๋ก๋ ๋ง์ง๋ง, ์ํคํ ์ฒ ๊ด์ ์์๋ ์น๋ช ์ ์ ๋๋ค.
๊ต์ฐจ ๋ชจ๋ ์กฐ์ธ์ ๋ชจ๋ ๊ฐ์ ๋ฌผ๋ฆฌ์ ๊ฒฐํฉ์ ๊ณ ์ฐฉํํฉ๋๋ค. ํน์ ๋ชจ๋์ ํ ์ด๋ธ ๊ตฌ์กฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ด๋ฅผ ์กฐ์ธํ๋ ๋ค๋ฅธ ๋ชจ๋ ๋ชจ๋์ ์ฟผ๋ฆฌ๊ฐ ๊นจ์ง๊ฒ ๋ฉ๋๋ค. ์ด๋ ์บก์ํ๋ฅผ ์ ๋ฉด์ผ๋ก ์๋ฐํ๋ ํ์์ ๋๋ค.
| ๊ตฌ๋ถ | ๊ต์ฐจ ๋ชจ๋ ์กฐ์ธ (Anti-pattern) | API ๊ธฐ๋ฐ ๋ฐ์ดํฐ ํฉ์ฑ (Recommended) |
|---|---|---|
| ๊ฒฐํฉ๋ | ๋งค์ฐ ๋์ (์คํค๋ง ๋ณ๊ฒฝ ์ ์ฐ์ ํ์) | ๋ฎ์ (์ธํฐํ์ด์ค ๋ค๋ก ์จ๊ฒจ์ง) |
| ์ฑ๋ฅ | ๋จ์ผ ์ฟผ๋ฆฌ๋ก ์ต์ ํ ๊ฐ๋ฅ | ๋คํธ์ํฌ/์ ํ๋ฆฌ์ผ์ด์ ์ค๋ฒํค๋ ๋ฐ์ |
| ๋ถ๋ฆฌ ๊ฐ๋ฅ์ฑ | MSA ์ ํ ์ ์ฟผ๋ฆฌ ์ ์ฒด ์ฌ์์ฑ ํ์ | ์๋น์ค ๋ถ๋ฆฌ ์ ์๋ํฌ์ธํธ๋ง ๋ณ๊ฒฝ |
| ๊ถ์ฅ ์ํฉ | ์ ๋ ๊ธ์ง (๊ธฐ์ ๋ถ์ฑ์ ๊ทผ์) | ์ฑ๋ฅ ์ด์ ๋ฐ์ ์ ๋ณ๋์ Query Model(CQRS) ๊ตฌ์ถ |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. Anti-pattern: DB Join์ ํตํ ์กฐํ (X)
// SELECT o.*, p.name FROM orders o JOIN products p ON o.product_id = p.id (X)
// 2. Recommended: ID ๊ธฐ๋ฐ์ ์ ํ๋ฆฌ์ผ์ด์
์๋น์ค ๊ฒฐํฉ (O)
package com.example.order.application;
import com.example.catalog.CatalogClient; // Catalog ๋ชจ๋์ API
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class OrderQueryService {
private final OrderRepository orderRepository;
private final CatalogClient catalogClient;
public OrderResponse getOrderDetails(String orderId) {
Order order = orderRepository.findById(orderId).orElseThrow();
// ํ ๋ชจ๋์ ๋ฐ์ดํฐ๋ DB ์กฐ์ธ์ด ์๋ API(ํน์ ์ง์ ์ฐธ์กฐ)๋ฅผ ํตํด ๊ฐ์ ธ์ด
ProductDto product = catalogClient.getProductById(order.getProductId());
return new OrderResponse(order, product);
}
}
Distributed Tracing in Monolith
์์ด๋ฌ๋ํ๊ฒ๋ ๋ชจ๋ํ ๋ชจ๋ ธ๋ฆฌ์ค์์๋ ๋ถ์ฐ ์ถ์ (Distributed Tracing) ๊ธฐ์ ์ด ํ์ํฉ๋๋ค. ์์ฒญ์ด ์ฌ๋ฌ ๋ชจ๋์ ๊ฒฝ๊ณ๋ฅผ ๋๋๋ค๋ฉฐ ์ฒ๋ฆฌ๋ ๋, ์ด๋ ๋ชจ๋์์ ๋ณ๋ชฉ์ด ๋ฐ์ํ๋์ง, ์ด๋ค ๋ชจ๋์ ๋ก์ง์ด ์คํจ์ ๊ทผ์์ธ์ง ํ์ ํ๊ธฐ ์ํด์์ ๋๋ค.
๊ฐ ๋ชจ๋ ํธ์ถ๋ง๋ค ๊ณ ์ ํ Trace ID๋ฅผ ์ ๋ฌํ๊ณ ๋ก๊ทธ์ ๋จ๊ธฐ๋ ์ต๊ด์ ์์คํ
์ ๊ฐ์์ฑ์ ๊ทน๋ํํฉ๋๋ค. ์ด๋ ๋จ์ํ ๋ชจ๋ํฐ๋ง์ ๋์ด, ํฅํ ์์คํ
์ด ๋น๋ํด์ ธ ์ค์ ๋ง์ดํฌ๋ก์๋น์ค๋ก ๋ถํ ๋ ๋ ์๋น์ค ๊ฐ์ ํต์ ํ๋ฆ์ ๋ฏธ๋ฆฌ ํ์
ํ ์ ์๋ ๊ท์คํ ์ง๋๊ฐ ๋ฉ๋๋ค.
๋ฐ์ดํฐ๋ ๋ชจ๋์ ์ฌ์ํ์ด๋ค
๋ชจ๋์ ์์ค ์ฝ๋๋ ๊ณต์ ๋ ์ ์์ด๋, ๊ทธ ๋ชจ๋์ด ๊ด๋ฆฌํ๋ ๋ฐ์ดํฐ์ โ๋ฌผ๋ฆฌ์ ๊ตฌ์กฐโ๋ ์ฒ ์ ํ ๋น๋ฐ๋ก ์ ์ง๋์ด์ผ ํฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ๊ณต์ ํ๋ ๊ฒ์ ๋ง์น ๋ค๋ฅธ ์ฌ๋์ ์ผ๊ธฐ์ฅ์ ํ๋ฝ ์์ด ์ฝ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. ์ํต์ ์ค์ง ์ธํฐํ์ด์ค๋ผ๋ ๋ํ๋ฅผ ํตํด์๋ง ์ด๋ฃจ์ด์ ธ์ผ ํฉ๋๋ค.
Summary
Modular Monolithic Architecture๋ โ์ด์์ ๋จ์ํจโ๊ณผ โ์ฝ๋์ ๊ฑด์ ์ฑโ ์ฌ์ด์์ ์ต์ ์ ๊ท ํ์ ์ฐพ๋ ์ ๋ต์ ์ ํ์ ๋๋ค. ์ฐ๋ฆฌ๋ ๋ชจ๋์ ํตํด ๋๋ฉ์ธ์ ๊ฒฉ๋ฆฌํ๊ณ (Module), ๋จ์ผ ๋ฐฐํฌ๋ฅผ ํตํด ์ด์ ๋น์ฉ์ ์ ๊ฐํ๋ฉฐ(Monolith), ๋ช ํํ ์ธํฐํ์ด์ค์ ์ํคํ ์ฒ ๊ฐ๋๋ ์ผ์ ํตํด ์์คํ ์ ๋ถ์์ ๋ง์ต๋๋ค. ํนํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง ์์ค์ ๋ ผ๋ฆฌ์ ๊ฒฉ๋ฆฌ๋ฅผ ์ค์ฒํ ๋, ๋ชจ๋ ธ๋ฆฌ์ค๋ ๋จ์ํ ์ฝ๋ ๋ญ์น๋ฅผ ๋์ด ์ธ์ ๋ ๋ง์ดํฌ๋ก์๋น์ค๋ก ์งํํ ์ ์๋ ์ ์ฐํ ์ํ๊ณ๊ฐ ๋ฉ๋๋ค.





