청소연구소 Android팀, CoroutineExceptionHandler로 마이그레이션하기

Jaeryo
청소연구소
Published in
4 min readOct 31, 2022

안녕하세요. 청소연구소 Android 팀 양민욱(aka. Jaeryo)입니다. ✋

최근 청소연구소 Android 팀은 API 에러 처리 구조를 개선하는 작업을 진행했습니다!

네트워크 요청은 기기의 네트워크 이슈를 고려해야 하고 의도적으로 서버에서 에러 코드를 내려주는 경우도 있어 적절한 에러 처리가 필요해요. 이 점에 대해 팀 내에서 어떤 구조가 좋을까 고민하는 시간을 가지기도 했는데요.

최종적으로 CoroutineExceptionHandler를 사용해서 개선해보자고 결론을 지었습니다. 이 글에서는 개선하고자 했던 이유, 어떻게 변경이 되었는지, 작업에 대한 느낀 점 등을 이야기해보려고 해요. 궁금하신 분들은 이 글을 끝까지 읽어주세요 🙂

예시로 작성된 코드들은 현업에서 실제로 사용하는 코드와 상이할 수 있습니다 :)

CoroutineExceptionHandler로 넘어간 이유

기존 에러 처리 구조는?

청소연구소 Android 팀은 Sealed class의 장점을 이용하여 API 요청을 성공과 실패를 구분 지어 각각 알맞게 처리해주고 있었어요. 이 코드는 꽤 매력적이었고 오랫동안 크리티컬한 이슈 없이 잘 동작했어요. 하지만 몇 가지 작은 단점들이 시간이 지날수록 신경 쓰이기 시작했습니다 ☹️

  1. 코드의 Depth가 깊어 코드의 역할을 한눈에 파악하기 어렵다.

위 코드는 API의 결과를 바로 변수에 넣어주는 단순한 기능이에요. 하지만 sealed class의 결과를 파싱해주기 위해 when 구문이 들어가게 되면서 한 줄로 끝날 코드의 양이 늘어나게 되었어요. 그 결과로 이러한 구조에 익숙하지 못한 개발자들은 한눈에 코드의 맥락을 파악하기 힘들 수도 있어요.

특히 에러를 무시하는 케이스의 경우 sealed class를 사용하는 구조의 통일성 때문에 간결한 코드를 구성하는 것이 쉽지 않기도 해요.

2. 불필요한 에러 처리 코드가 반복됨

대부분의 API 요청에 대한 에러 처리는 동일하기 때문에 에러 처리하는 코드가 불필요하게 반복적으로 선언해주고 있다는 느낌을 받았어요.

CoroutineExceptionHandler로 마이그레이션

BaseViewModel에서 CoroutineExceptionHandler 선언해주기

CoroutineExceptionHandler는 CoroutineContext에 추가하는 옵션 중 하나로 코루틴 계층에서 전파되는 Exception의 에러 처리 역할을 담당하고 있어요.

BaseViewModel에 선언한 CoroutineExceptionHandler를 쉽게 적용하기 위해서 cleaningScopeLaunch 함수를 만들어서 사용하고 있습니다.

viewModelScope를 사용하는 것이 아닌 cleaningScopeLaunch 사용한다면 에러 처리뿐만 아니라 로딩 상태 관리 등등 API 요청할 때마다 비슷한 패턴으로 반복적으로 사용되는 기능들을 묶어 줄 수 있어요.

sealed class 제거

결과적으로 cleaningScopeLaunch 내에서 Sealed class 처리하는 코드가 사라져서 훨씬 쉽게 API 통신 처리를 할 수 있었어요.

특별한 에러 처리

하지만 종종 특정 화면에서는 그에 맞는 에러 처리가 필요할 때가 있더라고요. 그런데 CoroutineExceptionHandler는 BaseViewModel에 선언되어 있어 개별적인 에러 처리 코드를 포함하기 어려워요. 그래서 첨부한 코드처럼 try-catch 또는 runCatching 처럼 Exception을 catch하는 코드를 통해 별도의 에러 처리 코드를 넣어주면 돼요!

마이그레이션 작업 진행 🚀

마무리

마이그레이션 작업은 순조롭게 진행이 되었고 현재는 코드 리뷰를 받고 있어요 🙂 앱의 전반적인 구조를 모두 뜯어내고 개선하는 작업이었기 때문에 변경된 코드의 양이 적지 않았는데요. 코드 리뷰해야 할 양을 보고 머리를 쥐어짜던 메튜의 모습이 떠오르네요… Android 팀, QA 팀에게도 항상 죄송하고 감사하다는 말씀을 드리며 마무리하겠습니다!

함께 즐겁게 일하실 팀원을 기다립니다.

--

--