1. 데이터 흐름 시각화
게시판 애플리케이션에서 글 저장과 글 수정 작업을 처리하는 데이터 흐름을 계층별로 시각화하면 다음과 같습니다:
[사용자] → HTTP 요청 (POST/PUT) → [Controller]
↓
비즈니스 로직 실행 → [Service]
↓
도메인 규칙 적용 → [Domain]
↓
DB 작업 요청 및 수행 → [Repository] ↔ [Database]
이를 도식화하면 다음과 같습니다:
+------------+ +-------------+ +-------------+ +-------------+ +-------------+
| 사용자 | ---> | Controller | ---> | Service | ---> | Domain | ---> | Repository |
+------------+ +-------------+ +-------------+ +-------------+ +-------------+
↕
[Database]
2. 계층별 데이터 흐름 상세 설명
2.1 Controller → Service
-
입력 데이터: HTTP 요청에서 받은 데이터를
DTO(Data Transfer Object)로 변환. -
처리 방식: URL과 메서드에 따라 적절한 Service 메서드 호출.
-
문제 사례
- 요청 데이터가 잘못되었거나, 누락된 경우 (
400 Bad Request). - URL이 잘못되어 라우팅되지 않는 경우 (
404 Not Found).
- 요청 데이터가 잘못되었거나, 누락된 경우 (
-
해결 방법
- 유효성 검사(@Valid): Spring Boot의
@Valid와@RequestBody를 사용하여 요청 데이터를 검증. - 예외 처리(Exception Handling):
@ControllerAdvice로 공통 예외를 처리.
- 유효성 검사(@Valid): Spring Boot의
@RestController
public class PostController {
@PostMapping("/posts")
public ResponseEntity<PostDto> savePost(@Valid @RequestBody PostDto postDto) {
PostDto savedPost = postService.savePost(postDto); // 서비스 호출
return ResponseEntity.ok(savedPost); // 성공 응답
}
// 공통 예외 처리
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleValidationException(MethodArgumentNotValidException ex) {
return ResponseEntity.badRequest().body("입력값이 잘못되었습니다.");
}
}
}
2.2 Service → Domain
-
입력 데이터: Controller에서 전달받은 요청 데이터를 비즈니스 로직에 따라 처리.
-
처리 방식
- 비즈니스 로직 실행 (예: 제목 검증, 게시글 수정).
- 필요한 데이터를
Domain 객체로 변환.
-
문제 사례
- 도메인 객체가 잘못된 데이터를 포함하거나 규칙을 위반하는 경우.
- 비즈니스 로직에서 처리되지 않은 예외 발생.
-
해결 방법
- 비즈니스 규칙 검증: Service 계층에서 규칙 검증(예: 제목이 100자를 초과하는지 확인).
- 적절한 예외 처리: 규칙 위반 시
IllegalArgumentException등 명확한 예외를 던지고 Controller에서 처리.
@Service
public class PostService {
public PostDto savePost(PostDto postDto) {
// 제목 검증
if (postDto.getTitle() == null || postDto.getTitle().isEmpty()) {
throw new IllegalArgumentException("제목은 필수입니다.");
}
// 도메인 객체 생성
Post post = new Post(postDto.getTitle(), postDto.getContent());
// 저장 요청
Post savedPost = postRepository.save(post);
return new PostDto(savedPost.getId(), savedPost.getTitle(), savedPost.getContent());
}
}
2.3 Domain → Repository
-
입력 데이터: 비즈니스 로직에 의해 생성된 도메인 객체.
-
처리 방식
- 도메인 객체를 데이터베이스에 저장하거나 수정 요청.
JPA와 같은 ORM을 통해 데이터베이스와 상호작용.
-
문제 사례
- 데이터베이스와의 연결 실패.
- 중복 데이터 저장(예: 고유 키 중복).
- 엔티티 매핑 문제(잘못된
@Entity설정).
-
해결 방법
- 유니크 제약 조건 설정: 데이터베이스에서
@Column(unique = true)와 같은 제약 조건 사용. - 데이터베이스 연결 오류 처리: 데이터베이스 연결 오류를
@Repository에서 캐치하고, 적절한 에러 메시지 반환.
- 유니크 제약 조건 설정: 데이터베이스에서
@Repository
public interface PostRepository extends JpaRepository<Post, Long> {
// Spring Data JPA가 기본적인 CRUD 메서드 제공
}
3. 각 계층에서 발생할 수 있는 문제와 해결 방법 요약
| 계층 | 발생 가능한 문제 | 해결 방법 |
|---|---|---|
| Controller | - 잘못된 요청 데이터 - 라우팅 오류 |
- @Valid를 사용한 요청 데이터 검증 - @ControllerAdvice를 통한 예외 처리 |
| Service | - 비즈니스 로직 위반 - 데이터 검증 실패 |
- 비즈니스 규칙을 Service 계층에서 먼저 검증 - 적절한 예외(Exception)를 던지고 Controller에서 처리 |
| Domain | - 도메인 객체가 잘못된 데이터를 포함 - 규칙 위반 시 예외 발생 |
- 도메인 객체 생성자에서 데이터 규칙(유효성) 확인 - 데이터 검증 실패 시 명확한 예외를 발생시킴 |
| Repository | - 데이터베이스 연결 실패 - 중복 데이터 저장 - 매핑 오류 |
- 데이터베이스 연결 오류를 적절히 처리 - 데이터 중복 방지를 위한 유니크 제약 조건 설정 - 올바른 @Entity와 매핑 관계 설정 |
4. 데이터 흐름 문제를 해결하며 유지보수를 향상시키는 팁
4.1 공통 예외 처리
- 모든 계층에서 발생할 수 있는 예외를
@ControllerAdvice로 중앙에서 관리. - 예: 데이터베이스 오류, 잘못된 요청 데이터.
4.2 계층 간 역할 분리
- Service 계층에서 비즈니스 로직만 담당하고, 데이터베이스 작업은 Repository에 위임.
- Domain 객체는 데이터와 관련된 규칙만 포함.
4.3 테스트 코드 작성
- 각 계층을 단위 테스트(Unit Test) 또는 통합 테스트(Integration Test)로 검증.
- Repository는 실제 데이터베이스와 통합 테스트를 실행하여 매핑 문제를 조기에 발견.
4.4 DTO 사용
- 데이터 전송 시 DTO(Data Transfer Object)를 사용하여, 도메인 객체와 요청 데이터 구조를 분리.
마무리
이 글에서는 게시판 애플리케이션의 데이터 흐름을 시각화하고, 각 계층에서 발생할 수 있는 문제와 이를 해결하는 방법을 살펴보았습니다. 다음 단계에서는 이 구조를 바탕으로 효율적인 테스트 코드 작성과 유지보수 전략을 다뤄보겠습니다.