Your Hiring Process Needs HTTP Status Codes
Because "we'll be in touch" is not an observable state. I submitted a job application recently. It...
개요 #
개발자 Ken W Alger가 채용 프로세스의 침묵을 HTTP 상태 코드에 빗댄 글을 Dev.to에 올렸다. 그는 직무 설명을 꼼꼼히 읽고, 이력서를 맞춰 고치고, 그 회사만을 위한 커버레터를 쓰고, "선택 사항"이라고 표시된 질문까지 답한 지원서를 제출했다. 그리고 아무것도 받지 못했다.
확인 메일도, "지원서를 접수했습니다"라는 안내도, 지원자 기록이 생성됐다는 신호도 없었다. 브라우저 화면에 뜬 제출 성공 메시지 하나, 그리고 어딘가 ATS(지원자 추적 시스템) 깊은 곳에서 자신의 지원서가 /dev/null로 직행하지는 않았으리라는 막연한 기대만 남았다.
그는 면접을 요구하는 게 아니라고 선을 긋는다. 채용 담당자가 지원자마다 피드백을 줘야 한다고 생각하지도 않는다. 원하는 건 상태 코드 하나다.
웹은 수십 년 전에 이 문제를 풀었다 #
한 시스템이 다른 시스템에 요청을 보내면, 받는 쪽은 무슨 일이 일어났는지 알려준다. 처리됐는지, 아직 진행 중인지, 요청이 잘못됐는지, 리소스가 사라졌는지, 서버에서 뭔가 터졌는지. HTTP에는 이걸 표현하는 어휘 체계가 통째로 있다.
반면 채용 시스템의 프로토콜은 이렇게 생겼다.
POST /careers/applications
[관측 가능한 응답 없음]그리고 3분 뒤일 수도, 6개월 뒤일 수도 있는 어느 시점에 이런 문장이 도착한다.
신중한 검토 끝에...Alger의 제안은 간단하다. "검토 중(Under Consideration)" 같은 모호한 지원자 상태를 새로 만들 게 아니라, 개발자들이 이미 아는 어휘를 쓰자는 것이다.
2xx — 성공, 이라고 주장되는 것들 #
200 OK — 사람이 당신의 지원서를 읽었다. 그 이상은 아무것도 함의하지 않는다. Alger는 이것만으로도 혁명적일 거라고 덧붙인다.
202 Accepted — 지원서를 접수했고 처리 대상으로 받아들였다. 그는 이게 채용 프로토콜 전체에서 가장 중요한 상태 코드라고 못 박는다. 지원자는 채용 담당자의 메모나 내부 워크플로 설명이 필요한 게 아니다. 필요한 건 이 한 줄이다.
202 APPLICATION_ACCEPTED이제 적어도 그 지원서가 존재한다는 사실은 안다.
204 No Content — 지원서는 정상 접수됐다. 다만 우리는 그 사실을 어떤 식으로도 알리지 않기로 했다.
3xx — 당신은 리다이렉트되었다 #
302 Found — 내부 지원자를 찾았다. 참여해줘서 고맙다.
304 Not Modified — 지원서가 47일째 "검토 중"이다. 지난번 확인했을 때와 달라진 게 없고, 그 전 23번도 마찬가지였으며, 다음번에도 그럴 것이다. 응답을 로컬에 캐싱하기를 권한다.
410 Gone — 지원할 당시엔 존재하던 포지션이 이제 없다. 추가 정보는 제공되지 않는다. Alger는 410이라도 있으면 쓸모가 있을 거라고 말한다. 지금의 발견 방식은 북마크해둔 채용 공고가 어느 날부터 채용 홈으로 리다이렉트되는 걸 눈치채는 것이기 때문이다.
4xx — 이건 당신 쪽 문제다 #
401 Unauthorized — 지원하려면 계정부터 만들어야 한다. 비밀번호는 14자 이상, 대소문자, 숫자, 특수문자, 그리고 고대 수메르 문자 하나를 포함해야 한다. 1997년 이후 써본 비밀번호와 겹쳐서도 안 된다. 그런 다음 방금 업로드한 이력서의 모든 항목을 손으로 다시 입력하게 된다. 이 계정은 두 번 다시 쓰지 않는다.
403 Forbidden — 경력도 자격 요건도 충족한다. 다만 이 Zoom 미팅이 성립할 수 있다고 우리가 정해둔 지리적 경계에서 37마일 밖에 산다.
404 Not Found — 채용 담당자를 찾을 수 없다. 리크루터도 없다. 공고도 없다. 이 요건을 누가 소유하는지 아무도 모른다.
408 Request Timeout — 7주간 연락이 없어 지원자가 다른 회사로 갔다. 채용팀은 내일 2차 면접 일정을 잡으려고 연락할 예정이다.
409 Conflict — 6년 전에 나온 기술을 12년간 프로덕션에서 다룬 경험을 요구한다. 이 충돌은 해소할 수 없다.
417 Expectation Failed — "연락드리겠습니다"라는 말에 앞으로 연락이 온다는 뜻이 담겨 있다고 기대했다. 아니었다.
422 Unprocessable Content — 경력은 관련이 있지만, 커리어 경로가 ATS에 미리 정의된 상자 안에 깔끔하게 들어가지 않는다. 사람의 개입이 필요할 수 있다. 사람은 없다.
425 Too Early — 공고가 올라온 지 14분 만에 지원했다. LinkedIn은 지원자가 612명이라고 표시한다. 우리도 궁금한 게 많다.
451 Unavailable For Legal Reasons — 문제는 당신의 자격이 아니다. 배경 조사 업체, 집행력이 불분명한 경업금지 조항, 아니면 아무도 먼저 꺼내고 싶어 하지 않는 비자 스폰서십 문제다.
5xx — 애초에 당신 탓이 아니었다 #
500 Internal Server Error — 내부에서 뭔가 잘못됐다. 리크루터가 퇴사했거나, 헤드카운트가 동결됐거나, 채용 담당자가 바뀌었거나, 재무팀이 예산을 재검토했거나, 조직이 개편됐거나, 공고가 실수로 올라갔다. 이 모든 경우를 우리는 같은 문장으로 전달한다.
다른 지원자와 함께 진행하기로 결정했습니다.
502 Bad Gateway — 리크루터는 채용 담당자를 기다리는 중이라고 한다. 채용 담당자는 다음 단계가 리크루팅 소관이라고 한다. 요청을 라우팅할 수 없다.
503 Service Unavailable — 담당 리크루터가 퇴사했다. 캘린더 링크는 아직 살아 있다.
504 Gateway Timeout — "금요일까지는 결정이 날 것 같습니다." 금요일은 지났다. 어느 금요일인지는 명세에 정의되어 있지 않다.
지원자는 분산 트레이싱을 원하지 않는다 #
농담처럼 늘어놓았지만 그 아래 진지한 논점이 하나 있다. Alger는 채용에 관측 가능성(observability) 문제가 있고, 사람들이 이걸 소통 문제로 착각한다고 말한다.
기업이 채용 과정의 모든 걸 공개할 수 없다는 건 그도 인정한다. 지원자 평가는 비공개고, 면접 피드백은 민감할 수 있으며, 채용 담당자에게는 후보들을 비교하고 판단할 여지가 필요하다. 아무도 이런 걸 요구하지 않는다.
GET /hiring-manager/private-thoughts/about-me문제는 기밀 논의를 공개하는 것과 아무 정보도 주지 않는 것 사이에 엄청나게 넓은 영역이 있다는 점이다.
채용 파이프라인에는 이미 상태가 있다. 지원서가 접수됐다. 검토 단계로 넘어갔다. 누군가 검토했다. 면접을 요청했다. 요건이 보류됐다. 포지션이 채워졌다. 취소됐다. 지원자가 탈락했다.
이 상태 전이는 이미 시스템 안에 존재한다. 기록되고, 타임스탬프가 찍히고, 리포트로 뽑힌다. 채용팀이 자기 퍼널을 측정하는 방식이 원래 그렇다. 그런데 정작 그 기록을 못 보는 유일한 사람이 지원자다.
Alger가 글 초반에 깔아둔 복선도 여기서 풀린다. 상태는 이미 존재한다. 그중 어느 것인지 보여주지 않기로 한 건 프라이버시 제약이 아니라 제품 결정이라는 얘기다.
재미없는 버전이면 충분하다 #
그가 그리는 지원자 포털은 딱 이 정도만 보여준다.
202 APPLICATION_RECEIVED Mar 04
200 REVIEWED Mar 19
304 NO_CHANGE Apr 02
304 NO_CHANGE Apr 30
410 POSITION_CLOSED May 12급진적인 투명성이 아니다. 투명성이라고 부르기도 민망한 수준이다. 하지만 시스템이 돌아가고 있다는 사실은 알려준다.
지원서가 사라진 건 아닌지 궁금해할 필요가 없어지고, 의미 없는 포털 새로고침이 줄어든다. 무엇보다 지원자가 침묵을 정보로 읽는 일을 막는다. 침묵은 "채용 담당자가 휴가 중"부터 "2주 전에 요건이 취소됨"까지 무엇이든 뜻할 수 있으니까.
결국 이건 지원자를 문서화되지 않은 엔드포인트로 쏘아 보낸 패킷이 아니라 프로세스의 참여자로 대하는 문제다.
200 OK #
Alger는 모든 지원이 면접으로 이어지리라 기대하지 않는다. 그렇지 않다는 경험적 증거를 충분히 쌓았다고 농담을 덧붙인다. 상세한 탈락 사유를 바라지도 않고, 기업이 그걸 꺼리는 이유도 이해한다. 403 REQUIREMENTS_NOT_MET이나 410 POSITION_FILLED 정도는 오히려 괜찮다고 말한다. 그것도 답이니까.
요즘 채용을 유독 답답하게 만드는 건 탈락이 아니다. 아예 아무 일도 일어나지 않고 있는 건 아닌지 알 수 없다는 불확실성이다.
소프트웨어 엔지니어들은 수십 년 동안 단순한 원칙 위에 시스템을 지어왔다. 한 시스템이 다른 시스템에 무언가를 요청하면, 응답에는 무슨 일이 일어났는지 이해할 만큼의 정보가 담겨 있어야 한다는 것.
지원자는 채용 인프라의 분산 트레이싱을 요구하는 게 아니다. 상태 코드 하나면 충분하다.
이 글은 위 출처를 바탕으로 한국 독자를 위해 재작성한 기사입니다. 원문의 사실과 수치에 근거하며, 별도의 견해를 포함하지 않습니다.


Photo by