TIL_20250418_프로젝트 리팩토링 설계

Kim jisu·2025년 4월 18일

TIL

목록 보기
34/43

1. 프로젝트 개요

  • 목적 : 분산 트랜잭션 기반으로 대회 신청 과정을 안정적·확장 가능하게 처리
  • 기술 스택 : Spring Boot 3, Kafka, Redis, PostgreSQL, Docker Compose, Zipkin/Prometheus, JPA + Hibernate
  • 아키텍처 스타일 : MSA + Event‑Driven (Kafka), 부분적 CQRS, Redis 기반 Saga State 저장소

2. 현행 구조 분석

관점주요 내용
레이어드 구조Presentation → Application (Service) → Domain → Infrastructure
DDD 도입 수준Aggregates·도메인 이벤트 개념 존재하나, 로직 대부분이 Service 계층에 집중
이벤트 흐름Kafka competition_saga 토픽에 Application/Payment/Cancellation SagaEvent 발행 후 Consumer 가 공통 처리
분산 트랜잭션오케스트레이션 기반 Saga 패턴 (SagaState + CompetitionSagaOrchestrator)
데이터 저장소RDB (영속 엔티티) + Redis (SagaState 캐시·임시 저장)
사용 패턴Repository, DTO, Mapper, Builder, Factory Method, Strategy, State, Saga

3. 문제점 정리

  1. 도메인 모델 빈약 : 비즈니스 규칙이 Service 에 집중 → 캡슐화 부족
  2. 상태 관리 복잡 : SagaStep ↔ Status 매핑 불명확, 조건문 다중
  3. 검색 로직 하드코딩 : ParticipantService.searchParticipants() if/switch 분기 증가 예상
  4. 이벤트‑핸들러 결합도 : Consumer 에서 비즈니스·보상·알림 로직 혼재
  5. 예외 처리 일관성 부족 : RuntimeException 섞여있고 ServiceCode 매핑 누락
  6. 테스트 부재 : 도메인·이벤트 흐름에 대한 단위/통합 테스트 부족

4. 리팩토링 목표

구분목표
도메인 강화규칙을 Aggregate 내부로 이전, 풍부한 도메인 모델 구현
패턴 정제상태 패턴·전략 패턴·템플릿 메서드 패턴 적용으로 조건문 제거 & 확장성 확보
CQRS 명확화Command/Query 서비스 완전 분리, 읽기 모델 최적화
이벤트 모듈화도메인 이벤트 → Spring @EventListener, Consumer 는 오케스트레이션 전담
예외 계층화DomainException → ServiceException → GlobalHandler 로 일관 처리
테스트 확보단위(도메인)·슬라이스(Repository)·통합(Saga flow) 테스트 추가

5. 주요 적용 설계

5.1 도메인 모델 (예)

public class Competition extends BaseEntity {
    // ... 필드
    public void apply(Participant p){
        if(isDuplicate(p)) throw new CompetitionException(ALREADY_APPLIED);
        if(isFull()) throw new CompetitionException(CAPACITY_FULL);
        mappings.add(CompetitionParticipantMapping.create(this,p));
        DomainEvents.publish(new ParticipantAppliedEvent(id,p.getId()));
    }
}

5.2 상태 패턴

  • ParticipantState 인터페이스 → AppliedState, PaidState, SelectedState, CancelledState 구현
  • CompetitionParticipantMapping 가 현재 State 객체 보유, 행동 위임

5.3 전략 패턴 (검색)

interface SearchStrategy { Page<?> search(String keyword, Pageable p); }
  • 구현체 TitleSearchStrategy, StatusSearchStrategy 등
  • SearchStrategyFactory 가 DI‑container 로부터 Map 주입받아 선택

5.4 템플릿 메서드 기반 Saga

  • AbstractSaga<T extends SagaEvent> 에 공통 단계 정의
  • ApplicationSaga / PaymentSaga 등이 세부 행동 오버라이드

5.5 예외 계층

  • DomainException(code, message) ← 모든 도메인 예외 상속
  • GlobalExceptionHandler 가 code → HTTP Status 매핑 일원화

6. 기대 효과

  1. 응집도↑, 결합도↓ : 도메인 규칙 집중, Service 간섭 감소
  2. 확장 용이        : 신규 상태·검색 타입 등 OCP 준수로 코드 수정 최소화
  3. 가독성 & 테스트성 : 상태 전이·이벤트 흐름 명료, 단위 테스트 작성 쉬움
  4. 신뢰성            : 일관된 예외 처리 + 멱등성 보장으로 오류·중복 처리 최소화
  5. 운영 편의        : 로그 상세화, 보상 로직 분리 ⇒ 장애 분석 속도 개선

7. 단계별 작업 목록 (Roadmap)

Phase작업산출물
1도메인 규칙 이관 / Aggregate 리팩터링Updated entity & event classes
2상태 패턴 도입 (Participant)state 패키지 + 테스트
3검색 전략 분리strategy 패키지, Factory
4CQRS 서비스 분리CommandService / QueryService
5AbstractSaga 생성 + 하위 Saga 마이그레이션saga 패키지 재구성
6예외 계층 & GlobalHandler 정비error 패키지, 공통 ApiResponse
7테스트 작성JUnit + Spring Boot Test 보고서
8문서화 & 코드 리뷰ADR, UML (PlantUML)

profile
Dreamer

0개의 댓글