콘텐츠 허브 프로젝트를 만들면서 일주일간 삽질하고 깨달은 것들을 쉽게 정리했습니다.
한 줄 요약
"조용히 실패하는 것이 가장 무섭다" — 이번 주 핵심 교훈
1. 서버 2개가 동시에 돌아가면 생기는 일
상황: 다이제스트 이메일이 안 왔다. 왜?
알고 보니 서버를 재시작할 때 기존 프로세스를 안 죽이고 새로 띄웠다. 두 개의 서버가 동시에 스케줄러를 돌리면서 서로 충돌.
해결책: PID 파일로 "지금 서버 돌아가고 있니?" 체크하는 스크립트 만듦
# 이런 식으로 단일 인스턴스 보장
if [ -f server.pid ] && kill -0 $(cat server.pid); then
echo "이미 실행 중!"
exit 1
fi
교훈: 백그라운드 서비스는 "하나만 돌아야 한다"를 코드로 보장해야 함
2. 에러가 났는데 아무도 모른다?
상황: 다이제스트 전송이 실패했는데, 로그 파일에만 남아서 한참 뒤에 발견
해결책: 실패하면 바로 Slack으로 알림 쏘기
async def send_system_alert(title, message):
# 실패 즉시 Slack webhook으로 알림!
await webhook.send(f"🚨 {title}\n{message}")
교훈: 로그는 디버깅용, 알림은 장애 감지용. 역할이 다르다!
3. AI한테 "꼭 해줘"라고 말해도 안 듣는다
상황: "Quick Scan 섹션을 꼭 포함해주세요"라고 했는데 Claude가 자주 빼먹음
해결책:
- "작성하세요" → "절대 생략하지 마세요"
- System prompt에 넣으면 더 잘 지킴
교훈: LLM한테는 권장이 아니라 금지로 말해야 듣는다
4. 이메일에서 CSS가 안 먹힌다
상황: 멋진 번호 매기기를 CSS counter로 만들었는데 Gmail에서 안 보임
진실: 이메일 클라이언트는 2005년에서 멈춰있음
- flexbox? ❌
- CSS grid? ❌
- counter-increment? ❌
- JavaScript? ❌
해결책: 그냥 <table>로 짜면 됨 (슬프지만 현실)
5. 소셜 미디어 시간 파싱의 함정
상황: LinkedIn에서 "3w · edited" 같은 텍스트를 시간으로 파싱해야 함
함정들:
•,·,-,–,—전부 다른 문자임- "Jan 15"가 올해인지 작년인지 모름
- 같은 피드인데 HTML 구조가 포스트마다 다름
해결책: 3단계 fallback 체인
<time datetime>태그 있으면 파싱- 알려진 셀렉터로 시도
- 전체 텍스트 스캔
교훈: "한 패턴으로 다 커버"는 환상. 최소 3단계 fallback 필요
6. AI가 "언급했다"를 어떻게 판단할까?
상황: AI 요약에서 실제로 링크한 콘텐츠만 "기타 콘텐츠"에서 빼고 싶음
잘못된 방법: 제목에 "OpenAI"가 포함되면 언급한 걸로 간주
→ "OpenAI"가 들어간 글 10개가 다 제외됨
올바른 방법: 마크다운 링크의 URL만 추출해서 매칭
urls = re.findall(r"\(https?://[^\)]+\)", ai_output)
교훈: 제목은 겹치고, URL은 고유하다
7. XSS 공격은 생각보다 쉽게 터진다
상황: 기술 블로그 제목에 <script> 같은 게 들어있으면 이메일이 깨짐
해결책: html.escape()를 markdown 변환 전에 적용
# 순서가 중요!
text = html.escape(text) # 먼저 이스케이프
text = text.replace("**", "<strong>") # 그다음 마크다운 처리
교훈: 보안 수정은 테스트 필수. 안 그러면 리팩토링할 때 실수로 지움
이번 주 숫자
| 항목 | 수치 |
|---|---|
| 새로운 교훈 | 19개 (#14~#32) |
| 추가된 테스트 | 11개 (103 → 118) |
| 고친 버그 | 8개 |
| 새 파일 | 3개 (start_server.sh, admin API, system alert) |
핵심 패턴 3가지
1. Fallback 체인
시도 A 실패 → 시도 B 실패 → 시도 C
한 가지 방법에 의존하지 말고 백업 경로를 만들어둔다.
2. 조용한 실패 방지
에러 → 로그 + 알림 + 재시도
에러가 나면 누군가는 알아야 한다.
3. 균일 정책
"HN만 5건 제한" → "모든 플랫폼 5건 제한"
특정 케이스만 고치면 다른 데서 터진다.
다음 주에는 이메일 실패 시 Slack fallback과 health check API 추가 예정!