dev notes

Dayner 영업시간 디자인 변경에 따른 리팩터링 일지 [1]

2024-08-227 min read
공유

개요#

Dayner에는 매달 정기 휴무일, 연중 휴일, 급한 일정으로 인한 운영시간 변경 등을 등록하는 기능이 있었습니다. 처음엔 그냥 날짜와 설명 정도만 보여주면 되는 화면이라 큰 고민 없이 갔습니다.

초기 디자인에서는 대부분 매주 월요일 정기 휴무만 표시하고 있었기 때문에, 영업시간 변경/휴일을 표시하는 type, date, description 필드만 있으면 충분했습니다.

~/yyyyMM 형식의 엔드포인트로 API 요청을 하면 영업일정(id, type, date, description)을 담은 DB에서 between 쿼리로 해당 월의 첫날~말일 데이터를 반환하는 구조였습니다.

영업시간 표시 디자인 변경 — Before/After 비교

영업시간 표시 디자인 변경 — Before/After 비교

문제는 디자인이 바뀌면서 시작됐습니다. 우측 사진의 24~25일처럼 연속된 일정 컴포넌트를 만들기 위해 프론트에서 과도한 자원을 소모한다는 의견이 제시된 것입니다.

변화가 적고 GET 요청이 대부분인 도메인 특성을 고려하면, 서버에서 프론트가 표현하기 쉬운 형태로 데이터를 가공한 뒤 캐싱으로 제공하는 방식이 가장 효율적이라고 판단해 여러 방안을 검토했습니다.

데이터 가공 방안 검토 — 서버 캐싱 전략

데이터 가공 방안 검토 — 서버 캐싱 전략

아이디어 1#

현재 기능을 유지하되, 같은 description 의 경우에는 date에 리스트 형식으로 표현합니다.

해당 기능을 담당했던 개발자분이 연속된 디자인을 구현하기 위해 description 비교로 리스트를 만들었는데, 이 로직을 서버로 옮기면 어떻겠냐는 아이디어를 제시했습니다.

장점: DB 마이그레이션이 필요하지 않습니다. 주어진 api 에 충실한 구현. 단점: 리스트를 만드는 과정에서 연속되어있는지, description이 같은지를 검증해보아야하기에 자원이 낭비됩니다.

서버 측 O(N), 프론트 측 O(N)

아이디어 2#

db 마이그레이션을 통해 startDate, endDate 속성을 추가합니다.

장점: 직관적인 data, 서버단에서 추가적인 작업을 할 필요가 없습니다. 단점: DB 마이그레이션이 이루어져야합니다! 또한 Between 쿼리를 이용하지 못해서 full scan이 이루어집니다.

서버 측 O(N), 프론트 측 O(1)

아이디어 3#

hasNext Boolean 옵션을 추가하여 연결 디자인에 대응합니다.

장점: DB 마이그레이션이 필요하지 않습니다. 단점: head, tail 에 대한 구분을 하기 위한 로직이 필요합니다.

서버 측 O(N), 프론트 측 O(N)

아이디어 4#

결국 우리가 필요한건? 타입을 나누어서 생각해보자.

연속 일정 표현을 위한 타입 분리 (head, mid, tail)

연속 일정 표현을 위한 타입 분리 (head, mid, tail)

연속된 일정을 위한 head와 tail 그리고 mid가 있겠습니다. 단일 일정을 위한 single 타입이 있고, 이 모든게 영업시간 변경/휴일 인지로 크게 나뉘어집니다.

blockType이라는 새로운 속성을 만들어서 각 일정의 날짜가 어떤 블록 타입(start, middle, end, single)인지 서버에서 판단한 뒤, 이 정보를 포함한 date 목록을 클라이언트로 전달하는 방식입니다.

장점: DB 마이그레이션 불필요, blockType으로 쉽게 판별, 프론트 로직 불필요. 서버 측 O(N), 프론트 측 O(1)

아이디어 5#

저장 시점에 blockType도 함께 저장하면 어떨까? (DB에 속성 추가) → 일정에 변화가 생기면 변경된 일정 앞뒤의 blockType을 모두 수정해야 하는 문제가 있습니다.

요청직전에 계산 + 캐싱 기능을 이용하자!

  1. 변화가 없다면 요청마다 계산을 하지 않아도 되고
  2. 캐싱 전략의 경우에는 GET 요청에 yyyyMM 파라미터를 이용해 저장해두고 yyyyMM에 생성/업데이트/삭제가 수행될 경우에는 캐시 evict을 수행하는 방식

여기까지 비교해보니 결국 중요했던 건 "어디서 계산하는 게 더 맞는가"였습니다. 서버에서 조금 더 가공해서 내려주면 프론트가 훨씬 단순해질 수 있었고, 반대로 서버 효율만 보다가 프론트에 부담을 미루는 선택도 얼마든지 할 수 있었습니다.

이번 리팩터링은 그 균형을 다시 보게 만든 작업이었습니다. 시스템 특성과 요청 패턴을 같이 놓고 보지 않으면, 한쪽 최적화가 다른 쪽 비용으로 돌아온다는 걸 꽤 분명하게 느꼈습니다.

Connected Notes