Layered Architecture란?
소프트웨어가 커질수록 코드는 복잡해지기 마련이다. 이 복잡성을 해결하는 가장 오래되고 검증된 방법은 '관심사의 분리'라는 것이 있는데 레이어드 아키텍처는 시스템을 유사한 관심사끼리 계층화하여 각 계층이 자신의 역할에만 집중하게 함으로써 유지보수성과 확장성을 높이는 방법론이다.
Layered Architecture(계층형 아키텍처)는 애플리케이션을 역할별로 계층을 나누어 책임을 분리하는 구조다. Spring 기반 서버에서는 일반적으로 다음 구조를 가진다.
Layered Architecture의 목적은 관심사의 분리이다.
Controller
(아래로)
Service
(아래로)
Repository
(아래로)
DB
각 계층은 자기 역할만 수행해야 하며, 아래 계층에만 의존하는 것이 기본 원칙이다.
Controller / Service / Repository 역할
Controller (Prensentation Layer)
- 역할: 외부 사용자의 요청을 가장 먼저 받고, 최종 응답을 반환
- 책임: 요청 데이터의 형식 검증(Validation), HTTP 상태 코드 결정 및 요청/응답 처리, 서비스 계층 호출, DTO 변환
- 주의:
- 비즈니스 로직이 포함되어서는 안된다
- 트랜잭션 처리를 하면 안된다
- DB 접근
Service (Application Layer)
- 역할: 사용자의 유스케이스(Use Case)를 구현하고 여러 도메인 객체를 조립한다
- 책임: 비즈니스 로직 수행, Repository 호출, 트랜잭션 관리, 도메인 객체 간의 협력 조율, 외부 API 호출 지시
- 주의: 모든 로직을 여기서 처리하면 서비스에 과집중 되어 유지보수가 힘들어진다.
Repository (Infrastructure Layer)
- 역할: 데이터베이스나 파일 시스템 등 물리적인 데이터 저장소에 접근한다
- 책임: 엔티티 객체의 저장, 조회, 삭제 수행, 쿼리 작성, DB 접근
- 특징: 비즈니스 로직 없음. 데이터 접근 전담 계층이다
핵심 이슈: 도메인 로직은 어디에?
Service 계층에 로직이 몰리는 문제
Spring 프로젝트에서 Service Layer 단에 비즈니스 로직을 구현하다 보면 아래와 같은 식으로 하나의 메서드에 여러 비즈니스 로직들이 추가되게 된다.
@Transactional
public void createOrder(...) {
// 유효성 검사
// 금액 계산
// 상태 변경
// 포인트 차감
// 로그 기록
// 알림 전송
}
위 코드의 문제점은 하나의 메서드에 해당 비즈니스 로직을 담당하는 여러 메서드들이 포함됨으로 인해 응집도가 낮아지고, 테스트가 어려워지는 상황이 발생할 수 있다. 이로 인해 서비스 계층이 비대해지면 코드가 중복되어 유지보수 면에서 좋지 않게 된다.
- 해결책: 비즈니스 로직을 도메인 엔티티(Entity) 내부로 옮겨야 한다. 엔티티 스스로 자신의 상태를 변경하고 검증하게 한다. 서비스는 그저 엔티티에게 "이 일을 해줘"라고 시키는 역할만 수행해야 한다.
public class Order {
private int price;
private int quantity;
public int calculateTotalPrice() {
return price * quantity;
}
}
그리고 Service 단의 createOrder 메서드에서는 아래와 같이 해당 엔티티에 접근하여 비즈니스 로직 메서드를 실행한다.
order.calculateTotalPrice();
책임 분리 원칙
| 위치 | 어떤 로직을 두는가 |
| Controller | 요청 처리 |
| Service | 유스케이스 조합 |
| Domain(Entity) | 도메인 규칙 |
| Repository | 영속성 |
DTO / Entity 분리 이유
Entity를 바로 반환하면 안 되는 이유
- 보안 문제 : password의 경우, Entity를 바로 반환하면 노출 위험이 있다.
- API 스펙과 도메인 분리 : API는 변경될 수 있으나 도메인은 안정적이어야 한다.
- 영속성 컨텍스트 문제
- Lazy Loading 이슈
- 양방향 연관관계 순환참조
- 무한 직렬화
- 계층 침범 방지
- Entity는 Repository 영역의 개념
- 외부 API 계층까지 퍼지면 레이어 경계 붕괴
DTO의 역할
- 요청/응답 모델
- 계층 간 데이터 전달
- 외부 인터페이스 보호막
올바른 구조
Controller <-> DTO
Service <-> Domain(Entity)
Repository <-> Entity반응형
'TIL' 카테고리의 다른 글
| [TIL] JOIN 전략 (0) | 2026.03.10 |
|---|---|
| [TIL] DDD 구성요소 (0) | 2026.02.24 |
| [TIL] 전략적 DDD와 전술적 DDD (0) | 2026.02.23 |
| [TIL] DDD 개념 & 설계 사고방식 (0) | 2026.02.20 |
| [TIL] 블로킹/논블로킹과 동기/비동기 (0) | 2026.02.10 |