Phase 4레슨 18
Hexagonal Architecture (Ports & Adapters)
Port, Adapter, Driving/Driven — 애플리케이션을 육각형으로
💡ELI5·
육각형과 포트
[HTTP] [gRPC] [CLI]
\ | /
\ | /
┌───[Driving Port: PlaceOrder]───┐
│ Domain │
│ ┌─────────────────────────┐ │
│ │ Order, User, ... │ │
│ └─────────────────────────┘ │
└──[Driven Port: OrderRepo]───────┘
/ | \
/ | \
[MySQL] [Postgres] [In-Memory]💡 비유 — 육각형 = 애플리케이션 코어. 각 변 = Port (연결 포트). 포트에 꽂는 플러그 = Adapter. 같은 포트에 다른 플러그를 꽂으면 다른 DB/프레임워크로 교체. 코어는 플러그가 뭔지 모른다.
🔬Deep Dive·
Driving vs Driven
| 구분 | 방향 | 예시 | 교체 예 |
|---|---|---|---|
| Driving Port | 외부 → 내부 (입력) | PlaceOrderUseCase 인터페이스 | REST → gRPC → CLI |
| Driven Port | 내부 → 외부 (출력) | OrderRepository 인터페이스 | MySQL → MongoDB → In-Memory |
| Driving Adapter | Driving Port를 호출 | REST Controller, gRPC Handler | 프레임워크 교체 |
| Driven Adapter | Driven Port를 구현 | MySQLOrderRepository | DB 교체 |
🔬Deep Dive·
실제 구조 예시
// Port (내부에 정의)
interface PlaceOrderPort {
execute(cmd: PlaceOrderCommand): Promise<Order>;
}
interface OrderRepositoryPort {
save(order: Order): Promise<void>;
}
// Domain (내부, 외부 모름)
class OrderApplication implements PlaceOrderPort {
constructor(private repo: OrderRepositoryPort) {}
async execute(cmd: PlaceOrderCommand) {
const order = Order.create(cmd.items);
await this.repo.save(order);
return order;
}
}
// Driving Adapter (외부 — REST)
class OrderRestController {
constructor(private app: PlaceOrderPort) {}
@Post('/orders')
async create(@Body() body) {
return this.app.execute(new PlaceOrderCommand(body.items));
}
}
// Driven Adapter (외부 — MySQL)
class MySQLOrderAdapter implements OrderRepositoryPort {
async save(order: Order) { /* SQL */ }
}⚖️Trade-off·
Hexagonal vs Clean
| 구분 | Hexagonal | Clean |
|---|---|---|
| 핵심 모델 | Port & Adapter (경계) | Layer (양파) |
| 강조점 | 외부와의 연결 포트 | 의존성 방향 |
| 실용성 | 인터페이스 기반 명확 | 계층 분리 명확 |
| 실제 | 혼용해서 사용 (같은 원칙) | 혼용해서 사용 |
❓ 체크포인트 질문
- 1.Port와 Adapter의 차이는?
- 2.Driving Port와 Driven Port의 차이는?
- 3.Hexagonal과 Clean Architecture의 공통점과 차이점은?
- 4.Hexagonal에서 REST API를 gRPC로 교체할 때 무엇이 바뀌는가?
- 5.Hexagonal Architecture가 테스트에 유리한 이유는?