회사명 노출 및 public repository 사용을 허락받았습니다.
T사 사용자들이 장소에 리뷰를 작성할 때 포인트를 부여하고, 전체/개인에 대한 포인트 부여 히스토리와 개인별 누적포인트를 관리하고자 합니다.
- 리뷰 작성 이벤트를 처리할 수 있는 API를 개발합니다.
- 사용자는 장소마다 리뷰를 1개 작성할 수 있고, 수정 또는 삭제할 수 있습니다.
- 리뷰 작성 보상 점수는 아래와 같습니다.
- 내용 점수: 1자 이상 텍스트 (1점), 1장 이상 사진 첨부 (1점)
- 보너스 점수: 특정 장소에 첫 리뷰 작성 (1점)
POST /events
{
"type": "REVIEW",
"action": "ADD", /* "MOD", "DELETE" */
"reviewId": "240a0658-dc5f-4878-9381-ebb7b2667772",
"content": "좋아요!",
"attachedPhotoIds": [
"e4d1a64e-a531-46de-88d0-ff0ed70c0bb8",
"afb0cef2-851d-4a50-bb07-9cc15cbdc332"
],
"userId": "3ede0ef2-92b7-4817-a5f3-0c575361f745",
"placeId": "2e4baf1c-5acb-4efb-a1af-eddada31b00f"
}
- 포인트 조회 API를 개발합니다.
- 실행
# local profile
> ./gradlew clean bootRun --args='--spring.profiles.active=local'
- h2-console 접속
http://localhost:8080/h2-console
- application.yml을 참고하여 설정 or 수정
datasource:
driver-class-name:net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url:${DATASOURCE_URL:jdbc:log4jdbc:mysql://localhost:4306/review_schema?useSSL=false&useUnicode=true&characterEncoding=UTF-8}
username:${DATASOURCE_USERNAME:root}
password:${DATASOURCE_PASSWORD:password1}
- 실행
# default profile
> ./gradlew clean bootRun
https://github.com/Hyune-c/traveler-mileage-service/wiki
- 레이어드 아키텍처 설계
- web 레이어 분리
- domain 레이어로 review와 point를 설계
- SRP를 준수한 service 레이어 (business 레이어)
- 포인트 적립을 Facade 패턴으로 설계
PointCreateFacade
- JPA 기능을 한정적으로 활용한 영속성 레이어 설계
- 성능이 필요한 기능은 querydsl 활용
- 과제 조건에는 포인트 변경의 소스가 리뷰뿐이지만, 실무라면 포인트 변경의 소스가 계속 늘어날 것입니다.
- 포인트는 이력이 중요하며 레이스 컨디션의 주체가 적고 조회가 주가 됩니다.
- 차후 마이크로 서비스의 분리 대상이 됩니다.
- 따라서 history-replay 기반의 설계로 이력과 현재 포인트 조회를 가져오도록 설계 했습니다.
- 가장 많은 요청인 현재 포인트 조회는 캐싱한 후 userId (createdBy) 기반으로 변경이 생기면 evict 합니다.
- 단순 이력으로 설계했기에 큐를 활용하거나 비동기 로직을 통해 빠른 응답을 기대하도록 개선할 수 있습니다.
- 마이크로 서비스로 분리된다면 CDC (Change Data Capture) 등의 기술을 활용합니다.
- 캐시는 구현되어 있지 않습니다.
- 레이어간/객체간 메시지 전달에 dto를 활용하고 구분된 네이밍을 정의
- web 레이어 dto - request, response
- service 레이어 dto - dto
- 가독성과 안전함을 고려한 코딩
- 함수형 프로그래밍 및 kotlin의 베스트 케이스 적용
- google style guide, sonarlint를 활용한 컨벤션 체크
- 가독성과 구현 의도를 알리기 위한 javadoc 작성 - public 메서드 위주
- 실무에서도 작성하는 편이지만, 구현 의도를 알리기 위해 조금 더 자세하게 작성했습니다.
- web 레이어의 bean validation만이라면 어노테이션만으로도 쉽게 됩니다.
- 하지만 구현 요구상
- 하나의 request에서 type에 따라 복수 종류의 요청을 처리해야하고, 비지니스 검증도 필요합니다.
- 그렇기에 조금 과하지만 Validator를 실험적으로 활용했습니다.
- transactionId를 통해 요청을 추적할 수 있습니다.
- 구현 방법에 따라 서버에서 발급한 transactionId/requestId를 사용하거나, 프론트에서 직접 발급할 수도 있습니다.
- 이 프로젝트에서는 내부 로깅용으로 에러 추적을 위해서만 사용합니다.