링크드인 아이패드앱 개발 후기

링크드인에서 아이패드앱을 개발한 후기를 공개했습니다.
모바일 웹 개발자로써는 정말 많은 것들을 배울 수 있는 글인데요,
한번 정리해 봤습니다.

링크드인 아이패드앱은 HTML5, backbone.js, underscore.js 를 사용해서 만들어졌습니다.

핵심 기능 중에 하나가 바로 무한 리스트인데요,
이 기능을 모바일에서 구현하기가 쉽지 않았다고 합니다.
모바일 디바이스는 메모리와 CPU가 작기 때문에 HTML에서 무한 리스트를 구현하면
자칫 디바이스가 뻗어버리는 현상을 겪게 됩니다.

규모가 있는 인터렉티브한 HTML5 앱을 만드는 것은 하나의 도전이죠.

긴 무한 스크롤 리스트를 만들기 위해서는 사실 Native 로는 UITableViewController를 사용하면
됩니다. UITableView에서는 재사용 가능한 UITableViewCells 들이 있고, 메모리와 CPU, 반응성 등이
최적화 되어 있습니다. 그런데 HTML5에서는 그러한 솔루션이 없다는 거죠.

UIWebView/Mobile Safari 는 엄격한 이미지 제한이 있습니다.
PNG, Tiff, Gif  이미지는 256MByte 메모리를 가진 디바이스 기준으로,
그 이하는 3Mbyte, 그 이상은 5Mbyte를 넘을 수 없습니다.
즉 1024*1024*3 정도 사이즈 이상은 256 Mbyte메모리 장치에는 올릴 수 없는 겁니다.
Jpeg은 디코딩해서 32Mbyte까지만 지원하며, Javascript는 10초 이상 걸리는 실행 스크립트는
실행이 되지 않게 되며, javascript의 총 메모리는 10Mbyte를 넘을 수 없습니다.

#1 이미지 언로딩 
HTML5 Canvas element에 이미지를 그리 수 있으나 매우 느립니다.
다른 방법을 고안해야 했었는데, 결국 이미지가 리스트에서 사라져서 스크린 밖으로
나갔을 때에 이미지의 src를 매우 작은 이미지로 교체하는 방법을 택했습니다.
이렇게 함으로써 이미지의 메모리 용량 문제를 해결했고, 빈이미지 src 문제도 해결했습니다.

#2페이지 숨기기
첫번째 팁인 이미지 언로딩이 앱이 뻗어버리는 문제를 완벽히 해결해주지는 못했습니다.
그래서 생각한 것이 Off Screen 된 엘리먼트에 대해서 visibility를 hidden으로 주는 것입니다. [그림참고]
이렇게 함으로써 더이상 앱의 메모리 문제가 발생하지 않았습니다.

#3 페이지 제거하기
페이지 invisible 셋팅이 80%의 use case를 소화해 내었습니다.  다만 아직도 앱이 가끔씩 뻗는 문제가
발생했습니다. 그래서 필요 없는 페이지들을 제거하기 시작했습니다.  [아래 그림 참고]

이렇게 하면 side effect가 발생하게 되는데, 왼쪽의 보이지 않는 페이지들을 제거하면 보여야할 페이지들이
왼쪽으로 붙어 버리는 현상이 발생하는 것입니다. 자연히 유저는 스크롤 포지션을 잃어 버리게 되는 것이죠.
따라서 제거된 페이지를 동일한 높이와 넓이를 가진 빈 Dom으로 대체하는 방법을 써야했었습니다.
이 Dom을 “stub”이라 불렀습니다.  [위 그림 참고]

언급된 세가지 기술들을 정리하면
유저가 페이지를 보고 있을 때에 스크린에 보여지는 페이지와 양 옆의 왼쪽, 오른쪽 화면 밖의
1페이씩에 대해서는 완전 로딩이 된 상태로 만듭니다. 유저가 양쪽 어느쪽으로든 움직이게 되면
이미 로딩 된 페이지가 보여지게 되고, 그 사이 또다른 페이지들을 로딩시켜 놓게 됩니다.

이 방법을 써서, 드디어 아이패드 시뮬레이터에서는 완벽하게 돌아갔습니다.
그러나, 실제 디바이스에서는 여전히 스크롤 Performance가 좋지 못했죠.

위쪽의 그림을 보면, 유저가  Page5를 보고 있을 때에 Page0, Page1은 stub으로 완전히 교체되어
제거 되었고, Page2는 invisible 상태, Page3은 이미지가 완전 unloaded된 상태가됩니다.
이 상태에서 유저가 앞쪽으로 스크롤 하게 되면, 보여지는 페이지로부터 얼마나 멀리 떨어져 있느냐
에 따라서 unload images/hide/remove 의 동작을 하게 됩니다.

아이패드 1의 경우에는 매우 적은 메모리를 가지고 있기 때문에 아이패드 2와는 달리
미리 로딩되는 페이지를 다르게 셋팅했습니다.

#4 이미지 리사이즈와 Box shadowing 을 피하라
추가로 퍼포먼스에 영향을 주는 CSS/HTML 최적화 두가지를 했습니다.
– 클라이언트 쪽에서의 HTML Img 태그의 width, height를 리사이징 하는 것을 피합니다.
– CSS Box shadowing을 피합니다. (웹킷에서 매우 느립니다.)
#5 Dom 노드를 최소화 하라
위의 최적화로 말미암아 링크드인 앱이 뻗지 않게 되었을까요? 사실 그랬다면 좋겠지만, 실제로는
그렇지 못했다고 합니다. 간간히 뻗었죠. 아이폰 앱을 개발해 본 경험상 Dom 갯수를 최소화 시키는 것이
메모리를 줄여 준다는 것을 알고 있었습니다.
그래서 우리는 Dom을 합치기 시작했습니다. 그 결과 우리가 아무리 많은 리스트를 좌우로 움직여 봐도
전혀 뻗지 않는 대단한 앱을 완성하게 되었습니다. [그림 참고]

완성된 앱의 동영상입니다. 디버그 창에서 UL 아래쪽에 있는 li 태그들의 수가 유지가 되고,
첫번째 li 아이템의 사이즈가 동적으로 변하는 것을 눈여겨 보세요.

마치며…
저 또한 회사에서 이와 비슷한 일을 하다보니, 이번 튜토리얼을 매우 재미있게 읽었습니다.
링크드 인의 이번 튜토리얼은 많은 모바일 웹을 개발하는 개발자들에게 Insight를 던져줄 것입니다.

국내에서도 갖다 붙이기 씩의 얇팍한 블로그들만 득실대지 말고,
이런 좋은 튜토리얼을 공유하는 장들이 많이 있었으면 좋겠네요.

원문 : http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5