| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- middleware
- lombok
- 일급 컬렉션
- spring security
- 일급 객체
- Spring
- factory
- OAuth 2.0
- Dependency Injection
- nestjs
- Volatile
- synchronized
- builder
- java
- Google OAuth
- Today
- Total
HJW's IT Blog
3 Layered vs Clean Architecture 본문
3계층 아키텍처 vs 클린 아키텍처 비교표
| 비교 항목 | 3계층 아키텍처 (Three-Tier Architecture) | 클린 아키텍처 (Clean Architecture) |
|---|---|---|
| 구조 | Presentation (UI) 계층 Business Logic (Service) 계층 Data (Repository) 계층 |
Entities (도메인 모델) Use Cases (비즈니스 로직) Interface Adapters (Controller, Presenter, Gateway) Frameworks & Drivers (DB, UI, External API) |
| 주요 개념 | 계층별 역할을 나누어 관심사 분리 | 의존성 방향을 내부(core)로 향하게 하여 높은 유지보수성과 테스트 용이성 제공 |
| 의존성 흐름 | UI → Service → Repository (하위 계층이 상위 계층을 의존) | 바깥 계층이 안쪽 계층을 의존 (Inner Circle → Outer Circle) |
| 데이터 흐름 | 클라이언트 요청이 UI를 통해 Service 계층을 거쳐 Repository를 통해 DB에서 데이터를 처리 | 비즈니스 로직(Use Case)이 중심이 되고, 외부 인터페이스(Adapter)는 이를 지원하는 형태 |
| 유연성 & 확장성 | 비교적 제한적 (계층 간 강한 결합이 발생할 수 있음) | 높은 유연성 (구현체 변경이 용이, 테스트가 쉬움) |
| 의존성 방향 | 하위 계층이 상위 계층을 의존하는 경우가 많음 | 외부가 내부를 의존하며, 내부(core)는 외부에 의존하지 않음 |
| 장점 | - 구조가 단순하고 직관적 - 빠른 개발 가능 - 기존 시스템과 연계 용이 |
- 도메인 로직을 중심으로 설계 가능 - 유지보수성과 테스트 용이 - 의존성 역전을 통해 유연한 설계 가능 |
| 단점 | - 서비스 계층이 점점 비대해지는 문제 발생 가능 - 변경 시 계층 간 영향이 큼 - 테스트 용이성이 낮음 |
- 초기 설계 및 학습 비용이 큼 - 프로젝트 규모가 작으면 과도한 설계가 될 수도 있음 |
클린 아키텍처의 핵심 : 의존성 역전
기존 3계층 방식에선 Service 가 직접 Repository 를 호출하는 형태이다. 그렇다면, 비즈니스 로직 -> 데이터 접근 계층 으로 의존성이 흐르게 된다.
클린 아키텍처와의 차이는 여기서 발생한다. 클린 아키텍저에서는 비즈니스 로직이 데이터 접근 방식에 대해 전혀 모르게 만드는 것이 목표이다.
즉, "비즈니스 로직이 DB를 몰라야 한다" 는 것이 가장 중요한 포인트이다.
클린 아키텍처는 비즈니스 로직(Service)이 Repository 가 아닌 Port(Interface) 에 의존하게 하며, Port 의 실제 구현은 Adapter 계층에서 하게 만듬으로써 이를 달성한다.
UseCase 는 오직 "데이터가 필요하다" 라는 사실만 알아야 한다.
3 계층 설계에서도 Repository를 추상화 할수 있지 않나?
다음과 같은 3 Layered 설계가 있다.
public interface OrderRepository {
Order save(Order order);
Optional<Order> findById(Long id);
}
public class JpaOrderRepository implements OrderRepository {
@Override
public Order save(Order order) {
// JPA 사용
}
@Override
public Optional<Order> findById(Long id) {
// JPA 사용
}
}
public class MySqlOrderRepository implements OrderRepository {
@Override
public Order save(Order order) {
// MySQL JDBC 사용
}
@Override
public Optional<Order> findById(Long id) {
// MySQL JDBC 사용
}
}
이 코드에서도 OrderRepository interface 만 사용하면 , DB 변경시 구현체만 갈아 끼울 수 있다. 유연성도 확보되며, Service 코드가 특정 기술에 직접 의존하지도 않는다.
하지만 여전히 부족한 이유
여전히 아키텍처의 방향성이 잘못 되어 있다. 비즈니스 로직이 여전히 DB 중심 으로 설계되어 있다.
문제점 1 : OrderRepository 인터페이스는 여전히 Repository 중심적
- 인터페이스를 사용하지만 결국 Repository 중심이다
- 비즈니스 로직에서 Repository를 제외할 수 없다
- 만약 DB 없이도 서비스가 동작해야 하는 상황이라면? ex) Test, 도메인 로직 실행 등...
문제점 2 : 비즈니서 로직과 DB 사이의 불완전한 분리
- 의존성의 흐름이 Service -> Repository 이다
- DB가 비즈니스 로직을 모르게 해야 한다는 클린 아키텍처의 원칙에 어긋난다
- 결국 Service 가 어떤 Repository 구현체를 쓰는지 신경 써야 한다.
클린 아키텍처 : Port & Adapter 적용
Port (Interface) 분리
public interface OrderRepositoryPort {
Order save(Order order);
Optional<Order> findById(Long id);
}
- 이때, Port 는 Repository 가 아님을 명시한다. 해당 Port 는 오직 Use Case 만을 위한 인터페이스지, DB를 위한 것이 아니다.
Adapter (구체적 구현체)
public class JpaOrderRepositoryAdapter implements OrderRepositoryPort {
private final JpaOrderRepository jpaRepository;
public JpaOrderRepositoryAdapter(JpaOrderRepository jpaRepository) {
this.jpaRepository = jpaRepository;
}
@Override
public Order save(Order order) {
return jpaRepository.save(order);
}
@Override
public Optional<Order> findById(Long id) {
return jpaRepository.findById(id);
}
}
OrderRepositoryPort를 Adapter 가 구현한다- 기술 스택 변경시 Adapter 만 수정하면 된다
- Use Case 는 Adapter 를 전혀 몰라도 된다.
Use Case (비즈니스 로직)
public class OrderService {
private final OrderRepositoryPort orderRepository;
public OrderService(OrderRepositoryPort orderRepository) {
this.orderRepository = orderRepository;
}
public void processOrder(Order order) {
// 비즈니스 로직 처리
orderRepository.save(order);
}
}
- Use Case 는
OrderRepositoryPort만 바라보므로, 어떤 DB를 사용하는지 몰라도 된다. - DB 와 비즈니스 로직의 완전한 분리
결론: 클린 아키텍처는 "비즈니스 로직을 기술적인 개념과 완전히 분리"하기 위해 필요하다!
3 layered 아키텍처 에서도 인터페이스를 활용하면 어느정도의 유연성은 확보할 수 있다. 하지만 여전히 Repository 개념을 포함하는 이상 DB와 저장 방식이 변경될 때 비즈니스 로직도 영향을 받을 가능성이 있다.
즉 클린 아키텍처의 핵심은 비즈니스 로직이 저장 방식을 전혀 몰라도 되도록 만드는 것이다.
"나는 데이터를 저장해야 한다" (클린 아키텍처) -> o
"나는 Repository를 써야 한다" (3계층 아키텍처) -> x
'개발 개념' 카테고리의 다른 글
| Port & Adapter 패턴 도입기 (1) | 2025.09.07 |
|---|---|
| PRG Pattern 은 왜 사용할까? (0) | 2025.01.16 |
| Builder Pattern 에 대한 고찰 (0) | 2025.01.10 |
| SOLID 와 TradeOff (0) | 2025.01.09 |
| 상속보단 합성을 사용하자 (0) | 2025.01.06 |