프론트엔드 개발을 하다 보면 성능 최적화 이야기를 정말 많이 듣는다.
하지만 정작 성능이 무엇이냐고 물어보면 의외로 명확하게 설명하기 어렵다.
최근 MDN의 Performance Fundamentals 문서를 읽다가 인상 깊었던 부분이 있었다.
MDN은 성능을 단순히 "빠른 코드"가 아니라
사용자가 얼마나 빠르고 부드럽게 느끼는가
라고 설명한다.
이번 글에서는 MDN의 내용을 바탕으로 웹 성능의 기본 개념들을 정리해보려고 한다.
개발자는 종종 숫자에 집중한다.
예를 들면
같은 것들이다.
물론 이런 지표들도 중요하다.
하지만 사용자는 이런 숫자를 체감하지 않는다.
사용자가 실제로 느끼는 것은 훨씬 단순하다.
결국 성능 최적화의 목적은 벤치마크 점수를 높이는 것이 아니라, 사용자가 답답함 없이 서비스를 이용할 수 있도록 만드는 것이다.
MDN에서는 웹 성능을 크게 네 가지 관점으로 설명한다.
사용자의 입력에 얼마나 빠르게 반응하는지를 의미한다.
예를 들어 사용자가 버튼을 클릭했을 때
버튼 클릭
↓
API 요청
↓
화면 변경
이 과정이 오래 걸리면 사용자는 서비스가 느리다고 느낀다.
실제로 사용자는 몇 초가 걸렸는지보다
"내 행동에 바로 반응했는가"
를 훨씬 중요하게 생각한다.
그래서 스켈레톤 UI, Optimistic Update 같은 기법이 등장하게 된다.
화면이 얼마나 부드럽게 움직이는지를 의미한다.
우리가 흔히 말하는 60FPS, 120FPS가 여기에 해당한다.
프레임이 떨어지면 다음과 같은 현상이 발생한다.
브라우저는 이러한 문제를 줄이기 위해 GPU를 활용한다.
특히 다음과 같은 속성은 GPU 가속을 받을 수 있다.
transform
opacity
반면 아래 속성들은 레이아웃 계산을 유발할 수 있다.
top
left
width
height
그래서 애니메이션을 구현할 때는 transform, opacity 기반으로 작성하는 경우가 많다.
메모리를 적게 사용하는 것이 항상 좋은 것은 아니다.
예를 들어
등을 적절히 메모리에 유지하면 오히려 더 빠른 사용자 경험을 제공할 수 있다.
중요한 것은
불필요하게 점유하는 메모리를 줄이는 것
이다.
대표적인 메모리 문제는 다음과 같다.
특히 React에서는 useEffect의 cleanup 함수가 중요하다.
성능은 배터리와도 연결된다.
특히 모바일 환경에서는 더욱 중요하다.
예를 들어
setInterval(() => {
doSomething();
}, 16);
처럼 지속적으로 작업을 수행하면
로 이어질 수 있다.
사용자가 오래 사용할 수 있는 서비스를 만드는 것도 성능 최적화의 일부다.
많은 사람들이 성능이라고 하면 페이지 로딩 속도만 떠올린다.
하지만 실제로는 훨씬 넓은 개념이다.
사용자가 서비스를 이용하는 과정은 다음과 같다.
첫 화면 표시
↓
사용 가능 상태
↓
부드러운 상호작용
↓
전체 콘텐츠 로딩 완료
이 모든 과정이 성능 경험을 구성한다.
특히 사용자는 모든 리소스가 완전히 로딩되는 시점보다
"언제부터 사용할 수 있었는지"
를 더 중요하게 느끼는 경우가 많다.
그래서 최근에는 체감 성능(User Perceived Performance)이 더욱 중요해지고 있다.
우리는 단순히 JavaScript 코드를 작성하지만, 브라우저 내부에서는 다양한 최적화가 이루어진다.
예를 들어
등이 있다.
특히 JavaScript 엔진은 자주 실행되는 코드를 머신 코드로 최적화해 실행 속도를 높인다.
그래서 객체 구조를 일정하게 유지하거나, 예측 가능한 코드를 작성하는 것이 성능에 영향을 줄 수 있다.
등을 활용해 불필요한 연산과 렌더링을 줄인다.
다만 모든 곳에 사용하는 것이 아니라
비용이 큰 연산에 선택적으로 적용하는 것
이 중요하다.
리스트를 한 번에 모두 렌더링하지 않고,
현재 화면에 보이는 영역만 렌더링한다.
예를 들어
같은 라이브러리가 대표적이다.
수천 개의 아이템을 다루는 경우 성능 차이가 크게 나타난다.
불필요한 API 요청은 사용자 경험을 악화시킨다.
예를 들어
API 10개 요청
↓
각 요청마다 네트워크 지연 발생
↓
체감 속도 저하
로 이어질 수 있다.
그래서 다음과 같은 전략을 사용한다.
예전에는 성능을
"코드가 얼마나 빠르게 동작하는가"
라고 생각했다.
하지만 실제 서비스를 개발하면서 느낀 건
"사용자가 얼마나 빠르게 느끼는가"
가 훨씬 중요하다는 점이었다.
사용자는 JIT 컴파일이나 번들 크기를 직접 보지 않는다.
대신
를 경험한다.
결국 좋은 성능이란 단순히 숫자를 개선하는 것이 아니라
사용자가 스트레스 없이 서비스를 이용할 수 있도록 만드는 것에 더 가깝다고 생각한다.