Spring 경계와 계약 아키텍처 정의 #3
1 changed files with 131 additions and 0 deletions
131
docs/adr/ADR-001-controller-service-repository-boundaries.md
Normal file
131
docs/adr/ADR-001-controller-service-repository-boundaries.md
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
# ADR-001: Controller-Service-Repository 경계 정의
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
본 프로젝트(runtime-role-smoke-202607140500)는 Spring Boot 기반의 역할 관리 시스템이다.
|
||||||
|
다층 아키텍처에서 각 계층의 책임과 의존성 방향을 명확히 정의하여:
|
||||||
|
- 코드 유지보수성 향상
|
||||||
|
- 단위 테스트 용이성 확보
|
||||||
|
- 계층 간 결합도 최소화
|
||||||
|
|
||||||
|
를 목적으로 한다.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
### 1. Controller 계층
|
||||||
|
|
||||||
|
**책임:**
|
||||||
|
- HTTP 요청/응답 처리
|
||||||
|
- 입력 검증(Validation) 수행
|
||||||
|
- Service 계층 호출 및 결과 매핑
|
||||||
|
- 예외를 HTTP 응답으로 변환
|
||||||
|
|
||||||
|
**금지 사항:**
|
||||||
|
- 비즈니스 로직 직접 구현 금지
|
||||||
|
- Repository 직접 호출 금지
|
||||||
|
- @Transactional 선언 금지
|
||||||
|
|
||||||
|
**구현 규칙:**
|
||||||
|
```java
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RoleController {
|
||||||
|
private final RoleService roleService;
|
||||||
|
|
||||||
|
@PostMapping("/roles")
|
||||||
|
public ResponseEntity<RoleResponse> createRole(@Valid @RequestBody RoleRequest request) {
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED)
|
||||||
|
.body(roleService.createRole(request));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Service 계층
|
||||||
|
|
||||||
|
**책임:**
|
||||||
|
- 비즈니스 로직 수행
|
||||||
|
- 트랜잭션 관리
|
||||||
|
- 도메인 객체 조작
|
||||||
|
- Repository 호출 및 결과 가공
|
||||||
|
|
||||||
|
**금지 사항:**
|
||||||
|
- HTTP 요청/응답 직접 처리 금지
|
||||||
|
- @RequestBody, @RequestParam 등 HTTP 어노테이션 사용 금지
|
||||||
|
|
||||||
|
**구현 규칙:**
|
||||||
|
```java
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class RoleService {
|
||||||
|
private final RoleRepository roleRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public RoleResponse createRole(RoleRequest request) {
|
||||||
|
// 비즈니스 로직
|
||||||
|
Role role = Role.create(request.getName(), request.getDescription());
|
||||||
|
Role savedRole = roleRepository.save(role);
|
||||||
|
return RoleResponse.from(savedRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Repository 계층
|
||||||
|
|
||||||
|
**책임:**
|
||||||
|
- 데이터베이스 접근
|
||||||
|
- CRUD 연산 수행
|
||||||
|
- 쿼리 메서드 정의
|
||||||
|
|
||||||
|
**금지 사항:**
|
||||||
|
- 비즈니스 로직 포함 금지
|
||||||
|
- Service 계층 직접 호출 금지
|
||||||
|
|
||||||
|
**구현 규칙:**
|
||||||
|
```java
|
||||||
|
@Repository
|
||||||
|
public interface RoleRepository extends JpaRepository<Role, Long> {
|
||||||
|
Optional<Role> findByName(String name);
|
||||||
|
boolean existsByName(String name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 의존성 방향
|
||||||
|
|
||||||
|
```
|
||||||
|
Controller → Service → Repository → Domain/Entity
|
||||||
|
↑
|
||||||
|
(Domain Event를 통한 역방향 허용)
|
||||||
|
```
|
||||||
|
|
||||||
|
**의존성 규칙:**
|
||||||
|
- 상위 계층은 하위 계층에만 의존
|
||||||
|
- 동일 계층 간 직접 의존 금지
|
||||||
|
- Domain 객체는 어떤 계층에도 의존하지 않음
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
### 대안 1: Transactional Script 패턴
|
||||||
|
- 모든 로직을 Controller에 포함
|
||||||
|
- 단점: 테스트 어려움, 코드 중복
|
||||||
|
- 채택하지 않음
|
||||||
|
|
||||||
|
### 대안 2: 도메인 주도 설계(DDD)
|
||||||
|
- Aggregate, Entity, Value Object 세분화
|
||||||
|
- 단점: 과도한 복잡성, 학습 곡선 높음
|
||||||
|
- 현재 프로젝트 규모에 과도하여 채택하지 않음
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
**Positive:**
|
||||||
|
- 각 계층의 책임이 명확하여 코드 가독성 향상
|
||||||
|
- 단위 테스트 시 Mock 객체 사용 용이
|
||||||
|
- 향후 MSA 전환 시 서비스 분리 용이
|
||||||
|
|
||||||
|
**Negative:**
|
||||||
|
- 간단한 CRUD 연산에도 다중 계층 코드 작성 필요
|
||||||
|
-初期開発時に多少のオーバーヘッド
|
||||||
|
|
||||||
|
**Mitigation:**
|
||||||
|
- Lombok, MapStruct 활용으로 보일러플레이트 감소
|
||||||
|
- 공통 응답/예외 처리基础设施建设
|
||||||
Loading…
Add table
Add a link
Reference in a new issue