[마이 프로젝트] 구글 블로그에 매일 순위가 저절로 바뀌게 하기

순위 목록이 매일 자동으로 갱신되는 구조를 나타낸 대표 이미지
어제 자료가 아직 없을 때가 있습니다.

한 줄 요약: 영화 박스오피스 순위는 어제 자료가 오늘 올라오는데, 올라오는 시각이 정해져 있지 않아 새벽에는 목록이 비어 보입니다. 자료가 있는 날짜까지 하루씩 거슬러 올라가고, 화면에 기준 날짜를 함께 보여 주는 방법을 정리합니다.

문제: 새벽에 열면 순위 목록이 텅 빈다

순위 목록을 손으로 고치지 않으려면 어제 자료를 자동으로 불러와야 합니다. 그런데 새벽에 페이지를 열면 어제 자료가 아직 올라와 있지 않아 목록이 비어 버립니다. 목록이 비면 페이지가 망가진 것처럼 보이기 때문에, 이 상황을 그냥 두면 방문자는 순위가 아니라 오류를 본다고 느낍니다. 특히 새벽 시간대에 처음 방문한 사람일수록 다시 오지 않을 가능성이 큽니다.

이 글은 그 문제를 해결한 방법을 순서대로 설명합니다. 구글 블로그 페이지에서 공공 영화 자료를 가져와 보여 주려는 분이 따라 할 수 있도록, 막힌 지점과 해결 방법, 남은 한계까지 모두 적었습니다.

아래 표는 이 글에서 다루는 네 가지 문제를 증상, 원인, 해결 순서로 먼저 정리한 것입니다. 이후 구역에서 하나씩 자세히 풀어 갑니다.

증상원인해결
새벽에 목록이 빔어제 자료가 아직 올라오지 않음자료가 있는 날짜까지 하루씩 거슬러 올라감
브라우저가 멈춤자료가 계속 없을 때 끝없이 뒤로 감거슬러 갈 일수 상한을 둠
해외에서 열면 날짜가 어긋남브라우저가 보는 사람의 시간대를 씀한국 시각으로 오늘을 구한 뒤 거기서 뺌
요청이 실패함월·일 한 자리에 0을 채우지 않음20260830처럼 붙여 쓴 여덟 자리로 만듦

자료는 하루 뒤에 나온다

이 방법은 영화진흥위원회가 제공하는 박스오피스 API를 전제로 합니다. 영화진흥위원회 오픈API 서비스 목록에는 일별 박스오피스, 주간/주말 박스오피스, 영화목록, 영화 상세정보 등이 올라와 있고, 영화관입장권통합전산망이 제공하는 오픈API 모음이라고 소개되어 있습니다.

일별 박스오피스는 어제 자료를 오늘 올려 주는 방식으로 다룹니다. 오늘 자료는 아직 없으므로 "어제"를 계산해서 요청해야 합니다. 문제는 자료가 올라오는 시각이 정해져 있지 않다는 점입니다. 그래서 새벽에 열면 어제 자료조차 아직 없을 수 있습니다.

하루씩 거슬러 올라가며 자료가 있는 날짜를 찾는 흐름
없으면 하루 더 뒤로 갑니다.

정리하면 요청 날짜를 고정해서는 안 됩니다. "어제"를 기본값으로 쓰되, 그 날짜에 자료가 없을 때를 대비한 다음 수를 미리 정해 두어야 합니다. 요청 날짜를 하나로 고정해 두면 자료가 없는 날마다 같은 빈 화면이 반복되기 때문입니다. 그 다음 수가 다음 구역에서 설명하는 거슬러 올라가기입니다. 이 구조는 어제 자료가 정상적으로 올라온 날에는 한 번만 요청하고 끝나므로, 평소에는 추가 비용이 없습니다.

하루씩 거슬러 올라가는 방법

해법은 단순합니다. 없으면 하루 더 뒤로 가서 다시 물어봅니다. 같은 함수를 날짜만 바꿔 다시 부르는 방식(재귀 호출)으로 짰습니다. 아래 코드는 실제로 쓴 함수입니다.

function findAvailableBoxOfficeDay(daysAgo){
  return loadBoxOfficeDay(daysAgo).then(function(result){
    var list = result && result.data
            && result.data.boxOfficeResult
            && result.data.boxOfficeResult.dailyBoxOfficeList;
    // 목록이 비었고 아직 더 뒤로 갈 수 있으면 하루 더 거슬러 간다
    if((!list || !list.length) && daysAgo < GP_MOVIE_CONFIG.boxOfficeFallbackDays){
      return findAvailableBoxOfficeDay(daysAgo + 1);
    }
    return result;
  });
}

읽는 순서는 이렇습니다. 먼저 daysAgo일 전 자료를 불러옵니다. 응답 안의 일별 박스오피스 목록이 없거나 비어 있으면, 그리고 아직 상한에 닿지 않았다면 daysAgo에 1을 더해 같은 함수를 다시 부릅니다. 목록이 있으면 그 결과를 그대로 돌려줍니다.

가장 중요한 줄은 상한을 비교하는 조건입니다. boxOfficeFallbackDays로 몇 일까지 거슬러 갈지를 정해 둡니다. 이 조건이 없으면 자료가 계속 없을 때 무한히 뒤로 갑니다. 실제로 처음에는 이걸 빠뜨려서 브라우저가 멈췄습니다.

며칠까지 거슬러 갈지 정하는 기준

상한은 너무 짧아도, 너무 길어도 문제입니다. 너무 짧으면 연휴에 비어 버립니다. API 점검이 겹치면 이틀 정도는 자료가 없을 수 있기 때문입니다. 너무 길면 오래된 순위를 최신인 것처럼 보여 주게 됩니다.

상한좋은 점위험
짧게 (하루 또는 이틀)항상 최신 순위만 보여 줌연휴나 점검이 겹치면 목록이 빔
길게 (여러 날)목록이 비는 일이 거의 없음오래된 순위를 최신으로 오해하게 함

그래서 며칠 안쪽으로 상한을 두고, 화면에 기준 날짜를 같이 표시했습니다. 날짜를 보여주는 게 중요합니다. 순위만 있으면 언제 것인지 알 수 없지만, 날짜가 있으면 하루나 이틀 전 순위여도 독자가 스스로 판단할 수 있습니다. 날짜 표시는 구현도 간단해서, 거슬러 올라간 일수를 그대로 날짜로 바꿔 순위 위에 한 줄 적어 두면 됩니다.

자동 갱신에서 정한 세 가지를 정리한 설명 이미지
실패해도 화면이 비지 않게 하는 게 목표입니다.

상한을 정할 때는 연휴 길이와 점검 가능성을 같이 떠올려 보면 됩니다. 며칠 연속 자료가 없을 수 있는 시기에는 상한을 조금 더 넉넉하게 두되, 그 대신 날짜 표시를 눈에 띄게 하는 식으로 균형을 잡습니다.

이 설계의 목표는 하나입니다. 실패해도 화면이 비지 않게 하는 것입니다. 자료가 있으면 최신을 보여 주고, 없으면 가까운 과거를 날짜와 함께 보여 줍니다.

날짜 계산에서 걸린 것 두 가지

첫째는 시간대입니다. 시간대를 맞추지 않으면 하루가 어긋납니다. 브라우저는 보는 사람의 시간대를 쓰기 때문에, 해외에서 열면 "어제"가 한국 기준 어제가 아닐 수 있습니다. 그래서 한국 시각으로 오늘을 구한 뒤 거기서 빼도록 했습니다.

MDN 문서에 따르면 날짜 형식 객체(Intl.DateTimeFormat)의 timeZone 옵션은 "Asia/Seoul" 같은 IANA 시간대 이름을 받고, 생략하면 실행 환경의 시간대를 씁니다. 즉 아무것도 지정하지 않으면 보는 사람의 시간대가 쓰이므로 한국 시간대를 직접 지정해야 합니다.

둘째는 날짜 형식입니다. API가 요구하는 날짜 형식은 20260830처럼 붙여 쓴 여덟 자리입니다. 한 자리 월과 일에 0을 채워 넣지 않으면 그냥 실패합니다. MDN 문서에서 같은 객체의 month와 day 옵션에 "2-digit"을 줄 수 있고, 연·월·일 조각은 formatToParts로 따로 꺼낼 수 있다고 설명합니다. 지역마다 순서와 구분 기호가 다르므로 조각의 종류로 찾아 이어 붙이는 방식이 안전합니다. 두 가지 모두 눈에 잘 띄지 않다가 특정 날짜나 특정 지역에서만 실패하는 유형이라, 한 번 정리해 두면 같은 실수를 막을 수 있습니다.

예시로 보는 날짜 계산

시간대가 왜 문제인지 숫자로 보겠습니다. 아래는 이해를 돕기 위한 계산 예시입니다. 실제 방문 기록이 아닙니다.

상황 (예시입니다)한국 시각 기준브라우저가 UTC일 때
한국 8월 31일 오전 0시 30분에 열람어제 = 8월 30일 → 요청 값 20260830현재 8월 30일 15시 30분 → 어제 = 8월 29일 → 20260829

한국과 UTC는 9시간 차이가 나기 때문에, 한국 새벽 0시 30분은 UTC로는 전날 15시 30분입니다. 같은 순간인데 "어제"가 하루 달라집니다. 이 차이 때문에 같은 순위가 한국에서는 최신, 해외에서는 하루 늦은 것으로 보일 수 있습니다. 한국 시각으로 오늘을 먼저 구하는 방식은 이 차이를 없앱니다. 특히 자정 전후에 접속이 몰리는 서비스라면 이 처리를 빼먹었을 때 오류가 가장 자주 드러납니다.

이 계산을 직접 해 보려면 현재 시각을 한국 시각으로 바꾼 뒤 하루를 빼고, 연·월·일을 2자리로 맞춰 이어 붙이면 됩니다. 그 결과가 API에 보낼 요청 값입니다.

이 표는 이 글에만 담은 계산 예시입니다. 시차 9시간은 한국과 UTC의 일반적인 차이이고, 날짜는 설명을 위해 임의로 정했습니다.

남은 한계와 다음에 고칠 것

끝까지 못 찾았을 때의 처리가 아직 부족합니다. 지금은 그냥 안내 문구를 띄웁니다. 마지막으로 성공했던 순위를 저장해 뒀다가 보여 주는 편이 나았을 것 같습니다. 그러면 자료가 오래 비어 있어도 화면이 완전히 비지는 않습니다. 이때도 기준 날짜는 반드시 같이 적어, 저장해 둔 값이라는 점이 독자에게 보이게 해야 합니다.

또 하나는 매번 새로 받아온다는 점입니다. 하루에 한 번만 바뀌는 자료인데 방문자마다 요청하는 것은 낭비입니다. 한 번 받은 결과를 일정 시간 재사용하면 요청 수를 줄일 수 있습니다. 하루에 한 번 바뀌는 자료라면 그날 안에서는 같은 결과를 다시 쓰는 것이 자연스러운 설계입니다.

정리하면 이 방법은 "비지 않게 하기"는 해결했지만 "마지막 성공값 보여 주기"와 "요청 줄이기"는 숙제로 남아 있습니다. 비슷한 기능을 만드는 분은 처음부터 이 두 가지를 같이 설계하면 고칠 일이 줄어듭니다.

다음 개선 순서도 정해 두었습니다. 먼저 마지막 성공값을 저장해 보여 주는 처리를 넣고, 그다음에 요청을 줄이는 재사용을 붙이는 순서입니다. 앞의 것이 사용자가 보는 빈 화면을 없애고, 뒤의 것이 서버와 방문자 모두의 부담을 줄이기 때문입니다.

확인 자료

함께 읽기