대참사의 시작
항공권 예약 시스템에서는 항공편이 여러 시간대를 오가기 때문에 ZonedDateTime이 더 적합하지 않냐는 의견이 제시됐다. 아차 싶었다. 예를 들어 인천에서 오후 3시 출발해 12시간 비행 후 뉴욕에 현지 시간 오후 2시에 도착하는 경우, 시간대 정보가 없으면 이 상황을 정확히 표현하기 어렵다.
결국 LocalDateTime보다는 ZonedDateTime이 적합하다는 결론이 났다. 문제는 기존 LocalDateTime으로 작성된 코드들을 ZonedDateTime으로 바꾸면서 테스트 코드가 다 터져 버렸다. 타입을 바꾸면 되는 문제라고 생각했는데 그게 아니었다.😱
사실 RequestBody로 받은 문자열을 @JsonFormat 어노테이션에다가 timezone만 추가해 주면 간단하게 끝나는 문제인데 이걸 일일이 추가하지 않고, 커스텀 로직으로 풀 수 없을까 고민하다가 시간을 낭비하는 실수를 범했다.
@ModelAttribute로 받은 문자열의 경우 @DateTimeFormat 어노테이션만으로 해결되지 않았다. 그 이유로는 @DateTimeFormat은 기본적으로 시간대(timezone) 정보를 처리하지 않기 때문에 별도의 Converter와 Config를 구현해야만 했다.
어쩌다 보니 전체 도메인 LocalDateTime을 손보게 되었고, 통합 테스트 코드 완료까지 1.5일이 추가로 걸렸다. 팀 전체 계획이 1.5일 밀린 건 아프지만, 덕분에 그동안 무관심했던 직렬화/역직렬화에 대해 많은 것을 배울 수 있었던 시간이었다.
Critical Chain
이번에 CCPM을 적용하며 한 가지 깨달은 점은 PM이 Critical Chain을 맡는다면, 둘 중 어딘가 하나는 포기해야 한다는 점이다. 개발에 집중하면서 동시에 PM에 대한 최대 퍼포먼스를 낼 수가 없다는 말인데... 물론 전지전능해서 이 2가지를 모두 해내는 일론 머스크 같은 사람도 있긴 하지만, 일반적으로는 어렵다는 게 내 결론이다.
현재 한 프로젝트에서 결이 다른 고도화 작업이 진행되고 있는 상황인데, 작업 간 특별한 의존성이 없고, 고도화란 작업 자체가 끝이 없는 것이므로 더 이상 Task 별 작업 진행도를 파악하는 게 무의미하다고 판단하였다. 결론적으로 내가 맡은 작업을 Critical Chain으로 변경했다. 앞으로의 Critical Chain은 내 개인의 진척도를 가늠하는 용도로 사용할 생각이다.
현재 계획보다 4일이 뒤져 있다. 2월 28일까지 로컬 환경에서 1000만 건의 데이터를 가지고 병목 지점을 찾고, 1차 쿼리 튜닝을 끝내야 하는데, 2월 26일 ~ 2월 28일이 발표 준비로 잡혀 있는 걸 감안하면 사실상 남은 시간은 3일뿐이다.
Buffer Management Chart
작업이 4일 뒤쳐졌는데 진도율은 6%이다. 왜냐하면 3.1 Task가 마감되는 시점부터 프로젝트 버퍼가 침투된다. 남은 기간 동안 진척률을 만회할 가능성이 있기 때문에 미리부터 PB를 침투시키지 않는다. 그러므로 정확한 실정을 파악하기 위해서는 Critical Chain과 같이 봐야만 한다. 만약 뒤쳐진 4일을 메꾸지 못한다면 프로젝트 버퍼 소비로 직결될 것이고, 결과를 미리 계산해 본다면 현재 진도율은 -40%라고 볼 수 있다.
모든 준비 완료
밤 11시가 되어 테스트를 위한 1,000만 건의 더미 데이터를 테이블에 장전했고, ngrinder script 작성 결과 HTTP 상태코드 200을 정상적으로 받는 걸 확인했다. 이로써 고도화를 위한 모든 셋팅이 끝났다. 이제는 진짜 성능을 측정하고 개선하는 일만 남았다!