안녕하세요. 와디즈 앱개발팀입니다.
와디즈 기술 조직은 과제에 따라 하나의 팀으로 뭉쳐 협업하곤 하는데요. 이번 글에서는 앱개발팀과 FE개발팀이 클라이언트개발팀으로 함께 와디즈 앱의 상세 페이지 진입 속도를 Android 약 38%, iOS 약 66% 개선한 경험을 소개하려고 해요.
그럼 개선 전과 개선 후의 로딩 속도 차이를 보고 시작할게요!
도입 배경
클라이언트개발팀으로 앱개발팀과 FE개발팀은 어떤 것을 개선할 수 있을지 함께 고민했는데요. 상세 페이지는 가장 많이 탐색 되는 지면이기 때문에 그 로딩 속도를 개선하는 것을 목표로 설정하게 되었어요.
앞서 와디즈 웹은 SPA 방식으로 상세 페이지 진입 속도를 개선한 상황이었는데요.
여기서 SPA란 Single Page Application의 약자로 최초에 한 번 페이지 전체를 로드하고, 이후부터는 Ajax를 통해 데이터를 바인딩하여 화면을 바꾸는 방식이에요.
앱에서는 상세 페이지 진입 시에 웹뷰를 새로 생성하고, URL을 로드하는 방식으로 동작해 매번 페이지 전체를 불러오고 있었어요. 그 때문에 웹에서의 개선 사항을 반영할 수 없었죠. 만약 앱에서도 상세 페이지의 웹뷰가 SPA 방식으로 동작하게 된다면 로딩 속도를 개선할 수 있겠다는 가설을 세웠습니다.
어떻게 개선했을까요?
기존 앱의 상세 페이지에서는 사용자가 닫기 또는 뒤로 가기 버튼을 누르는 등 페이지가 닫힐 때마다 웹뷰도 함께 사라졌어요. 그래서 SPA 방식을 적용하기 어려운 상황이었죠. 이 문제를 해결하기 위해 저희는 상세 페이지가 사라져도 웹뷰가 유지되는 방법을 고민했어요.
그 결과, 아래 사진처럼 웹뷰만 별도로 분리해 유지하고, 필요할 때마다 화면에 다시 표시할 수 있도록 설계했어요. 이를 PoC(Proof of Concept)를 통해 검증했습니다.
상세 개발 방안
화면에 띄울 때
- 앱이 최초 실행되면 재사용 할 웹뷰를 미리 생성하고, SPA 전환이 가능하도록 준비 페이지를 로드해요.
- 사용자가 상세 페이지 진입할 때 새로운 화면을 띄우고, 미리 생성해 둔 웹뷰를 화면에 붙여요.
- 웹에 SPA 전환을 요청하면 웹에서 데이터를 로드한 뒤 화면에 보여줘요.
화면이 닫힐 때
- 화면에 붙여진 웹뷰를 다시 분리해요.
- 웹뷰 외의 다른 이벤트 리스너와 객체들을 메모리에서 해제합니다.
상세 페이지에 진입할 때마다, 이 과정이 일어나고 덕분에 더 빠른 로딩으로 좋은 사용자 경험을 제공할 수 있게 되었어요.
기존에 웹뷰에서 제공하던 콜백들은?
페이지를 로드하면, 로드가 시작될 때 Android의 onPageStarted
, iOS의 webView(_:didCommit:)
이 호출되고 로드가 완료되었을 때 Android의 onPageFinished
, iOS의 webView(_:didFinish:
가 호출돼요.
그런데 SPA 전환으로 페이지가 변경되면, 위와 같은 WebView 관련 메소드들이 호출되지 않아요. 기존에 처리하던 작업을 할 수 없죠.
그 대응으로 웹과 앱 간의 통신 인터페이스로 처리할 수 있도록 정했어요.
와디즈 웹 → 앱 이벤트 정의
- accepted : 앱에서 웹으로 SPA 요청을 했을 때, 웹에서 SPA 방식으로 처리 가능하다고 다시 알려주는 이벤트
- loaded : 상세 페이지 데이터가 모두 불렸을 때
- rendered : 상세 페이지에 화면이 그려졌을 때
- failed : 로드 실패하였을 때
변경된 방식에 있어 고민한 것은?
새로운 방식이라고 해서 오로지 장점만 있는 것은 아니에요. 변경된 방식을 채택할 때 고민할 점이 많았어요. 예상치 못한 부작용이 발생할 수도 있기 때문이죠. 이에 대비해 여러 질문과 대응책을 준비했어요.
웹뷰를 미리 생성했을 때 발생하는 문제는?
미리 생성된 웹뷰는 문제를 일으킬 수 있어요. 예를 들어, 새로운 웹 페이지가 업데이트되면 변경 사항이 웹뷰에 적용되지 않을 수 있고, 로그인 세션이 만료될 수도 있어요. 이런 문제를 피하고자, 30분 주기로 웹뷰를 SPA 전환이 아닌 URL을 새로 로드하도록 했습니다. 그래서 새로운 요청이 들어오면 항상 최신 상태를 유지할 수 있게 되었어요.
웹, 앱이 이벤트를 수신받지 못하는 상황이라면?
SPA 방식으로 페이지가 전환되면, 웹뷰 콜백을 받을 수 없기 때문에 웹에서 전달받는 이벤트는 매우 중요해요. 웹과 앱이 이벤트를 수신받지 못하는 상황에서 기다리는 것 보다는 새로 페이지를 로드하는 것이 최선이라 생각했어요. 두 가지 대응책을 마련했습니다.
첫 번째로, 웹이 SPA 전환을 처리할 수 있는 환경인지 확인하기 위해 accepted 이벤트를 기다립니다. 만약 0.2초 안으로 accepted 이벤트가 오지 않으면, 처리 불가능한 환경이라 판단하여 페이지를 새로 로드해요.
두 번째로, SPA 요청에 대한 응답 값을 확인합니다. SPA 요청에 대한 응답 값이 true일 때는 정상적인 상황으로, SPA 방식으로 화면을 전환해요. 하지만 false 또는 null 일 경우에는 SPA 방식으로 화면 전환을 할 수 없다고 판단하는데요. 이때 페이지를 새로 로드합니다.
메모리 누수
안드로이드 앱의 개발 및 테스트 과정에서 재사용되는 웹뷰와 Fragment가 연결되어 있을 때 메모리 누수가 발생하는 문제가 생겼어요. 메모리 누수가 있으면 앱의 메모리 사용량이 계속해서 늘어나면서 전반적인 성능에 영향을 미칠 수 있어요.
이를 해결하기 위해, 상세 페이지가 닫힐 때 웹뷰와 Fragment를 완전히 분리했어요. onDestroyView
, onDetach
에서 웹뷰의 이벤트 리스너나 WebViewClient, WebChromeClient 등을 해제했어요.
override fun onDestroyView() {
super.onDestroyView()
webView?.setOnKeyListener(null)
webView?.webChromeClient = null
webView?.webViewClient = WebViewClient()
}
override fun onDetach() {
super.onDetach()
webView = null
}
RemoteConfig와 A/B 테스트를 이용하여 장애 대응
개선하고자 하는 페이지가 사용자들이 가장 많이 접근하는 상세 페이지라서, 장애 대응이 매우 중요했어요. 장애 발생에 대비하기 위해 두 가지 방법을 고려했어요.
이 접근 방식을 통해 사용자 경험을 개선하는 동시에 장애 대응에도 능동적으로 대응할 수 있었어요.
개선 모니터링
개선된 로딩 속도를 모니터링하기 위해 Firebase Performance를 활용하여 새로운 attribute를 추가했어요.
성공, 실패, 미지원 케이스로 개선 사항을 구분하여 사용자들의 환경에서 어떤 추이를 보이는지 확인할 수 있었는데요. 모니터링 과정에서 SPA로의 전환 비율이 약 60%에 이른다는 사실을 확인했어요. 이는 사용자들이 페이지 간 이동을 더 빠르고 효율적으로 경험하고 있다는 것을 의미해요.
아래 그래프와 같이 개선 후 로딩 속도가 개선되었음을 확인할 수 있었습니다.
마치며
하이브리드 영역 개발이라는 점에서 이번 과제는 조금 어려움이 있었어요. 이슈가 발생했을 때 원인을 추적하는 등 웹과 앱 사이의 많은 소통도 필요했죠. 그때마다, 긍정적이고 의욕적으로 협업에 임해주신 FE 개발팀, QA팀께 감사의 말을 전하고 싶어요. 함께했기 때문에 프로젝트를 즐거운 마음으로 마무리할 수 있었습니다.
앞으로도 클라이언트개발팀으로 여러 팀이 협력해 와디즈 서비스를 발전하고 사용자들에게 더 나은 경험을 제공하고자 해요. 함께 발전해 나가는 과정에서 새로운 아이디어와 혁신을 발견할 수 있기를 기대합니다.
궁금한 내용이 남아 있나요? 👀
FE개발팀이 SPA 방식으로 웹 상세 페이지 속도를 개선한 이야기가 궁금하다면? 👉 클릭
앱개발팀의 Compose Multiplatform 도입기 👉 클릭