[hot deal] API 설계 과정에서의 고민

1. Redis와 Kafka를 활용해서 물건 구매 로직을 구현한 이유

1. Redis를 이용한 실시간 재고 관리

물건 구매 요청이 들어오면 Redis에서 물건 수량을 즉시 감소하도록 설계했습니다. 서비스는 예약된 시간에만 오픈되기 때문에, 서비스 시작 전 Redis에 물건의 초기 수량을 미리 저장해두는 방식으로 준비하고 있습니다. 현재는 물건 수량 감소 로직만 구현되어 있지만, 추후 서비스가 안정화되면 Redis에 물건 수량을 미리 저장하는 로직도 추가할 계획입니다.

2. Kafka를 이용한 순차적 DB 반영

한 번에 대량의 구매 요청이 들어올 경우를 대비해 Kafka를 사용하여 데이터의 순차 처리를 보장하고자 했습니다. 물건 구매 요청이 발생하면 해당 요청을 Kafka에 기록하고, Kafka의 Consumer가 이를 순차적으로 처리하여 DB에 재고 수량을 반영합니다. 이렇게 함으로써 재고의 정확한 일관성을 유지하고, 대량의 요청이 들어와도 순차적으로 처리할 수 있습니다.

 

2. MemberService와 AuthService를 분리하기

처음에는 Member 도메인 내에서 인증(Auth)을 진행했지만, 점점 도메인이 커지면서 관리가 복잡해졌습니다. 특히 Spring Security 클래스들이 추가되면서 필요한 기능과 클래스가 급격히 늘어났고, Member 도메인이 비대해졌습니다. 이러한 상황에서 관심사 분리의 필요성이 명확해졌고, 결국 MemberService와 AuthService를 분리하게 되었습니다.

분리 효과는 크게 두 가지입니다:

  1. 테스트 용이성: AuthService와 MemberService가 독립적으로 동작하면서 테스트가 간편해졌습니다.
  2. URL 개선: 인증 URL이 간소화되어, /member/login 대신 /login으로 변경할 수 있었습니다.

 

3. 커스텀 애노테이션 사용 범위

- URL에 버전 번호를 추가하는 커스텀 애노테이션 만들기

API는 시간이 지나면서 기능이 추가되거나 변경될 수 있습니다. 이를 고려해 URL에 버전 번호(/v1/, /v2/ 등)를 포함해 관리하고 있습니다. 하지만 매번 Controller 클래스에 직접 "/v1"을 추가하는 방식은 비효율적이라고 판단하여, 이를 대체할 수 있는 커스텀 애노테이션 @V1을 만들었습니다. 이를 통해 애노테이션 하나만으로 자동으로 버전에 대한 URL이 추가되도록 설정해, 코드가 더 간결해졌습니다.

 

- 필드 유효성 검사에 대한 커스텀 애노테이션 만들기

필드의 유효성 검사에도 커스텀 애노테이션을 활용했습니다. 필드 유효성 검사는 여러 클래스에서 공통으로 적용할 수 있는 로직이기 때문에, 커스텀 애노테이션으로 재사용 가능한 형태로 구현하여 편리함과 코드 일관성을 동시에 얻을 수 있었습니다.

 

4. 테스트를 좀 더 잘하기 위해 도입한 것들: Fixture 클래스와 FixtureMonkey, 그리고 TestContainer

테스트를 작성하면서, 매번 새로운 객체를 생성하는 코드가 여러 클래스에 반복되어 코드가 중복되고 관리가 어려워졌습니다. 이를 해결하기 위해 공통적인 초기화 작업을 모아놓은 FixtureClass를 만들었습니다. FixtureClass 를 사용하여 테스트에서 필요한 기본적인 설정을 한 곳에 모아, 코드의 간결함과 유지보수성을 크게 개선했습니다.

 

또한, 테스트를 더 동적으로 수행하기 위해 FixtureMonkey를 함께 사용했습니다.

FixtureMonkey는 무작위 값으로 객체를 생성해주어 테스트 데이터를 보다 유연하게 관리할 수 있게 도와주는 도구입니다. 하지만 무작위 객체 생성에 시간이 걸리면서, 메인 로직이 객체 생성 전에 완료되어 테스트가 실패하는 경우가 발생하기도 했습니다. 그래서 현재는 FixtureClass와 FixtureMonkey를 혼합하여 사용하여 테스트의 효율성을 높이고 있습니다.

 

테스트 시 또 하나 중요하게 고려한 점은 실제 환경과 비슷한 인프라에서 테스트하는 것이었습니다. 로컬 환경과 배포 환경이 다를 수 있기 때문에, TestContainer를 도입해 항상 동일한 환경에서 테스트를 실행할 수 있도록 했습니다. 이를 통해 테스트를 위한 별도의 인프라를 준비할 필요 없이 테스트 컨테이너에서 직접 필요한 환경을 설정하고 재현할 수 있어, 테스트가 더욱 일관성 있고 효율적으로 이루어지게 되었습니다.