← 01 THINK어떻게 생각하는가

화면은 아무 문제 없다고 말했다

검색 조건 하나가 반년 가까이 고장 나 있었습니다. 에러도 빈 화면도 없었습니다. 화면만 봐서는 알 수 없는 고장이 있습니다.

이 쪽은 원문을 쉬운 말로 다시 쓴 판입니다. 저자가 쓴 문장은 원문 쪽에 있습니다.

회사 이름, 서버 주소, 회원 정보는 뺐습니다. 매물번호는 시험용 가짜 숫자입니다.

회사 안에서 직원들이 쓰는 관리 화면을 고치는 일입니다.

오늘 고친 고장 일곱 개가 한 가지를 똑같이 갖고 있었습니다. 화면에는 아무 문제가 없었습니다. 빨간 글씨도, 빈 화면도, 뱅글뱅글 도는 표시도 없었습니다. 그냥 조용히 틀린 답을 보여 줬습니다.

첫 번째 — 검색 조건 이름을 잘못 적어 뒀다

프로그램이 서버에게 "이런 조건으로 찾아 줘"라고 물을 때, 조건의 이름을 정확히 맞춰야 합니다.

서버가 아는 이름은 is_live 였습니다. 프로그램이 보내던 이름은 isLIVE 였습니다. 비슷하지만 다른 이름입니다.

기록을 뒤져 보니 처음 만든 날부터 그랬습니다. 163일 동안이요.

왜 아무도 몰랐나

여기가 핵심입니다.

이 서버는 모르는 조건을 받으면 "그런 거 없다"고 거절하지 않고 그냥 무시합니다. 무시하면 조건 없이 전부 찾아 줍니다.

그런데 화면에서는 이 두 가지가 똑같이 보입니다.

  • 조건이 안 걸려서 전부 나온 것
  • 조건에 맞는 게 정말 전부인 것
화면 — 둘이 똑같다40건 나옴조건 무시됨40건 나옴정말 전부임구별할 방법이 없다보내는 요청 — 다르다이름 틀림 → 서버가 버린다이름 맞음 → 서버가 읽는다여기서만 알 수 있다조건을 눌렀는데 목록이 그대로면, 원래 다 그런가 보다 하고 넘어갑니다.그 짐작이 163일 동안 매번 맞아 보였습니다 — 화면만 봤으니까요.

그래서 검사를 화면이 아니라 보내는 요청에 걸었습니다. 서버로 나가는 요청을 중간에서 가로채 이름이 맞는지 직접 읽습니다. 화면은 보지 않습니다.

검사는 두 가지를 봅니다.

  1. 새 이름이 나가는지
  2. 옛 이름이 남아 있지 않은지

두 번째가 더 중요합니다. 첫 번째만 보면, 옛 이름을 지우지 않고 새 이름만 더해도 검사를 통과합니다. 서버가 모르는 이름은 무시하니 그 상태로도 잘 돌고, 다음 사람은 두 이름을 다 써야 하는 줄로 배우게 됩니다.

두 번째 — 검사는 실패를 본 뒤에야 검사다

오늘 고친 것마다 고친 걸 일부러 되돌려서 검사가 실패하는지 먼저 봤습니다. 일곱 번.

이 습관이 오늘 두 번 값을 했습니다.

한 번은 다른 고장을 잡았습니다. 되돌려서 돌려 보니, 처음에 이상하다고 느꼈지만 연결하지 못했던 값이 그대로 나왔습니다.

한 번은 제 검사 자체의 잘못을 잡았습니다. 되돌렸는데 예상과 다른 지점에서 실패했습니다. 보니 제가 "요청이 1건보다 많아지면 통과"라고 적어 뒀는데, 화면을 처음 열 때 이미 2건이 나가고 있었습니다. 그래서 검사가 누르기 직전에 이미 통과해 버리고 낡은 요청을 읽고 있었습니다.

통과하는 검사는 아무것도 증명하지 않습니다. 실패하는 걸 본 검사만 증명합니다. 그리고 그걸 확인하는 과정이 검사 자신의 잘못도 드러냅니다.

세 번째 — 3개월 전에 지운 걸 되살렸다

"링크로 들어오면 조건 칸이 비어 있다"는 지적을 받고, 조건 칸을 하나 더 만들었습니다. 검사 통과, 저장.

그 뒤에 기록을 보다가 이걸 발견했습니다.

2026-06-01  이 검색에서 그 입력 칸 제거

3개월 전에 일부러 지운 칸을 제가 되살린 것이었습니다. 이유도 단순했습니다 — 같은 값을 두 칸에서 받고 있었고, 그 작업이 중복을 정리한 것이었습니다.

제가 못 알아챈 데는 이유가 있었습니다. 그 칸이 보이는지 확인하는 검사가 아직 남아 있었습니다. 칸을 지울 때 검사를 같이 안 지웠습니다. 그래서 코드는 "없다"고 하고 검사는 "있어야 한다"고 하는 상태였고, 마침 그 검사 묶음이 안 돌던 기간이라 아무도 못 봤습니다.

결국 칸을 안 만드는 쪽으로 풀었습니다. 링크로 들어온 값을 원래 있던 칸에 넣으면 거기 그대로 보이고 지울 수도 있습니다. 칸을 늘리지 않고 문제가 사라졌습니다.

무언가 더하기 전에 그게 지워진 적 있는지 봅니다. 30초면 됩니다.

그리고 기능보다 오래 살아남은 검사는 틀린 편을 듭니다. 기능을 지울 때 그 검사도 같이 지워야 합니다.

네 번째 — "전체"를 특별한 날짜로 표현했다

등록일 조건에 "전체"를 고르면, 프로그램이 아주 옛날 날짜 하나를 보냈습니다. 아무 항목보다 과거인 날짜를요. 그러면 결과적으로 전부 나옵니다.

문제는 그 날짜가 특별한 값이라는 걸 아는 코드에서만 안전하다는 것입니다. 모르는 코드가 그걸 보면 진짜 날짜로 믿습니다.

같은 프로그램에 반대 방향도 있습니다. "기간 제한 없음"을 9999-12-31 로 저장합니다. 그리고 그쪽에서 이미 한 번 터진 흔적이 코드에 남아 있습니다 — 어떤 화면이 그 날짜를 진짜 종료일로 믿어서 표가 깨졌던 기록입니다.

"전체"는 특별한 값이 아니라 조건을 아예 안 보내는 것이어야 합니다.

이게 링크 고장의 나머지 절반이기도 했습니다. 링크로 들어오면 등록일 조건이 "1개월 이내"로 남아 있어서, 오래된 항목이 걸러져 0건이 됐습니다. 그런데 링크로 찾는 대상이 원래 오래된 항목이라, 거의 항상 터지는 조합이었습니다.

다섯 번째 — 화면에 보이는 글자가 그대로 서버로 간다

상태를 바꾸는 요청이 숫자 코드가 아니라 한글 글자를 받습니다. "검증실패" 같은 것을요. 정해진 네 개 말고 다른 걸 보내면 거절합니다.

그런데 그 글자 목록이 두 곳에 따로 적혀 있었습니다. 값이 같아서 지금까지는 문제가 없었습니다.

보통 화면 글자 목록이 갈라지면 글자만 달라집니다. 그런데 이 글자는 서버로 나가는 값입니다. 한쪽만 고치면 거절당합니다. 하나로 합쳤습니다.

여섯 번째 — 눌릴 것처럼 생겼는데 아무 일도 안 하던 버튼

상태 바꾸는 버튼이 이미 만들어져 있었습니다. 누르면 무슨 일이 일어날지도 받을 수 있게 되어 있었는데, 아무도 그걸 넘겨 주지 않아서 보여 주기만 하고 있었습니다.

그런데 손가락 모양 커서도 나오고 올리면 색도 바뀝니다. 눌러도 아무 일이 없습니다.

연결하면서 서버가 실제로 받는 값만 눌리게 하고 나머지는 흐리게 내렸습니다. 서버가 받는 값이 화면에 보이는 값보다 좁습니다 — 여덟 개 중 세 개만, 아홉 개 중 네 개만 바꿀 수 있습니다. 지금 값도 못 누르게 했습니다. 같은 값을 다시 보내면 서버만 왕복하고 바뀌는 게 없으니까요.

남기는 것

일곱 개 전부 에러 없이 조용히 틀렸습니다. 코드도 통과하고 콘솔도 깨끗했습니다. 화면은 정상이라고 말했고, 매번 그 말이 맞아 보였습니다.

그래서 남기는 규칙은 전부 "무엇을 증거로 삼을 것인가" 에 관한 것입니다.

  • 검색 조건은 화면이 아니라 보내는 요청으로 확인합니다. 모르는 조건을 조용히 무시하는 서버에서는 화면이 증거가 못 됩니다.
  • 고친 걸 되돌려 검사가 실패하는 걸 봅니다. 안 보면 그 검사가 무엇을 지키는지 모릅니다.
  • 더하기 전에 지워진 적 있는지 봅니다.
  • 기능을 지울 때 그 검사도 지웁니다.
  • "전체"는 조건을 안 보내는 것으로 표현합니다.
  • 화면 글자가 서버로 가는 값이면 한 곳에만 적습니다.

아직 증거가 없는 것

오늘 만든 검사는 가짜 서버로 돌립니다. 프로그램 쪽 길이 맞는지만 증명합니다. 실제 서버에 물어봐야 하는 게 네 가지 남았습니다 — 지금은 잘 돌지만 왜 잘 도는지 문서로 확인하지 못한 것들입니다.

그것도 화면이 정상이라고 말하는 상태의 한 종류입니다.