본문으로 건너뛰기

막간: Javascript는 더 이상 Java가 필요하지 않다

원래 Javascript는 Java를 보조하는 스크립팅 언어로 구상되었다. 그리고 모든 복잡한 프로그래밍 작업들은 Java를 사용해서 수행될 걸로 예상되었다. 하지만 Javascript 경험이 쌓이면서 웹 개발자들은 그들이 진짜로 필요했던 게 Javascript라는 것을 깨닫기 시작했다.

13.1. Javascript 전도사(The Evangelist)

브라우저에서의 JavaScript 사용이 증가함에 따라, JavaScript 교육자와 전도사들이 등장했다. 그중 가장 영향력 있는 인물 중 한 명은 Douglas Crockford였다. 그는 소프트웨어 개발 커뮤니티에서 JavaScript에 대한 인식을 바꾸는 데에 큰 역할을 했다. "JavaScript: 세계에서 가장 오해받는 프로그래밍 언어" [Crockford 2001a]라는 짧은 온라인 에세이로 시작된 일이었다. 또 다른 에세이에서 Crockford [2001e]는 다음과 같이 설명했다.

Javascript가 처음 나왔을 때 나는 Javascript가 내 관심을 끌 만한 가치가 없다고 생각했다. 많은 시간이 지나서 난 다시 Javascript를 살펴보게 되었는데 그때서야 나는 브라우저 속에 숨겨져 있는 이 언어가 훌륭한 프로그래밍 언어임을 알게 되었다. 처음의 내 관점은 Sun과 Netscape가 초기 Javascript에 대해서 이야기한 많은 잘못된 진술들에 기반해 있었다. Sun과 Netscape는 Javascript가 Java의 경쟁자로 보이지 않도록 하기 위해 여러 잘못된 진술을 하고 말았다. 그런 잘못된 진술들은 아마추어 시장을 겨냥한 수많은 형편없는 Javascript 책들에서 계속 메아리친다.

Douglas Crockford [2001d; 2002a; 2003; 2006]는 JavaScript의 Scheme과 비슷한 클로저와 Self와 비슷한 객체 모델을 알렸고 어떻게 사용하는지 사람들에게 설명했다. 하지만 그는 Javascript의 단점과 별난 부분들을 얼버무리고 넘어가지 않았다. Crockford[2001e; 2002d]는 그런 단점과 별난 부분들을 식별할 뿐 아니라 그것들을 고쳐주는 JSLINT를 만들고 홍보하였다. 이는 최초의 널리 사용된 Javascript linter1 유틸리티였다. Crockford [2001c; 2019b]는 또한 Javascript 개발자들에게 minimization2 개념을 소개하고 JSMIN 유틸리티를 만들었다. JavaScript의 좋은 부분만 사용하고 나쁜 부분을 피하는 방법을 알려주는 베스트셀러[Crockford 2008b]를 쓰기도 했다. 결국 그는 Javascript 표준화 활동에 참여하게 되었다.

Crockford는 단순함을 옹호했다. 그리고 Javascript의 객체와 배열 리터럴 문법의 일부를 언어와 독립적인 데이터 교환 포맷으로 사용함으로써 XML의 복잡성을 해결할 수 있다는 것을 깨달았다. 그는 이 널리 채택된 포맷을 "JavaScript Object Notation" 또는 "JSON" [Crockford 2002b,c; Crockford 2019a]이라고 명명했다. 이 간단한 포맷은 어떤 언어에서도 쉽게 파싱될 수 있었다. 특히 JavaScript에서는 eval 함수가 JSON 데이터 레코드를 JavaScript 객체로 변환할 수 있어서 JSON을 다루기가 특히 쉬웠다.3

13.2. 풍부한 인터넷 응용 프로그램과 AJAX(Rich Internet Applications and AJAX)

초기의 대화형 웹 애플리케이션은 주로 폼(form) 기반으로 이루어졌다. 사용자들이 HTML 폼에 데이터를 입력하면 브라우저는 그 데이터를 웹서버로 보냈고 웹서버가 그 데이터를 처리하면서 데이터베이스를 업데이트했다. 그 다음 업데이트된 HTML 프레젠테이션이 브라우저로 다시 전송되어 보여졌다. Javascript는 브라우저 측에서 기본적인 입력 데이터 유효성 검사와 서버가 생성한 HTML의 간단한 동적 변경을 위해 사용되었다. 이러한 스타일의 웹 애플리케이션은 이후 Web 1.0이라고 불리게 되었다4.

일부 웹 애플리케이션은 사용자와의 상호 작용이 매우 많았고 따라서 지연 시간이 짧은 사용자 인터페이스를 요구했다. 이런 상황에서 일부 개발자들이 지연 시간이 짧은 웹 애플리케이션을 개발하려고 하는 것은 당연했다.

1995년 Netscape가 자사 웹 브라우저에 Java, Javascript를 둘 다 도입했을 때 원래 계획은 Java가 복잡한 대화형 웹 애플리케이션 구현을 위한 주요 언어가 되고 Javascript는 주로 form 기반 애플리케이션에 사용되는 언어가 되는 것이었다[Shah 1996]. 1990년대 후반과 2000년대 초반에 많은 "풍부한 웹 애플리케이션" [Allaire 2002]이 Java 애플릿으로 구축되었다.

1997년 Microsoft는 기업용 이메일 클라이언트의 웹 버전을 출시했다. Outlook Web Access (OWA) [Bilic 2007; Van Eaton 2005]는 Web 1.0 스타일의 애플리케이션으로 구현되었다. OWA 1.0은 동적 HTML(Dynamic HTML5)과 새로운 브라우저 API인 XMLHTTP [Hopmann 2006]를 사용하는 더 풍부한 버전으로 이어졌다. XMLHTTP는 웹 페이지를 완전히 다시 로딩하는 과정 없이도 웹 페이지의 Javascript 코드가 서버와 비동기적으로 데이터를 주고받을 수 있게 해주었다. DHTML과 XMLHTTP의 조합은 웹 페이지가 세션당 한 번만 로드되고 이후에는 데이터와 서비스에 원격으로 접근하는 대화형 애플리케이션으로 작동하게 만들어 주었다.

2000년대 상반기 동안 다양한 조직들이 이런 기술 혹은 유사한 기술들을 사용하여 웹 애플리케이션을 구축했다. 하지만 이런 웹 애플리케이션 스타일은 구글이 GMail, Google Maps와 기타 애플리케이션들을 구축하는 데 사용하기 전까지는 널리 알려지지 않았다. Jesse James Garrett [2005]은 이러한 스타일을 설명하기 위해 “AJAX”라는 용어를 만들었다. AJAX와 이를 사용하여 구축된 소셜 미디어 애플리케이션은 Web 2.0g 시대의 특징이 되었다.

Web 2.0과 AJAX의 등장은 Javascript가 웹 개발에서 하는 역할에 있어서 중요한 전환점이었다. Javascript는 원래 정적인 페이지에 동적인 요소를 추가하는 역할을 하는 언어였다. 그런데 이제는 다채로운 인터넷 애플리케이션을 작성하는 것으로 Javascript의 역할이 변화하고 있었다.

동시에 브라우저 생태계는 점점 더 복잡해지고 있었다. 시장 점유율이 매우 낮은 다양한 대체 브라우저들이 언제나 존재했다. 이는 브라우저의 주요 개발 업체들이 브라우저의 활발한 개발을 서서히 포기함으로써 가능해졌다. Netscape는 AOL에 의해 인수된 이후 브라우저 개발을 포기해 갔으며 Microsoft는 시장 지배를 달성한 이후 그리했다. 이런 상황은 새로운 브라우저들이 등장할 기회를 만들어냈다. Firefoxg6 [Mozilla 2004], Operag [Opera 2013], Apple Safarig [Melton 2003] 그리고 마지막으로 Google Chrome[Kennedy 2008] 등이 점차 의미 있는 시장 점유율을 얻게 되었다.

새로운 브라우저들은 모두 각자의 해석에 따라 ES3 JavaScript 명세와 W3C에 의해 부분적으로 명세된 브라우저 플랫폼 API를 구현했다. 하지만 플랫폼 명세는 불완전하거나 엄밀하지 않았다. 대부분의 새 브라우저들은 플랫폼 API를 다양한 방식으로 확장하거나 수정했다. 이 새로운 브라우저들이 등장하는 동안에도 많은 사용자들은 버그가 많고 최신 언어 기능과 플랫폼 API를 지원하지 않는 구버전 Internet Explorer와 Netscape를 사용하고 있었다.

웹 브라우저는 한 가지 중요한 점에서 대부분의 다른 애플리케이션 플랫폼과 다르다. 애플리케이션은 사용자의 환경에서 즉시 실행할 수 있는 소스 코드 형태로 배포된다. 이런 방식은 개발자가 특정 버전의 컴파일러와 런타임 라이브러리를 선택하고 애플리케이션을 빌드하고 테스트한 후 이진 파일 형태로 사용자에게 배포하는 전통적인 시나리오와 다르다. Douglas Crockford7는 여러 강연에서 웹 개발의 이런 부분들을 다음과 같이 특징지었다. "사용자가 언어 프로세서를 선택한다(보통 관련 지식 없이 말이다)" 웹 개발자는 사용자가 어떤 브라우저를 선택하든 간에 그 브라우저에서 그들이 만든 웹 페이지와 웹 애플리케이션이 잘 작동하도록 보장해야 했다.

브라우저간의 차이를 다루는 한 가지 방법은 각각의 호환되지 않는 브라우저마다 애플리케이션의 별도 버전을 만드는 것이다. 웹 서버는 웹 페이지를 요청할 때 브라우저가 제공하는 식별 정보를 기반으로 각각의 브라우저마다 다른 버전의 페이지를 전송할 수 있다. 하지만 일반적으로 대부분의 애플리케이션 소스 코드는 모든 버전에서 공유되며 브라우저 차이를 처리하기 위한 작은 변형만이 존재한다. 이는 애플리케이션의 여러 버전(거의 서로 비슷한)을 유지보수하는 개발 및 운영상의 도전을 만든다.

애플리케이션 소스 코드의 여러 구분된 버전을 관리하는 어려움을 피하는 다른 방법도 있다. 애플리케이션이 단일 소스 파일을 가지고 있으면서 해당 애플리케이션이 브라우저 내에서 실행되는 동안 브라우저별 특수한 변형이 파일 내에서 동적으로 선택되도록 하는 것이다. 이런 브라우저별 변형들은 브라우저 스니핑(특정 브라우저 버전 식별) 또는 기능 테스팅(특정 기능 또는 버그의 존재 식별)을 수행하는 관용적인 코드 시퀀스를 사용하여 선택된다.

브라우저간의 호환성에 더해진 AJAX 스타일 애플리케이션의 복잡성 문제는 웹 애플리케이션 구축을 단순화하기 위한 애플리케이션 프레임워크와 라이브러리의 출현으로 이어졌다. 초기 프레임워크에는 Prototype [Stephenson et al. 2007], MooTools [Proietti 2006], Dojo [Russell et al. 2005]등이 있었다. 가장 널리 채택된 것은 jQuery[Resig 2006]였다 [W3Techs 2010]. 이런 초기 프레임워크와 라이브러리들은 일반적으로 AJAX 스타일 애플리케이션에 대한 구조를 제공했다. 그리고 그런 애플리케이션이 자주 수행하는 작업의 코드 작성을 단순화할 수 있게 하는 고급 추상화도 제공했다. 또한 브라우저의 기능적인 다양성들을 숨기고 내부적으로 다룸으로써 많은 상호 호환성 이슈를 해결했다.

특정 종류의 라이브러리는 매우 중요해서 그런 라이브러리들을 부르는 새로운 단어도 만들어졌다. "폴리필g"이라는 단어는 Remy Sharp [2010]에 의해 만들어졌는데 브라우저에 의해 제공되어야 하지만 빠져 있는 API를 제공하는 라이브러리를 부르는 데 쓰인다. 잘 설계된 폴리필의 경우 폴리필이 제공하는 기능이 이미 사용 가능한지를 동적으로 확인하고 해당 기능이 내장되어 있지 않거나 호환되지 않는 경우에만 자체적으로 설치된다. 초기의 폴리필 라이브러리들은 초기의 브라우저 경쟁 과정에서 이어져온 레거시 기능 변형들을 숨기거나 오래된 브라우저에서 새 브라우저 기능들을 지원하게 함으로써 브라우저들을 더 상호 호환 가능하도록 만드는 데에 초점을 두었다. 한 유명 브라우저에서 존재하지만 다른 브라우저에는 없는 기능이 있을 경우 폴리필은 웹 애플리케이션이 모든 브라우저에서 동일한 코드를 사용하여 해당 기능을 사용 가능하게 해줄 수 있다. 브라우저들의 상호 호환성이 개선되어 감에 따라 폴리필은 새로운 브라우저의 기능이나 새로운 Javascript의 기능에 대한 얼리 액세스를 제공하는 방법으로 일반적으로 사용되게 되었다. 또한 새로운 기능을 설계하는 과정에서 해당 기능의 폴리필 라이브러리를 만드는 것이 일반적이 되었다. 폴리필 사용은 개발자들에게 유용했을 뿐 아니라 새로운 기능과 API 디자인에 관한 귀중한 개발자 피드백을 만들었다.

독립적으로 짜인 여러 코드 조각들을 단순하게 결합하는 방식으로 Javascript 애플리케이션을 만들 경우 이름 충돌이 흔히 발생했다. 많은 프레임워크와 라이브러리가 일종의 모듈성 메커니즘을 제공했다. 이런 메커니즘은 일반적으로 네임스페이스 객체와 즉시 실행 함수 표현식(IIFE8)을 사용해서 구성되었다. 네임스페이스 객체는 함수나 변수에 대한 한정된 이름 접근을 제공하는 것이 주요 목적인 싱글톤 객체이다. JavaScript 1.0의 내장 Math 객체가 네임스페이스 객체이다. 네임스페이스 객체의 한계점은 네임스페이스의 모든 이름이 public이라는 것이다. 이 한계점은 네임스페이스 객체를 모듈 패턴의 IIFE와 결합하여 사용하는 것으로 극복할 수 있다. 그림 22에서 그 예시를 볼 수 있다.

모듈 패턴은 여러 변형이 있다. 하지만 기본 개념은 IIFE(혹은 어떤 경우에는 named function)의 렉시컬 스코프를 사용하여 일부 private 상태와 함수들을 캡슐화하는 것이다. IIFE는 네임스페이스 객체를 반환하는데, 이 객체는 public하게 접근 가능해야 하는 캡슐화된 함수들을 속성으로 가진다.

Douglas Crockford가 모듈 패턴을 대중화시킨 사람으로 불릴 때가 많지만 모듈 패턴은 다른 많은 Javascript 프로그래머들에 의해 각각 독립적으로 만들어졌을 걸로 예상된다.

// 모듈 패턴을 사용해서 Services 정의
var Services = function() {
var privateJobCount = 0; // "모듈"의 private 변수
return { // namespace 객체를 반환
jobCount: function { return privateJobCount },
job1: function() { this.jobCount++ }
}
}(); // Services는 함수의 호출 결과로 초기화된다

// namespace 객체의 엔티티 접근
Services.job1();
console.log(Services.jobCount()); // 1을 출력해야 한다

그림 22. Javascript 모듈 패턴의 예시. Services 함수는 내부 구현을 캡슐화한다. Services 함수는 호출된 시점에 초기화되고 "모듈"의 공개 인터페이스를 외부에 노출하는 용도의 네임스페이스 객체를 반환한다.

13.3. 브라우저 게임 이론(Browser Game Theory)

브라우저 전쟁g[Borland 2003] 동안 Netscape와 Microsoft는 새로운 웹사이트 기능 도입의 영역에서 서로를 능가하는 혁신을 하려고 노력했다. 두 회사 모두 각자의 고유한 기능들을 사용하도록 개발자들을 설득하려고 했으며 "[XXX]에서 가장 잘 작동합니다"라는 마케팅 캠페인을 벌였다. 하지만 브라우저 사용자들은 자신이 선호하는 브라우저에서 웹사이트가 제대로 작동하지 않을 때 짜증을 냈다. 그리고 웹 개발자들도 다양한 브라우저를 지원하기 위해서 사이트의 여러 버전을 만들어야 하는 걸 좋아하지 않았다.

Microsoft는 Netscape의 시장 점유율을 빼앗기 위해서 기술적인 수단과 비-기술적인 수단을 가리지 않고 많은 투자를 하고 있었는데, 그동안에도 Javascript의 진화를 위해서는 경쟁뿐 아니라 협력도 필요하다는 인식이 있었다. 1997년 7월의 TC39 회의에서는 ECMA-262의 첫 번째 판 작업이 거의 완료되어 가고 있었는데 그때 Microsoft의 Scott Wiltamuth는 향후 ECMAScript 개발에 대한 협력 서약(그림 23)을 발표했다.

Brendan Eich는 언젠가부터 시장 논리가 브라우저 구현자들로 하여금 제품의 개선을 위해서 할 수 있는 것들을 심각하게 제한한다는 것을 깨달았다고 회상한다. 예를 들어 이런 부분들이 있었다.

  • breaking change(버그 수정조차도)는 사용자들을 떠나게 할 수 있다.
  • 새로운 브라우저는 기존의 브라우저들의 형식에 맞추어야 한다.
  • 딱 하나의 브라우저에서만 일어나는 혁신은 헛된 일이다.
  • 뭔가 새로운 것을 시도하는 브라우저는 시장 점유율을 잃기가 쉽다.

Eich는 이 상황이 아마 내쉬 균형[Nash 1950] 상태임을 인식했다. 그리고 브라우저 구현자들이 겪고 있는 이러한 제약 상황들에 "브라우저 게임 이론"이라는 단어를 붙였다.

첫 번째 제약은 때때로 "웹을 깨뜨리지 마라!"라는 구호로 표현된다. 웹 페이지는 일반적으로 HTML과 Javascript 소스 코드의 형태로 서버에 저장되며 이 코드들은 사용자가 페이지에 접근할 때마다 브라우저에 의해서 다시 해석된다. 많은 페이지들이 그 제작자에 의해서 유지보수되지 않지만 여전히 활발하게 사용된다. 몇몇 페이지들은 지속적인 유용성을 갖거나 역사적인 중요성을 갖는 문서들이다. 브라우저가 소스 코드를 해석하는 방식에 이전 방식과 호환성이 없는 변경 사항(breaking change)이 생기면 페이지가 읽을 수 없어지거나 작동하지 않게 될 수 있다. 만약 그런 변경 사항이 하나의 브라우저에서만 생겼다면 사용자는 다른 브라우저로 전환해야 할 수도 있다. 만약 그 변경사항이 브라우저들 간에 널리 퍼졌다면 유지보수되지 않는 일부 웹 페이지들은 영구적으로 손상될 수 있다. 이 사실은 웹 표준을 만드는 사람들에게도 제약을 가한다. 새로운 기능을 도입하거나 변경을 강제하는 표준이 브라우저 구현자들에게 무시될 수도 있기 때문이다. 만약 브라우저 구현자들이 보기에 새로운 표준이 중요한 기존 웹 컨텐츠를 무효화할 것 같다면 그들은 그 표준을 무시할 것이다.

오늘날의 브라우저 개발자들은 단독 플랫폼의 혁신을 통해서 경쟁하는 것이 제한적이라는 것을 일반적으로 이해하고 있다. 웹의 상호 호환성에 대한 요구사항과 개방형 표준 기반 때문이다. 브라우저는 성능, 보안, 신뢰성, 사용성과 같은 구현 품질의 영역에서 경쟁할 수 있고 실제로 그렇게 한다. 그러나 브라우저 애플리케이션 플랫폼의 기본적인 기술적 수준을 발전시키는 것은 일반적으로 모든 주요 브라우저들 간의 협력을 필요로 한다.

다른 방식으로 작업하기
ECMAScript 표준에 대한 Microsoft의 서약

  • 우리는 ECMAScript에 영향을 미치는 새로운 아이디어를 만들고 그것을 비밀로 하지 않고 그룹에 제시할 것입니다.
  • 우리는 그룹에서 광범위한 합의가 이루어진 개념을 구현할 것입니다.
  • 우리는 그룹을 인도하고 있는 아키텍처 원칙을 따를 것이고 이 원칙을 무시하거나 원칙에 모순되는 플랫폼을 출시하지 않을 것입니다.
  • 우리는 ECMA에 먼저 제출하지 않은 ECMAScript 확장 기능을 출시하지 않을 것입니다.
  • 우리는 ECMA에서 승인한 모든 ECMAScript 표준을 구현할 것입니다.
  • 우리가 아직 승인되지 않은 ECMAScript 기능을 지원한다면 이를 명확히 식별할 것입니다.

그림 23. 1997년 7월의 TC39 회의에서 있었던 Microsoft의 서약[TC39 1997g]

브라우저 게임 이론은 JavaScript의 진화에서 중요한 요소였다. 또한 Javascript가 성공적이 된 이유를 이해하는 관점을 제공한다. 그리고 Javascript의 역사에서 있었던 많은 혁신들의 성공과 실패에 대한 설명도 준다.

Footnotes

  1. 소스 코드를 검토하여 좋지 않은 코드 스타일과 오류가 발생하기 쉬운 요소들을 찾아내는 개발 도구이다.

  2. 주석 삭제, 공백 제거, 이외에도 코드의 동작을 유지하면서 소스 코드를 더 짧게 바꿀 수 있는 변환을 적용하여 Javascript 프로그램의 다운로드 크기를 물리적으로 줄이는 것이다.

  3. JSON을 처리하기 위해 eval을 사용하는 것은 코드 인젝션 공격에 프로그램을 노출시킬 수 있기 때문에 보안 위협이 될 수 있다는 것이 결국 밝혀졌다. 모던 자바스크립트 엔진들은 그런 공격을 허용하지 않는 전용 JSON 파서를 제공한다.

  4. DiNucci[1999]가 Web 1.0, Web 2.0이라는 용어를 초기에 사용했다.

  5. 동적 HTML(DHTML)은 활성화된 웹 페이지의 HTML 요소를 동적으로 수정하는 데에 JavaScript를 사용한다.

  6. Brandan Eich가 선임 아키텍트였던 Netscape의 Mozilla 프로젝트 결과물이다.

  7. 2019년의 개인적인 대화

  8. 즉시 실행 함수는 블록 스코프를 대신할 수 있었다. 이 기법은 Scheme 프로그래머들에게 알려져 있었고 2000년대 초중반에 Javascript 프로그래머들에게 널리 쓰였다. Ben Alman[2010]이 IIFE라는 용어를 만들었다.