Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

예외 노이즈를 줄이는 실전 가이드: 에러 트래커를 깨끗하게 유지하는 법

어떤 애플리케이션도 실제 사용자와 첫 대면 이후에는 원래의 모습 그대로 있을 수 없습니다. 사람들이 실제로 앱을 사용하기 시작하면 반드시 각종 오류에 부딪히게 됩니다.

그래서 대부분의 앱은 운영 환경에 들어가면 오류를 추적하고 보고하는 체계를 갖춥니다. exception_notification 같은 간단한 도구를 쓸 수도 있고, Honeybadger나 Raygun 같은 웹 서비스를 활용할 수도 있습니다.

그런데 곧 문제를 발견하게 됩니다. 똑같은 예외가 하루에도 몇 번씩 반복해서 보고되는 것입니다. 의존하고 있는 외부 웹 서비스가 불안정할 수도 있고, 사용자가 회원가입 때 이메일 주소를 잘못 입력해서 발송 메일이 전부 반송되는 경우일 수도 있습니다. 예외는 말 그대로 '예외적인' 상황, 즉 예상치 못한 일이어야 합니다. 그런데 하루에 서른 번씩 보이는 오류가 과연 얼마나 '예상치 못한' 것일까요?

이런 문제는 단순히 보고만 하고 무시하는 것보다 더 좋은 해결 방법이 있습니다. 대부분의 시끄러운 예외는 몇 가지 기본 유형으로 분류할 수 있고, 유형별로 노이즈를 줄이면서 동시에 사용자 경험까지 개선할 수 있는 패턴이 존재합니다.

네트워크가 다운됐을 때

혼자서 동작하는 앱은 거의 없습니다. 대부분 다른 애플리케이션과 통신합니다. 하지만 지오로케이션 API가 죽거나 EC2에 장애가 생겼을 때, 어차피 당장 할 수 있는 조치도 없으면서 수천 건의 예외 알림에 시달리고 싶지는 않을 겁니다.

신뢰할 수 없는 외부 서비스를 다룰 때는 Michael Nygard의 『Release It!』에서 소개된 서킷 브레이커(Circuit Breaker) 패턴을 활용해 보세요.

서킷 브레이커의 기본 아이디어는 매우 단순합니다. 보호하려는 함수 호출을 서킷 브레이커 객체로 감싸면, 이 객체가 실패 여부를 감시합니다. 실패가 임계값에 도달하면 서킷 브레이커가 작동(trip)하여, 이후의 모든 호출은 실제 보호된 함수를 실행하지 않고 즉시 오류를 반환합니다.

즉, 외부 서비스가 다운되면 자동으로 연결 시도를 멈추고 해당 기능 없이 나머지 기능을 계속 제공할 수 있습니다. 자가 복구(self-healing)까지 구현하면 일정 시간이 지난 뒤 앱이 스스로 서비스 상태를 다시 확인하게 만들 수도 있습니다.

서킷 브레이커 패턴은 원래 연쇄 장애(cascading failure)를 막기 위해 고안된 것이지만, 예외 알림을 제한하는 용도로도 활용할 수 있습니다. 이 패턴을 적용하면 정말로 알림을 받아야 하는 순간은 브레이커가 작동했을 때와 복구에 실패했을 때뿐입니다. 수천 건의 예외를 단 몇 건으로 줄일 수 있는 것이죠. 그래도 많다고 느껴진다면, 연속으로 몇 번 재시도에 실패한 경우에만 보고하도록 설정하면 됩니다. (아니면 아예 더 안정적인 다른 서비스로 갈아타는 것도 방법입니다!)

이 패턴을 적용하려면 공수가 들지만, 사용자 경험 역시 함께 좋아집니다. 사용자는 투박한 에러 페이지 대신 "이 기능은 현재 사용할 수 없으니 잠시 후 다시 시도해 주세요"라는 안내 메시지를 보게 됩니다. 올바른 시점에 전달되는 훨씬 유용한 정보입니다.

gmaaaail.com은 당신이 의도한 주소가 아니었죠

자주 마주치는 또 다른 유형의 예외는 잘못된 사용자 데이터에서 비롯됩니다.

예를 들어 누군가 회원가입할 때 이메일 주소를 잘못 입력했다고 해보죠. "justinweiss@gmaill.com"이라고 적었지만 실제로는 "justinweiss@gmail.com"을 의도했던 겁니다. 이론상 gmaill.com도 유효한 이메일 형식일 수 있지만, 결과적으로 보내는 모든 메일이 반송되고 이메일 제공업체로부터 반송 통보를 받게 됩니다.

이런 통보는 그저 노이즈일 뿐입니다.

대신 양방향으로 접근하세요. 잘못된 데이터를 사전에 차단하고, 그래도 나중에 실패한다면 해당 기능을 끄고 사용자에게 알려주는 것입니다.

이메일의 경우, 저는 신규 사용자가 가입할 때 mailcheck-js 젬(gem)을 사용해 "gmail.com", "yahoo.com" 같은 도메인 오타를 자동으로 교정해 줍니다:

{% img img-responsive /images/posts/email-spellcheck.gif 477 451 Ooh, fancy. %}

그런 다음에도 이메일이 반송된다면, 해당 사용자에게 보내는 이메일 발송을 중단합니다.

특정 사용자에게 기능을 껐다면, 기능이 비활성화되었다는 사실과 해결 방법도 반드시 알려줘야 합니다. 사이트 상단에 배너를 띄우는 것이 일반적으로 좋은 방법입니다. 예를 들면 이렇습니다. "최근 보내드린 이메일이 전달되지 않아 귀하에게 보내는 이메일 발송을 중단했습니다. 여기를 클릭해 이메일 주소를 수정해 주시면 바로 다시 활성화해 드립니다."

더 정확한 데이터를 확보할 수 있고, 사용자의 이메일이 허공으로 사라지는 일도 막을 수 있습니다. 그저 무시해 왔던 에러 알림보다 훨씬 나은 결과입니다.

404와 RoutingError 처리

사이트의 깨진 링크나 누락된 에셋은 파악하고 싶겠지만, 이런 것들은 예외 트래커에 담길 항목이 아닙니다.

이런 '반쯤 예상되는 오류'들은 개별적으로 알림을 받지 말고 한데 모았다가 한 번에 처리하세요. 발생할 때마다 통보받을 필요가 없습니다. 푸시(push)가 아니라 풀(pull) 방식으로 확인해야 합니다.

RoutingError나 404는 Google Search Console(구 Google Webmaster Tools) 같은 도구로 처리할 수 있습니다. 구글이 크롤링한 페이지 중 404를 반환하는 목록을 보여주기 때문입니다. 또는 link-checker 같은 도구를 릴리스 전 점검 프로세스에 포함시켜 사이트 내 링크를 검증할 수도 있습니다.

예외는 실행 가능해야 합니다

예외 알림 이메일을 받는 일은 드물어야 합니다. 에러 트래커에 노이즈가 너무 많으면 진짜 문제를 제때 발견하고 수정하지 못하게 됩니다.

보고 있는 예외들 때문에 부끄럽기보다 짜증이 난다면, 그것은 노이즈 문제가 있다는 신호입니다. 여기서 소개한 패턴들을 활용해 노이즈를 줄이면서 동시에 사용자에게 더 나은 경험을 제공하세요.

지금까지 제가 가장 자주 접한 시끄러운 예외 유형 몇 가지를 살펴봤습니다. 하지만 모든 유형을 다룬 것은 아닐 겁니다. 여러분의 앱에서 가장 성가신 예외는 무엇인가요? 위의 카테고리에 해당하나요, 아니면 새로운 유형인가요? 하루 수백 번씩 알림이 울리는 상황에서 어떻게 대처하고 계신가요?