제 트위터 계정인 http://twitter.com/outsideris로 접속하면 http://twitter.com/#!/outsideris로 리다이렉트 되는데 URL의 중간에 있는 #!를 해시뱅(HashBang)이라고 부릅니다.(저도 이번에 알게 되었네요.) 처음에 저 URL을 보았을때 상당히 찝찝했습니다. "이 보기 좋지 않은 URL은 무엇인가?"정도의 생각을 하면서 넘어갔던 같습니다.
저는 약간 웹 순수주의자에 가깝기 때문에 웹에 기본은 HTML이고 극단적으로 말하자면 요즘 같은 게임이나 지도같은 특이케이스 아니고 웹사이트라면 자바스크립트를 끈 채로도 동작할 수 있어야 한다고 생각합니다. 물론 그것을 지향점이라는 것이지 현실적인 어려움을 부정하는 것은 아닙니다. 여기서 현실적인 어려움이란 개발자나 관련자의 마인드나 기술 부족이나 일정관련된 문제등을 이야기 하는 것이고 위에 말한대로 다 하기 어려운 부분이 있지만 가능하다면 그렇게 되어야 된다고 생각합니다. 그런 부분에는 URL이 시맨틱해야 한다고 생각하는 것도 포함되어 있기 때문에 URL가운데 의미없는 #!가 들어가 있는 것은 눈에 영 거슬렸습니다. 그렇게 넘어갔다가 최근에 다른 글을 보다가 해시뱅에 대해서 많은 논의에 대한 글을 보게 되어서 관련 글들을 읽고보고 정리합니다.
해시뱅(#!)은 무엇인가?
해시뱅에 대해서 이야기 하기 전에 일반적인 웹사이트의 동작을 먼저 보겠습니다.
- 사용자가 브라우저에 http://twitter.com/outsideris를 입력합니다.
- 브라우저가 http://twitter.com/outsideris를 서버로 보냅니다.
- http://twitter.com가 가리키는 트위터서버로 이동이 됩니다.
- 서버는 /outsideris가 무엇인지 알기 때문에 적당한 HTML을 만들어서 클라이언트에게 리턴합니다.
- 사용자가 브라우저에 http://twitter.com/#!/outsideris를 입력합니다.
- 브라우저가 #뒤에 부분인 !/outsideris를 로컬에 저장하고 http://twitter.com/를 서버에 보냅니다.
- http://twitter.com가 가리키는 트위터서버로 이동이 됩니다.
- 서버는 루트페이지의 HTML을 대량의 자바스크립트 링크와 함께 클라이언트에게 리턴합니다.
- 브라우저가 자바스크립트를 실행시키고 /outsideris를 파싱해서 oustideris에 대한 데이터를 서버에 요청합니다.
- 서버에서 받은 데이터를 화면에 적절하게 뿌려집니다.
왜 해시뱅이 필요한가?
해시뱅이 필요한 이유는 단일 페이지 웹애플리케이션을 만들기 위해서입니다. 해시뱅을 사용하는 사이트들은 전통적인 웹사이트가 아닌 웹애플리케이션이라고 보아야 합니다. 자바스크립트의 성능이 급격히 증가한 이후에 페이지의 전체를 로딩하는 대신에 페이지를 딱 한개만 두고 자바스크립트 만으로 모든 메뉴를 다루는 것에 대한 요구사항가 생겼고 그것을 구현하기 위해서는 페이지가 갱신되지 않는 것이 중요한데 현재 기술로는 페이지 갱신없이 URL을 변경할 수 있는 방법이 없습니다. 그렇기 때문에 페이지 갱신없이 URL이 변경되는 것처럼 보이도록 하기 위해서 해시뱅을 사용하는 것입니다. 해시뱅에서 #뒤에 이는 부분을 fragment identifier라고 부릅니다.
기존의 레가시를 위해서 웹애플리케이션도 북마크할 수 있고 링크를 공유하고 검색엔진에 인덱싱 될수 있으려면 현재는 해시뱅이 없이는 불가능합니다. 해시뱅을 사용한 것은 전통적인 웹사이트의 레가시를 깨뜨리지 않으려는 절충안이라고 볼 수 있습니다. 현재 기술로써는 웹애플리케이션과 웹사이트를 동시에 지원할 수는 없기 때문에 어느쪽이든 한쪽을 선택할 수밖에 없는 것이었습니다. 해시뱅을 사용하고 있는 곳에서도 pushState같은 기술이 완전히 보급되어 웹애플리케이션과 웹사이트를 동시 지원할 수 있게 되는 것이 가장 좋다는 데는 이견이 없습니다.(현재 사파리, 크롬, 파이어폭스가 지원하고 있습니다.)
이는 과도기적인 기술입니다. HTML5의 Histroy API인 pushState가 모든 브라우저에서 지원이 된다면 보기싫은 해시뱅은 사용하지 않아도 되지만 현재 pushState는 일부의 브라우저에서만 지원이 가능한 것이기 때문에 그때까지 이같은 요구사항을 이뤄내기 위해서 해쉬뱅이라는 것이 도입된 것입니다. 해시뱅을 사용하는 곳에서도 해시뱅이 별로 이쁘지 않고 완벽하지도 않다는 것은 동감하지만 현실적으로 유용하다는 것입니다.
해시뱅은 웹에 좋지 않습니다.
해시뱅의 문제점은 단순히 이쁘지 않은 URL의 문제가 아닙니다. 이는 웹페이지가 아닌 자바스크립트 웹애플리케이션이기 때문에 자바스크립트가 동작하지 않으면 사이트전체가 동작하지 않습니다. 단순히 자바스크립트를 사용할 수 없는 환경에 있는 사용자 뿐만 아니라 어떤 문제로든 자바스크립트 파일이 제대로 로드되지 않는다면 사용자는 사이트를 전혀 이용할 수가 없습니다.(인터넷이 좋지 않은 환경등에서는 얼마든지 발생할 수 있는 일입니다.)
자바스크립트 로드문제 뿐만 아니라 스크립트 오류 혹은 흔히 실수하는 JSON에서 마지막 엘리먼트뒤에 콤마(,)를 찍는 단순한 실수로도 전체 웹사이트를 망가뜨릴 수 있습니다. 더군다나 웹사이트에 광고를 게제하는 경우 광고가 포함하고 있는 자바스크립트는 일반적으로 품질이 좋지 않기 때문에 이 자바스크립트로 인하여 웹사이트가 망가질 수 있습니다. 이는 컨텐츠가 자바스크립트와 아주 강력하게 커플링 되었음을 의미하는데 프로그래밍에서 커플링은 항상 좋지 않은 것으로 인식되어 왔습니다.
국내에서는 유명하지 않지만 Gwaker와 LifeHacker라는 사이트가 올 초에 해시뱅을 사용해서 리뉴얼하고 오픈하면서 이 잠재적인 문제로 사고가 크게 터졌었다고 합니다. 이전의 LifeHacker는 100만개의 페이지를 가진 사이트였지만 새로운 사이트는 100만개의 Fragment Identifier를 가진 하나의 페이지가 된 것입니다. (이유는 모르겠지만) 수시간동안 자바스크립트 파일이 로드되지 않았고 그 덕에 사용자들은 두 사이트의 어떤 컨텐츠에도 접속을 할 수 없었습니다. 이 장애가 해결되기 까지는 거의 하루가 걸렸던것 같습니다. 기존의 웹에 비해서 해시뱅이 깨지기 쉬운 웹이라는 것을 Gwaker와 LifeHacker가 몸소 보여준 격이 되었습니다.
또 다른 문제로는 크롤러의 문제가 있습니다. 크롤러는 검색엔진이 웹사이트의 내용을 알기 위해서 사이트의 컨텐츠를 긁어가는 봇인데 대부분의 크롤러는 HTTP 1.1과 URL 스펙(RFC-2396같은)을 따르고 있는데 이것을 따르는 크롤러는 자바스크립트를 실행시키지 않기 때문에 해시뱅으로 만들어진 사이트의 컨텐츠를 가져갈 수 없습니다. 크롤러가 보는 페이지는 내용이 없는 빈 페이지일 뿐입니다.
구글은 fragment idendifier URL을 변경하는 것으로 이 문제를 해결했습니다. 예를 들어 www.example.com/ajax.html#!key=value 와 같은 해시뱅 URL을 구글은 www.example.com/ajax.html?_escaped_fragment_=key=value와 같은 괴상한 URL로 변경이 합니다. 이렇게 변경된 URL은 실제 컨텐츠를 가리키는 URL이 되고(서비스 업체에서 그렇게 만들어야 겠죠.)구글을 이것을 색인합니다. 구글은 이것을 일반적인 앵커용도의 #과 웹애플리케이션에서 사용한 #를 구별하기 위해서 #뒤에 !를 붙혀서 웹애플리케이션 사이트들을 구별할 수 있도록 제시함으로써 해시뱅이 생기게 된 것입니다. 하지만 현재 구글봇만 색인이 가능하고 실제로 Gwaker와 LifeHacker가 문제가 생겼을때 구글 검색 및 여러 뉴스 사이트에서 Gwaker와 LiferHacker가 제외되었다고 합니다.
또한 이제 캐시를 제대로 할 수 없게 되었습니다. 중개서버가 이를 다룰 수 있는 방법이 없기 때문에 사이트는 모든 트래픽을 다루어야 합니다. 그리고 구글봇이나 웹브라우저 기반의 봇만 마이크로포맷의 데이터를 볼 수있기 때문에 마이크로 포맷을 비롯한 시맨틱 기술들이 잠재적으로 버려졌습니다. 페이스북의 Like 위젯같은 경우 페이지의 URL로 구분을 하기 때문에 글에 위젯을 달기 위해서는 추가적인 작업이 필요하게 되었습니다. 더군다나 이는 리퍼러도 깨뜨립니다. 리퍼러에는 fragment identifier가 넘어오지 않기 때문에 리퍼러를 보고 실제 방문자가 찾아온 원글을 찾아갈 수 없게 되었습니다.
결론
양쪽의 의견이 다 어느정도 합리적이라고는 보지만 저 같은 경우에는 해시뱅을 반대하는 입장입니다. 게임같은 경우가 아닌 트위터나 LifeHacker는(LifeHacker는 현재는 원래로 돌아간듯 합니다.) 페이지 설질상 애플리케이션보다는 컨텐츠의 성격이 강하기 때문에 애플리케이션을 선택한 것 자체가 그다지 좋지 않은 선택이었다고 생각하는 편입니다.
URL이 퍼머링크의 역할을 하는 것이나 검색의 중요성, 웹브라우저뿐만 아니라 모든 크롤러나 리더등도 내용을 문제 없이 읽을수 있어야 하는 것은 웹의 근본에 포함되어야 하는 것이기 때문에 설사 과도기적이라고 하더라도 이런 돌연변이 형태의 것이 생기는 것은 그다지 찬성할 수 없습니다.(각 서비스에 따라 다른 의견을 가질수는 있겠지만요.) 관련글들에서 본것 처럼 curl로 사이트의 정보를 얻을 수 없다면 그 사이트는 이미 깨진 것이라는 것에 동의하고 있습니다.
사실 구글도 해시뱅을 사용하고 있지는 않지만(아마 구글을 크롤링하는 곳은 없어서인지 몰라도) 그냥 #만을 사용해서 웹애플리케이션처럼 리뉴얼 되어있습니다. 그래서 현재 curl로 구글에 요청해서 검색결과를 받아올 수 없습니다. 얼마전에 검색결과를 가져와서 보여주는 예제 소스를 짜다가 이문제를 발견했었는데 그당시에는 원인도 자세히 몰라서 무척 고생한 기억이 납니다.
금융권이나 정부기관같은 한국형1 사이트들도 아닌 어느정도 웹의 사상등을 이해하고 있다고 생각하던 구글이나 트위터가 이런 선택을 했다는 것은 약간 실망스러운 부분입니다.
[참고 글]
Thoughts on the Hashbang
Breaking the Web with hash-bangs
Broken Links
Hash, Bang, Wallop.
- 여기서 한국형이란 웹의 사상을 전혀 이해하지 못한채 요구사항만으로 기술을 억지로 가져다 붙혀서 엉망으로 만들어버렸다는 의미로 사용했고 대부분의 한국형이란 말이 붙은 것들도 결과물을 보면 그다지 다르지 않다고 생각합니다. [Back]
좋은글 올리셨네요. ~~^^
해쉬뱅을 사내 관리프로젝트에 몇군데 사용중이지만,
기본적으로 저도 해쉬뱅은 반대입장이네요. ㅋ
구글에서 해쉬뱅을 크롤링 하기 위한 정책이 황당하더군요. ㅋ. 이에 맞추어 검색결과에 나오기 위해서는
해쉬뱅에 연결되는 Static 페이지또한 만들어야하고요. ㅋ.
암튼 설명을 자세히 하셔서 .. 그럼 수고하세요.~~
평소에 궁금하던거라 날잡아서 찾아보고 정리했네요....
알아보고 나니까 더 맘에 안들어졌습니다. 더 퍼지기 전에 빨리 pushState문제가 해결되었으면 좋겠습니다.
누군가의 고민이나 생각이 담긴 글은 언제나
단순 정보성 글보다 훨씬 몰입하여 읽게 되네여.
(그동안 몰입 안 했다는 의미일지도;;;)
글 본지는 꽤 됐지만 격무에 시달리느라 뒤늦게 답글 달아 봅니다.
여러글의 내용을 모아모아.. ㅡㅡ;;
바쁜건 좀 괜찮아지셨는지...
결국 또 속았;;;;
앗;;; 머가 속아요?
#!를 어쩔수 없이 사용했더니 이게 해시뱅이란 거 였군요.
이런 과도기적인 기술을 택했던이유는 분명히 있을거라 생각이 됩니다.
저또한 브라우저 리소스관리 측면이나, 자바스크립트의 안정성에 대한 불신등이 고정관념으로 자리잡혀 이런 통짜싸이트를 구축하는건 절대 안된다는 입장이었는데 막상 해보니 여러가지 우려했던 부분들이 현재 기술로 다 풀린다는걸 깨달았습니다. 물론 UI 아키텍처를 설계하는 전문가가 있어야한다는 전재조건이 있어야하지만 앞으로 HTML5가 일반화된다면 이러한 부분까지 모두 커버가 될꺼라고 생각합니다. 이런 과도기때 미래기술이될 표준웹의 UI 아키텍처 방법론을 먼저 선점한다면 미래를 봤을때 해당기업의 엄청난 가치의 기술적 자산이 될거라 생각이 됩니다. 세계의 웹기술을 선도하는 구글과 페이스북에서의 이러한 행보는 아주 적합하고 잘하고 있다고 생각이 됩니다. 지나가는 행인이 딴지한번 걸어봤습니다. ^^
^^ 딴지는 아닌듯 하지만 딴지도 환영합니다. ㅎ
저도 과도기적인 기술을 무조건 반대하는 것은 아니고 불필요하게 사용하는 것에 반대할 뿐입니다. 말씀하신대로 필요한 이유가 있기 때문에 아키텍쳐상 필요하다고 여러 조건을 고려한 후에 적용할 수 있다고 생각합니다.
관련된 스터디를 하고 있었는데 귀한 글 잘 봤습니다. :)
안녕하세요 이고잉님 ^^ 방문해 주셔서 감사합니다. 이고잉님도 한번 뵈야하는데 ^^
앵귤러를 공부하다가 #!이 도대체 먼지 찾던중 찾았습니다.
블로그에 참고하여 포스팅했습니다. :-)
감사합니다.
SPA 쓰면 어쩔수 없으면서도 애매한 녀석이죠. 큰 서비스 아니면 저는 보통은 #!는 버리고 가려고 하지만요 ㅎㅎ
글 감사합니다.
angularjs 로 만들어진 사이트에 현재
$http.get으로 데이터 가져온 뒤 뒤로가기 버튼 실행시
이전페이지로 이동되게끔 하는 부분을 처리할려고 하는데요.
많이 생각하게 만들어주는 글 같습니다.
네 angularjs에는 html5mode 도 있긴 하지만 관련하신 내용은 push state쪽을 보시면 정보를 얻으실 수 있을 겁니다.
아... 이런 글이 2011년에 쓰여졌군요. 정말 많은 도움이 되었습니다.
요즘은 해시뱅을 많이 못본것 같긴 하네요.