Victor

[연재] × 자동화가 매일 밤 내 사이트를 망가뜨리고 있었다

연재 · 2026-08-23

로그 맨 끝에 "실패 0" 이라고 적혀 있었습니다

 

제 맥에는 매일 아침 09시에 저 혼자 깨어나는 작업이 하나 있었어요. 네이버 블로그에 새 글이 올라왔는지 보고, 있으면 홈페이지로 옮겨다 놓고, 사이트를 다시 만들어 올리는 일입니다. 그게 남긴 기록은 이렇게 생겼습니다.

 

[2026-07-23 09:41:38] ─── 동기화 시작 ───
[2026-07-23 09:41:42] 카테고리 14개 · 글 278편 목록 저장 (제외 1카테고리)
[2026-07-23 09:41:42] 본문: 수집 0편 · 건너뜀 278 · 실패 0
[2026-07-23 09:41:42] 새 글 없음 — 배포 생략
[2026-07-23 09:41:42] ─── 완료 ───

 

실패 0. 빨간 줄 하나 없어요. 시작했고, 세어봤고, 할 일이 없어서 안 하고, 완료. 이보다 더 얌전한 로그가 있을까 싶습니다.

 

그런데 이 작업은 그동안 제 사이트를 조용히 망가뜨리는 쪽으로 서 있었습니다. 정확히는, 언제든 망가뜨릴 수 있는 자세로 매일 아침 팔을 들고 있었어요.

 

고장이 난 게 아닙니다. 하나도 안 고장 났어요. 시킨 대로 정확히 돌았습니다. 그 사이에 일의 방향이 반대로 뒤집혔고, 크론은 그걸 모릅니다. 알 방법도 없고요.

 

 

오늘은 이 얘기입니다. 에러도 안 나고 알림도 안 울리는데 틀어져 있는 것을 사람이 어떻게 알아채는가. 그리고 그걸 알았을 때 고칠 것인가 끌 것인가.

 

이 자동화가 원래 하던 일

 

먼저 이게 왜 있었는지부터요.

 

저는 2024년 2월부터 네이버 블로그에 글을 써왔습니다. 지금 거기에 289편이 쌓여 있어요. 내돈내산 리뷰, 키보드 스위치 분석, 맛집, 독후감, 대학원 생존기 같은 것들입니다.

 

 

7월에 제 도메인으로 홈페이지를 열면서, 이 글들을 새 사이트로 옮겨오는 걸 만들었습니다. 옮기는 방향은 네이버 → 홈페이지 였고요. 한 번 옮기고 끝낼 수도 있었지만, 앞으로도 네이버에 글을 쓸 테니 매일 자동으로 따라오게 하는 게 맞다고 봤습니다.

 

그래서 크론에 딱 한 줄을 걸었어요. 크론은 맥이 정해진 시각에 명령을 대신 실행해 주는 장치입니다. 알람시계라고 보시면 돼요.

 

0 9 * * *   cd .../naver_import && python3 sync.py >> sync.log 2>&1

 

맨 앞 0 9 가 "매일 09시 00분"입니다. 나머지 별표 셋은 "날짜·달·요일은 안 따진다"는 뜻이고요.

 

sync.py 가 하는 일은 다섯 단계였습니다.

 

1. 네이버에서 글 목록을 새로 받아온다 2. 아직 안 가져온 글만 본문을 받는다 3. 사진을 받는다 4. 사이트를 다시 만든다 5. 새 글이 있을 때만 올린다

 

굵게 칠한 두 군데가 중요해요. 이미 받아둔 글은 건너뛰니까 278편을 매일 다시 긁을 일이 없고, 새 글이 없으면 배포도 안 합니다. 그래서 위의 로그가 3~4초 만에 끝난 거예요. 덕분에 맥이 잠들어서 하루를 통째로 걸러도 문제가 안 됩니다. 다음에 깨어날 때 밀린 글까지 같이 따라와요.

 

사진 받는 쪽은 규칙을 하나 더 붙였습니다. 원본이 없어졌다는 답(404)이 오면 다시 시도하지 않고 바로 포기하게요. 없는 걸 세 번 더 두드려봐야 계속 없거든요. 실제로 이 규칙에 걸린 사진이 9장 있습니다.

 

  이미지 실패 224325918803#25: HTTP Error 404: Not Found
  이미지 실패 223829450383#26: HTTP Error 404: Not Found
  ...
이미지 3115개 저장 · 건너뜀 0 · 실패 9

 

여기까지는 잘 돌았어요. 실제로 글 278편과 사진 3,115장이 이걸로 넘어왔습니다. 지금 사이트에 있는 글 256편 중 대부분이 이때 건너온 것들이에요.

 

 

 

그런데 화살표가 반대로 돌아갔습니다

 

문제는 이 자동화가 잘 돌아서 제 할 일을 끝냈다는 데서 시작합니다.

 

278편을 다 옮기고 나니까, 어느 순간부터 제 글쓰기 습관이 바뀌었어요. 이제는 홈페이지에 먼저 씁니다. 지금 읽고 계신 이 연재만 해도 전부 홈페이지에서 시작한 글이에요.

 

 

그리고 다 쓴 글을 네이버로 옮겨다 붙입니다. 원본이 있는 쪽이 뒤집힌 거예요.

 

  • 예전: 네이버가 원본 → 홈페이지가 사본
  • 지금: 홈페이지가 원본 → 네이버가 사본

 

이건 제 머릿속에서 일어난 변화입니다. 코드는 한 줄도 안 바뀌었어요. 그래서 크론은 여전히 네이버가 원본이라는 전제로 매일 09시에 팔을 들고 있었던 겁니다.

 

그리고 이걸 알아챈 계기가… 없습니다. 진짜로요.

 

에러가 난 것도 아니고, 알림이 울린 것도 아니고, 화면이 이상해진 것도 아니에요. 그냥 "이제 홈페이지에 먼저 쓰고 네이버로 옮기지" 하고 생각하다가, 바로 옆에 "근데 저 크론은 아직 네이버에서 홈페이지로 끌어오는 방향인데" 가 붙어버린 거예요. 그게 전부입니다.

 

자동화의 진짜 무서운 점이 여기 있다고 생각해요. 고장은 티가 납니다. 전제가 바뀐 건 티가 안 나요. 고장 난 기계는 멈추거나 빨간 등이 켜지는데, 전제가 바뀐 기계는 아주 성실하게 계속 돕니다. 어제와 똑같은 얼굴로요.

 

첫 번째 위험: 협찬 글이 저 혼자 복제됩니다

 

그럼 그대로 두면 뭐가 생기는가. 두 가지였습니다.

 

첫 번째가 협찬 글입니다. 제 네이버 블로그에는 협찬 리뷰가 51편 있어요.

 

 

협찬은 "네이버 블로그에 게재한다"는 조건으로 받는 겁니다. 제품을 받고, 써보고, 그 블로그에 리뷰를 올리는 거예요. 어디에 올리느냐가 계약의 일부인 셈이죠.

 

 

그런데 그 글이 제가 손도 안 댄 사이에 다른 사이트에 그대로 다시 올라가면, 협찬사 입장에서 이건 얘기가 다를 수 있습니다. 게재 범위를 제가 마음대로 넓힌 게 되니까요. 문제 삼겠다고 하면 할 말이 없어요.

 

여기서 제일 마음에 안 들었던 건 "문제가 될 수도 있다"가 아니라 "제가 아무것도 안 해도 매일 아침 자동으로 벌어진다" 는 쪽이었습니다. 실수를 해서 사고가 나는 거면 조심하면 돼요. 그런데 이건 가만히 있는 게 곧 실행입니다. 그게 자동화의 성질이고요.

 

두 번째 위험: 같은 글이 두 벌이 됩니다

 

두 번째는 좀 더 조용한 쪽입니다.

 

홈페이지에 쓴 글을 네이버에 옮겨 붙였다고 해볼게요. 그러면 그 글은 이제 네이버에 있는 새 글이에요. 크론이 보기엔 그냥 새 글입니다. 다음 날 아침이면 그걸 홈페이지로 끌어옵니다.

 

결과는 이렇게 돼요.

 

홈페이지: [원본] 어떤 글
홈페이지: [네이버에서 온 사본] 같은 글

 

같은 사이트 안에 같은 글이 두 벌 생깁니다. 목록에 나란히 뜨고요. 검색엔진 입장에서는 "이 사이트는 자기 글을 자기가 베껴놨네"가 되는데, 그러면 둘 중 어느 쪽을 보여줄지 검색엔진이 골라버립니다. 제가 고를 수가 없어요.

 

실제로 지금 네이버에 Victor House 라는 카테고리가 하나 생겨 있습니다. 홈페이지에 올린 것들을 네이버에서 알리려고 만든 자리예요. 지금 글 2편이 들어 있습니다.

 

 

두 편 다 제가 만든 키보드 스위치 도구 얘기고요. 홈페이지에 있는 이 화면을 소개하는 글입니다.

 

 

크론이 살아 있었다면 이 두 편은 다음 날 아침에 홈페이지로 넘어옵니다. 홈페이지에서 출발해서 네이버를 한 바퀴 돌고 홈페이지로 돌아오는 거예요. 글이 자기 자신을 낳는 셈입니다.

 

막아둔 건 있었어요. 그런데 그게 '한 번'짜리였습니다

 

여기서 변명을 하나 하자면, 아무 대비도 안 해둔 건 아니었습니다. 이관에는 제외 목록이 있었어요. 여기 적힌 카테고리와 글은 안 가져옵니다.

 

"categories": ["세상 흘러가는 이야기", "Victor House", "협찬리뷰"],
"logNos": ["223405483806", "224110367669", "223907752002"]

 

카테고리 단위로 통째로 빼는 칸이 있고, 글 하나만 빼는 칸이 따로 있어요. 실제로 여기 손을 댄 적도 있습니다. 7월 28일에 글 한 편을 빼야 할 일이 있어서 아래 칸에 번호를 넣었어요. 그 뒤로 그 글은 다시 안 들어옵니다.

 

그런데 이걸 다시 보다가 좀 서늘해졌습니다.

 

이 목록은 카테고리 이름이 글자 그대로 같아야 작동합니다. 띄어쓰기 하나, 대소문자 하나만 달라도 못 걸러요. 그리고 카테고리는 네이버 글쓰기 화면에서 드롭다운 하나로 고르는 거예요. 글을 쓰다가 카테고리를 한 번만 잘못 고르면, 그 글은 제외 목록을 그냥 통과해서 다음 날 아침에 넘어옵니다.

 

더 마음에 걸린 게 하나 있었어요. 마지막으로 돌았던 동기화가 저장해둔 카테고리 목록을 열어봤는데, 거기 Victor House 라는 이름이 없습니다. 그때는 카테고리가 15개였고, 지금은 16개예요. 그 카테고리는 이관이 멈춘 다음에 만들어졌거든요.

 

그러니까 제외 목록에 적힌 이름은, 이관하는 코드가 한 번도 본 적 없는 이름이었습니다. 제가 손으로 적어 넣은 글자일 뿐이에요. 오타가 있어도 아무도 안 알려줍니다. "그런 카테고리 없는데요?" 하고 경고해 주는 사람이 없어요. 조용히 아무것도 안 걸러지고, 로그에는 여전히 실패 0 이라고 찍힙니다.

 

정리하면 이렇습니다.

 

막는 방법언제 뚫리나
협찬 글카테고리 이름으로 제외카테고리를 한 번 잘못 고르면
사본 생성카테고리 이름으로 제외이름을 한 글자 다르게 적으면

 

한 번의 실수로 깨지는 방어는 방어가 아닙니다. 특히 그 한 번이 언제 일어났는지 아무도 안 알려주는 구조라면요.

 

그래서 정교하게 고치는 대신 껐습니다

 

여기서 갈림길이 나왔어요.

 

기술적으로 더 나은 답은 분명히 고치는 쪽입니다. 제외 조건을 촘촘하게 만들면 돼요. 카테고리 이름 말고 번호로 거른다든가, 홈페이지에 이미 있는 제목이면 안 가져온다든가, 목록에 없는 카테고리 이름이 적혀 있으면 경고를 띄운다든가. 반나절이면 다 붙일 수 있습니다.

 

그런데 저는 이관 자체를 껐습니다. 크론에서 그 한 줄을 지웠어요.

 

이유는 하나였습니다. 조건을 붙이는 건 위험을 작게 만드는 일이고, 끄는 건 위험을 없애는 일이에요. 조건을 다섯 개 붙여도 여섯 번째 구멍은 남습니다. 그리고 이 자동화는 이제 저한테 필요가 없었어요. 옮길 글은 다 옮겨왔고, 새 글은 어차피 홈페이지에서 시작하니까요.

 

필요 없는 기능을 정교하게 지키는 것만큼 아까운 일이 없더라고요. 필요가 없어졌으면 끄는 게 맞습니다. 자동화를 만든 사람이 자동화를 아까워하기 시작하면, 그때부터는 도구가 사람을 부리는 쪽이 돼요.

 

대신 '되돌리는 법'을 같이 적었습니다

 

다만 끄는 것도 방식이 있다고 봤습니다. 그냥 지우고 끝내면, 반년 뒤의 제가 "여기 뭐가 있었던 것 같은데" 하고 헤매게 되거든요.

 

그래서 세 가지를 같이 했어요.

 

하나, 원래 크론을 파일로 남겼습니다. crontab.이관중단전.txt 라는 이름으로요. 지운 게 아니라 옆으로 치워둔 겁니다.

 

둘, 다시 켜는 명령을 문서에 적었습니다. 한 줄이면 돌아옵니다.

 

crontab naver_import/crontab.이관중단전.txt

 

한 번만 손으로 돌리고 싶을 때 쓰는 명령도 같이 적어뒀고요.

 

cd blog/naver_import && python3 sync.py

 

셋, 왜 껐는지를 적었습니다. 이게 제일 중요했어요. 명령만 적어두면 반년 뒤의 저는 그걸 보고 그냥 다시 켭니다. "아 이런 게 있었네" 하고요. 그러면 오늘 한 일이 통째로 없던 일이 돼버려요.

 

그래서 문서 맨 위에 "이관은 네이버 → 홈페이지 방향이었는데, 지금은 방향이 반대가 됐다" 는 문장부터 적었습니다. 다시 켜려는 사람이 제일 먼저 읽어야 하는 건 명령어가 아니라 끈 이유니까요.

 

끄는 것도 되돌릴 수 있게 껐다. 이 표현이 스스로 제일 마음에 들었어요.

 

이미 옮겨온 278편은 안 지웠습니다

 

같이 정한 게 하나 더 있습니다. 이관은 껐지만 이미 옮겨온 글 278편은 그대로 뒀어요.

 

이게 헷갈리기 쉬운 지점인데, 저는 이 둘이 완전히 다른 결정이라고 봤습니다.

 

  • 끄는 것 = 앞으로 이 일을 안 하겠다
  • 지우는 것 = 지금까지 한 일을 없던 걸로 하겠다

 

앞의 것은 언제든 되돌릴 수 있어요. 크론 한 줄 다시 넣으면 됩니다. 뒤의 것은 못 되돌립니다. 사진 3,115장을 다시 받아야 하고, 그중 9장은 원본이 이미 없어져서 영영 못 받아요.

 

그러니까 되돌릴 수 있는 것부터 하고, 못 되돌리는 건 안 한다. 지금 사이트에 글이 256편 있는 건 그래서예요. 크론은 멈췄지만 그 크론이 옮겨온 결과물은 멀쩡히 살아 있습니다.

 

지금 두 화면을 나란히 놓으면

 

한 달쯤 지난 지금, 이걸 껐다는 사실이 화면에 눈으로 보입니다.

 

네이버 맛집 지도 카테고리는 21편이에요. 제일 최근 글이 8월 14일에 올린 아이스크림 가게 얘기고요.

 

 

같은 카테고리가 홈페이지에서는 17편입니다. 제일 최근 글이 작년 10월이에요.

 

 

21편과 17편. 이거 처음 보면 딱 버그처럼 보이죠. 넉 편이 안 넘어왔고, 열 달째 안 넘어오고 있으니까요.

 

그런데 이건 고장이 아니라 제가 그렇게 정한 결과입니다. 그리고 바로 이래서 문서를 쓴 거예요. 이 차이를 나중에 발견한 사람(=반년 뒤의 저)은 십중팔구 "동기화가 깨졌네" 하고 고치려 들 겁니다. 그때 옆에 문서가 없으면, 고치는 게 곧 되돌리는 게 돼요.

 

의도적으로 만든 차이는 문서가 없으면 버그로 오해받습니다. 그리고 오해받은 의도는 다음 사람 손에 조용히 지워지고요.

 

같은 성질의 사건 하나 더 — 배포는 됐는데 화면은 안 바뀌던 일

 

성격이 똑같은 사고를 하나 더 겪은 적이 있어서 같이 적어둘게요. 이쪽도 "에러는 안 나는데 틀린 답을 보여주던" 종류입니다.

 

사이트에 올리는 파일 중에 계산을 담당하는 파일과 자료를 담은 파일이 따로 있어요. 핸드폰 보험 계산기가 그런 구조입니다.

 

 

브라우저는 한 번 받아온 파일을 한동안 재사용합니다. 매번 새로 받으면 느리니까요. 그래서 "이 파일은 캐시하지 말아라"라고 알려주는 설정이 있는데, 제 사이트에서는 그 설정이 계산 파일에는 안 먹고 있었습니다. 재보니까 화면 파일에는 먹고, 계산 파일에는 안 먹더라고요. 고쳐놨다고 믿고 있던 게 처음부터 죽어 있었던 거예요.

 

이게 왜 위험하냐면, 자료만 새로 받고 계산은 옛날 걸 쓰는 상태가 생기기 때문입니다. 실제로 어떤 상품의 분류를 바꾼 날, 새 계산이 옛 자료를 읽어서 네 시간 동안 틀린 화면이 떠 있었어요. 배포는 성공이라고 찍혔고요.

 

해결은 설정을 고치는 게 아니라 주소를 바꾸는 쪽이었습니다. 파일 내용을 요약한 짧은 문자열을 주소 끝에 붙이는 거예요.

 

<script src="catalog.js">  →  <script src="catalog.js?v=3f9a1c2b">

 

내용이 바뀌면 주소가 바뀌니까 브라우저는 받을 수밖에 없어요. 캐시 설정이 먹든 안 먹든 상관이 없어집니다.

 

그리고 여기에도 규칙을 하나 넣었습니다. 지문을 하나도 못 붙였으면 실패로 처리한다는 거예요.

 

0건은 정상이 아니다. 붙일 것이 없다면 부를 이유도 없었다.

 

붙일 게 없는데 "0개 완료"라고 초록불을 켜면, 그건 오늘 이 글에서 계속 나온 그 문제로 돌아갑니다. 아무 일도 안 한 것과 잘 해낸 것이 로그에서 똑같아 보이는 상태요.

 

사람은 어디에 남았나

 

이번 편에서 코드가 한 일은 사실 없습니다. 코드는 시킨 대로 완벽하게 돌았어요. 사람이 한 일만 있었습니다.

 

하나, 전제가 바뀐 걸 알아챈 것. 이건 화면이나 로그에 안 나옵니다. "내 습관이 바뀌었다"와 "저 기계는 옛 습관을 전제로 돈다"를 나란히 놓을 수 있는 건 사람뿐이에요. 기계는 자기 전제를 의심하지 않습니다.

 

둘, 고치는 대신 끄기로 정한 것. 조건을 붙이는 게 더 그럴듯하고 더 재미있어요. 그런데 필요 없어진 기능이면 없애는 게 맞습니다. 이 판단은 코드를 봐서는 안 나와요. "이 기능이 나한테 아직 필요한가"는 코드 밖의 질문이니까요.

 

셋, 끄면서 되돌리는 길을 남긴 것. 원본 크론을 파일로 두고, 다시 켜는 명령을 적고, 왜 껐는지를 제일 위에 적었습니다.

 

넷, 이미 한 일은 안 건드린 것. 껐다고 결과물까지 지우면 못 되돌립니다.

 

마지막으로 이번에 배운 걸 한 줄로 적으면 이렇습니다.

 

배운 것
고장보다 무서운 건 전제가 바뀐 채 잘 도는 것고장은 멈추지만 이건 매일 성실하게 돈다
"실패 0"은 "맞게 하고 있다"가 아니다시킨 걸 했다는 뜻일 뿐이다
한 번의 실수로 깨지는 방어는 방어가 아니다그 한 번이 언제였는지 아무도 안 알려준다
필요 없어진 기능은 정교하게 지키지 말고 끈다조건을 다섯 개 붙여도 여섯 번째 구멍은 남는다
끄는 것도 되돌릴 수 있게 끈다원본과 이유를 남기면 끈 것도 하나의 선택지가 된다
끄는 것과 지우는 것은 다른 결정이다앞은 되돌릴 수 있고 뒤는 못 되돌린다
의도적인 차이는 문서가 없으면 버그로 오해받는다그리고 조용히 원상복구된다
아무것도 안 한 것과 잘 해낸 것이 같아 보이면 안 된다0건은 성공이 아니라 신호다

 

자동화를 붙일 때 저는 "이게 잘 돌까"를 걱정했었어요. 이제는 하나 더 봅니다. "이게 왜 필요했는지가 아직 유효한가."

 

전자는 로그가 알려줍니다. 후자는 안 알려줘요. 그건 아직 사람이 봐야 하는 자리더라고요.

 

#크론탭 #cron #자동화 #자동화실패 #네이버블로그 #블로그이관 #백업자동화 #중복콘텐츠 #검색최적화 #SEO #협찬리뷰 #정적사이트 #개인홈페이지 #홈페이지만들기 #파이썬 #파이썬스크립트 #웹크롤링 #캐시 #브라우저캐시 #배포자동화 #클라우드플레어페이지스 #무료호스팅 #롤백 #운영기록 #문서화 #기술부채 #바이브코딩 #AI코딩 #클로드 #휴먼인더루프

댓글

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

    오류 신고 · 제안

    관리자 Victor에게 전달됩니다