TL;DR — 혼자 AI 에이전트들이랑 작은 사진 서비스를 굴립니다. 얼마 전 코드를 고쳐서 배포를 했는데, 시스템이 "배포 성공"이라고 깔끔하게 알려줬어요. 서버 상태를 확인하는 신호도 초록불(200 OK)이었고요. 그래서 저는 다 됐구나 하고 넘어갔습니다. 그런데 한참 뒤에 우연히 홈페이지를 열어보니 이미지가 전부 깨져 있었어요. 서버는 분명 멀쩡히 살아 있었는데, 정작 손님이 볼 화면은 망가져 있던 거죠. 그날 배운 게 있어요. "서버가 떠 있다"와 "서비스가 제대로 작동한다"는 완전히 다른 문장이라는 것. 이 글은 그 조용한 실패에 대한 기록입니다.
저는 사진 일을 20년 했고, 지금은 AI 에이전트 여러 대를 데리고 혼자 회사를 굴립니다. 사진관 시절과 가장 다른 점을 하나 꼽으라면, 이제는 제 일의 결과가 자동화된 신호들을 통해 저한테 보고된다는 거예요. "배포 완료", "상태 정상", 초록불, 체크 표시. 하루에도 이런 신호를 수십 개씩 받습니다.
그런데 얼마 전, 그 초록불 하나에 제대로 데였어요.
"성공"이라고 적혀 있었습니다
사건은 단순했어요. 서비스 코드를 좀 손봐서 새 버전을 올렸습니다. 배포 과정에서 에러는 한 줄도 없었어요. 마지막에 시스템이 "성공"이라고 또렷이 찍어줬고요. 습관처럼 서버 상태도 확인했는데, 거기도 초록불이었습니다. 흔히 헬스체크(health check)라고 부르는, "너 살아 있니?"를 묻는 자동 점검이요. 서버는 "응, 살아 있어(200 OK)"라고 대답했어요.
저는 그걸로 끝냈습니다. 다 됐다고 생각했어요.
한참 뒤에, 정말 우연히 홈페이지를 직접 열어봤습니다. 그런데 화면이 이상했어요. 사진을 다루는 서비스인데, 메인 화면의 이미지 카드가 전부 깨진 아이콘으로 떠 있었습니다. 손님이 가장 먼저 보는 얼굴이, 깨진 그림 조각들로 도배돼 있었던 거예요. 그것도 제가 발견하기 전까지 한동안요.
처음엔 등골이 서늘했어요. 분명히 "성공"이라고 했는데. 분명히 서버는 초록불이었는데. 도대체 뭐가 잘못된 거지?
알고 보니, 좋은 의도 한 줄이 범인이었어요
원인을 파보니 어이가 없었습니다. 범인은 악성 버그가 아니라, 예전에 제가 좋은 마음으로 넣어둔 설정 한 줄이었어요.
원래 그 설정의 의도는 착했어요. "용량 큰 이미지 파일들은 코드 저장소에 같이 올리지 말자"는 거였죠. 저장소를 가볍게 유지하려는, 교과서적으로 옳은 습관이에요. 그런데 이 한 줄이, 정작 화면에 꼭 필요한 이미지들까지 싸잡아서 배포 꾸러미에서 빼버린 거였습니다. 새 버전을 만들 때 이미지들이 통째로 빠진 채로 포장됐고, 서버는 그 빈 꾸러미를 들고 멀쩡히 일어선 거예요.
여기서 진짜 무서운 지점은 이겁니다. 그 어떤 단계도 에러를 내지 않았어요.
- 포장(빌드) 단계: 이미지가 빠졌다는 걸 문제 삼지 않았어요. 그냥 있는 것만 담고 "완료".
- 배포 단계: 꾸러미를 서버에 올리는 데 성공했으니 "성공".
- 헬스체크: 서버 프로그램 자체는 잘 떠서 응답하니까 "정상(200 OK)".
모든 신호가 초록불이었어요. 그 누구도 거짓말을 하지 않았습니다. 다만 아무도 "그래서 손님 화면이 멀쩡하냐"는 질문을 하지 않았을 뿐이에요.
'살아 있다'와 '제대로 작동한다' 사이의 거대한 틈
그날 제가 배운 건, 초록불에도 층위가 있다는 거였어요. 저는 그동안 이걸 뭉뚱그려서 "잘 됐다"로 퉁쳐 읽고 있었던 거고요.
- 배포가 성공했다 = 새 꾸러미를 서버에 올리는 데 성공했다. (꾸러미 안이 멀쩡한지는 안 봄)
- 서버가 살아 있다 = 프로그램이 떠서 응답을 한다. (그 응답으로 그려지는 화면이 멀쩡한지는 안 봄)
- 페이지가 멀쩡하다 = 손님이 보는 화면이 깨지지 않았다. (여기는 아무도 자동으로 확인 안 하고 있었음)
- 손님이 살 수 있다 = 화면을 넘어 결제까지 막힘이 없다. (당연히 더 안 봄)
저는 첫 두 칸이 초록불인 걸 보고, 나머지 칸까지 다 초록불일 거라고 믿어버린 거예요. 그런데 이 칸들 사이에는 생각보다 깊은 틈이 있었습니다. 자동화는 정직해요. 내가 "이걸 확인해"라고 시킨 것만 확인합니다. 안 시킨 건 통과시키죠. 그것도 아주 조용히, 초록불을 켜면서요.
사진관을 할 때는 이런 틈이 없었어요. 인화를 마치면 제 손에 사진이 쥐어졌고, 저는 그걸 눈으로 보고 손님에게 건넸으니까요. 결과물과 저 사이에 아무것도 없었습니다. 그런데 자동화된 시스템에서는, 결과물과 저 사이에 "성공"이라는 글자가 끼어들어요. 그리고 저는 어느새 실제 결과물 대신 그 글자를 보고 안심하는 사람이 돼 있었던 거예요.
그래서 바꾼 것: '살아 있나'에 더해 '보이나'를 묻기로
한참 자책하다가 방향을 정했어요. 헬스체크를 없애자는 게 아니라, 헬스체크가 묻지 않는 질문을 누군가는 묻게 하자는 쪽으로요.
1. "떠 있나" 다음에 "보이나"를 자동으로 묻는다
서버가 살아 있는지만 확인하던 자리에, 한 겹을 더 얹었어요. 배포가 끝나면 실제로 손님이 보는 핵심 화면 몇 개를 자동으로 한 번 열어보고, 이미지까지 제대로 불러와지는지를 확인하게요. "서버가 응답하나"가 아니라 "화면이 그려지나"를 묻는 거죠. 흔히 스모크 테스트라고 부르는 건데, 이름은 중요하지 않아요. 핵심은 점검의 질문을 손님의 눈높이까지 끌어내린 것이에요.
2. 손님에게 나가기 전에, 미리보기 한 판을 거친다
새 버전을 바로 손님 앞에 세우지 않고, 그 전에 똑같은 환경에서 한 번 펼쳐보는 단계를 두기로 했어요. 무대에 올리기 전 리허설인 셈이죠. 깨질 거면 손님이 아니라 리허설에서 깨지게요.
3. 마지막 한 번은 사람 눈으로 본다
그리고 제일 사진관다운 결정. 아무리 자동 점검을 겹겹이 둬도, 마지막엔 제가 직접 화면을 한 번 봅니다. 자동화가 "성공"이라고 말해도, 손님이 처음 보는 그 화면을 제 눈으로 1초라도 보는 습관을 들였어요. 20년 동안 인화된 사진을 눈으로 검수하던 그 행동을, 화면 검수로 옮겨온 거죠.
이 세 개를 관통하는 건 하나예요. "성공"이라는 글자를 결과물 그 자체로 착각하지 말 것.
솔직한 고백 — 이 안전망도 완벽하진 않아요
여기까지 써놓고 보니 제가 무슨 해법을 다 찾은 사람처럼 보일까 봐 또 민망해집니다. 그래서 정직하게 적어둘게요.
제가 새로 둔 점검들은, 결국 "이번에 내가 겪은 실패"를 잡는 그물이에요. 이미지가 깨지는 종류의 사고는 이제 걸러지겠죠. 그런데 다음번엔 분명 제가 상상도 못 한 다른 데서 조용히 깨질 거예요. 글자 색이 배경이랑 똑같아진다든지, 특정 손님한테만 결제 버튼이 안 보인다든지. 그때도 모든 초록불은 멀쩡히 켜져 있을 거고요.
그러니까 저는 "조용한 실패를 영원히 없앴다"고 말할 수 없어요. 다만 그날 이후로 한 가지 습관이 남았습니다. 초록불을 보면, 그게 정확히 무엇까지를 보장하는 신호인지 한 번 더 따져보는 것. "성공"이라는 글자 앞에서 자동으로 안심하는 대신, "이 성공은 어디까지의 성공이지?"라고 묻는 것. 어쩌면 1인 회사에서 자동화를 늘려갈수록, 진짜로 길러야 할 건 더 많은 자동 점검이 아니라 이 의심하는 습관 하나일지도 모르겠어요.
생각해보면 사진관 시절에도 비슷한 게 있었어요. 인화기가 "출력 완료" 램프를 켜도, 저는 늘 사진을 빛에 비춰 한 번 봤거든요. 램프는 기계가 자기 할 일을 끝냈다는 뜻이지, 사진이 잘 나왔다는 뜻이 아니었으니까요. 그 둘을 헷갈리지 않는 게 사진사의 기본이었어요. AI로 도구만 바뀌었을 뿐, 본질은 똑같더라고요. 기계의 '완료'와 결과물의 '괜찮음'은 다른 말이다.
그래서 묻고 싶어요
자동화된 시스템 위에서 무언가를 굴리고 계신 분들께 묻고 싶습니다.
- 여러분이 매일 보는 그 "성공" 신호는, 정확히 어디까지를 보장하나요? 서버가 떠 있다는 것까지인가요, 손님이 실제로 쓸 수 있다는 것까지인가요?
- 그 신호와 손님의 실제 경험 사이에, 아무도 자동으로 확인하지 않는 빈칸이 있진 않나요?
- 마지막으로 여러분이 직접, 손님의 눈높이에서 결과물을 본 게 언제인가요?
저는 "기계의 완료를 결과의 괜찮음으로 착각하지 말자"는 한 줄로 정리하고 있어요. 초록불은 고맙지만, 초록불은 어디까지나 "내가 물어본 것"에만 켜지니까요. 물어보지 않은 곳은, 오늘도 조용히 통과되고 있을지 모릅니다.
비슷하게 조용한 실패에 당해보신 분 있으면, 어떻게 그물을 치고 계신지 정말 궁금합니다. 저도 아직 그물코를 넓혀가는 중이라서요.