막혔던 세 가지 증상과 각각 열어본 파일, 거기서 찾은 한 줄을 나란히 놓은 표. 숨기기 권한 문제는 프론트엔드 액션 파일에서, 쿠키가 안 실리는 문제는 Go 표준 라이브러리 주석에서, 컨테이너가 죽는 문제는 이미지의 시작 스크립트에서 답을 찾았다.

·8분 읽기·업데이트:

검색으로 안 나오던 답이 세 번 다 소스에 있었습니다


블로그에 댓글 기능을 붙이면서 크게 세 번 막혔습니다. 세 번 다 검색으로는 답이 안 나왔고, 세 번 다 남이 만든 코드를 직접 열어서 풀었습니다.

우연이라기엔 세 번이라 적어둡니다.

1. “숨기기”가 권한 없이 눌렸습니다

댓글을 하나 달아놓고 휴대폰으로 들어가 봤더니, 남의 댓글에 숨기기 메뉴가 있었습니다. 로그인도 안 했는데요.

검색해도 안 나왔습니다. 이건 버그 신고가 올라올 만한 종류가 아니라서요. 그래서 저장소를 받았습니다.

git clone --depth 1 --branch v1.16.4 \
  https://github.com/umputun/remark42.git

전부 읽을 생각은 없었습니다. 화면에 보이는 그 단어부터 찾았습니다.

grep -rn "hideUser" app

그러면 그 기능이 실제로 무슨 일을 하는지 적힌 파일이 바로 나옵니다.

// store/user/actions.ts
hiddenUsers[user.id] = user;
setItem(LS_HIDDEN_USERS_KEY, JSON.stringify(hiddenUsers));

여기서 끝입니다. 서버로 아무 요청도 안 갑니다. 브라우저 저장소에만 적습니다.

권한 문제가 아니었습니다. 시끄러운 사람 글을 내 눈에서만 치우는 기능이라 로그인이 필요 없게 만들어둔 겁니다. 문서에는 “Hide”라고만 적혀 있고 그게 어디까지 적용되는지는 없었습니다.

내친김에 옆 파일도 봤습니다.

// components/comment/comment-actions.tsx
{!currentUser && (
  <Button kind="link" onClick={onHideUser}>
    {intl.formatMessage(messages.hide)}
  </Button>
)}

자기 댓글에는 안 뜨고 남의 댓글에만 뜬다는 것도 여기서 확인했습니다. 세 줄짜리 조건문 하나가 화면 캡처 열 장보다 정확했습니다.

2. 쿠키가 안 실렸습니다

로컬에서 댓글을 달면 “승인되지 않음”이 떴습니다. 서버 로그에는 제 요청이 정상으로 찍혀 있었고요.

브라우저가 쿠키를 안 보내고 있었습니다. 그럼 서버가 쿠키를 어떻게 보내고 있는지 봐야 합니다. 설정에 AUTH_SAME_SITE라는 게 있고 기본값이 default인데, 이 default가 뭔지가 문서로는 분명하지 않았습니다. (당시 문서 한 곳에는 Lax와 같다고 적혀 있었는데 그건 틀린 설명이었고, 지금 문서에는 “lax와 같지 않다”고 고쳐져 있습니다.)

grep -rn -i "samesite" app/cmd/server.go
SameSite string `long:"same-site" env:"SAME_SITE"
  choice:"default" choice:"none"
  choice:"lax" choice:"strict"
  default:"default"`

설정의 기본값은 대체로 이렇게 한 줄에 적혀 있습니다. 문서를 뒤지는 것보다 이걸 찾는 게 빠릅니다.

그런데 여기까지 봐도 default가 무슨 뜻인지는 모릅니다. 이 값은 Go 표준 라이브러리로 넘어갑니다. 그래서 한 단계 더 내려갔습니다.

grep -n -A12 "switch c.SameSite" \
  /usr/local/go/src/net/http/cookie.go
case SameSiteDefaultMode:
	// Skip, default mode is obtained
	// by not emitting the attribute.

주석 한 줄이 답이었습니다. default는 “SameSite를 아예 안 적는다”는 뜻이고, 크롬 계열 브라우저는 안 적힌 쿠키를 Lax로 취급합니다. 그래서 사이트가 다르면 안 실립니다.

표준 라이브러리는 이런 게 많습니다. 문서에 없는 게 소스 주석에는 있습니다. 어차피 컴퓨터에 이미 깔려 있으니 받을 필요도 없습니다.

이 김에 하나 더 봤습니다. 익명 사용자를 어떻게 구분하는지 궁금해서요.

func(user string, r *http.Request) string {
	return user + r.RemoteAddr
}

이름 + 접속 IP. 이 한 줄로 “PC와 휴대폰이 왜 다른 사람으로 보이는지”가 설명됩니다. 이건 아예 찾을 생각도 못 했던 답인데, 근처를 보다가 걸렸습니다.

3. 컨테이너가 뜨자마자 죽었습니다

로그가 15MB인데 같은 줄만 반복됐습니다. 로그만 봐서는 그 반복이 뭘 하다 난 건지 알 수가 없었습니다.

컨테이너는 볼 데가 정해져 있습니다. Dockerfile과 시작 스크립트입니다.

어떤 종류의 궁금증에 어떤 파일을 여는지 정리한 표. 화면 동작은 화면에 보이는 단어로 검색하고, 설정 기본값은 설정 정의부에서, 언어의 기본 동작은 표준 라이브러리 주석에서, 컨테이너가 죽는 문제는 Dockerfile과 시작 스크립트에서 찾는다.

COPY docker-init.sh /srv/init.sh
CMD ["/srv/remark42", "server"]

시작 스크립트를 열었더니 이런 게 있었습니다.

if [ -d "/srv/var" ]; then
	chown -R app:app /srv/var || echo "WARNING: ..."
else
	echo "ERROR: /srv/var doesn't exist..."
	exit 199
fi

만든 사람이 “이거 빠뜨리는 사람 많다”고 판단해서 확인을 박아둔 겁니다. 이런 건 문서가 아니라 코드에 남습니다.

그리고 제 로그를 채우던 정체도 여기 있었습니다.

find . -regex '.*\.\(html\|js\|mjs\)$' \
  -print -exec sed -i "..." {} \;

-print. 파일 목록을 찍는 옵션입니다. 로그를 채우던 게 이거였습니다.

소스를 봐도 안 풀린 것

여기까지만 적으면 소스를 열면 다 풀리는 것처럼 보이니, 안 풀린 것도 적습니다.

저 준비 스크립트가 왜 끝나지 않았는지는 끝내 못 밝혔습니다. 스크립트를 다 읽었고, 최신 버전과 한 글자씩 비교까지 했는데 다른 데가 없었습니다.

소스를 여는 게 만능은 아닙니다. 다만 “모르겠다”의 범위가 줄어듭니다. 이 경우 “왜 안 되는지 전혀 모르겠다”에서 “이 스크립트는 정상인데 내 환경에서만 안 끝난다”로 좁아졌습니다. 그 상태에서 스크립트를 건너뛰는 우회를 선택했고, 뭘 건너뛰는지 알고 건너뛰었으니 나중에 문제가 생겨도 어디를 볼지 압니다.

정리하면서 알게 된 것

세 번을 겪고 나니 규칙 비슷한 게 생겼습니다.

언제 여는가 — 문서와 실제 동작이 어긋날 때. 검색 결과가 죄다 다른 버전 이야기일 때. 같은 “왜 이렇게 되지”가 두 번 반복될 때.

전부 읽지 않는다 — 세 번 다 실제로 읽은 건 열 줄 남짓입니다. 궁금한 게 화면에 보이는 동작이면 그 단어로 검색하고, 설정값이면 설정 정의부를 보고, 컨테이너면 Dockerfile을 봅니다. 어디를 열지가 정해져 있으면 남의 코드도 무섭지 않습니다.

버전을 맞춰서 받는다 — 이게 은근히 중요합니다.

git clone --depth 1 --branch v1.16.4 ...

내가 돌리는 게 v1.16.4인데 최신 소스를 읽으면 헛수고입니다. --depth 1은 전체 역사를 안 받는다는 뜻이라 훨씬 빠릅니다.

부수입이 있다 — 목적한 답 말고 근처에서 하나씩 더 건집니다. 익명 ID가 이름+IP라는 것, 자기 댓글에는 숨기기가 안 뜬다는 것. 둘 다 안 찾던 답인데 근처에 있었습니다.

마지막으로

전에는 오픈소스 저장소를 “필요하면 기여하는 곳” 정도로 봤습니다. 지금은 매뉴얼로 씁니다.

문서는 사람이 시간 내서 쓰는 거라 늘 실제보다 뒤처집니다. 코드는 지금 돌아가고 있는 것 그 자체입니다. 그리고 대부분의 프로젝트는 우리가 궁금해할 만한 것 옆에 이미 주석을 달아뒀습니다.

git clone 한 줄이면 되는데 저는 너무 오래 미뤘습니다.

고친 곳

2026년 9월 29일, 글에 붙일 참고 문서를 하나씩 다시 열어보다가 본문과 어긋나는 곳을 찾아 고쳤습니다.

  • “브라우저는 안 적힌 쿠키를 Lax로 취급한다”를 “크롬 계열 브라우저는”으로 좁혔습니다.
  • “문서에 안 적혀 있었다”를 고쳤습니다. 당시 문서에는 틀린 설명이 있었고, 지금은 고쳐졌습니다.
  • 코드블록 두 곳의 줄 이어쓰기 기호가 \\로 두 번 찍혀 있어서 \ 하나로 고쳤습니다. 그대로 복사하면 명령이 안 돌았습니다.

참고한 문서


댓글

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