클라이언트단 자바스크립트에 대한 5가지의 놀라우리 만큼 고통스러운 것들[번역]

원본 글 : http://bit.ly/1fvDV6c. By Quinn Slack — February 17, 2014, at 8:43pm UTC


역자의 말 : 리치 자바스크립트 프레임워크가 모든 웹사이트에서 적용해야 하는 것으로 착각할 수 있지만 나름 이것들이 가지는 문제들이 여러가지로 지적되고 있다. 그러나 원인을 알면 문제를 해결할 수 있듯이, 아마도 멀지 않은 미래에 이러한 문제점이 하나 둘 해결되리라 기대하면서 번역해서 공유한다.

이렇게 많은 어려움이 예상되었지만, 실제로 얼마나 힘들 지는 몰랐다.

(1) 검색 순위 올리기도 나쁘고 트위터/페이스북 프리뷰하기도 나쁘다

검색 엔진 크롤러(crawler)와 SNS 프리뷰 스크레이퍼(scraper)는 자바스크립트만 가능한 웹사이트를 로드할 수 없고 이를 위해서 대체 버전을 서비스하는 것은 복잡하고 속도가 늦다.

크롤러가 웹사이트를 읽을 수 있도록 하는데는 2가지 방법이 있다.

서버에서 브라우저 인스턴스를 만들고 이 브라우저 상에 어플리케이션의 자바스크립트를 실행해서 DOM객체로 부터 만들어지는 HTML을 덤프(PhantomJS 또는 WebLoop를 이용해서)할 수 있다. 또는 크롤러를 위해서 웹사이트 상에 서버에서 생성한는 다른 HTML 버전을 만들 수 있다.

전자의 경우는 각 페이지를 로드하기 위해 헤드가 없는(headless) 브라우저나 탭(tab)을 spawn(자식 프로세스를 만들어 실행하는 것)해야 하는데, 이것은 HTML만을 만드는 것보다 훨씬 많은 시간과 시스템 자원을 필요로 한다. 사용하는 프레임워크에 따라, 페이지를 렌더링해서 덤프해야 하는 시점을 결정하는데 또한약간의 작업이 더 소요된다. 페이지를 캐시할 수 있지만, 이것은 최적화를 위한 조치에 불과하고, 페이지가 자주 변경될 경우에는 더 복잡하게 구현해야 한다. 이것은 몇 초정도 페이지 로드 시간을 느리게 하여 검색 엔진의 순위에 악영향 을 미친다. (이 문장은 PhantomJS가 Xvfb와 WebKit를 필요로했다고 잘 못 언급했었다.)

간단한 사이트일 경우에는 (대체 서버사이드 사이트를 만드는) 후자의 방법만으로도 충분하지만, 수 많은 종류의 페이지가 있는 경우에는 악몽이다. 그리고 구글이 대체 사이트를 메인 사이트와 심하게 차이가 있다고 여기면 심한 벌칙을 부과할 것이다. 웹사이트의 트래픽이 급격하게 감소할 때까지는 선을 넘어 선 것을 알지 못 할 것이다.

(2) 신뢰할 수 없는 통계와 모니터링

대부분의 분석도구들은, 페이지 이동을 위해 HTML5 history API(pushState)를 사용할 때는, 에러가 쉽게 발생하기 쉬운 수작업으로 통합을 해야 필요가 있다. 이것은 어플리케이션이 pushState를 이용해서 새로운 페이지로 언제 이동해야 하는지를 자동으로 감지할 수 없기 때문이다. 설상 감지를 할 수 있다고 해도, 새로운 페이지에 대한 기타 정보(페이지 타이틀과 추적할 필요가 있는 기타 다른 페이지특이 지표)를 수집하기 위해서 어플리케이션으로부터의 신호를 여전히 기다릴 필요가 있을 것이다.

이러한 문제를 어떻게 수정해야 할까? 해결방안은 클라이언트측 라우팅 라이브러리와 통합하려는 특정 분석툴 둘 다에 달려 있다. Backbone.js와 함께 구글 분석기(Google Analytics)를 사용한다면? backbone.analytics를 시도해 보기 바란다. UI-Router와 함께 Heap을 사용한다면? 자신만의 $stateChangeSuccess 후크를 설정한 후 heap.track을 호출하기 바란다.

아직 아무런 조치를 취하지 않은 상태다. 최초 페이지 로딩을 추적할 것인가? 혹시 그것을 이중으로 추적할 것인가? 페이지 로드 실패를 추적할 것인가? pushState 대신에 replaceState를 사용한다면 어떨까? 분석기 후크를 잘 못 설정했다는 것을 아는 것 조차 힘들다. 또는 의존성(dependency)을 업그레이드했을 때, 분석기를 자주 상호 점검하지 않는다면, 후크들이 깨질 것인지를 아는 것조차 어렵니다. 그리고 문제꺼리를 발견할 때, 놓쳤던 분석 데이터를 복구하거나 중복된 것을 제거하는 것 조차 어렵다.

(3) 느리고 복잡한 빌드 툴

Grunt와 같은 프론트엔드 자바스크립트 빌드 툴은 설정이 복잡하고 때로는 속도가 느려질 수 있다. ng-boilerplate와 같은 놀라운 프로젝트가 있어서, 설정하는데 시간을 소비하지 않아도 되지만, 그래도 여전히 속도가 느리고, 빌드 단계를 추가하고자 할 때 복잡성을 피할 수 없다. (복잡성에 대햐서 설명한 것을 알고 싶다면, ngbp의 Gruntfile을 살펴 보기 바란다.)

Gruntfile과 기타 모든 옵션을 지정하여, 일단 어플리케이션을 완벽하게 설정했다 하더라도, 여전히 느린 자바스크립트 빌드 시간을 견뎌야 한다. 개발 속도를 향상시키기 위해서 개발과 운영 빌드 환경을 별도로 구분할 수 있지만, 나중에 발목을 잡힐 수 있다. 특히나 AngularJS에서 그런 상황을 접할 수 있는데, 임의의 기능을 사용할 경우 코드를 uglify 하기 전에 ngmin을 사용해야 한다. 사실, uglify 한 자바스크립트는 개발용 자바스크립트와는 다르게 동작하기 때문에 여러차례 Sourcegraph(주로 컨덴츠를 제공하는 사이트)가 깨진 적이 있다.

그러나, 상황은 점점 더 좋아지고 있다. Gulp는 거대한 기능 향상을 가져왔다.

(4) 느리고 신뢰할 수 없는 테스트

자바스크립트만 있는(Javascript-only) 웹사이트를 테스트하기 위해서는 Selenium, PhantomJS, WebLoop와 같은 브라우저 기반의 테스트 프레임워크를 사용할 필요가 있다. PhantomJS를 제외하고 대개 이러한 테스트 프레임워크를 설치하기 위해서는, (최근 업데이트된 PhantomJS 빌드는 이러한 사전 요구사항들을 제거하기 했지만) Xvfb를 설정한 후 WebKit과 자바 의존성(dependencies)을 인스톨해야 하고, 아마도 테스트를 위해서 로컬 VNC 클라이어트와 서버를 실행해야 할 것이다. 최종적으로, 또한, CI(continuous integration) 서버 상에 이 모든 것을 설정해야 할 필요가 있다.

대조적으로 서버단에서 생성된 페이지를 테스트하는 것은 대개 URL을 불러와서 HTML을 파싱하는 라이브러리만 필요한데, 이것들은 설치하여 설정하기가 훨씬 간단하다.

브라우저 테스트 작성을 시작한 경우, 비동기적 로딩을 처리해야만 한다. 즉, 아직 로드되지 않는 페이지 요소에 대해서는 테스트를 할 수 없으며, 주어진 시간내에 로드되지 못하면, 테스트 실패하게 된다. 이러한 문제를 해결하기 위해서 브라우저 테스트 라이브러리는 헬퍼(helper) 함수를 제공해 주지만, 그 마저도 복잡한 페이지에서만 제법 도움이 될 수 있다.

(Selenium과 파이어폭스 또는 WebKit를 조합하는) 과중한 브라우저 테스트 장비들과 (브라우저 테스트시 비동기적 로딩 문제로 인한) 훨씬 더 복잡한 테스트 환경을 함께 구축할 때 얻는 것을 뭔가? 테스트는 더 많은 설정이 필요할 것이고 실행시 더 많은 시간이 걸릴 것이고, 훨씬 더 신뢰할지 못할 것이다.

(5) 느린 속도를 문제시 하지 않고 덮어 둔다.

(AngularJS, Backbone, Batman, CanJS, Ember, Meteor, Knockout, Spine 등과 같은) 리치 자바스크립트 어플리케이션(rich javascript applications)에서는, 페이지 전환이 대개 즉각적으로 일어나고 페이지 상의 모든 요소들은 서버로부터 비동기적으로 로드 된다. 서버측 어플리케이션에서는, 일반적으로 이와 반대이다. 즉, 모든 데이터가 서버단에서 로드되어야만 페이지가 클라이언트로 보내지게 된다.

이 말은 클라이언트단 어플리케이션의 승리 같아 보이지만, 사실은 멋지게 변장한 저주일 수 있다.

사용자가 링크를 클릭한 직 후 페이지를 로딩하는 모습을 보여 주는 클라이어트단 자바스크립트 어플리케이션을 생각해 보자. 로드되는데 5초 정도 걸리는 데이터를 심어 놓은 사이드바를 가진 페이지로 이동한다고 가정해 보자. 초면에는 빠르게 느껴지지만 사이드바에서 정보가 필요할 때는 사이트가 엄청나게 느리다고 느끼게 된다. 원하는 특정 컨텐츠를 즉각적으로 로드하고 싶어도, 스핀 로딩 이미지와 페이지에 데이터가 로드된 직 후에 나타나는 지터링(jitter) 현상을 여전히 감수해야만 한다.

특정 페이지에 새로운 기능 추가를 원하는 개발자가 있다고 가정해 보자. 이 기능이 빠르게 로드되어야 한다(모든 것이 비동기적인 상황에서)것은 논할 필요가 없는 것이어서, 페이지의 하단에 있는 어떤 내용이 몇 초 늦게 로드될 꺼라고 누가 걱정하겠는가? 그래서 몇번이고 반복해서 결국은 전체 사이트가 느려지고 지터링이 느껴지기 시작한다.

서버측 어플리케이션에서는, 특정 API 호출이 느려질 경우, 전체 페이지가 호출이 완료될 때까지 차단될 것이다. 서버측 속도를 측정하는 것이 더 쉽고 서버측 속도 저하는 모든 사람에게 똑 같이 영향을 미치기 때문에 서버측 속도 저하 문제는 무시할 수 없는 것이다. 그러나, 클라이언트측 자바스크립트 어플리케이션에서는 속도저하를 무시하는 것이 더 쉬운 일이다.

훌륭한 개발팀은 이러한 실수들을 피해야 한다고 주장할 수 있고, 클라이언트 측 자바스크립트 프레임워크가 원인이 아니라고 주장할 수 있다. 맞는 이야기지만, 클라이언트 측 자바스크립트 프레임워크는 속도저하의 비용을 겨우 조금 줄여 준다. 이것으로 개발팀의 인센티브가 변경되기도 한다.

최효성

Comments