Skip to content

자바스크립트의 책임 : Part Ⅰ

수치에서도 확인할 수 있지만 자바스크립트는 성능 면에서 막중한 책임이 있다. 지금과 같은 추세가 유지된다면 일반 페이지는 적어도 400킬로바이트로 전송될 것이다. 텍스트 기반 리소스처럼 자바스크립트도 대부분 압축된 상태로 전송된다. 그러므로 자바스크립트는 변하지 않고 압축된 상태 그대로 전송되는 유일한 것이라 할 수 있다.
불행히도 리소스 전송 시간을 줄이는 것은 전체 성능에서 큰 부분을 차지한다. 하지만 압축은 자바스크립트가 완전히 도달한 후 브라우저가 스크립트를 처리하는 시간에는 영향을 미치지 않는다. 서버에 400킬로바이트로 압축된 자바스크립트를 전송하면 이는 실제로 메가바이트 단위로 압축 해제되어 브라우저에서 처리될 것이다. 이런 작업 부하를 얼마나 잘 견디는가는 디바이스에 달려 있다. 다양한 디바이스가 수많은 자바스크립트를 얼마나 능숙하게 처리하는지에 대한 자료가 많이 있지만 사실 아주 작은 용량이라도 처리하는 시간은 디바이스마다 크게 다르다.
예를 들어 이 테스트용 프로젝트는 압축되지 않은 23킬로바이트의 자바스크립트를 서버에 전송한다. 2017년 중반 맥북 프로의 크롬에서는 25밀리세컨드만에 이를 읽어 들이지만 노키아 2 안드로이드폰에서는 190밀리세컨드까지 늘어난다. 꽤 차이가 있지만 어쨌든 페이지 로딩은 둘 다 모두 빠른 편이다.
이제 중요한 질문으로 넘어가보자. 이 작은 노키아 2가 일반적인 페이지를 어떻게 읽어 들인다고 생각하는가? 정말 답답할 것이다. 아무리 연결이 빠르더라도 자바스크립트로 가득한 웹 페이지 처리에 많은 시간이 걸리므로 인내심이 필요하다.

A performance timeline for a JavaScript-heavy website. Most of the timeline is JavaScript.
그림 1. 과도한 자바스크립트가 메인 스레드를 독점한 노키아 2 안드로이드폰 브라우저의 성능 타임라인.

디바이스와 네트워크의 웹 탐색 기능은 날이 갈수록 향상되어 편리하게 이용하고 있다. 이를 더욱 활용하기 위해서는 자바스크립트를 책임감 있게 사용할 수 있어야 한다. 그것은 우리가 무엇을 만드는지뿐 아니라 어떻게 만드는지를 이해하는 것에서 시작된다.

 

‘웹사이트’ vs ‘애플리케이션’을 바라보는 사고방식

명칭이란 참으로 이상해서 용어를 대략적으로 부정확하게 식별하더라도 그 의미 자체는 모든 사람이 암묵적으로 이해한다. 꿀벌과 말벌 사이에 상당한 차이가 있는데도 ‘꿀벌’이라는 용어를 ‘말벌’의 의미로도 쓸 때가 많다. 하지만 이런 차이점으로 대상을 다르게 대할 수도 있다. 예를 들어 말벌집을 완전히 제거하고 싶지만 꿀벌이 매우 이롭고 취약한 곤충이기 때문에 말벌집을 옮기는 방법을 택할 수도 있다.
‘웹사이트’와 ‘웹 애플리케이션’이라는 용어도 혼용된다. 이 둘은 말벌과 꿀벌의 차이보다는 덜 명확하지만 혼동하면 골치 아픈 결과를 가져올 수 있다. 이 문제는 단순한 ‘웹사이트’와 완전한 기능을 갖춘 ‘웹 애플리케이션’을 동일시한다는 데 있다. 만약 비즈니스를 위한 정보성 웹사이트를 만들고 있다면 적어도 DOM의 변경을 관리하거나 클라이언트 측 라우팅을 구축하는 강력한 프레임워크는 사용하지 않을 것이다. 적합하지 않은 도구를 사용하는 것은 사이트 사용자에게 손해일 뿐 아니라 생산성도 떨어질 것이다.

하지만 웹 애플리케이션을 만들 때는 주의해야 한다. 수천 가지는 아니더라도 수백 가지의 개별 패키지를 설치하는데, 그중 일부는 안전하지 않을 수도 있다. 또한 모듈 번들을 위해 복잡한 설정도 작성한다. 혼란스럽지만 어디나 있는 이런 개발 환경에서 빠르고 쉽게 개발하려면 지식을 갖추고 경계심을 가져야 한다. 이 내용이 의심스럽다면 프로젝트의 루트 디렉터리에서 npm ls --prod를 실행하고 목록의 모든 항목을 알고 있는지 확인해보기 바란다. 모두 알고 있다 해도 여러분의 프로젝트에 포함되어 있는 서드파티 스크립트까지 다 알기는 어려울 것이다.

우리는 웹사이트와 웹 애플리케이션의 사용 환경이 같다는 것을 잊어버린다. 둘 다 네트워크와 디바이스에 커다란 영향을 미치는 동일한 환경에 놓여 있다. 이런 제약 사항은 우리가 만든 것을 ‘애플리케이션’이라 부르기로 결정한다고 해서 갑자기 사라진다거나 사용자의 휴대전화가 마법처럼 새로운 힘을 얻는 것도 아니다.

우리가 만든 것을 누가 사용할지 검토하고 사용자가 접속하는 인터넷 환경이 우리가 가정한 환경과 다를 수 있다는 사실을 항상 유념해야 한다. 우리가 제공하는 서비스나 솔루션의 목적을 생각해야만 그에 맞는 훌륭한 결과물을 만들 수 있다. 비록 만들기가 신나지 않더라도 말이다.

이는 자바스크립트에 대한 의존도와 그 용도가 무엇인지 (HTML과 CSS는 일단 제외하고) 재평가하고 성능과 접근성을 떨어뜨리는 비효율적인 패턴이 있는지 재확인할 수 있는 계기가 될 것이다.

 

프레임워크의 비효율적인 패턴은 더 이상 사용하지 말자

이전에 함께 일했던 팀에서 프로젝트의 생산성을 높이기 위해 프레임워크를 사용했는데, 이때 사용하는 프레임워크의 코드베이스에서 몇 가지 이상한 점을 발견했다. 여러 가지 중에서 공통된 한 가지 문제점은 비효율적인 접근성과 성능을 보이는 패턴이 종종 발생한다는 것이었다. 다음의 리액트 구성 요소를 예로 들어보자.

여기에는 주목할 만한 접근성 관련 문제가 있다:

  1. <form>을 사용하지 않으면 form이 아니다. 사실 부모 <div>role="form"을 지정하여 사용할 수도 있다. 이와 비슷한 방법이지만 form을 만들 때는 적절한 actionmethod 요소를 수행하기 위해 <form>을 제대로 사용하는 것이 좋다. 특히 action 요소는 매우 중요하다. 자바스크립트가 일부 누락되어도 구성 요소가 서버 렌더링되는 것은 물론이고 form이 해당 action 요소를 수행할 수 있도록 보장해주는 역할을 한다.
  2. <span> 요소가 접근성에 이점이 있다고 해서 <label> 요소 대신 사용할 수는 없다.
  3. form을 전송하기 전에 클라이언트 측에서 무언가를 수행하도록 한다면 <button>onClick 핸들러에 있는 action을 <form>요소의 onSubmit 핸들러로 수정해야 한다.
  4. 덧붙여 말하면 IE10 이상 대부분의 브라우저에서 HTML5에 이메일 유효성 검사가 내장되어 있는데도 자바스크립트에서 왜 이메일 주소의 유효성을 확인해야 할까? 스크린 리더에서 제대로 동작하기 위해 약간의 노하우는 필요하지만 브라우저의 기능과 적절한 input type, 그리고 required 속성을 잘 이용하면 된다.
  5. 접근성 관련 문제는 아니지만 구성 요소는 어떤 상태에서도 라이프사이클 메서드에 의존하지 않는다. 그러므로 이런 구조는 완전한 리액트 대신 자바스크립트를 매우 적게 사용하는 상태비저장형stateless 구성 요소로 리팩토링할 수 있다.

 

앞의 내용을 토대로 다음과 같이 리팩토링할 수 있다.

이제 이 구성 요소는 자바스크립트를 덜 사용하지만 접근성은 더 향상된다. 자바스크립트 홍수 속에서 몇 줄을 삭제하는 것만으로도 훨씬 편안해질 수 있다. 브라우저가 자체적으로 제공하는 기능이 많으므로 최대한 이를 활용할 수 있어야 한다.

프레임워크를 사용할 때만 접근하기 어려운 패턴이 발생한다고는 할 수 없지만 자바스크립트만 선호한다면 결국 HTML과 CSS에 대한 이해에서 차이를 드러낼 것이다. 이런 지식의 차이는 우리가 미처 알지 못하는 실수를 종종 일으킬 것이다. 프레임워크는 분명 생산성을 높이는 유용한 도구가 될 수 있다. 하지만 핵심 웹 기술에 대해 지속적으로 공부해야 우리가 어떤 도구를 사용하든 쓸모 있는 경험을 만들 수 있다.

 

웹 플랫폼을 통해 더 멀리, 더 빠르게

프레임워크에 대한 주제를 다루면서 웹 플랫폼 자체가 강력한 프레임워크임에 틀림없다고 말할 수 있게 되었다. 앞에서 살펴보았듯이 기존의 마크업 패턴과 브라우저 기능을 활용하는 것이 훨씬 더 낫다. 대안은 이를 재창조하는 것이다. 하지만 우리가 보장한 그런 모든 노력에도 더 심각한 문제를 불러일으킨다. 그러므로 우리가 설치하는 모든 자바스크립트 패키지의 제작자가 문제를 포괄적이고 신중하게 해결했다고 가정하는 것이다.

 

단일 페이지 애플리케이션

개발자가 처리해야 할 문제 중 하나는 프로젝트에 맞지 않더라도 단일 페이지 애플리케이션single page applications : SPA 모델을 적용해야 한다는 것이다. 물론 SPA의 클라이언트 측 라우팅을 통해 성능을 높일 수 있지만 다른 무언가를 잃을 수도 있다. 브라우저 자체의 내비게이션은 동기적이지만 여러 가지 기능을 제공한다. 그중 하나는 복잡한 세부 설정을 통해 이력을 관리한다는 점이다. 자신의 선택과 상관없이 자바스크립트가 없는 사용자는 접근 권한을 완전히 잃지는 않는다. 자바스크립트가 없을 때 SPA를 유지하려면 서버 측 렌더링은 갑자기 고려해야 할 사항이 된다.

Two series of screenshots. On the left, we have a blank screen for several seconds until the app appears after 5.24s. On the right, the basic components appear at 4ms and the site is fully usable at 5.16s.
그림 2. 느린 연결 상태에서의 애플리케이션 로딩 비교. 왼쪽 애플리케이션은 전적으로 자바스크립트에 의존하여 페이지를 로딩한다. 오른쪽 애플리케이션은 서버에서 응답이 이루어지지만 클라이언트 측에 hydrate 기능을 사용하여 기존 서버의 렌더링된 마크업과 연결한다.

 

클라이언트 측 라우터가 페이지의 어떤 콘텐츠가 변경되었는지 사용자에게 알려주지 않으면 접근성에 문제가 생길 수 있다. 이런 문제로 페이지에서 무엇이 바뀌었는지 알아내기 위해 보조 기술을 사용하는데, 이는 꽤 어려운 작업이 될 수 있다.

그리고 우리의 오래된 천적인 오버헤드가 있다. 일부 클라이언트 측 라우터는 매우 작지만 여기에서 해결되지 않는 리액트, 호환 가능한 라우터, 때로는 상태 관리 라이브러리까지 135킬로바이트가량의 절대 최적화할 수 없는 용량이 있음을 인정할 것이다. 그러므로 개발할 때 클라이언트 측 라우터가 얼마나 안 좋은지, 만들고자 하는 것 중 포기해야 할 것이 있는지 등을 고려해야 한다. 대개 만들고자 하는 것 중 포기하려는 것을 선택하는 편이 좋다.

만약 내비게이션 성능이 우려된다면 rel=prefetch를 통해 문서 일부를 미리 가져올 수 있다. 프리페치prefetch는 우선순위가 낮아서 대역폭의 중요한 자원과 경쟁할 일이 거의 없기 때문에 캐시에 저장된 문서를 바로 불러와 페이지 로딩 속도를 혁신적으로 개선할 수 있다.

Screenshot showing a list of assets loaded on a webpage. 'writing/' is labeled as prefetched on initial navigation. This asset is then loaded in 2ms when actually requested by the user.
그림 3. HTML 내에서 writing/을 사용하면 초기 페이지를 프리페치한다. 사용자가 writing/ URL을 호출하면 브라우저 캐시에서 HTML이 즉시 로드된다.

 

링크 프리페칭link prefetching의 주요 단점은 잠재적인 낭비가 있을 수 있음을 알고 있어야 한다는 것이다. 구글에서 만든 작은 링크 프리페칭 스크립트인 Quicklink는 이런 문제점을 완화하기 위해 클라이언트 연결이 느리거나 데이터 세이버 모드가 활성화되어 있는지 확인하고 기본적으로 크로스 오리진cross-origin에서 링크 프리페칭을 막는다.

이미 잘 알고 있듯이 서비스 워커service workers는 우리가 클라이언트 측 라우팅을 사용하든 사용하지 않든 재방문한 사용자의 성능을 높이는 데 크게 기여한다. 서비스 워커를 사용하여 미리 캐싱해두면 링크 프리페칭을 사용하는 것과 마찬가지의 많은 이점을 얻을 수 있으며 링크 프리페칭보다 요청과 응답을 더 잘 제어할 수 있게 된다. 여러분이 생각하고 있는 사이트가 ‘애플리케이션’이든 아니든 간에 서비스 워커를 적용하는 것이 오늘날 자바스크립트를 가장 책임감 있게 사용하는 방법이라 할 수 있다.

 

자바스크립트는 레이아웃 문제의 해결 방안이 아니다

만약 레이아웃 문제를 해결하기 위해 패키지를 설치하고 있다면 다시 한 번 스스로에게 “나는 무엇을 달성하려고 하는가?”라고 물어보자. CSS는 이런 작업을 수행하기 위해 설계되었으며 효과적인 사용을 위한 추상화도 필요 없다. 자바스크립트 패키지로 해결되는 레이아웃 문제의 대부분은 박스 배치, 정렬 및 크기 조정, 텍스트가 넘칠 때의 관리전체적인 레이아웃 시스템이며 이는 현재 CSS로 모두 해결할 수 있다. 프로젝트를 시작할 때 프레임워크가 없어도 최신 레이아웃 엔진인 플렉스박스나 그리드로 충분히 가능하다. CSS가 ‘프레임워크’라 할 수 있는 셈이다. 기능 쿼리feature queries가 있으면 새로운 레이아웃 엔진을 적용하기 위해 레이아웃을 점진적으로 개선하는 것도 어렵지 않다.

레이아웃과 화면 문제를 해결하기 위해 자바스크립트를 사용하는 것은 이전부터 있던 일이다. 2009년 모든 웹사이트가 당시 더 훌륭한 브라우저에서 보이는 것처럼 IE6에서도 보이도록 우리 스스로 거짓말을 해가며 만들어야 했다. 2019년인 지금, 아직도 모든 브라우저에서 동일하게 보이도록 웹사이트를 개발하고 있다면 개발 목적을 다시 생각해보아야 할 것이다. 에버그린 브라우저Evergreen Browser(사용자가 따로 재설치하지 않아도 브라우저가 자동으로 업데이트를 수행한다-옮긴이)에서는 가능하던 것이 지원되지 않는 몇몇 브라우저도 항상 있을 것이다. 모든 플랫폼에서 똑같이 보여야 한다는 관점은 헛된 추구일 뿐 아니라 점진적 향상의 주요한 적이라 할 수 있다.

 

자바스크립트를 죽이려는 것은 아니다

자바스크립트에 나쁜 감정은 없으니 오해하지 않았으면 한다. 자바스크립트로 인해 직업을 얻었고, 솔직히 말해서 10년 넘게 내 즐거움의 원천이었다. 다른 장기적인 관계와 마찬가지로 자바스크립트에 더 많은 시간을 할애하면서 더 많이 알 수 있었다. 자바스크립트는 해가 갈수록 더 유능하고 우아한 언어로 발전하여 풍부한 기능의 언어가 되었다.

하지만 자바스크립트와 사이가 안 좋을 때가 있다. 나는 자바스크립트에 대해서 비판적인 시각을 갖고 있다. 어쩌면 웹을 개발할 때 자바스크립트를 첫 번째 수단으로 보는 경향을 발전시킨 것에 대해 비판적이다라는 표현이 더 정확할지도 모른다. 크리스마스트리 조명과 뒤엉킨 공처럼 이것들을 하나하나 떼어내다보면 지금의 웹이 얼마나 자바스크립트에 취해 있는지 알게 된다. 심지어 필요하지 않을 때도 거의 모든 것을 위해 자바스크립트에 손을 뻗치고 있다. 때때로 숙취가 얼마나 안 좋을지 궁금해진다.

앞으로 다룰 글에서는 과도한 자바스크립트의 물결을 막기 위해, 그리고 모든 사람이 어디서나 적어도 이전보다는 사용하기 편한 웹을 만들기 위해 무엇을 해야 하는지에 대해 더 유용한 조언을 할 것이다. 그중 일부는 예방책에 대해서 다룰 것이며, 일부는 ‘해장술’을 줄일 수 있도록 도울 것이다. 어떤 경우든 그 결과는 같기를 바란다. 나는 우리 모두가 웹을 사랑하고 옳은 길로 가고 싶어 한다고 믿고 있으며 이를 위해 우리가 어떻게 해야 전체를 포괄할 수 있고 더 탄력적인 웹을 만들 수 있는지 생각해보았으면 한다.

 

도서 소개


매트 마키스의 『웹디자이너를 위한 자바스크립트』
자바스크립트의 기본 원리를 상세히 설명하여 디자이너나 개발자 또는 자바스크립트 초보자도 손쉽게 자바스크립트를 배울 수 있습니다. 기본 문법과 규칙, 함수, 객체, 루프의 개념을 예제와 함께 알기 쉽게 설명하고 자바스크립트의 강점인 간결하고 반복을 최소화하는 코드 작성법을 보여줍니다.

저작권 정보이 글은 A List Apart 기사를 번역한 것입니다. 저작권자의 정당한 허락을 받은 저작물로 한국어판 저작권은 웹액츄얼리에 있습니다. 웹액츄얼리의 서면 동의 없이 무단 전재, 복제를 금합니다. 원본은 Responsible JavaScript : Part I에서 확인할 수 있습니다.
참여를 기다립니다!웹액츄얼리에서 웹디자인 관련 영문 번역자를 찾습니다. 웹 콘텐츠 번역에 관심 있는 분은 메일로 간략한 본인 소개와 번역 이력을 보내주시면 연락드리겠습니다. 
books@webactually.com


맨위로