도로 CCTV를 보여주는 앱을 안드로이드로 포팅하면서, iOS 쪽이 쓰던 공공 교통정보 API 스펙을 처음부터 다시 읽었습니다.
그러다 알았습니다. iOS 라이브 버전은 고속도로 CCTV를 한 대도 보여준 적이 없었습니다. 스토어 문구에는 "고속도로"라는 키워드까지 넣어뒀는데도요.
당신이 쓰는 API의 파라미터 중, 이름만 보고 의미를 짐작한 것이 몇 개입니까?
필터처럼 보이는 이름이었습니다
이 API의 type 파라미터는 결과를 좁히는 필터처럼 보입니다. 실제로는 어느 데이터셋을 읽을지 고르는 값입니다.
type=its→ 국도 카메라만 있는 데이터셋type=ex→ 고속도로 카메라만 있는 완전히 다른 데이터셋
같은 지리적 범위로 두 값을 각각 호출해봤습니다.
type=its → 42건 (국도)
type=ex → 296건 (고속도로)7배입니다. 앱은 처음부터 its만 부르고 있었습니다.
신고로는 절대 안 걸리는 결함입니다
"경로 위 카메라를 보여준다"고 파는 앱에서, 팔고 있던 것의 대부분이 안 보이는 채로 라이브에 나가 있었습니다.
그런데 화면은 정상으로 보입니다. 국도 카메라는 몇 개씩 뜨니까요. "카메라가 아예 안 뜬다"는 신고는 들어올 수가 없습니다. 사용자는 이 도로에 카메라가 원래 없다고 생각합니다.
빈 화면은 신고되지만, 덜 찬 화면은 신고되지 않습니다.
여기서 선택이 갈립니다
두 데이터셋을 합쳐서 보여주기로 했습니다. 그런데 화면에 "고속도로/국도"를 구분해 표시하려면 각 카메라의 도로 종류를 알아야 합니다.
카메라 이름에 "고속도로"가 들어 있으면 고속도로로 분류하면 될 것 같습니다.
당신이라면 이름으로 재판정하겠습니까, 출처를 기억하겠습니까?
이름 판정은 틀립니다. 실제 고속도로 카메라 중에는 순환선·분기점 같은 표기만 있고 "고속도로"라는 단어가 없는 것들이 있습니다. 이름으로 판정하면 그런 카메라가 국도로 잘못 분류됩니다.
판정 기준은 이름이 아니라 어느 데이터셋에서 왔는지여야 합니다. 이름은 표시용이고, 분류는 출처가 정합니다.
합칠 때의 함정 둘
- 중복 제거가 필요합니다. 좌표와 이름이 같은 카메라가 두 데이터셋에 동시에 존재할 수 있습니다.
- 한쪽이 실패해도 다른 쪽은 살려야 합니다. 둘 다 실패했을 때만 오류를 던집니다. 한쪽 실패를 "카메라 0대"로 접으면 설명 없는 빈 지도만 남습니다.
그리고 별개의 함정 하나가 더 있었습니다. 관대한 JSON 파서 옵션을 켜두면, API가 키 이름 오류일 때 돌려주는 XML 에러 본문을 따옴표 없는 문자열로 해석해서 파싱 성공으로 처리합니다. 결과는 빈 목록이고, 화면에는 "이 경로에는 카메라가 없습니다"가 뜹니다.
진짜 에러가 정상적인 빈 상태로 둔갑합니다. 엄격한 파싱으로 바꿔서 이 경우가 실제 에러로 잡히게 했습니다.
자가진단
- API 파라미터 하나를 골라, 값을 바꿔서 같은 조건으로 두 번 호출해봤습니까? 건수가 7배 차이 나면 그건 필터가 아닙니다.
- 화면이 "비어 보이지 않는다"는 것과 "다 나왔다"는 것을 구분합니까?
- 파서가 에러 응답을 성공으로 삼키고 있지 않습니까? 관대한 파싱은 이걸 조용히 합니다.
솔직한 부분
이 결함이 언제부터 있었는지는 명확합니다 — 처음부터입니다. 앱은 한 번도 고속도로 카메라를 부른 적이 없습니다. 그동안 아무도 신고하지 않았고, 저도 스펙을 다시 읽기 전까지 몰랐습니다.
포팅이 아니었으면 계속 몰랐을 겁니다. 다시 읽은 이유가 버그가 아니라 다른 플랫폼 작업이었다는 게 이 이야기에서 제일 불편한 부분입니다.
당신 앱이 부르는 API에서, 필터처럼 생긴 파라미터 하나를 골라 다른 값으로 한 번만 호출해보세요.