내가 맡은 파트 도메인 비즈니스 로직 개선 및 예외 처리 구조 개선
1. 기본 배송지 관리 로직 개선
문제 상황
배송지 도메인을 구현하면서 사용자는 하나의 기본 배송지만 유지해야 한다는 비즈니스 요구사항이 존재했다.
처음에는 단순히 배송지의 isDefault 값만 변경하면 된다고 생각했지만, 다음과 같은 문제가 발생할 수 있었다.
- 새로운 배송지를 기본 배송지로 지정했을 때 기존 기본 배송지가 유지되어 여러 개의 기본 배송지가 생성될 가능성
- 기본 배송지로 설정된 배송지를 삭제했을 때 사용자의 기본 배송지가 존재하지 않는 문제
따라서 기본 배송지 변경과 삭제 과정에서 데이터 정합성을 유지할 수 있는 로직이 필요했다.
2. 기본 배송지 변경 로직 구현
기본 배송지를 변경하는 경우 기존 기본 배송지를 먼저 확인하도록 구현했다.
기존 기본 배송지 조회:
findByUserAndIsDefault(address.getUser(), true)
기존 기본 배송지가 존재한다면:
oldAddress.updateDefault(false);
를 호출하여 기존 배송지를 기본 배송지에서 해제한 후 새로운 배송지를 기본 배송지로 변경하도록 처리했다.
이를 통해 사용자마다 하나의 기본 배송지만 유지되도록 구현했다.
3. 기본 배송지 삭제 처리
기본 배송지 삭제 시 단순히 삭제 처리만 진행하면 사용자의 기본 배송지가 사라지는 문제가 발생할 수 있었다.
따라서 삭제 대상 배송지가 기본 배송지인지 확인 후 처리하도록 구현했다.
삭제 처리:
address.markAsDeleted(userId);
삭제 대상이 기본 배송지인 경우:
findFirstByUserOrderByCreatedAtDesc()
를 통해 가장 최근 생성된 배송지를 조회하고 해당 배송지를 새로운 기본 배송지로 지정했다.
이를 통해 기본 배송지가 없는 상태를 방지하고 데이터 정합성을 유지할 수 있었다.
4. DTO 책임 분리 및 응답 구조 개선
문제 상황
기존에는 요청 DTO와 응답 DTO의 역할이 명확하게 분리되지 않았고, Entity 데이터를 DTO로 변환하는 과정에서 변환 로직이 Service 계층에 포함되는 문제가 있었다.
Service에서 비즈니스 로직과 DTO 변환 로직을 함께 처리하면서 코드의 책임이 분산되었다.
개선 방향
Request DTO와 Response DTO를 목적에 맞게 분리했다.
Request DTO
클라이언트 요청 데이터 관리
- DeliveryRequestDto
- DeliveryUpdateRequestDto
Response DTO
API 응답 데이터 관리
- DeliveryResponseDto
- DeliveryDetailResponseDto
- DeliveryUpdateResponseDto
또한 Response DTO 내부에 from() 메서드를 추가하여 Entity → DTO 변환 책임을 DTO에서 관리하도록 개선했다.
이를 통해 Service 계층에서는 비즈니스 로직 처리에 집중할 수 있도록 구조를 개선했다.
5. Global Exception 구조 적용
문제 상황
예외 발생 시 각 Service에서 직접 예외 메시지를 관리하면서 예외 처리 방식이 일관되지 않은 문제가 있었다.
또한 프로젝트 규모가 커질수록 새로운 예외 추가 시 관리가 어려워질 가능성이 있었다.
개선 방향
Custom Exception과 GlobalExceptionHandler 구조를 적용했다.
구조:
Service
↓
CustomException 발생
↓
GlobalExceptionHandler 처리
↓
통일된 ErrorResponse 반환
ErrorCode Enum을 활용하여 예외 코드와 메시지를 중앙에서 관리하도록 구성했다.
적용 결과
- 예외 응답 형식 통일
- 중복된 예외 처리 코드 감소
- 비즈니스 로직과 예외 처리 책임 분리
- 새로운 예외 추가 및 수정 용이
6. 동시성 문제 고민
현재 기본 배송지 변경 로직은 단일 요청 기준에서는 데이터 정합성을 보장한다.
하지만 동시에 여러 요청이 발생하는 경우 Race Condition이 발생할 가능성이 있다.
예:
- 사용자가 동시에 두 개의 배송지를 기본 배송지로 변경 요청
- 두 요청 모두 기존 기본 배송지를 조회
- 서로 다른 배송지를 기본 배송지로 설정
- 결과적으로 하나 이상의 기본 배송지가 존재할 가능성
이를 해결하기 위해 추후:
- Pessimistic Lock
- DB Unique Constraint
등을 적용하여 동시성 문제를 개선할 예정이다.
배운 점
이번 작업을 통해 단순 CRUD 구현보다 중요한 것은 도메인의 비즈니스 규칙을 코드로 어떻게 보장하는가라는 점을 배웠다.
특히 기본 배송지처럼 하나의 상태만 유지되어야 하는 데이터는 단순한 필드 변경이 아니라 변경 과정 전체를 관리해야 한다는 것을 알게 되었다.
또한 DTO 변환 책임과 예외 처리 책임을 분리하면서 각 계층이 자신의 역할에 집중하는 구조가 유지보수성 향상에 중요하다는 것을 경험했다.
오늘의 정리
- 기본 배송지 변경/삭제 과정에서 데이터 정합성을 유지하는 비즈니스 로직 구현
- DTO from() 메서드를 활용해 Entity → DTO 변환 책임 분리
- CustomException + GlobalExceptionHandler를 적용하여 예외 처리 구조 개선
- 향후 Race Condition 해결을 위해 Lock 및 DB 제약 조건 적용 필요성 확인
'심화_AI를 활용한 백엔드 아키텍처 심화 과정' 카테고리의 다른 글
| [내일배움캠프 사전캠프] 19회차 TIL(7/21 화) - Docker Image, Container (0) | 2026.07.21 |
|---|---|
| [내일배움캠프 사전캠프] 18회차 TIL(7/16 목) - 스프링 컨테이너 (0) | 2026.07.16 |
| [내일배움캠프 사전캠프] 16회차 TIL(7/14 화) (0) | 2026.07.14 |
| [내일배움캠프 사전캠프] 15회차 TIL(7/10 금) (0) | 2026.07.10 |
| [내일배움캠프 사전캠프] 14회차 TIL(7/9 목) (0) | 2026.07.09 |