Skip to content

swan.song 사전 과제 제출합니다.#26

Open
Unagi-zoso wants to merge 44 commits intoej31:mainfrom
Unagi-zoso:feature/select-stock
Open

swan.song 사전 과제 제출합니다.#26
Unagi-zoso wants to merge 44 commits intoej31:mainfrom
Unagi-zoso:feature/select-stock

Conversation

@Unagi-zoso
Copy link

@Unagi-zoso Unagi-zoso commented Feb 16, 2025

해결한 부분

  • 요구 API 작성 (디자인, 응답 값, 유효성 검사)
  • 테스트 코드 작성
  • format 파라미터를 통한 json, xml 제공
  • Rate Limiter 작성
  • 커스텀 에러 작성
  • Logging
  • 배포

고민한 부분

  • JDBC : 데이터의 삽입 없이 조회만 하면 되기에 JdbcTemplate 과 DTO 를 통해 간단히 쿼리를 구현했습니다.
  • Filter, Aspect 사용 : API Key 인증, 에러 핸들링, 로깅, 반환 포맷 변환은 비즈니스 코드와 관심사를 분리할 수 있을 것 같아
    AOP, Filter 를 통해서 구현했습니다.
  • 다양한 Test 코드 네이밍 스펙 : 각 레이어 및 객체 별 자연스럽게 읽히는 쪽으로 네이밍 스펙을 각기 가져갔습니다.
  • Test DB : 간단한 기능을 구현하기에 H2 DB 로 환경을 구축했습니다.
  • 동시성을 고려한 Rate Limiter : 서버가 한 대이기에 Synchronized , ConcurrentHashMap 을 사용해 동시성 문제를 방지했습니다.

잘 부탁드리겠습니다.

감사합니다.

yml 을 선호하여 변경합니다. 그 외 전체 파일에 Intellj 기본 포매팅을 적용했습니다.
다뤄야할 쿼리가 많지않아 JDBC 라이브러리로 해결하려 합니다.

커넥션풀 크기에 대한 제한이 있었기에 적정값인 3으로 설정했습니다. (최대 5개)
간단한 규모의 프로젝트라 테스트 컨테이너 없이 H2 정도로 구축합니다.
단순 조회만 하기에 JdbcTemplate 을 통해 구현했습니다.
기존 StockTestFixture 에 있던 Company 관련 Fixture 들을 이전했습니다.
기존에는 infrastructure 레이어에서 관리했는데 다른 레이어에서도 사용할 것이라 이전합니다.
API KEY 미입력 시 400 상태번호를
API KEY 가 일치하지 않을 시 403 상태번호를 반환합니다.
API 성공, 실패 시 공통된 형태 유지를 위해 사용합니다.
StockInfoDto 가 전 레이어에서 공통적으로 사용되어 dto 자체를 다른 레이어들과 같은 depth 에 위치해도 좋을 것 같아 이전합니다.
LocalDateTime 직렬화를 위해 직렬화 도구를 직접 빈으로 등록했습니다.
Spring Boot Validation
main 로직에서 util 패키지가 생성될 예정이라 테스트 helper 용 패키지 이름을
support 로 변경합니다.
format 파라미터가 xml 일 시 xml 로 반환하고 그 외일 시 json 으로 반환합니다.
전역 예외 처리는 Spring MVC 범위 내에서만 유효하기에 Filter 단 예외처리를 위해 구현했습니다.
메인에서 IDE 자동완성이나 성능상 이유로 관리합니다.
ApiKeyAuthFilter 를 따로 두었기에 제거합니다.
포매팅이 어긋난 부분이 보여 일괄 적용합니다.
기존에는 minimum-idle 옵션이 maximum-pool-size 와 차이가 없어 비활성되었다. 그래서 maximum 보다 작게 설정하여 활성화시켰다.
Spring Boot Starter Logging 으로 slf4j 를 사용합니다. 버전 호환의 편의를 위해 Spring Boot Starter 를 이용했습니다.

logging rotate 는 다음과 같습니다.
INFO 이상
- maxHistory : 30일
- totalSizeCap : 500MB

ERROR
- maxHistory : 7일
- totalSizeCap : 200MB
예외 필터에서일괄적으로 관리하기 위해 추가했습니다.
기존에는 servlet 의 sendError 로 다루고 있어 응답 형식도 달라 좋지 못했습니다.
Spring Boot 최근 버전에선 Main-Class 를 못 찾는 경우가 있어 추가했습니다.
외부 배포를 위해 bootJar 를 이용합니다.
내용 상세에 특정 응답 값을 설계한 이유를 주석으로 달아란 요구가 있어 추가했습니다.

응답 값의 뜻이 ApiResponse 같은 응답 포맷을 의미하는 것인지 아니면 API 별 상태번호 선정 이유를 의미하는지 물어봤을 것 같은데 시간이 부족하여 그러지 못하였다.
@Unagi-zoso
Copy link
Author

API 철학

Interface 인 만큼 이후에 자잘한 변화가 일어나지 않게끔 신중하게 스펙을 정하는데 가장 신경을 씁니다.
이번 과제의 경우엔 모든 스펙이 주어졌지만 실제 협업을 하는 상황에선 사용자(프론트엔드 개발자 같은 ..)와의 많은 대화 후에
API 를 설계했습니다.
만약 필요에 의해 API 의 버전을 바꾸어야한다면 변경 없이 확장만으로 해결할 수 없을지 고민합니다.
기본적으로 RESTful 한 API 를 지향하여 URL 에서 자원의 관계나 HTTP 메소드로 API 의 목적, 행동을 예측할 수 있도록 신경을 씁니다.
이번 과제의 경우엔 API 스펙이 다 주어져 따로 고려하진 않았습니다.


이번 과제에서 버저닝을 의식한 부분은 아래와 같습니다.

@RestController
@RequestMapping("/api/v1/stocks") // 버전 1 API 임을 명시
public class StockController {
    // 생략
}

@Unagi-zoso
Copy link
Author

Unagi-zoso commented Feb 16, 2025

배포 후 컨테이너 상태
스크린샷 2025-02-17 오전 7 41 34

테스트 시연 자료

@Unagi-zoso
Copy link
Author

Log rotation 정책

INFO 이상의 일반 로그는 30일간 유지되며 파일 크기가 500MB 초과하면 오래된 로그가 삭제됩니다.
ERROR 레벨의 로그는 7일간 유지되며 파일 크기가 100MB 초과하면 오래된 로그가 삭제됩니다.

단기간 과제라 수치 자체에는 큰 의미 없이 일반적인 값을 넣었습니다.
운영상황에서 로그 파일이 계속 커지면 서버 컴퓨터에 제한이 생길 수 있어 이런 rotation 정책을 추가했습니다.

@Unagi-zoso
Copy link
Author

배포 관련

애플 실리콘 환경에서 개발해 리눅스 환경으로 운영할 예정이였습니다.
이때 플랫폼 차이의 불편함을 줄이기 위해 도커를 이용해 컨테이너로 관리, 배포 했습니다.

단기성 프로젝트라 자원 할당에는 신경쓰지 않았습니다.

그외에는
최신 SpringBoot 3.4.X 버전을 사용하다보니 JarLauncher 를 못 찾는 문제가 있었는데
공식 문서를 확인하고 Gradle 에 반영해 해결했습니다.

@Unagi-zoso Unagi-zoso changed the title swan 사전 과제 제출합니다. swan.song 사전 과제 제출합니다. Feb 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant