튜터님 Q & A
응답 DTO 변환 로직의 위치
질문
현재 Presentation 계층에 Response DTO가 있습니다. 그래서 컨트롤러에서 Service DTO를 Response DTO로 변환하고 있었어요. 이 부분에 대해 리뷰가 들어왔는데, Application 계층에 Response DTO를 위치시키고 응답 DTO로 변환하는 로직도 함께 두면 의존성이나 테스트 효율성이 더 좋다는 의견을 주셨습니다. 이해는 가지만, 컨트롤러와 뷰 사이에서 필요한 DTO를 서비스의 비즈니스 로직으로 보는 게 마음에 걸립니다.
답변
엄밀히 말하면 DTO는 전송 객체이기 때문에 사용하는 계층에 맞춰 패키지를 위치시키는 것이 일반적입니다. 주는 쪽과 받는 쪽 중 주는 쪽에 두는 것이죠. 하지만 정답이 없는 문제입니다. 대규모 프로젝트에서는 DTO 패키지를 별도로 모아두는 방법도 있습니다.
- 컨트롤러에서 처리할 경우 역할 분담이 명확해지는 이점이 있습니다.
- 서비스에서 처리할 경우 리팩토링과 테스트 관점에서 깔끔해지는 장점이 있습니다.
실제 회사에서도 컨벤션이 다르고, 매퍼 클래스를 사용하기도 하며, 같은 팀 내에서도 파트가 다르면 구조가 다른 경우가 많습니다. 자주 바뀌지 않기 때문에 DTO를 분해해서 계층을 완전히 분리하는 것이 가장 확실한 방법이 될 수 있습니다. 매퍼를 활용해 중간 계층을 만드는 방법도 있습니다.
안티패턴일 수 있지만 MSA의 장점과 맞물려 있을 것 같습니다. 공통 코드는 잘 정리하지만, 같은 팀 내에서도 파트가 다르면 구조가 달라지는 경우가 많습니다. 스타일을 따로 가져가는 것도 괜찮을 것 같습니다.
Kafka 특강
LinkedIn에서 시작된 분산 스트리밍 플랫폼인 Kafka는 Publish-Subscribe 모델을 기반으로 다중 구독과 큐의 장점인 부하 분산을 지원한다. 메시지를 디스크에 일정 기간 저장하여 재생 및 복구 작업에 활용할 수 있다.
모놀리식 → MSA 전환
- 트래픽 증가 시 스케일 아웃이 필요할 때
- 다양한 프로그래밍 언어의 자유로운 사용 가능
Kafka를 사용하는 이유
- 대기열 관리
- 다중 처리 가능
- 게시/구독 구조
- 내결함성 등 여러 장점
MSA에서는 분산 시스템의 필요성이 대두되지만, 결합도를 낮추기 위해 Kafka를 도입한다.
팀 활동
소통 오류
가게 스케줄
초기에 예약 가능한 식당의 시간대를 관리하는 가게 스케줄 테이블이 있었다. 동시성 문제에 대해 논의가 있었지만, 이를 명확히 정리하지 않아서 다른 팀원이 관련된 예약 기능을 구현한 후 스크럼을 통해 오해가 있다는 것을 발견했다. 이 테이블은 현재 예약 정보를 관리하고 있었고, 정규화에 어긋나는 것 같았지만 동시성 문제 해결을 위한 솔루션이다.
알림 서비스
처음에 알림 서비스는 수동적인 서비스라고 생각했다. MSA의 목적에 맞춰 추상적으로 설계하고 REST API를 통합했지만, 다른 팀원은 알림 서비스가 Kafka의 컨슈머 역할을 한다고 이해하고 있었다. Kafka 사용을 유지하는 방향에서 더 고민해보기로 했다.
알림 템플릿
알림 템플릿에 대해 호출 도메인의 담당자와 소통하며 진행할 줄 알았는데, 정해진 템플릿과 파라미터 정보만 요구받았다. 템플릿을 먼저 샘플로 제공하고 추가로 필요한 부분을 정리했다. 알림 API를 호출할 때 데이터를 JSON 문자열로 받으려 했지만, 각 서비스별로 API를 분리하는 것이 더 편리할 것 같다고 제안다. 하지만 회의 후 전반적인 도메인 설계를 다시 해야겠다고 느꼈습니다.
상황 분석
- 각 서비스가 독립적으로 동작하고, 느슨하게 결합되는 MSA의 핵심 원칙에 따르면 추상적으로 설계하여 유연성을 확보하는 시도는 합리적이다.
- 실시간 이벤트 처리에 유리하지만, 특정 메시지 브로커에 강하게 의존할 위험이 있다.
- 템플릿마다 API를 제공하는 것은 명확하지만 서비스 간 결합도가 높아질 수 있다.
도메인 재설계
알림 서비스의 역할과 책임을 재정의할 필요가 있었다.
- “이 서비스가 단순히 메시지를 전달하는 역할인가?”
- “템플릿 처리와 비즈니스 로직을 포함한 복합적인 역할을 해야 하는가?”
Kafka 컨슈머
Kafka 컨슈머 역할이 필요하다면, 이를 별도의 서비스로 분리하여 이벤트 스트리밍 데이터를 전처리한 후 알림 서비스에 전달하는 방식이 좋을 것 같다. 이렇게 하면 알림 서비스는 메시지 전달에만 집중할 수 있습니다.
이벤트(전처리) 서비스
이벤트 수집과 데이터 변환 등의 책임을 맡아 서버를 분리하는 것이 MSA에 적합하지만, 동일한 트래픽 흐름을 유지하고 인프라 및 네트워크 비용을 줄이기 위해 서버 내에서 서비스(로직상)로만 분리하는 것도 괜찮아 보인다.
- 웨이팅 서비스
- 이벤트 발생 시 데이터를 Kafka에 적재한다. (웨이팅 등록, 미루기, 리마인드 알림 등)
- 전처리 서비스
- Kafka의 메시지를 소비하여 알림에 전송할 데이터를 전처리한다.
- 필요한 경우 추가 데이터를 가져오거나 표현을 정리한다.
- 템플릿에 데이터를 바인딩하여 알림 서비스에 전달한다.
- 알림 서비스
- 전처리된 데이터를 받아 해당 채널(슬랙, 이메일 등)로 전송한다.
템플릿 서비스
알림이 발생할 때마다 DB에서 템플릿을 가져와야 하는데, 템플릿은 추가되거나 변경될 일이 적기 때문에 DB I/O를 줄이기 위해 캐시 서버를 도입하는 것이 좋겠습니다.