일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 일급 객체
- Volatile
- Spring
- OAuth 2.0
- java
- middleware
- Dependency Injection
- lombok
- spring security
- builder
- 일급 컬렉션
- Google OAuth
- factory
- synchronized
- nestjs
- Today
- Total
HJW's IT Blog
3 Layered vs Clean Architecture 본문
#3Layered #CleanArchitecture
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)는 외부에 의존하지 않음 |
장점 | - 구조가 단순하고 직관적 - 빠른 개발 가능 - 기존 시스템과 연계 용이 |
- 도메인 로직을 중심으로 설계 가능 - 유지보수성과 테스트 용이 - 의존성 역전을 통해 유연한 설계 가능 |
단점 | - 서비스 계층이 점점 비대해지는 문제 발생 가능 - 변경 시 계층 간 영향이 큼 - 테스트 용이성이 낮음 |
- 초기 설계 및 학습 비용이 큼 - 프로젝트 규모가 작으면 과도한 설계가 될 수도 있음 |
🚀 클린 아키텍처의 핵심 : 의존성 역전 (Dependency Inversion)
기존 3계층 방식에선 Service
가 직접 Repository
를 호출하는 형태이다. 그렇다면, 비즈니스 로직 -> 데이터 접근 계층 으로 의존성이 흐르게 된다.
클린 아키텍처와의 차이는 여기서 발생한다. 클린 아키텍저에서는 비즈니스 로직이 데이터 접근 방식에 대해 전혀 모르게 만드는 것이 목표이다.
👉 즉, "비즈니스 로직이 DB를 몰라야 한다" 는 것이 가장 중요한 포인트이다.
클린 아키텍처는 비즈니스 로직(Service)이 Repository
가 아닌 Port(Interface)
에 의존하게 하며, Port
의 실제 구현은 Adapter
계층에서 하게 만듬으로써 이를 달성한다.
👉 UseCase(Service)
는 오직 "데이터가 필요하다" 라는 사실만 알아야 한다.
🚀 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와 저장 방식이 변경될 때 비즈니스 로직도 영향을 받을 가능성이 있다.
즉 클린 아키텍처의 핵심은 비즈니스 로직이 저장 방식을 전혀 몰라도 되도록 만드는 것이다.
✅ "나는 데이터를 저장해야 한다" (클린 아키텍처)
❌ "나는 Repository를 써야 한다" (3계층 아키텍처)
'개발 개념' 카테고리의 다른 글
PRG Pattern 은 왜 사용할까? (0) | 2025.01.16 |
---|---|
Builder Pattern 에 대한 고찰 (0) | 2025.01.10 |
SOLID 와 TradeOff (0) | 2025.01.09 |
상속보단 합성을 사용하자 (0) | 2025.01.06 |
단일 책임 원칙, 얼마나 쪼개야 ‘적당함’일까? (1) | 2025.01.03 |