세 가지 증상과 처음 의심한 것, 그리고 실제 원인을 나란히 놓은 표. 조회수가 안 보인 건 0을 숨기도록 내가 만들어서였고, 예약 발행이 안 된 건 그 기능을 만든 적이 없어서였고, 날짜가 하루 밀린 건 시간대를 한 줄 안 적어서였다.

·7분 읽기

이번엔 세 번 다 제가 쓴 코드가 문제였습니다


지난 글에서 세 번 막혔는데 세 번 다 남이 만든 코드에 답이 있었다고 썼습니다.

그 글을 올리고 며칠 지나서 또 세 번 막혔습니다. 이번에는 세 번 다 제가 쓴 코드가 문제였습니다.

앞 글이랑 짝을 이루는 것 같아 그대로 적습니다.

1. “안 되는” 게 아니라 “안 보이는” 거였습니다

글 아래에 조회수를 붙여뒀는데, 새로 올린 글 네 편에 한 줄도 안 떴습니다.

통계 서버 문제인가 싶어 주소를 직접 눌러봤습니다.

/counter/blog/korean-web-typography/.json
→ 200  {"count":"3"}

/counter/blog/comments-on-a-static-blog/.json
→ 404  {"count":"0"}

숫자가 있는 글은 200으로 잘 옵니다. 실제로 그 글에 들어가 보니 “조회 3”이 잘 떠 있었습니다.

그럼 안 뜨는 쪽은 왜 안 뜨나. 제가 쓴 코드를 봤습니다.

const n = Number(String(raw).replace(/[^0-9]/g, ''));
if (!n) return;

0이면 아무것도 안 보여주게 제가 만들어놨습니다.

이걸 만들면서 쓴 글에 제가 이렇게 적어놨더군요. “아무도 안 본 글에 조회 0을 붙여두는 건, 굳이 안 해도 되는 자기소개입니다.”

맞는 판단이었다고 아직도 생각합니다. 그런데 새 글 네 편이 전부 0이니까 네 편 다 아무것도 안 뜨는 상태가 됐고, 저는 그걸 고장으로 읽었습니다. 여기에 통계 쪽이 최대 4시간까지 캐시한다는 것까지 겹쳤고요.

고장이 아니라 제가 시킨 대로 돌아가고 있었습니다.

“안 된다”와 “안 보인다”는 다릅니다. 안 보이는 거면 먼저 “내가 숨기라고 시킨 코드가 있는지”를 봐야 합니다.

2. 고장 난 게 아니라 만든 적이 없었습니다

글 세 편을 한 번에 올리기 아까워서, 작성일을 이틀씩 앞으로 잡아뒀습니다. 예약 발행처럼 쓰려고요.

배포하고 블로그를 열었더니 세 편이 다 올라와 있었습니다.

이번에도 코드를 봤습니다. 그런데 볼 게 없었습니다.

const posts = (await getCollection('blog')).sort(
  (a, b) =>
    b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
);

가져와서 정렬만 합니다. 미래 날짜를 거르는 줄이 한 줄도 없습니다. 목록, 홈, 태그, RSS, 글 페이지까지 다섯 군데가 전부 이랬습니다.

버그를 찾고 있었는데, 그 기능은 애초에 만든 적이 없었습니다. 날짜 칸이 있으니까 당연히 그렇게 동작할 거라고 혼자 생각했던 겁니다.

안 만든 기능은 고장 나지도 않습니다. 당연한 말인데, 막상 그 상황에서는 “왜 안 되지”부터 하게 됩니다.

거르는 함수를 하나 만들어서 다섯 군데를 그걸로 바꿨습니다.

export async function getVisiblePosts() {
  const all = await getCollection('blog');
  const published = import.meta.env.DEV
    ? all
    : all.filter(
        (p) => p.data.pubDate.getTime() <= Date.now(),
      );
  return published.sort(
    (a, b) =>
      b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
  );
}

개발 서버에서는 예약글도 보이게 뒀습니다. 미리 보려고요.

그리고 하나 더. 정적 사이트는 날짜가 됐다고 저절로 안 열립니다. 페이지는 빌드할 때 만들어지니까, 그날 다시 한 번 빌드해야 생깁니다. 이건 예약 발행을 붙이고 나서야 깨달았습니다.

3. 제 컴퓨터에서만 맞았습니다

예약 발행을 붙이고 나서 더 이상한 걸 발견했습니다.

작성일을 오전 10시 4분으로 잡아뒀는데, 계산해보니 실제로 열리는 시각이 저녁 7시 4분이었습니다. 9시간 차이입니다.

시간대를 안 적었을 때 9시간이 어디서 생기는지 보여주는 그림. 작성 화면에 오전 10시 4분으로 적으면 시간대 표시 없이 저장되고, YAML은 시간대가 없는 값을 UTC로 읽고, 빌드 서버도 UTC라 그대로 넘어가서, 한국 시간으로는 저녁 7시 4분에 열린다.

배포된 페이지를 열어 날짜 태그를 봤더니 답이 바로 나왔습니다.

<time datetime="2026-09-10T10:04:00.000Z">

끝에 Z. 세계 표준시라는 표시입니다. 제가 적은 건 한국 시간 오전 10시였는데요.

원인은 이렇습니다. 작성 화면은 시간대를 안 붙이고 저장합니다.

pubDate: 2026-09-10T10:04:00

그리고 YAML 규칙상 시간대가 안 붙은 날짜는 UTC로 읽습니다. 배포 서버도 UTC로 돌아가니 아무 데서도 안 걸리고 그대로 넘어갑니다. 제 컴퓨터에서만 맞아 보였던 겁니다.

같은 이유로 날짜 표시도 틀어져 있었습니다. 새벽에 올린 글이 하루 전 날짜로 찍혔습니다.

두 군데를 고쳤습니다. 시간대가 안 적힌 값은 한국 시간으로 읽게, 날짜를 화면에 찍을 때도 한국 시간으로.

date.toLocaleDateString('ko-KR', {
  timeZone: 'Asia/Seoul',
  year: 'numeric', month: 'long', day: 'numeric',
});

timeZone 한 줄입니다. 이 한 줄이 없어서 며칠 동안 날짜가 하루씩 밀려 있었습니다.

그래서 어떻게 구분하나

세 번을 겪고 나니 순서가 좀 잡혔습니다. 남의 코드를 열기 전에 제 코드에 물어볼 게 있습니다.

“안 된다”인가, “안 보인다”인가 — 안 보이는 거면 숨기는 조건이 어딘가 있습니다. 대개 제가 넣은 겁니다.

그 기능을 만들긴 했나 — 이게 제일 허무한데 제일 자주 걸립니다. 설정 칸이 있다고 동작이 따라오는 건 아닙니다. 코드에서 그 단어로 한 번 검색해보면 3초면 끝납니다.

내 컴퓨터에서만 맞는 건 아닌가 — 시간대, 파일 이름 대소문자, 경로 구분자. 이런 건 로컬에서 절대 안 걸립니다. 배포된 화면을 열어서 실제 값을 확인해야 합니다. 저는 <time datetime> 하나 보고 답을 찾았습니다.

남은 이야기

앞 글에서 “남의 코드를 열면 답이 있다”고 썼는데, 그건 절반만 맞았습니다.

답이 있는 쪽을 먼저 정하는 게 먼저입니다. 남의 코드를 아무리 잘 읽어도 문제가 내 코드에 있으면 안 나옵니다. 이번에 저는 통계 서버를 의심하면서 시간을 썼는데, 정작 답은 불과 며칠 전에 제가 직접 쓴 if (!n) return; 한 줄에 있었습니다.

세 번 다 고치는 데는 한 줄에서 열 줄이면 됐습니다. 오래 걸린 건 어디를 볼지 정하는 부분이었습니다.

참고한 문서


댓글

로그인도 이메일도 필요 없습니다. 이름만 적고 편하게 남겨주세요.