Victor

[연재] 개인 홈페이지 — 글과 도구를 한 곳에

연재 · 2026-08-17

어제 쓴 글이 아래에 있었습니다

 

같은 날에 글 두 편이 나간 날이었어요. 목록을 열었는데 나중에 쓴 글이 아래에 있었습니다.

 

날짜는 둘 다 같으니까 정렬이 갈릴 데가 없었던 거예요. 그때 제 코드는 날짜가 같으면 제목을 거꾸로 세워서 순서를 정했습니다. 제목이라뇨. 글 순서가 제목 첫 글자로 정해지고 있었던 겁니다. 독자 입장에서는 오늘 올라온 새 글이 어제 것 밑에 깔려 있는 거고요.

 

고친 건 두 번에 나눠서였어요. 커밋 시각이 이렇습니다.

 

7월 24일 19:35  같은 날 나간 글은 회차가 큰 쪽을 위로
7월 24일 19:38  머리말에 시분을 받아 같은 날 글 순서를 가른다

 

3분 차이입니다. 처음엔 "연재 회차가 큰 쪽이 나중 글이니까 그걸로 가르자"고 했다가, 3분 뒤에 연재가 아닌 글은 회차가 없다는 걸 깨닫고 다시 손댄 거예요. 그래서 지금은 글 머리말에 시분을 적을 수 있게 해뒀습니다. 작성일: 2026-08-23 09:01 이렇게요.

 

여기서 한 번 더 걸렸습니다. 시분을 그냥 날짜에 붙여버리면 안 되더라고요.

 

이 사이트는 글을 미리 써두고 날짜가 되면 나가는 구조입니다. 오늘보다 뒤인 날짜가 적힌 글은 아직 안 내보내요. 그런데 판정을 글자 비교로 합니다. 그러면 이렇게 됩니다.

 

'2026-07-25 16:30'  >  '2026-07-25'      ← 참

 

시분이 붙은 순간 그 글은 "오늘보다 뒤"가 되어버립니다. 당일 아침에 배포가 돌아도 안 나가요. 그래서 지금 코드는 날짜와 시분을 갈라서 받습니다. 날짜는 발행 판정과 주소에 쓰고, 시분은 순서를 가르는 데만 씁니다.

 

date, _, time = stamp.strip().partition(" ")

 

한 줄이에요. 그런데 이 한 줄이 없으면 글이 조용히 안 나갑니다. 에러도 안 나고, 배포도 성공했다고 뜨고, 그냥 그 글만 없어요.

 

 

이 편은 이런 얘기입니다. 글을 인터넷에 올리는 것과, 사람이 들어와서 사는 사이트를 만드는 건 다른 일이더라고요.

 

만들수록 흩어졌습니다

 

이 시점까지 만든 걸 세어보니 이랬습니다.

 

  • 육아휴직 급여 계산기
  • 카드 혜택
  • 지분·지배구조
  • 성경 아틀라스
  • 기술사 스터디

 

다섯 개예요. 그리고 다섯 개가 전부 따로 떠 있었습니다. 각자 주소가 있었고, 서로 링크도 없었어요.

 

제일 곤란했던 건 남한테 보여줄 때가 아니라 제가 볼 때였습니다. "내가 뭘 만들었더라"를 한눈에 못 봤어요. 주소를 하나씩 기억해서 쳐야 했고, 몇 개는 이름도 헷갈렸습니다.

 

그리고 글은 또 별개였어요. 글은 네이버 블로그에 있고, 도구는 각자 주소에 있고, 둘은 아무 관계도 아니었습니다. 같은 사람이 만든 건데 그걸 알 방법이 없었어요.

 

여기서 정한 게 이 편의 전부입니다. 한 집으로 들이자.

 

솔직히 말하면 이건 만들기 더 어려운 쪽이에요. 도구마다 사이트를 하나씩 두는 게 훨씬 쉽습니다. 각자 알아서 굴러가고, 하나 고쳐도 나머지가 안 깨지니까요. 한 곳에 모으면 뭐 하나 잘못 건드렸을 때 전부가 같이 넘어집니다.

 

그런데도 모으기로 한 이유는 그냥 흩어진 걸 못 견뎌서였어요. 이건 기술적 판단이 아니라 취향에 가깝습니다. AI한테 "어느 쪽이 낫냐"고 물으면 아마 "목적에 따라 다릅니다"라고 답했을 거예요. 실제로 그럴 거고요. 이건 물어서 나오는 답이 아니었습니다.

 

 

저녁 두 시간 반의 기록

 

시작이 언제였냐면, 육아휴직 계산기를 완성한 날 저녁이었습니다. 계산기 마지막 커밋이 18시 44분이었고, 홈페이지 첫 커밋이 같은 날 19시 53분이에요. 한 시간 조금 넘게 지나서요.

 

그날 밤 커밋을 시각 순으로 늘어놓으면 이렇습니다.

 

19:53  본진(개인 홈페이지) 초안
19:55  모바일 정리
20:31  익명 댓글 추가
21:29  글마다 조회수·댓글 수
21:54  네이버 글 287편 이관, 카테고리 구조 반영
22:01  히어로를 Victor House 로, 푸터를 그리드 밖으로
22:06  네이버 글 이미지 렌더링
22:08  이미지를 화면 크기에 맞게 줄여서 배포

 

두 시간 반입니다. 껍데기가 19시 55분에 이미 서 있고, 나머지 두 시간은 "집이 되려면 뭐가 더 필요한가"를 하나씩 붙인 시간이에요.

 

순서를 다시 보면 재미있습니다. 두 번째로 붙인 게 댓글이에요. 디자인보다, 글 이관보다 먼저였습니다. 글 몇 편 없는 사이트에 댓글창부터 달아둔 거죠. 히어로 문구를 고친 건 두 시간이나 지나서고요.

 

만드는 축은 이렇게 정했어요. 파이썬 파일 하나가 전부를 만들어 낸다.

 

python3 build.py

 

이거 한 줄이면 첫 화면, 글 목록, 카테고리별 목록, 글 페이지 300몇 장, 연재 목차, 개인정보처리방침, 사이트맵까지 전부 새로 만들어집니다. 글을 하나 추가하려면 마크다운 파일을 폴더에 넣기만 하면 돼요. 나머지는 이 파일이 합니다.

 

외부 라이브러리는 안 씁니다. 마크다운 변환기도 안 갖다 썼어요. 대신 제가 실제로 쓰는 문법만 처리합니다. 코드에 이렇게 적어놨습니다.

 

# 글에 실제로 쓰인 것은 제목·인용·문단뿐이다. 범용 파서를 쓰지 않고
# 쓰는 문법만 처리한다. 새 문법을 쓰기 시작하면 여기에 추가한다.

 

이게 나중에 저를 한 번 물었는데, 그 얘기는 뒤에서 하겠습니다.

 

 

왼쪽에 뭘 세울 것인가

 

집에 들어왔을 때 제일 먼저 보이는 게 왼쪽 기둥입니다. 여기에 뭘 세우느냐가 사실상 사이트의 성격이에요.

 

제 답은 카테고리와 도구였습니다.

 

def sidebar(posts, active=""):
    """왼쪽은 카테고리다. 285편이 한 목록에 있으면 아무도 못 찾는다."""

 

글 285편을 한 줄로 세워놓고 "찾아보세요" 하면 아무도 안 찾습니다. 그래서 왼쪽 위는 카테고리예요. 독후감, 내돈내산 리뷰, 키보드 스위치, 맛집 지도, 대학원 생존기… 이런 이름 옆에 편 수가 붙습니다.

 

그 아래가 도구 목록입니다. 도구를 성격별로 묶어서 세웠어요. 생활에 쓰는 것, 기업 데이터, 기록해 두는 것. 육아휴직 계산기는 "생활", 지분·지배구조는 "기업 데이터", 성경 아틀라스와 기술사 스터디는 "기록"입니다.

 

그리고 도구마다 숫자를 하나씩 붙였어요. 카드 혜택 옆에 "1,180장", 지분·지배구조 옆에 "55개 그룹", 성경 아틀라스 옆에 "66권 · 10개 시대", 기술사 스터디 옆에 "325개 주제".

 

이 숫자를 붙인 이유가 있습니다. 이름만 봐서는 그게 뭔지 모르거든요. "카드 혜택"이라고만 쓰여 있으면 카드 몇 장짜리인지, 쓸 만한 건지 알 수가 없어요. 1,180장이라고 적혀 있으면 한 번은 눌러봅니다.

 

그런데 여기서 하나 조심할 게 생겼어요. 손으로 박아둔 숫자는 곧 거짓말이 된다는 것. 데이터가 늘어나면 화면의 숫자는 그대로인데 실제는 달라지니까요. 그래서 자주 바뀌는 숫자는 코드에 박지 않고 수집 결과 파일에서 읽어오게 했습니다. 아직 안 모은 항목이면 숫자 대신 성격을 적어요.

 

 

285편에서 뭔가를 찾으려면

 

카테고리로 나눠도 한 카테고리에 백 편씩 있으면 여전히 못 찾습니다. 그래서 목록 위에 검색창과 정렬 버튼을 붙였어요.

 

7월 24일 16시 31분 커밋에 이렇게 적혀 있습니다.

 

사이트 개편: 디자인 v2 · 검색 · 정렬 · 방문자 카운터 · 제휴 링크

 

여기서 재미있는 제약이 하나 있었어요. 이 사이트에는 서버가 없습니다. 미리 만들어둔 파일을 그냥 내려주는 구조라, 검색어를 받아서 찾아줄 놈이 없어요.

 

보통은 이럴 때 검색 서비스를 붙입니다. 돈이 들거나, 남의 서버에 글을 다 올려야 하거나, 둘 다예요.

 

그래서 브라우저가 하게 했습니다. 목록 페이지에는 이미 285편의 제목과 발췌가 다 들어 있거든요. 화면에 안 보일 뿐이지 이미 와 있는 겁니다. 그러니까 검색어를 치면 그 자리에서 안 맞는 줄을 숨기면 돼요.

 

var show = !q || li.textContent.toLowerCase().indexOf(q) > -1;
li.style.display = show ? '' : 'none';

 

이게 전부입니다. 서버도, 요금도, 색인도 없어요. 대신 한계가 명확합니다. 목록에 있는 글만 찾아지고, 본문 안쪽은 못 찾습니다. 글이 수천 편이 되면 이 방식은 못 씁니다.

 

정렬도 붙였어요. 최신순, 오래된순, 그리고 조회수순입니다. 조회수순이 좀 까다로웠는데, 조회수는 페이지를 열 때 따로 받아오는 값이라 처음엔 없거든요. 그래서 조회수가 도착하면 정렬을 다시 한 번 적용하게 했습니다.

 

window.__resort = function () { if (mode === 'views') apply(); };

 

이런 게 안 되어 있으면 들어온 사람이 조회수순을 눌렀는데 목록이 안 바뀌거나, 반쯤 바뀌다 맙니다. 고장 났다고 알려주지도 않아요. 그냥 이상한 사이트가 됩니다.

 

 

읽은 사람이 말을 걸 자리

 

댓글을 붙이면서 제일 먼저 정한 건 기능이 아니라 태도였습니다.

 

로그인 없이 씁니다. 이름 칸도 비워두면 익명이에요. 회원가입 같은 건 아예 안 만들었습니다.

 

이건 편해서가 아니라, 로그인을 만들면 제가 남의 개인정보를 보관하게 되기 때문이었어요. 이메일 받고, 비밀번호 받고, 그걸 지킬 책임을 지는 겁니다. 개인 블로그 댓글 몇 줄 받자고 질 책임이 아니라고 봤습니다.

 

대신 익명으로 열어놓으면 당연히 스팸이 옵니다. 그래서 막는 걸 층층이 뒀어요.

 

  • 2자 미만은 못 씀, 1000자 넘으면 못 씀
  • 같은 내용이 10분 안에 또 들어오면 거부 — 봇은 같은 문구를 연달아 뿌립니다. 사람이 같은 말을 10분 안에 두 번 쓰는 일은 드물고요
  • 링크가 3개를 넘으면 거부
  • 한 사람이 30초 안에 두 번 못 올림
  • 보이지 않는 입력칸을 하나 둬서, 거기 뭔가 적혀 있으면 봇으로 봅니다. 사람 눈에는 안 보이니까 사람은 못 채워요

 

그리고 여기가 좀 특이한데, 쓴 사람도 자기 댓글을 못 지웁니다.

 

-- 읽기는 누구나, 쓰기도 누구나(익명 허용). 수정·삭제 정책은 두지 않는다
-- → anon 키로는 남의 댓글을 고치거나 지울 수 없다.

 

로그인이 없으니까요. "이거 내 댓글이에요"를 증명할 방법이 없는데 삭제를 열어주면 아무나 남의 댓글을 지울 수 있게 됩니다. 그래서 아예 지우는 문을 안 만들었어요. 대신 댓글마다 신고 버튼이 있고, 신고가 들어오면 제가 지웁니다.

 

화면에도 그렇게 적어뒀습니다.

 

로그인 없이 쓰는 대신, 등록한 댓글은 직접 지울 수 없습니다.
지워야 할 댓글은 옆의 신고를 눌러주세요.

 

불편한 걸 숨기지 않고 그냥 적는 쪽을 골랐어요. 이런 건 AI가 알아서 정해주지 않습니다. "익명 댓글 붙여줘"라고 하면 붙여주는데, 못 지우는 걸 그대로 둘지 로그인을 만들지는 만드는 사람이 정하는 겁니다.

 

 

방문과 열람은 다른 숫자입니다

 

조회수도 그날 밤에 붙였습니다(21시 29분). 처음엔 단순했어요. 글을 열면 1 올리는 거죠.

 

바로 문제가 보였습니다. 같은 사람이 새로고침할 때마다 오르면 그 숫자는 아무 의미가 없어요. 제가 글을 고치면서 열 번 새로고침하면 조회수가 10이 됩니다. 그래서 같은 글은 6시간에 한 번만 세게 했어요.

 

여기까지는 그냥 만드는 얘기고, 진짜는 그다음이었습니다.

 

7월 29일 아침 커밋이 이겁니다.

 

사이트 지표 — 방문과 열람을 갈라 센다

 

무슨 얘기냐면요. 왼쪽 기둥 아래에 방문자 수를 띄우고 싶었습니다. "오늘 몇 명, 누적 몇 명" 이런 거요. 그런데 그걸 위해 테이블을 새로 만들기가 귀찮아서, 이미 있는 조회수 저장소를 그대로 재활용했어요. __visit__2026-07-29 같은 가짜 글 이름을 만들어서 거기에 방문 수를 쌓는 방식입니다.

 

잘 굴러갔어요. 그런데 나중에 "글이 얼마나 읽혔나"를 정리하려고 보니 이렇게 되어 있었습니다.

 

  • 가장 많이 읽힌 글 1위 — __visit__2026-07-26
  • 2위 — __visit__2026-07-25
  • 3위 — __visit__2026-07-24

 

상위 목록이 날짜로 도배됐습니다. 합계도 방문 수와 조회수가 섞여서 두 배로 부풀어 있었고요.

 

고치면서 코드에 이렇게 적어뒀습니다.

 

# 방문수는 글이 아니라 '__visit__YYYY-MM-DD' 가상 슬러그로 쌓인다.
# 글 조회수와 섞어 놓으면 상위 목록이 날짜로 도배되고 합계도 두 배로
# 부푼다. 갈라서 센다.

 

지금은 두 숫자가 따로 나옵니다. 방문은 사람이 몇 번 들어왔나, 열람은 글이 몇 번 읽혔나예요.

 

이게 왜 중요하냐면, 하나로 뭉치면 아무것도 모르게 되기 때문입니다. 숫자 하나가 올랐을 때 사람이 늘어난 건지 글이 읽힌 건지 구분이 안 돼요. 방문이 늘고 열람이 안 늘면 사람이 첫 화면만 보고 나간 겁니다. 방문은 그대로인데 열람이 늘면 오던 사람이 더 읽는 거고요. 완전히 다른 상황인데 한 숫자로는 같아 보입니다.

 

이건 기계가 못 잡아요. 두 값을 더하는 코드는 아무 문제 없이 잘 돌아가거든요. "내가 뭘 알고 싶은가"를 정하는 게 먼저였고, 그건 사람 몫이었습니다.

 

 

없는 주소로 들어오면 뭘 보여주나

 

7월 28일에 이걸 알았습니다. 이 사이트에는 "없는 페이지" 화면이 없었어요.

 

없으면 어떻게 되냐면, 그냥 첫 화면이 뜹니다. 그것도 "못 찾았다"가 아니라 "정상"이라는 표시를 달고 뜹니다.

 

이게 왜 나쁘냐면요.

 

주소를 오타 내서 들어와도 첫 화면이 뜹니다. 내가 내린 글 주소로 들어와도 첫 화면이 뜹니다. 검색엔진이 보기엔 첫 화면과 똑같은 내용의 페이지가 무한히 있는 사이트가 되는 거예요. 그걸 읽고 "이건 중복이네" 하고 버립니다.

 

문제는 버리는 것 자체가 아니라, 그 읽기 몫이 새 글에서 빠진다는 겁니다. 검색엔진이 사이트 하나를 읽어주는 양은 정해져 있는데, 그 예산을 첫 화면 복사본을 읽는 데 다 쓰는 셈이니까요.

 

고친 건 파일 하나 만드는 거였습니다. 뿌리에 404.html을 두면 호스팅이 알아서 "없는 페이지"라고 표시를 달고 내줍니다. 화면은 이렇게 간단해요.

 

없는 주소입니다
주소가 바뀌었거나, 글을 내렸거나, 오타일 수 있습니다.
글 목록에서 찾기 · 첫 화면으로

 

왼쪽 기둥은 그대로 뒀어요. 잘못 들어온 사람이 아무것도 없는 화면을 보고 그냥 나가버리지 않게요.

 

그리고 이 페이지는 사이트맵에 안 넣습니다.

 

# 뿌리에만 둔다. 사이트맵에는 안 넣는다 — 없는 주소를 읽어달라고 할 이유가 없다.

 

같은 커밋에 하나가 더 들어 있습니다. 올린 뒤에 다시 보고 글을 하나 내렸어요. 올릴 때는 괜찮다고 생각했던 글인데, 나중에 다시 읽어보고 뺐습니다.

 

내린 글이 있다는 것과 404를 붙인 게 같은 날인 건 우연이 아닐 겁니다. 글은 내리는 것으로 끝이 아니라, 내린 자리에 뭐가 뜨는지까지가 내리는 일이더라고요.

 

 

새 글이 올라온 걸 검색엔진이 언제 아나

 

사이트맵은 처음부터 있었습니다. 그런데 안을 보니 이랬어요.

 

<url><loc>...</loc><changefreq>weekly</changefreq></url>
<url><loc>...</loc><changefreq>weekly</changefreq></url>
<url><loc>...</loc><changefreq>weekly</changefreq></url>

 

313장이 전부 똑같습니다. "이 페이지는 매주 바뀝니다"를 313번 말하고 있었어요.

 

그런데 구글은 이 값을 안 읽습니다. 안 읽는 값을 313번 적어놓고 나머지 정보는 안 준 거예요. 그러니 무엇부터 읽을지 고를 근거가 하나도 없습니다. 실제로 2024년에 쓴 이관 글 44장이 앞줄에 서고, 어제 쓴 연재가 뒤로 밀려 있었어요.

 

바꾼 건 페이지마다 날짜를 적는 것이었습니다. 구글이 실제로 쓰는 값이거든요. 글 페이지에는 그 글 쓴 날짜, 카테고리 목록에는 거기 걸린 글 중 가장 최근 날짜를 적습니다.

 

여기서 하나 안 한 게 있어요. 모르는 날짜는 안 적었습니다.

 

# 없는 날짜는 안 적는다 — 지어내면 다음부터 구글이 이 사이트의 날짜를 안 믿는다.

 

개인정보처리방침 같은 페이지는 날짜가 없어요. 그런 건 그냥 비워둡니다. 오늘 날짜로 채워 넣으면 당장은 좋아 보이는데, 매번 그러면 "이 사이트는 매일 전부 바뀐다"는 소리가 되고 그다음부터는 아무것도 안 믿어줍니다.

 

그날 저녁에 RSS도 붙였어요. 커밋 메시지가 이렇습니다.

 

7월 28일 18:56  RSS 피드 — 네이버가 새 글을 빨리 물어가라고

 

사이트맵과 RSS는 하는 일이 다릅니다. 사이트맵은 "이런 주소들이 있습니다"는 목록이고, RSS는 "방금 이 글이 올라왔습니다"는 알림에 가까워요. 매일 아침 새 글이 나가는 사이트라 이게 값을 합니다.

 

RSS 만들다가 자잘한 데서 또 걸렸습니다. RSS는 날짜에 시각까지 적게 되어 있는데, 네이버에서 옮겨온 옛 글들은 시각이 없어요. 0시로 채우면 같은 날 올라온 글 열 편이 전부 같은 시각이 되고, 읽는 쪽에서 순서가 뒤죽박죽이 됩니다. 그래서 시각 없는 글은 아침 9시로 뒀습니다.

 

 

연재를 45편 쓰기로 해놓고

 

이 사이트에는 연재 목차 페이지가 있습니다. 글 머리말에 연재: 이름 · 회차: 21 이렇게 적어두면 세 가지가 자동으로 생겨요.

 

1. 연재 목차 페이지 2. 각 글 아래 "◀ 이전 · 목차 · 다음 ▶" 3. 목차에 진행률 막대

 

목차에는 아직 안 쓴 편도 회색 글씨로 미리 떠 있습니다. 글이 올라오면 자동으로 링크가 되고요. 독자가 앞으로 뭐가 올지 알 수 있게 하려고 그렇게 했어요.

 

코드에 이유를 적어놨습니다.

 

# 45편짜리 연재를 손으로 관리하면 반드시 어긋난다. 회차를 적는 것 말고는
# 아무것도 안 하게 만든다.

 

그런데 이 목차를 세워놓고 보니 계획이 계속 늘어나더라고요. 만드는 것마다 "이것도 한 편 써야지"가 붙습니다. 목차에 회색 줄이 하나씩 늘어나는데, 늘리는 건 아무 비용이 안 들어요. 그냥 한 줄 적으면 되니까요.

 

7월 24일 밤에 이걸 잘랐습니다.

 

21:26  연재 계획 44편으로 — 편 몇 개 제거

 

만든 도구들 중에 몇 개는 편을 안 쓰기로 했어요. 이유는 단순합니다. 다 쓸 자신이 없어서였습니다. 44편도 한 달 반이 넘는 분량이거든요.

 

이건 좀 짚고 싶은 대목이에요. 계획을 늘리는 건 아무나 하는데, 줄이는 건 아무도 안 합니다. AI한테 "이 연재 계획 어때?"라고 물으면 대개 "이런 편도 있으면 좋겠네요"가 나옵니다. 빼자는 말은 잘 안 나와요. 왜냐하면 뭘 빼는 건 내가 뭘 못 하는지를 아는 데서 나오는 판단인데, 그건 저만 아는 정보니까요.

 

 

한글 폴더 이름 때문에 사진이 안 떴습니다

 

7월 25일 낮에 이상한 걸 발견했어요. 연재 3편의 사진이 화면에 하나도 안 떴습니다.

 

파일은 분명히 올라가 있었어요. 폴더 이름도 맞고, 파일 이름도 맞고, 주소를 직접 쳐도 뭔가 응답은 옵니다. 그런데 이미지 자리에는 깨진 아이콘만 있었어요.

 

원인이 좀 어이없었습니다. 한글은 컴퓨터에 저장되는 방법이 두 가지예요.

 

'한'이라는 글자를 통째로 하나로 저장하는 방식이 있고, 'ㅎ'+'ㅏ'+'ㄴ'을 붙여서 저장하는 방식이 있습니다. 화면에는 똑같이 '한'으로 보여요. 사람 눈으로는 절대 구분이 안 됩니다.

 

그런데 맥에서 폴더를 만들면 뒤쪽 방식으로 저장되고, 웹페이지가 이미지를 달라고 할 때는 앞쪽 방식으로 요청합니다. 호스팅은 이 둘을 다른 폴더로 봤어요. 그래서 "그런 폴더 없는데요"가 된 겁니다.

 

고친 건 복사할 때 폴더 이름을 앞쪽 방식으로 강제하는 한 줄이었습니다.

 

rel = unicodedata.normalize("NFC", str(f.relative_to(src)))

 

이런 종류의 버그가 저는 제일 무섭습니다. 눈으로 봐서는 틀린 데가 없거든요. 폴더 이름을 복사해서 나란히 놓고 비교해도 똑같습니다. 코드도 멀쩡하고, 배포도 성공했고, 에러 로그도 깨끗해요. 그냥 사진만 안 뜹니다.

 

사진 얘기가 나온 김에 하나 더요. 홈페이지에 올릴 때 사진을 가로 1400픽셀로 줄여서 내보냅니다. 원본은 평균 376KB인데, 글 하나에 스무 장이면 독자가 7MB를 내려받아야 하거든요. 본문 폭이 700픽셀 남짓이라 1400이면 고해상도 화면에서도 충분합니다.

 

줄이면서 사진 방향도 같이 굽습니다.

 

im = ImageOps.exif_transpose(im) or im

 

폰 카메라는 사진을 늘 같은 방향으로 저장하고, 어느 쪽이 위인지는 파일 안에 따로 적어둬요. 그 표시를 적용하지 않고 저장하면 세로로 찍은 사진이 전부 옆으로 눕습니다. 이걸 안 걸어서 사진 열여덟 장이 90도 누운 채로 나간 적이 있어요. 원본은 안 건드리고 사본만 만듭니다.

 

 

화면은 멀쩡한데 아무 일도 안 일어나는 고장

 

앞에서 마크다운 변환기를 직접 만들었다고 했잖아요. 쓰는 문법만 처리하는 걸로요.

 

이게 한 번 물었습니다. 표 문법이 없는 변환기에 표를 썼어요. 파이프 문자가 그대로 화면에 나갔습니다.

 

| 구간 | 지급률 |
|---|---|

 

이게 저렇게 생긴 채로 글에 실렸어요. 만든 사람이 자기 도구의 한계를 까먹은 겁니다. 웃긴 건 제가 만든 것도 아니고 저는 그냥 "표 문법도 처리해줘"라고 안 했을 뿐인데, 쓸 때는 당연히 될 거라고 생각했다는 거예요.

 

비슷한 종류의 고장이 하나 더 있어서, 그건 아예 검사를 붙였습니다.

 

페이지 안에 자바스크립트가 들어가는데, 이게 문법이 하나만 틀려도 통째로 안 돕니다. 문제는 화면이 멀쩡해 보인다는 거예요. 글도 잘 보이고 디자인도 그대로입니다. 댓글 폼이 그냥 반응만 안 해요. 등록을 눌러도 아무 일도 안 일어납니다. 에러 메시지도 없고요.

 

그래서 배포 전에 만들어진 페이지를 전부 훑으면서 스크립트 문법을 검사하게 했습니다. 하나라도 틀리면 배포를 중단합니다.

 

if bad:
    raise SystemExit(f"스크립트 문법 오류 {bad}건 — 배포를 중단합니다.")

 

푸터 문구도 한 번 고쳤어요. 원래는 "서버도 데이터베이스도 쓰지 않습니다"라고 적혀 있었는데, 댓글과 조회수를 붙이면서 그게 거짓말이 됐습니다. 개인정보처리방침에는 저장한다고 써놓고 푸터에서 아니라고 하면 앞뒤가 안 맞잖아요. 지금은 이렇게 적혀 있습니다.

 

글과 화면은 정적 파일로 만듭니다.
댓글과 조회수만 외부 데이터베이스에 저장합니다.

 

기능을 붙일 때 같이 고쳐야 하는 문장이 어딘가에 있다는 걸, 저는 이때 처음 생각했어요.

 

 

그래서 사람이 어디에 남았나

 

기계가 한 것. 페이지 생성기 전체, 마크다운 변환, 반응형 레이아웃, 댓글 시스템, 조회수 집계, 사이트맵·RSS 생성, 이미지 리사이즈 파이프라인, 스크립트 문법 검사. 첫 판이 두 시간 반 만에 섰습니다. 저 혼자였으면 이 중 첫 화면 하나도 못 만들었어요.

 

사람이 한 것은 네 가지입니다.

 

첫째, 한 곳에 모으기로 한 것. 도구마다 사이트를 따로 두는 쪽이 만들기는 훨씬 쉽습니다. 하나 건드려도 나머지가 안 깨지고요. 흩어진 걸 못 견딘 건 저였어요. 이건 물어서 나오는 답이 아니고, 나오더라도 "목적에 따라 다릅니다"가 나옵니다. 뭘 못 견디는지는 만드는 사람만 압니다.

 

둘째, 방문과 열람을 갈라 센 것. 두 값을 더하는 코드는 아무 문제 없이 잘 돌아갔어요. 에러도 없고 숫자도 나옵니다. 다만 그 숫자로는 아무것도 알 수 없었을 뿐이에요. 사람이 늘어난 건지 글이 읽힌 건지 구분이 안 되니까요. 무엇을 알고 싶은지를 정하고 나서야 세는 방법이 정해졌습니다.

 

셋째, 연재 계획을 잘라낸 것. 목차에 회색 줄을 하나 더 적는 건 아무 비용이 안 듭니다. 그래서 계획은 가만 두면 늘어나요. 44편으로 줄이면서 몇 편을 뺐는데, 뭘 뺄지는 제가 뭘 못 하는지를 아는 데서 나온 판단이었습니다. 그건 저만 아는 정보예요.

 

넷째, 올린 뒤에 다시 보고 글을 내린 것. 이게 제일 사람다운 일이었던 것 같아요. 올릴 때는 괜찮다고 봤던 글입니다. 시간이 좀 지나고 다시 읽으니까 아니더라고요. 검사 도구가 잡아준 게 아니고, 규칙에 걸린 것도 아닙니다. 그냥 다시 읽었더니 아니었어요. 그리고 내리고 나서 그 자리에 뭐가 뜨는지까지 확인하는 게 내리는 일의 나머지 절반이었습니다.

 

이 편을 쓰면서 계속 든 생각이 있어요. 사이트를 만든다고 하면 보통 화면 만드는 일을 떠올립니다. 그런데 이 두 시간 반과 그 뒤 일주일에서 실제로 시간을 잡아먹은 건 화면이 아니었어요.

 

  • 같은 날 두 편이 나가면 어느 쪽이 위인가
  • 없는 주소로 들어오면 뭘 보여주나
  • 새 글이 올라온 걸 검색엔진이 어떻게 아나
  • 읽은 사람이 말을 걸 자리가 있나
  • 지워달라는 댓글은 누가 지우나

 

전부 화면에는 안 보이는 것들입니다. 그런데 이게 없으면 그냥 인터넷에 올려둔 파일 뭉치예요. 집이 아니라요. 그리고 이런 질문은 만들기 전에는 하나도 안 떠올랐습니다. 만들고 나서, 살아보고 나서 하나씩 나왔어요.

 

다음 편

 

여기까지가 집을 지은 얘기입니다. 왼쪽에 글이 서고 그 아래 도구가 서고, 파이썬 파일 하나가 전부를 만들어 내는 구조가 됐어요.

 

다음 편은 다시 도구 얘기로 돌아갑니다. 시장 지표예요. 코스피, 코스닥, 환율을 한 화면에 놓는 도구입니다.

 

거기서는 장이 끝나자마자 등락률이 0.00%가 되어 있었어요. 그래프는 하루치 곡선을 멀쩡히 그리고 있는데 옆의 숫자만 0이었습니다. 같은 시장을 두 값으로 말하지 않으려면 무엇을 기준으로 잡아야 하는가 — 그 얘기입니다.

 

#개인홈페이지 #홈페이지만들기 #정적사이트 #사이트제작 #파이썬 #빌드스크립트 #마크다운 #블로그만들기 #댓글달기 #익명댓글 #스팸차단 #조회수 #방문자카운터 #사이트맵 #RSS #404페이지 #SEO #검색엔진최적화 #서버없이 #무료호스팅 #웹개발 #바이브코딩 #클로드 #AI코딩 #휴먼인더루프 #예약발행 #연재 #유니코드 #EXIF #이미지최적화

댓글

    로그인 없이 쓰는 대신, 등록한 댓글은 직접 지울 수 없습니다. 지워야 할 댓글은 옆의 신고를 눌러주세요.
    네이버 블로그글 원문 보러가기 →유튜브 쇼츠만드는 장면 20초로 보기 →
    관리자 Victor · 문의는 우상단 신고·제안으로 남겨주세요.
    글과 화면은 정적 파일로 만듭니다. 댓글과 조회수만 외부 데이터베이스에 저장합니다 — 개인정보처리방침

    오류 신고 · 제안

    관리자 Victor에게 전달됩니다