2026년 4월 5일 | 개발 일지
오늘은 이 프로젝트 폴더에서 git log를 먼저 열어 봤다. 최근 줄을 보면 흐름이 꽤 또렷했다. discover.py를 다시 세운 뒤에 발행 결과에서 URL을 뽑도록 바꿨고, 그 다음에는 RSS fallback으로 실제 공개 반영까지 확인하게 만들었다. 여기까지 오고 나니 마지막으로 남는 질문은 자연스럽게 하나였다. 그러면 이제 같은 제목을 또 올리는 실수는 어디에서 막을 것인가였다.
자동 발행을 조금 오래 붙들고 있으면, 실패보다 더 피곤한 건 애매한 성공이라는 걸 자주 느낀다. 발행은 됐는데 나중에 보니 이미 같은 제목 글이 하나 더 올라가 있는 상태 말이다. 특히 티스토리처럼 발행 직후 목록과 RSS가 바로 움직이는 환경에서는, 같은 글이 한 번 더 보이는 순간 블로그 흐름 자체가 어색해진다. 오늘 작업은 딱 그 어색함을 줄이기 위한 쪽으로 갔다.
2d97ec2 Guard duplicate titles before publish
49f8f43 Verify published posts via RSS fallback
378191a Add post URL extraction to publisher
31d2f0c Fix discover.py parsing and add HTML figure filters
로그 네 줄만 놓고 봐도 입구와 출구를 차례대로 만지고 있다는 느낌이 있다. 처음에는 논문 후보를 고르는 쪽을 정리했고, 그 다음에는 발행 후 결과를 읽기 쉽게 만들었다. 오늘은 그 두 작업 사이에 남아 있던 틈, 그러니까 발행 버튼을 누르기 직전의 마지막 확인을 코드 안으로 가져왔다.
1. 왜 지금 이 체크가 필요했는가
최근 발행 흐름은 전보다 훨씬 또렷해졌다. 성공하면 URL을 바로 읽을 수 있고, 응답이 애매해도 RSS를 다시 보면서 post_id를 복구할 수 있게 됐다. 그런데 이 흐름만으로는 아직 부족했다. 성공한 뒤를 확인하는 장치는 생겼는데, 애초에 중복 발행을 하지 않도록 막는 장치는 상대적으로 얇았기 때문이다.
이런 문제는 평소에는 잘 안 보이다가, 세션이 흔들리거나 자동화가 재시도될 때 갑자기 드러난다. 로컬에 HTML 초안이 남아 있고, 공개 페이지에도 비슷한 제목이 이미 있고, 발행 쪽에서는 한 번 더 시도할 수 있는 상황이 겹치면 사람이 마지막에 손으로 확인해야 한다. 나는 요즘 이 프로젝트에서 그런 종류의 수동 판단을 조금씩 줄이는 쪽에 더 무게를 두고 있다.
- 발행 성공 후 확인만으로는 중복 생성 자체를 막지 못한다.
- 같은 제목 재발행은 블로그 메인 목록에서 바로 티가 난다.
- 한 번 중복이 생기면 삭제, 로그 정리, 인식 보정까지 후속 비용이 커진다.
결국 오늘의 목적은 단순했다. 발행이 끝난 뒤에 수습하지 말고, 누르기 전에 한 번 더 막자. 이 프로젝트에서 최근 커밋 흐름을 보면 꽤 자연스러운 다음 단계였다.
2. 구현은 작지만 효과는 꽤 직접적이다
오늘 추가한 건 거창한 새 기능은 아니다. 제목을 읽고, RSS 최신 항목에서 같은 제목이 있는지 먼저 확인하는 작은 헬퍼를 넣었다. 그리고 publish_one 쪽에서는 에디터를 열고 내용을 밀어 넣기 전에 이 함수를 먼저 거치도록 바꿨다. 이미 같은 제목이 공개되어 있으면 새 발행을 진행하지 않고, 기존 공개 URL과 RSS 시각을 바로 반환하는 쪽으로 정리했다.
이 구조가 마음에 드는 이유는 실패 모양이 덜 흐려지기 때문이다. 예전에는 사람이 RSS를 열어 보고 메인 페이지를 다시 열고, 그다음에야 "아 이건 이미 올라갔구나"를 알 수 있었다. 지금은 발행기 자체가 그 판단을 먼저 해준다. 자동화가 좋은 이유는 속도 때문만이 아니라, 판단 순서를 코드 안으로 옮길 수 있기 때문이라고 나는 자주 느낀다.
오늘 바뀐 흐름은 이렇다.
1) HTML에서 제목을 읽는다.
2) RSS 최신 항목에서 같은 제목을 찾는다.
3) 이미 공개된 제목이면 새 발행을 중단한다.
4) 아니면 기존 발행 흐름을 그대로 진행한다.
말로 적으면 아주 단순하지만, 실제 운영에서는 이런 한 단계가 전체 피로도를 꽤 많이 줄인다. 중복은 한 번 생기면 고치는 데 드는 시간이 길고, 무엇보다 블로그를 보는 입장에서 흐름이 깨진다. 그래서 나는 요즘 이런 작은 가드 코드를 기능 추가보다 더 중요하게 볼 때가 많다.
3. 오늘 작업에서 따로 확인한 것들
코드를 넣고 나서는 바로 두 가지를 확인했다. 하나는 문법이 깨지지 않는지, 다른 하나는 실제 RSS 제목과 비교가 제대로 되는지였다. 이미 공개된 최근 글 제목으로 대조했을 때는 매칭이 정상적으로 잡혔고, 없는 제목으로 돌렸을 때는 그대로 비어 있는 결과가 나왔다. 이런 종류의 검증은 눈으로 보기에는 소소하지만, 발행기 쪽에서는 꽤 중요하다. 조건 분기가 맞지 않으면 중복 차단이 아니라 엉뚱한 글까지 막아버릴 수 있기 때문이다.
그리고 오늘 커밋은 최근 로그 흐름에 맞춰 아주 직선적으로 남겼다. discover 쪽에서 후보 품질을 잡고, publish 쪽에서 결과 해상도를 높인 뒤, 이제는 발행 전에 한 번 더 중복을 걷어내는 순서다. 나는 이런 식으로 커밋들이 서로 문장을 이어 주는 느낌을 좋아한다. 한 줄씩 보면 작아 보여도, 이어서 보면 프로젝트가 어디로 가는지가 보이기 때문이다.
- RSS 제목 매칭 헬퍼 추가
- 새 발행 전에 같은 제목 공개 여부 선확인
- 중복이면 기존 URL과 RSS 시각을 바로 돌려주도록 정리
특히 오늘은 "발행 후 복구"보다 "발행 전 차단" 쪽으로 무게중심이 조금 이동했다는 점이 마음에 든다. 자동화는 자꾸 고장난 뒤 고치는 방향으로만 가면 결국 관리 도구가 된다. 반대로 문제가 생기기 전에 멈추게 만들면, 그제야 운영 도구에 가까워진다.
4. 지금 이 프로젝트에서 더 중요한 건 기능 수보다 안전한 순서다
요즘 이 프로젝트를 만지면서 계속 드는 생각은, 큰 기능 몇 개보다도 실수하기 어려운 순서를 만드는 게 더 중요하다는 점이다. 후보를 잘못 고르지 않게 하고, 발행 결과를 흐리지 않게 하고, 같은 제목을 한 번 더 올리지 않게 하는 것. 겉으로 보면 전부 작은 보강인데, 실제 블로그 운영에서는 이런 순서가 쌓일수록 사람 손이 덜 들어간다.
오늘 작업도 딱 그 연장선에 있었다. 눈에 띄는 UI가 생긴 건 아니고, 새로운 명령이 추가된 것도 아니다. 대신 발행 버튼을 누르기 전에 잠깐 멈춰 서서 "이 제목, 이미 올라간 건 아닌가"를 먼저 묻게 됐다. 나는 이런 질문이 코드 안에 들어가는 순간을 꽤 좋아한다. 사람의 체크리스트가 스크립트의 기본 동작이 되는 순간이기 때문이다.
아마 다음에도 비슷한 방향으로 더 다듬게 될 것 같다. 결과를 잘 보여주는 것에서 한 걸음 더 가서, 잘못된 결과가 애초에 덜 만들어지게 하는 쪽. 오늘은 그 흐름 안에서 RSS를 단순한 사후 확인 수단이 아니라, 발행 직전의 마지막 안전장치로 한 단계 더 끌어온 날이었다.
5. 최근 git log를 보고 글을 쓰는 방식도 조금 달라졌다
개발 일기를 쓸 때 최근에는 작업 하나만 떼어내서 적기보다, 먼저 git log가 어떤 흐름을 만들고 있는지부터 보게 된다. 오늘도 그 습관이 꽤 도움이 됐다. 바로 직전 커밋이 RSS fallback 검증이었기 때문에, 오늘의 중복 가드는 뜬금없는 새 아이디어가 아니라 그 연장선 위에 자연스럽게 놓였다. 로그를 먼저 보면 글도 덜 과장되고, 무엇을 했는지보다 왜 지금 그걸 했는지가 더 선명해진다.
나는 이런 점이 개발 일기에서는 꽤 중요하다고 생각한다. 같은 코드 수정이라도 맥락 없이 적으면 그날그날의 메모처럼 보이기 쉽다. 반대로 최근 몇 줄의 기록 속에서 위치를 잡아 주면, 작은 수정도 프로젝트의 방향 안에서 읽힌다. 오늘 작업은 기능을 크게 벌린 날은 아니었지만, 프로젝트가 점점 덜 헷갈리고 덜 중복되게 움직이도록 만드는 날이었다. 지금 이 자동화에서는 그런 종류의 하루가 의외로 오래 남는다.
결국 오늘 남긴 커밋은 코드를 조금 바꾼 기록이면서 동시에 운영 기준을 하나 더 고정한 기록이기도 하다. 발행이 성공했는지 확인하는 데서 끝나지 않고, 같은 제목이면 아예 다시 올리지 않는 쪽으로 기본 동작을 움직였다. 앞으로 이 프로젝트를 더 손보더라도, 나는 이런 식의 변화가 계속 쌓였으면 좋겠다. 기능이 많아지는 속도보다, 실수를 덜 만드는 속도가 더 빠른 자동화.
'[개발 일기]' 카테고리의 다른 글
| GraphRAG Scoring Profile Eval 루프 (0) | 2026.04.06 |
|---|---|
| GNN Baseline: Propagated Cosine (1) | 2026.04.05 |
| GNN Baseline: Supervised Scoring 추가 (0) | 2026.04.04 |
| GraphRAG Trace Diff와 랭킹 이동 (0) | 2026.04.04 |
| GraphRAG Query Coverage (0) | 2026.04.03 |