Why NextWhy Next
목록으로
💻 개발4분 읽기

지우면 끝날 문제를, 나는 오래 붙들고 있었다

certificate pinning 버그로 앱이 죽었을 때, 지우면 십 분이면 끝날 일을 살린 채 고치려다 몇 시간을 썼습니다. 장애 앞에서 복구보다 완벽한 수정을 택했던 날의 회고.

핵심 요약

장애가 났을 때 먼저 물어야 할 것은 '이걸 어떻게 고치지'가 아니라 '이게 지금 꼭 있어야 하나'다. 완벽한 수정은 불이 꺼진 뒤에 해도 된다. 나를 막은 건 지식의 부재가 아니라 실수했다는 불안이었고, 급할수록 감정과 판단을 떼어놓는 연습이 필요하다.

목차

앱이 갑자기 열리지 않았다. 원인은 우리가 얼마 전에 넣어둔 certificate pinning이었고, 사실 그 기능은 지금 당장 없어도 되는 것이었다. 지우고 다시 배포하면 십 분이면 끝날 일이었다. 그런데 나는 그 기능을 살린 채로 고쳐보겠다고 몇 시간을 썼다.

이건 그 몇 시간 동안 내가 무엇을 잘못 판단했는지, 그리고 그게 왜 기술 문제가 아니라 마음의 문제였는지에 대한 회고다.

무슨 일이 있었나

certificate pinning은 앱이 서버 인증서를 검증할 때 미리 심어둔 인증서하고만 통신하도록 묶어두는 보안 기법이다. 앱과 서버 사이에 누군가 끼어들어 통신을 가로채는 중간자 공격을 막으려고 넣는다. 이론상으로는 튼튼한 방어막이다.

문제는 이 방어막이 서버를 향해서도 작동한다는 데 있다. 서버 쪽 인증서가 갱신되거나 설정이 조금이라도 어긋나면, 앱은 자기가 아는 인증서와 다르다는 이유로 진짜 우리 서버조차 신뢰하지 못한다. 그 순간 앱은 연결을 끊는다. 사용자 입장에서는 아무것도 안 했는데 앱이 먹통이 된다.

그날의 순서는 이랬다.

  • 앱이 갑자기 서버에 접속하지 못했다. 처음에는 일시적인 네트워크 문제라고 생각했다.
  • 시간이 지나도 상태가 그대로였다. 특정 사용자만이 아니라 접속 자체가 막혀 있었다.
  • 로그를 뒤지다 pinning 검증 단계에서 연결이 끊긴다는 걸 확인했다. 원인을 팀에 공유했다.
  • 수정하고 다시 배포했다. 그제야 앱이 정상으로 돌아왔다.

글로 적으면 네 줄이지만, 두 번째와 세 번째 줄 사이가 길었다. 그리고 그 시간의 대부분은 기술적으로 막혀서가 아니라, 내가 엉뚱한 목표를 붙들고 있어서 길어진 것이었다.

정작 나를 붙든 건 기술이 아니라 감정이었다

지금 돌아보면 이상하다. 나는 그 기능을 지워도 된다는 걸 이미 알고 있었다. 우리 앱에서 certificate pinning이 지금 반드시 필요한 기능이 아니라는 것도 알았다. 그러니 기능을 걷어내고 배포하는 게 가장 빠른 복구라는 계산은 어렵지 않게 나온다. 그런데도 나는 "기능은 그대로 두고 문제만 고쳐야 한다"는 생각에서 빠져나오지 못했다.

불안이 시야를 좁혔던 것 같다. 큰 사고를 냈다는 자책이 먼저 올라오니, 머릿속이 가장 빠른 복구가 아니라 가장 완전한 수정을 찾는 쪽으로 기울었다. 기능을 지우는 선택은 왠지 문제에서 도망치는 것처럼 느껴졌다. 제대로 된 엔지니어라면 원인을 정면으로 고쳐야 한다는, 그럴듯하지만 그 순간에는 해로운 자존심이 있었다.

그래서 나는 어려운 길을 붙들었다. 인증서 설정을 맞춰보고, pinning 로직을 다시 들여다보고, 이 조합이면 통과할까 저 조합이면 통과할까를 시험했다. 하나씩 되짚는 동안 사용자는 계속 앱을 못 쓰고 있었다. 결국 기능을 제거하고 배포하면서 문제는 풀렸다. 그런데 그렇게 끝내고 나니, 이 결말은 처음 삼십 분 안에도 낼 수 있었다는 게 분명해졌다.

무엇이 잘못된 판단이었나

복기해보면 실수는 기술적인 것이 아니었다. 나는 원인을 비교적 빨리 찾았다. 잘못된 건 원인을 찾은 다음의 목표 설정이었다.

장애가 났을 때 나는 무의식적으로 "이 기능을 어떻게 고치지"를 목표로 잡았다. 하지만 그 순간 진짜 목표는 "사용자를 최대한 빨리 정상 상태로 되돌리는 것"이어야 했다. 이 둘은 자주 같은 방향을 가리키지만, 이날처럼 갈라지는 순간이 있다. 기능을 고치는 것과 서비스를 복구하는 것이 다른 길일 때, 나는 습관적으로 전자를 골랐다.

한 가지 더 솔직하게 적자면, 자책이 판단을 더 나쁘게 만들었다. 사고를 냈다는 감정이 앞서면 복구가 아니라 속죄를 하려 든다. 쉬운 해결책이 눈앞에 있어도, 그걸 택하면 내 실수를 대충 덮는 것 같아 마음이 불편해진다. 그래서 굳이 어려운 길로 자신을 몰아간다. 그 어려움이 문제를 더 잘 풀어주지는 않는데도 그렇다.

그래서 정한 원칙

다음 장애 때 나는 원인을 찾자마자 이 세 가지를 순서대로 묻기로 했다.

  1. 지금 문제를 일으키는 이 기능이나 코드가, 당장 이 순간 꼭 필요한가.
  2. 제거하거나 우회하거나 이전 버전으로 되돌려도 되는가.
  3. 빠르게 복구해두고, 제대로 된 수정은 장애가 끝난 뒤에 해도 되는가.

셋 중 하나라도 "그렇다"가 나오면, 대개 그쪽이 옳은 길이다. 완벽한 수정은 불이 꺼진 다음에 해도 늦지 않는다. 사용자가 서비스를 못 쓰고 있는 그 순간에 필요한 건 복구지 완성이 아니다.

원칙 하나를 더 붙였다. 장애 대응 중에 내가 지금 불안한 상태라는 걸 알아차리면, 결정을 내리기 전에 한 번 멈추기로 했다. "이게 가장 빠른 복구인가, 아니면 내가 실수를 만회하려는 건가." 이 질문 하나가 나를 다시 목표 쪽으로 돌려놓는다.

남은 생각

기술적인 대응 매뉴얼은 많다. 롤백을 먼저 고려하라, 영향 범위를 줄여라 같은 조언은 어디에나 있고 나도 알고 있었다. 그런데 그날 나를 막은 건 그 지식의 부재가 아니라, 지식을 실행하지 못하게 만든 감정이었다.

그래서 이번 일에서 진짜로 얻은 교훈은 원칙 목록 그 자체보다, 급할 때일수록 감정과 판단을 떼어놓아야 한다는 감각이다. 침착한 사람이 더 나은 선택을 하는 게 아니라, 자기가 지금 침착하지 않다는 걸 아는 사람이 더 나은 선택을 한다. 다음 장애 때 내가 더 잘하고 싶은 건 바로 그 부분이다.

관련 글