안녕하세요. IMQA 개발팀 남상우입니다.
이번 포스팅에서는 화면에서 일어나는 성능 저하를 개선하는 방법에 대해 이야기해 보겠습니다.
배포하고 나면 왜 느릴까?
많은 개발자분께서 개발 시 성능이 저하되는 요인들을 발견했다면 배포 전에 수정하였을 겁니다. 그러나 개발 때는 보이지 않았던 성능 저하 요소들이 배포 후에는 쏙쏙 나타나기 시작하는데요.
무엇이 문제였을까?
대표적인 몇 가지 케이스가 있습니다. 많은 분께서 실수하거나 놓치기 쉬운 케이스인데요.
- 개발 환경과 사용자 환경이 너무 다른 것
- IMQA 서비스에 수집된 데이터 기준으로 정적 리소스에 대한 처리가 안 된 것
- 정적 리소스 중 이커머스에서 가장 많은 타입인 이미지에 대한 처리가 안 된 것
이렇게 세 가지입니다. 그 외의 케이스들도 많겠지만 대표적으로 배포 후에 놓치게 되는 것들입니다.
1. 개발자 환경은 사용자 환경과 완전히 다르다.
실제로 배포 후에 앱을 깔아서 확인해 보면 동작이 충분히 빠르진 않을 겁니다. 배포된 앱에서는 이미지가 중간중간 그려지고 있거나, 시간이 지나면서 없던 콘텐츠가 생겨 웹뷰 레이아웃이 움직이는 현상이 보이기도 합니다.
사용자는 모바일로 경험하고 있지만 개발자는 데스크탑으로 작업하고 확인하여 성능 저하에 대해서 체감을 많이 못 합니다. 따라서 사용자 환경과 가장 비슷하게 확인하려면 같은 기종의 모바일로 테스트해야 하지만 브라우저에서도 그나마 모바일과 비슷하게 확인하기 위해서는 최소 네트워크 속도만은 모바일로 맞춰야 합니다.
브라우저에서 네트워크 속도 변경하기
데스크탑과 모바일에서 가장 큰 변화는 네트워크 속도입니다. 평균적으로 4배가량 속도 차이가 납니다. 실제 blog.imqa.io 사이트 기준으로 데스크탑에서 네트워크 속도 제한하지 않는 것과 속도 제한을 한 것을 비교해 보면 아래와 같은 차이를 보입니다.
* 좌: 개발자가 본 화면(데스크탑에서 속도 제한 없는 블로그)
* 우: 사용자의 화면(데스크탑에서 속도 제한 적용한 블로그)
네트워크 변경만으로 서비스가 모바일에서 어떻게 동작하는지 예측이 가능합니다. 간단하게 크롬 브라우저의 개발자도구에서 네트워크 탭에 속도를 변경하시면 속도 제한이 가능합니다.
2. 캐시 정책을 추가하지 않았다.
리소스를 보면 정적 리소스인데 계속적으로 요청과 응답을 반복하여 랜더링 속도 저하의 원인이 되고 있었습니다.
이 부분을 어떻게 개선할까 고민해 보면 정적 리소스를 압축하는 방법과 캐시를 적용하여 정적 리소스에 대한 반복적인 요청과 응답의 시간을 줄이는 것이 있습니다. 그 중 가장 쉽게 할 수 있는 방법 중 하나는 캐시를 적용하는 방법입니다.
캐시 적용하지 않아도 상관없지 않나?
캐시를 적용하지 않는다면 사용자 환경에서는 매번 정적 리소스를 요청하고 응답받고 있습니다.
만약 서비스하는 앱이 동적으로 컴포넌트가 랜더링되고 있다면 매번 정적인 리소스를 가지고 오는 것은 DCL 시간을 지체하는 요소 중 하나일 것입니다.
DOMContentLoaded(DCL)는 DOM이 형성되는 시점을 이야기하며 이때부터 스크립트에서 DOM이 접근 가능하다.
DCL 시간을 조금이라도 빠르게 하기 위해서는 매번 요청하여 가지고 올 필요 없는 정적 리소스에 대한 캐시가 필요합니다. 간단하게 특정 데모를 기준으로 캐시 적용 전과 후를 개발자도구로 확인해 보면 확연한 차이가 보입니다.
캐시를 적용하기 전
캐시를 적용하기 전에는 DCL이 1.49초가 걸렸으며 완전히 페이지가 로드되기까지는 1.81초가 소요되었습니다. 매번 정적 리소스를 요청하고 응답하게 되면서 화면을 그리는 시간을 지체시키게 됩니다.
캐시를 적용한 후
캐시를 적용한 후에는 DCL이 0.824초가 걸렸으며 완전히 페이지가 로드되기까지는 0.871초가 걸렸습니다. 변하지 않는 정적 리소스를 캐시 처리로 인해 요청과 응답시간이 0초가 되면서 사용자에게는 더욱 빠르게 서비스를 제공할 수 있게 됩니다.
정적 리소스에 캐시를 적용하면 DCL이 빨라지며 사용자에게는 빠르게 서비스를 제공할 수 있습니다.
Webpack을 사용한 캐싱 전략
웹팩에서는 빌드한 결과물에 캐싱 상태를 적용시켜 정적 리소스를 반복적으로 http를 요청하지 않게 설정하는 기법이 있습니다.
웹팩 설정 파일에서 아래 코드와 같이 설정하여 브라우저 캐시 적용 시 파일명이 변경된 것으로 브라우저가 인지하여 다시 불러옵니다.
// webpack.config.js
output: {
filename: '[name].[chunkhash].js', //[hash],[chunkash]
path: path.resolve(__dirname, 'dist')
}
3. 모바일에 사이즈가 큰 이미지를 제공하고 있었다.
캐시로 리소스에 대한 처리를 했음에도 이커머스 같은 서비스들은 자주 바뀌는 이미지 리소스에 대한 개선도 필요합니다.
모바일 환경은 데스크탑과는 다르게 제약이 많습니다. 자원적인 제약, 네트워크 속도에 대한 제약, 그리고 백그라운드에 실행되어 있는 앱도 무시 못 하지요. 그렇기 때문에 이미지 리소스 하나를 올리더라도 사이즈가 큰 리소스를 사용하면 서비스에 영향을 많이 끼치게 됩니다.
특히 중요한 점은 이 부분은 운영하면서도 나타나는 문제이기도 하기에 개발자가 그만큼 신경 써줘야 합니다.
이미지 CDN을 활용해 주세요.
CDN을 사용하게 되면 url의 매개 변수에 따라 이미지 크기를 설정하거나 포맷을 변경하는 등 편리하게 모바일 환경에 맞게 적용할 수 있습니다.
HTML은 기본적으로 반응형 이미지를 제공해 주고 있어요.
CDN 서버가 없는 경우, img 태그에 기본적으로 반응형 이미지를 제공할 수 있게 도와주고 있습니다. 태그의 속성만 잘 사용해도 동적으로 화면 사이즈에 맞게 이미지를 불러올 수 있습니다.
<!-- 동적으로 이미지 변경 -->
<img
srcset="300w.jpg 300w, 600w.jpg"
sizes="(max-width: 300px) 300px, 600px"
src="300w.jpg"
alt="테스트이미지"
/>
CSS를 활용하는 방법도 있어요.
이미지를 바로 불러올 수 있지만 CSS를 통해서도 해상도에 맞는 이미지를 불러와야 할 경우가 있습니다.
미디어 쿼리는 CSS에 화면의 width, height 크기에 따라서 노출시킬 수 있습니다. 미디어 쿼리의 사이즈를 세분화하면 좀 더 부드럽게 해상도에 따른 이미지 변경을 할 수 있습니다.
@media (max-width: 300px) {
.desktop_image {
display: none;
}
}
@media (min-width: 600px) {
#mobile_image {
display: none;
}
}
마치며
API가 완벽해서 요청에 대한 빠른 응답을 주더라도 사용자의 화면에서 느리게 표현된다면 결국 사용자에게는 느린 서비스가 될 겁니다. 화면에서도 실제로 많은 성능 저하 요인들이 많이 발견되고 크리티컬한 부분들도 있습니다.
그래서 포스팅을 통해 화면에서 발생할 수 있는 성능 저하를 개선하는 방법을 소개해 봤는데요. 많은 분께서 성능을 개선하시는데 도움이 되었으면 좋겠습니다.
웹페이지 성능 개선을 다룬 영상과 자료도 함께 확인해 보세요.