웹의 진화는 정말 빠릅니다. 웹으로 할 수 있는 게 점점 더 많아진다는 것은 웹 개발자들에게는 즐거운 일입니다.

요즘은 웹의 단점을 보완할 수 있는 기술들도 점점 더 진화하고 있습니다.

처음 HTML5가 발표됐을 때만 해도, 웹에서 직접 동영상을 실행할 수 있다는 것만 해도 꽤 놀라운 일이었습니다.
HTML5 이전에는 웹에서 동영상을 실행하려 해도, 꽤나 많은 코드가 필요하곤 했고, 툭하면 관련 스크립트가 작동을 멈추면서 사용자에게 ‘스크립트를 계속 실행하시겠습니까?’ 하는 불쾌한 메시지를 던지기 일쑤였습니다.
그것을 피하려면 사용자가 직접 동영상 프로그램을 다운받아 설치하도록 유도해야 했죠.

하지만, 지금은 사용자 경험을 향상시킬 수 있는 강력한 브라우저 API가 매우 많습니다.

백그라운드 동기화 API, 알림 API 등을 이용하면 브라우저를 띄우지 않았을 때도 서비스워커로 작업할 수 있습니다. 사용자가 스마트폰을 주머니에 둔 사이에, 또는 브라우저를 끄고 컴퓨터 앞에서 자리를 비운 사이에도 데이터를 동기화하고 웹사이트 방문자에게 알림을 보낼 수 있습니다.

“어? 그건 웹이 아니라 네이티브 앱 아냐?”라는 생각이 들 수 있지만, 분명한 웹입니다.

위와 같은 최신 기능을 지원하는 웹사이트를 ‘프로그레시브 웹 앱’이라고 합니다.

프로그레시브 웹 앱

앱이라고 이름 붙여져 있지만 분명한 웹이고, 웹에 이런저런 기능들이 더해졌을 뿐입니다.

그래서 저는 이런 이름을 별로 좋아하지 않습니다. 앱이 아닌데도 앱이라고 이름 붙여서 혼동을 유발하거든요.

프로그레시브 웹 앱이라는 용어는 웹 디자이너인 프랜시스 베리먼(Frances Beriman)이라는 사람이 붙인 이름입니다.

그의 웹사이트에서 왜 이런 이름을 붙였는지 밝히고 있으니 심심하면 한 번 읽어봐도 좋겠네요.

프랜시스 베리먼은 프로그레시브 웹 앱이라는 용어는 “당신의 상사, 투자자, 마케팅 담당자를 위한” 것이며, “HTML5가 HTML과 별 관련이 없는 것처럼 마케팅 용어”라고 말합니다.

프로그레시브 웹 앱을 제대로 구현해 놓는다면 “다운로드에 대해 mb 당 비용을 지불해야하는 사용자, 낡은 폰을 가지고있는 사용자”들에게 설치형 앱과 유사한 경험을 줄 수 있습니다.

이 프로그레시브 웹 앱의 기술적 기반이 되는 것이 바로 서비스 워커입니다.(프로그레시브 웹 앱에 대해서는 다음 포스팅에서 더 자세히 다루겠습니다. 다뤄야 할 게 너무 많습니다.)

자바스크립트 워커

서비스 워커는 자바스크립트 워커(Javascript Worker)에 몇몇 기능을 더한 것입니다.

자바스크립트가 웹에서 실행되는 환경은 점점 좋아지고 있습니다. 브라우저의 자바스크립트 엔진이 빠르게 발전하면서 자바스크립트 실행 환경은 과거에 비해 비약적으로 좋아졌습니다.

하지만, 여전히 자바스크립트의 발목을 잡고 있는게 있는데, 그것은 자바스크립트 언어 자체의 특성입니다.

자바스크립트는 단일 스레드 언어입니다. 아무리 처리할 일이 많아도 한 번에 하나씩만 처리하죠.

대단히 복잡하고 큰 일을 처리하고 있다면, 다른 일들은 그 일이 다 끝날 때까지 마냥 대기 상태에 있습니다. 예를 들어, UI 이벤트를 처리하고 대량의 API 데이터를 쿼리 및 처리하고 DOM을 조작해야하는 사이트를 상상해보십시오. 불행히도 브라우저의 자바스크립트 런타임의 제한으로 인해 이 모든 것이 동시에 이루어질 수는 없습니다.

이런 병목현상을 해결하기 위한 대안으로 등장한 게 자바스크립트 워커입니다. 자바스크립트 워커는 현재 window와는 다른 전역 맥락에서 동작하는 워커 스레드에서 작동합니다.

Worker?

웹 브라우저에서 실행되는 자바스크립트는 일반적으로 브라우저 창에 출력되는 문서(DOM)를 다룹니다.
사용자가 이벤트를 입력하면 DOM에 변화를 주고, 화면도 갱신하죠. 우리는 자바스크립트와 DOM으로 이런 일을 해낼 수 있습니다.

하지만, 자바스크립트 워커로는 이런 일을 할 수 없습니다. 왜 그럴까요?

아래 사진은 1927년 독일 바이마르 공화국 시절에 만들어진 SF영화 메트로폴리스의 한 장면입니다. 영화를 공부하는 사람들에게는 꼭 봐야 할 고전 명작 중 하나죠.

Metropolice

메트로 폴리스의 지상 세계는 정말 화려합니다. 영원한 번영과 안락만이 있는 세계입니다. 이 세계는 DOM과 자바스크립트의 세계이기도 합니다. 이 세계에서 살아가기 위해서는 매우 많은 비용을 치러야 합니다.
하지만, 지상 세계는 혼자 굴러가지 않습니다. 지상 세계(DOM과 자바스크립트)의 사람들은 너무 느리고 게을러서 누군가가 그들이 하지 못하는 일을 대신해줘야 합니다.
바로 지하세계의 Worker(노동자)들 입니다.

Metropolice

지하 세계는 비참한 노동의 연속입니다. 그리고, 이들은 지상 세계로 올라올 수 없습니다. 지상 세계에 있는 DOM에 접근해서 컨트롤 하는 것도 당연히 할 수 없습니다.

지난 포스팅에서 말했듯이, DOM은 너무 느려서 개발자의 작은 실수만으로도 브라우저가 상당히 느려질 수 있습니다.
하지만, 상류세계인 DOM에 접근하지 못하도록 완벽히 차단된 환경에서 작동하는 스크립트가 있다면, 웹 브라우저는 기존 문서를 렌더링하는 동시에 이 스크립트를 병렬로 실행할 수 있습니다.
그래서, 지상 세계의 사람들은 지하 세계에 Worker들을 가둬놓고, 자신의 세계에 접근하지 못하게 합니다. 그리고, 부담스러운 일들을 모두 지하 세계로 넘겨버리기로 합니다.

서비스 워커

서비스 워커는 자바스크립트 워커와는 다른 독특한 능력이 있습니다. 앞에서 말씀드렸듯이, 서비스 워커는 자바스크립트 워커에 기능을 더한 것입니다.

웹 세상에서는 사용자가 URL을 입력하면 브라우저가 웹 서버에 요청을 보냅니다.

그런데, 만약 브라우저가 요청을 보내기도 전에 뭔가 작업하도록 지시할 수 있는 도구가 있다면 어떨까요? 서비스 워커는 바로 이것을 가능하게 해주는 도구입니다.

위의 지상세계와 지하세계의 예를 조금 더 확장해 봅시다. 지상 세계의 사람들은 자신들이 지하세계 사람들을 먹여 살린다고 생각할지 모릅니다. 하지만, 사실은 정반대입니다. 지하세계 사람들이 지상 세계의 사람들을 먹여 살립니다.

지하 세계의 사람들은 지상 세계의 사람들이 없이도 살아갈 수 있습니다.

브라우저가 해당 웹사이트에 접속해 자바스크립트를 다운로드 받고, DOM을 생성하기 전에 이미 서비스 워커는 작동을 시작합니다.

서비스 워커가 지상 세계인 DOM에 접근할 수 없는 또 다른 이유이기도 합니다. 서비스 워커가 실행될 때는 DOM이 존재하지 않습니다. 곧, 지상 세계 없이도 지하 세계의 서비스 워커는 자신의 일을 수행하는 것입니다.

서비스워커 개념도

보안 제약사항

서비스 워커는 마치 바이러스처럼 유저가 웹사이트에 방문할 때 브라우저의 백그라운드에 몰래 설치됩니다.

그 후에는 유저가 요청을 보낼 때마다 서비스워커가 먼저 요청을 가로챕니다. 일종의 프록시와 같은 구실을 합니다.

서비스 워커의 이런 특성 때문에 중요한 두 가지 보안상 제한 조건이 있습니다.

1) HTTPS 보안 프로토콜이 반드시 필요
- http 환경에서는 서비스 워커가 작동하지 않습니다.

2) 비 CORS는 실패함
- 기본적으로, CORS를 지원하지 않는 타사 URL에서 리소스를 가져오는 작업은 실패합니다.

브라우저 API 접근(fetch API, cache API)

서비스워커가 하는 일은 많지 않습니다. 하지만, 서비스 워커의 목적을 생각한다면 이게 당연합니다.

서비스 워커는 한다발의 기능 덩어리가 아니라, 개발자가 스스로 기능을 추가할 수 있도록 브라우저의 저수준 API에 대한 접근을 열어놓는 것입니다.

서비스 워커로 브라우저의 fetch API, cache API와 같은 저수준에서의 기능에 접근할 수 있습니다.

수십년 동안 fetch와 cache는 브라우저의 몫이었습니다. 하지만, 서비스워커 덕분에 개발자는 이 기능들을 마음껏 사용할 수 있게 되었습니다.

fecth API

자바스크립트는 이벤트를 감시하는 코드를 넣어놓고, 사용자가 이벤트를 발생하면 애니메이션을 재생하거나 서버에 요청하거나 하는 등의 일을 수행합니다.
서비스 워커도 마찬가지입니다. 이벤트를 감시하는 코드를 작성해 이벤트가 발생하면 즉시 실행합니다.
다만, 서비스 워커는 사용자가 발생시키는 이벤트가 아니라, 브라우저의 이벤트를 감시합니다.
브라우저 역시 특별한 일을 할 때 이벤트를 발생시킵니다. 브라우저가 하는 일은 fetch(가져오기) 이벤트를 통해 이루어집니다.

예를 들어, 아래와 같습니다.

1) 브라우저 주소창에 URL이 입력될 때,
2) 이미지를 가져올 때,
3) css를 가져올 때,
4) 자바스크립트 파일을 가져올 때 등등……
….

fetch API 이벤트를 감시함으로써, 개발자는 그에 따른 기능들을 추가할 수 있습니다.

cache API

자주 수정되지 않는 파일들은 HTTP캐시에 저장됩니다.
HTTP캐시는 웹브라우저 성능 향상에 크게 도움이 됩니다.
하지만, 아쉬운 점도 있습니다. HTTP캐시는 하나의 큰 덩어리로 관리됩니다. 모든 웹사이트가 단 하나의 HTTP 캐시를 공유하기 때문에 저장 공간도 넉넉치 않습니다.

이 HTTP 캐시의 단점을 보완하는 것이 cache API입니다.(기존의 HTTP 캐시를 대체하는 것이 아닙니다! 기존 HTTP캐시는 그대로 사용합니다. 다만, 보완적으로 cache API를 사용하는 것입니다.)
캐시 API에서는 한 덩어리로 관리되는 HTTP 캐시와 달리, 항목을 좀 더 세밀하게 관리할 수 있습니다.
예를 들어, 이미지 전용 캐시와 스크립트 전용 캐시 등을 따로 나누어 관리할 수 있습니다.

fetch API와 cache API로의 접근 덕분에 서비스 워커를 통해 웹사이트의 성능을 향상시킬 수도 있습니다.

예를 들어, 특정 이미지를 캐시에 저장해 두고,

1) fetch API를 통해 브라우저의 이미지 요청을 감지하면,
2) 캐시에서 이미지를 꺼내주고,
3) 캐시에 이미지가 없으면 서버에 이미지를 요청
4) 이미지를 캐시에 저장

웹의 단점 중 하나는 접속할 때마다 관련한 파일을 일일이 다운받아야 한다는 것입니다.

인터넷 환경이 좋지 않거나, 데이터가 아까운 사용자에게는 꽤나 단점이 될 수 있죠. 서비스워커는 완벽하지는 않더라도 이에 대한 훌륭한 대안이 될 수 있습니다.

서비스 워커로 구현 가능한 기능

현재 서비스 워커로는 아래와 같은 기능을 활용할 수 있습니다.

1) 백그라운드 동기화 기능과
2) 푸시 알림 기능

앞으로 서비스 워커의 활용도는 더 늘어날 것 같습니다.

3) 주기적 동기화 기능
4) 지오펜싱 기능

백그라운드 동기화

백그라운드 동기화는 사용자가 안정적인 인터넷 연결 전까지 행동을 미루는 것입니다. 사용자가 오프라인 상태이거나, 브라우저를 닫은 상태에서도 데이터 전송 및 수신을 완료하도록 허용하는 것이죠.

예를 들어, 서버로부터 데이터를 수신 중 인터넷이 끊기거나 사용자가 브라우저를 닫더라도, 서비스워커는 여전히 작업중 중지하지 않고 대기 상태로 돌입할 수 있습니다. 다시 온라인 상태가 되면 데이터를 수신해 사용자에게 보여줍니다.

백그라운드 동기화 기능은 아래 영상을 참조할 수 있습니다.

푸시 알림 기능

푸시 알림

자신의 페이스북 계정에 들어가면 위와 같은 푸시 알림 허용 팝오버가 뜨는 경우를 볼 수 있습니다.

이때 ‘허용’을 누르면 브라우저에서 페이스북 페이지를 닫아도 브라우저로부터 “아무개가 회원님의 게시물을 좋아합니다”와 같은 메시지를 받을 수 있습니다.

이 기능은 서비스 워커를 활용한 것입니다. 서비스워커를 활용하면 브라우저를 닫아도 사용자에게 푸시 알림을 보낼 수 있습니다.

푸시 알림에 대한 더 많은 설명은 Joseph Medley의 글을 참조하실 수 있습니다.

참조

1) 《서비스 워커로 만드는 오프라인 웹사이트》제레미 키스, 웹 액츄얼리 코리아
2) https://developers.google.com/web/fundamentals/primers/service-workers?hl=ko
3) https://www.html5rocks.com/en/tutorials/workers/basics/
4) https://developers.google.com/web/updates/2015/12/background-sync?hl=ko
5) https://developers.google.com/web/updates/2015/03/push-notifications-on-the-open-web?hl=ko