Thursday, November 26, 2009

Google Web Toolkit과 Eclipse Galileo를 이용한 고성능 웹 개발

Google Web Toolkit과 Eclipse Galileo를 이용한 고성능 웹 개발

Michael Galpin, Software architect, eBay

요약: GWT(Google Web Toolkit)에 대한 이야기를 들어보았을 것입니다. 그리고 GWT를 사용하면 Java™ 프로그래밍 언어로 웹 애플리케이션을 작성한 후 컴파일하여 JavaScript로 만든 다음 웹 브라우저에서 이 JavaScript를 실행하게 된다는 것도 알고 있을 것입니다. 또한 GWT를 사용하면 Java의 정적 형식 지정 기능과 Eclipse 등의 우수한 도구를 활용하여 생산성을 높일 수 있습니다. 아마도 GWT 기반의 유용하고 깔끔한 위젯은 여러 번 보았겠지만 GWT를 사용하여 고성능 웹 애플리케이션도 작성할 수 있다는 사실은 모르고 있었을 것입니다. 이 기사에서는 Google Plug-in과 Eclipse Galileo를 함께 사용하여 컴파일러 최적화, 지연된 바인딩 및 Ajax 최적화와 같은 GWT의 성능 기능을 활용하는 방법에 대해 설명합니다. 개발자 성능은 GWT의 중요한 부분이므로 Google Plug-in for Eclipse를 통해 생산성을 높이는 방법에 대해서도 살펴봅니다.

원문 게재일: 2009 년 10 월 20 일
번역 게재일: 2009 년 11 월 10 일
난이도 : 중급
영어로 보기

전제 조건

이 기사에서는 GWT의 여러 기능을 살펴본 후 이러한 기능을 활용하여 고성능 웹 애플리케이션을 작성하는 방법에 대해 설명한다. 이 기사는 GWT에 대한 개요가 아니며 GWT에 대한 경험이 있는 독자를 대상으로 한다. 또한 이 기사에서는 독자가 Java 기술에 대해서도 알고 있고 JavaScript, CSS 및 HTML에도 익숙한 것으로 가정한다. 최신 버전의 GWT를 사용하는 것이 좋다. 이 기사에서는 V1.7을 사용하고 있으며 Google Plug-in for Eclipse도 사용한다. 이 기사에서는 V1.1의 Google Plug-in을 Eclipse V3.5(Galileo)와 함께 사용한다. Mozilla Firefox용 Firebug 플러그인도 사용한다. V1.4.2의 Firebug를 Firefox V3.5.2와 함께 사용한다(참고자료 참조).

빠른 JavaScript

GWT는 Java를 JavaScript로 컴파일하는 기능으로 잘 알려져 있으며 이 기능을 통해 Java 개발자는 동적 웹 애플리케이션을 개발할 수 있다. 모든 코드가 JavaScript로 컴파일되며 GWT의 여러 성능 기능은 JavaScript를 브라우저에서 빠르게 실행하기 위해 설계되었다. GWT에는 브라우저별 최적화 및 효율적인 Ajax를 포함한 여러 가지 성능 기능이 있지만 이러한 기능의 대부분은 GWT의 Java-to-JavaScript 컴파일러부터 시작된다. 따라서 이 기사에서는 GWT의 성능 관련 기능부터 설명한다.

컴파일러 최적화

GWT 컴파일러는 Java 코드를 브라우저에서 실행되는 JavaScript로 변환한다. 하지만 Java 기술을 JavaScript로 변환하는 기능만 제공하는 것이 아니라 코드의 실행 속도를 높여 주는 여러 가지 최적화 기능도 제공한다. 그러나 GWT에서 생성되는 JavaScript는 소스 코드로 난독화되어 있어 쉽게 읽을 수 없기 때문에, 이러한 최적화를 통해 수행되는 작업을 정확히 이해하기가 어려울 수 있다. 따라서 컴파일러에 의해 수행된 최적화를 보다 잘 이해할 수 있도록, GWT 컴파일러에서 사용자가 읽을 수 있는 JavaScript를 생성하는 방법에 대해 먼저 설명하려고 한다.

GWT 컴파일러에는 세 가지 작업 모드가 있다. 기본 모드는 obfuscated이며 이 모드에서는 GWT 컴파일러가 난독화된 JavaScript를 생성한다. 이 JavaScript는 읽기가 어려울 뿐만 아니라 압축도 되어 있기 때문에 용량이 작아서 인터넷을 통해 빠르게 로드할 수 있다. 또한 크기가 작기 때문에 브라우저에서 JavaScript를 빠르게 구문 분석할 수 있다.

최신 웹 브라우저에서 gzip 압축이 지원되고 있고 대부분의 웹 서버에서 gzip 압축을 사용하여 JavaScript를 전송하고 있기 때문에 이 방법이 유선을 통해 압축된 JavaScript를 전송하는 방법과 별로 다르지 않다고 생각할 수도 있을 것이다. 하지만 GWT 컴파일러는 JavaScript를 단순히 압축하는 수준에 그치지 않고 gzip 압축을 활용할 수 있는 방식으로 압축 작업을 수행한다. 다시 말해서 GWT에서 난독화된 JavaScript는 이미 압축되어 있음에도 불구하고 gzip을 통해 더욱 높은 밀도로 압축할 수 있다. 따라서 웹 서버에서 gzip을 사용하지 않을 경우 GWT 난독화를 사용하면 속도가 크게 개선되며 gzip을 사용하고 있을지라도 GWT 난독화를 통해 속도 향상 효과를 얻을 수 있다.

프로덕션 코드의 경우에는 난독화된 JavaScript를 생성하도록 GWT 컴파일러를 설정해야 한다. 하지만 이렇게 하면 생성된 JavaScript를 거의 읽을 수가 없다. 이를 확인하기 위해 GWT에서 난독화된 JavaScript를 보여 주는 Listing 1을 살펴보자.


Listing 1. 난독화된 JavaScript
function qH(){return np} function mH(){} _=mH.prototype=new mu;_.gC=qH;_.tI=0;function uH(){uH=ZH;sH={};tH=[];sH[LM]=[Is,Hs,Js];sH[JM]=[rt,qt,st];Xv(tH,yn,LM);Xv(tH,To,JM)} var sH,tH;function AH(a){a.b=oH(new mH);return a} function BH(a){var b,c,d,e,f,g,h,i,j,k;g=ox(new cx,MM);f=OA(new FA);j=XH(new  VH,NM,OM);KA(f,j.b+sJ+j.c);pw(g.B,PM,true);Zw(gA(QM),f);Zw(gA(RM),g);f.B.focus() ;k=Jg(f.B,NJ).length;k>0&&JA(f,0,k);c=py(new my);Lf((tf(),c.b.B),SM);c.o=true; b=ox(new cx,TM);b.B.id=UM;i=Py(new Ny);h=Ty(new My);d=UA(new RA);pw(d.B,VM,true); VA(d,Uy(new My,WM));VA(d,i);VA(d,Uy(new My,XM));VA(d,h);d.b=(kz(),jz);VA(d,b); Ax(c.j,d);Mx(c);vw(b,FH(new DH,c,g),(sh(),rh));e=KH(new IH,a,g,f,i,h,c,b); vw(g,e,rh);vw(f,e,(hi(),gi))} function CH(){return rp} function xH(){} 

다행스럽게도 GWT 컴파일러는 훨씬 쉽게 읽을 수 있는 JavaScript를 작성하도록 쉽게 설정할 수 있다. 즉, -style=PRETTY 인수를 컴파일러에 전달하기만 하면 된다. 이렇게 하면 Google Plug-in for Eclipse까지도 쉽게 사용할 수 있게 된다. GWT 컴파일을 시작하면 그림 1과 같은 대화 상자가 표시된다.


그림 1. GWT 컴파일러 옵션
GWT 컴파일러 옵션

컴파일러에서 생성되는 JavaScript를 보려면 그림 1에서 Pretty 설정을 선택한다. 그러면 위 코드가 Listing 2와 같은 코드로 표시된다.


Listing 2. Pretty JavaScript
var $wnd = parent; var $doc = $wnd.document; var $moduleName, $moduleBase; var $strongName = '21B409FCD39529C5A9DB925F7D8D9A95'; var $stats = $wnd.__gwtStatsEvent ? function(a) {return     $wnd.__gwtStatsEvent(a);} : null; $stats && $stats({moduleName:'gwtperf',subSystem:'startup',evtGroup: 'moduleStartup',millis:(new Date()).getTime(),type:'moduleEvalStart'}); var _; function nullMethod(){ }  function equals(other){   return this === (other == null?null:other); }  function getClass_0(){   return Ljava_lang_Object_2_classLit; }  function hashCode_0(){   return this.$H || (this.$H = ++sNextHashId); }  function toString_0(){   return (this.typeMarker$ == nullMethod || this.typeId$ == 2?this.getClass$():Lcom_google_gwt_core_client_JavaScriptObject_2_classLit) .typeName + '@' + toPowerOfTwoString(this.typeMarker$ == nullMethod || this.typeId$ == 2?this.hashCode$():this.$H || (this.$H = ++sNextHashId), 4); }  function Object_0(){ }  _ = Object_0.prototype = {}; _.equals$ = equals; _.getClass$ = getClass_0; _.hashCode$ = hashCode_0; _.toString$ = toString_0; _.toString = function(){   return this.toString$(); } ; 

이 코드 또한 최적화된 JavaScript이지만 훨씬 쉽게 이해할 수 있다. 물론 이렇게 하면 작성된 JavaScript의 용량이 많이 늘어난다. 그림 2와 같이 Firefox용 Firebug 플러그인을 사용하여 이를 확인할 수 있다.


그림 2. JavaScript 파일 크기 비교: Obfuscation과 Pretty
JavaScript 파일 크기 비교: Obfuscation과 Pretty

그림 2에서는 Obfuscated JavaScript(위쪽)와 Pretty JavaScript(아래쪽)로 컴파일된 동일한 GWT 애플리케이션(Google Plug-in에서 작성된 시작 프로젝트)을 보여 준다. 이 그림을 보면 Obfuscated에서 Pretty로 변환되면서 JavaScript의 크기가 58KB에서 146KB로 변경된 것을 알 수 있다.

이제 GWT 컴파일러가 코드를 최적화하는 방법을 살펴보자. GWT는 사용자가 소프트웨어 엔지니어링 베스트 프랙티스를 사용하여 코드를 작성할 수 있다는 가능성을 염두에 두고 설계되었다. GWT에서는 올바른 유형의 추상화를 가져와서 강력하고 유지 가능한 코드를 작성할 수 있으며 이 경우 GWT는 매우 빠른 코드로 컴파일하게 된다. 이제 사용자를 모델링 사용자를 위한 간단한 샘플 클래스를 살펴보자(Listing 3 참조).


Listing 3. Person 클래스
public class Person {     final String firstName;     final String lastName;     public Person(String firstName, String lastName) {         this.firstName = firstName;         this.lastName = lastName;     }          public String getName(){         return firstName + " " + lastName;     } } 

이제 GWT 시작 프로젝트에서 다음 코드(Listing 4)를 변경한다.


Listing 4. 원본 GWT 시작 프로젝트 코드
final TextBox nameField = new TextBox(); nameField.setText("GWT User"); 

이제부터 위에서 본 하드 코딩된 문자열 대신 Person 오브젝트를 사용하려고 한다. 이를 위한 변경은 Listing 5와 같다.


Listing 5. Person을 사용하기 위해 수정된 코드
final TextBox nameField = new TextBox(); final Person user = new Person("GWT", "User"); nameField.setText(user.getName()); 

간단한 변경이기는 하지만 애플리케이션에 유용한 추상화라는 것을 쉽게 알 수 있을 것이다. 하지만 이 경우에는 성능 관점에서 주의를 기울여야 한다. 즉, 오브젝트를 작성하고 메소드를 실행하기 위해 오버헤드가 발생할 수 있다. 이제 GWT 컴파일러에서 이 문제를 해결하는 방법을 살펴보자. Listing 6에서는 원본 코드의 컴파일된 버전을 보여 준다.


Listing 6. JavaScript로 컴파일된 원본 코드
nameField = $TextBox(new TextBox()); nameField.element['value'] = 'GWT User' != null?'GWT User':''; 

이제 Listing 5의 코드가 JavaScript로 컴파일된 결과를 살펴보자. Listing 7에서 이 코드를 보여 준다.


Listing 7. JavaScript로 컴파일된 수정된 코드
  user = $Person(new Person(), 'GWT', 'User');   $setText_1(nameField, user.firstName + ' ' + user.lastName); 

이 코드의 첫 번째 행에서는 Person 클래스에 대한 JavaScript 생성자를 호출한다. 이 행에서는 Java 코드가 바로 변환된다. 두 번째 행에는 간단한 변경 사항이 적용되었다. Person 인스턴스의 getName() 메소드를 호출하는 대신 이 메소드가 인라인으로 처리되었다. 즉, 메소드에 대한 호출이 메소드의 본문으로 대체되었다. 이는 역사적으로 C/C++ 및 Java 컴파일러에서 수행되는 일반적인 최적화이지만 GWT 컴파일러가 빠른 JavaScript를 활용하고 생성하기 위해 사용하는 방법이기도 하다.

오브젝트 지향 개발에서는 여러 구현을 가지고 있을 수 있는 공통 인터페이스를 추상화한 다음 이 인터페이스와 작동하는 코드를 작성하는 방식이 일반적으로 사용되며 이렇게 하면 기존 리소스를 효과적으로 재사용할 수 있다. 이는 성능에 영향을 미치면서 찾아보기 및 메소드 디스패치를 추가할 수 있는 또 하나의 유용한 엔지니어링 추상화이다. 이제 GWT 컴파일러를 통해 이 작업을 수행하는 방법을 살펴보자. Eclipse의 리픽토링 도구를 사용하여 Listing 3에서 설명한 Person 클래스의 인터페이스를 쉽게 추출할 수 있다. 이 도구를 Thing이라고 하자. Listing 8에서 이 도구를 보여 준다.


Listing 8. Thing 인터페이스를 사용하여 리팩토링된 코드
public interface Thing {     String getName(); } public class Person implements Thing {     final String firstName;     final String lastName;     public Person(String firstName, String lastName) {         this.firstName = firstName;         this.lastName = lastName;     }          public String getName(){         return firstName + " " + lastName;     } } 

이제 Person을 사용하는 클라이언트 코드는 Thing 인터페이스를 사용하도록 변경되어야 하며 Listing 9에서 변경된 클라이언트 코드를 보여 준다.


Listing 9. 리팩토링된 클라이언트 코드
Thing user = new Person("GWT", "User"); nameField.setText(user.getName()); 

컴파일된 코드는 어떻게 변경되었을까? 성능 저하가 발생했을까? Listing 10을 직접 살펴보자.


Listing 10. 재컴파일 이후의 리팩토링된 코드
user = $Person(new Person(), 'GWT', 'User'); $setText_1(nameField, user.firstName + ' ' + user.lastName); 

아무 것도 변경되지 않았다는 것을 알 수 있을 것이다. 만일 이 인터페이스의 구현이 두 개이고 두 구현이 모두 사용되고 있다면 어떻게 되었을까? Listing 11에서 이에 대한 코드를 보여 준다.


Listing 11. Thing의 다중 구현
public class Company implements Thing {     private final String name;     public Company(String name){         this.name = name;     }     public String getName() {         return this.name;     } } // client code final TextBox nameField = new TextBox(); Thing user = new Person("GWT", "User"); Thing userCompany = new Company("ACME"); nameField.setText(userCompany.getName() + " " + user.getName()); 

Listing 12에서는 GWT 컴파일러에 의해 생성된 JavaScript를 보여 준다.


Listing 12. 컴파일된 다중 구현
user = $Person(new Person(), 'GWT', 'User'); userCompany = $Company(new Company(), 'ACME'); $setText_2(nameField, userCompany.name_0 + ' ' + (user.firstName + ' ' + user.lastName));             

이 코드를 보면 컴파일러가 인터페이스를 제거하고 getName() 메소드의 각 구현을 인라인 처리했음을 알 수 있다. 이 코드도 최적화되어 있기는 하지만 Listing 13과 같은 작업을 수행하게 되면 최적화 효과가 떨어질 수 있다.


Listing 13. 컴파일러 훼손하기
private String mkString(Collection things, char separator){     StringBuilder sb = new StringBuilder();     for (Thing thing : things){         sb.append(thing.getName());         sb.append(separator);     }     return sb.deleteCharAt(sb.length()).toString(); } // client code final TextBox nameField = new TextBox(); Thing user = new Person("GWT", "User"); Thing userCompany = new Company("ACME"); nameField.setText(mkString(Arrays.asList(user, userCompany), ' ')); 

Listing 13에서는 새 추상화를 추가했으며, 이 추상화는 Thing 오브젝트의 컬렉션을 받고 각 Thing에 대한 getName()을 호출한 결과를 병합하는 도우미 함수이다. 또한 구분자가 이 함수에 대한 매개변수로 추상화되었다. 이제 Listing 14에서 컴파일된 JavaScript를 살펴보자.


Listing 14. 컴파일된 mkString 코드
function $mkString(things, separator){   var sb, thing, thing$iterator;   sb = $StringBuilder(new StringBuilder());   for (thing$iterator = $AbstractList$IteratorImpl(new AbstractList$IteratorImpl(),  things); thing$iterator.i < thing =" dynamicCast($next_1(thing$iterator)," user =" $Person(new" usercompany =" $Company(new">

Listing 14의 코드는 Java 소스 코드처럼 복잡하다. 이 코드의 루프에서는 dynamicCast 함수가 호출된다. 이 코드는 전달된 오브젝트를 지정된 형식으로 변환할 수 있는지 확인하는 데 사용되는 JavaScript이다. 이 경우에는 오브젝트가 Thing을 구현한 오브젝트인 Person또는 Company인지 확인한다. 이 코드에는 인터페이스에 대한 코드가 추가되었고 인터페이스의 다중 구현이 있기 때문에 GWT 컴파일러에서 수행할 수 있는 최적화 작업이 줄어든다.

지금까지 살펴본 모든 최적화는 GWT 컴파일러에서 수행된 언어 레벨 최적화였다. 하지만 GWT에서는 브라우저 관련 최적화도 수행할 수 있다. 이러한 유형의 최적화는 일반적으로 지연된 바인딩이라는 포괄적인 개념 하에서 일괄적으로 처리된다.

지연된 바인딩

오늘날에는 Mosaic 이후 다양한 웹 브라우저가 사용되고 있으며, 이로 인해 웹 개발자들은 많은 어려움을 겪고 있다. 많은 JavaScript 프레임워크에 대한 주요 요구 사항 중에는 조금 더 편하게 작업할 수 있도록 브라우저 간 차이를 완화해 달라는 요구가 있다. 이 요구 사항을 충족하기 위해 일반적으로 두 가지 방법이 사용된다. 첫 번째 방법은 브라우저 간에 이식 가능한 코드를 작성하는 것이다. 이는 최소한의 공통 항목만을 코드로 작성하는 방법으로 최선의 경우, 최적화 효과가 조금만 떨어지지만 대부분의 경우에는 최적화 효과가 많이 떨어진다. 다른 방법은 브라우저를 인식하여 각 브라우저에 최적화된 코드를 사용하는 것이다. 이 경우에는 스파게티 코드가 많아지기 때문에 브라우저에서 실행되지 않는 많은 양의 코드가 브라우저에 전달된다.

GWT의 지연된 바인딩 아키텍처에서는 다양한 브라우저에 대한 여러 버전의 JavaScript를 컴파일할 수 있다. 먼저 간단한 JavaScript가 브라우저에 다운로드되어 브라우저를 인식한 다음 최적화된 JavaScript가 다운로드된다. 그림 2를 다시 한번 보면 .nocache.js 파일이 다운로드되어 있는 것을 볼 수 있다. 이 파일은 브라우저를 인식하는 코드이며, 이 경우에는 4KB이다. 이 파일은 기본적으로 Opera, Safari, Gecko(Firefox V2 이하), Gecko V1.8(Firefox V3+), Internet Explorer V6 및 Internet Explorer V8 등의 네 가지 순열을 검색한다.

브라우저 간의 차이를 만드는 전형적인 API의 예는 요소의 innerText 특성을 설정하는 것이다. 이 작업은 서버에 대한 프로시저 호출을 처리하는 콜백 핸들러의 시작 프로젝트에서 수행된다. 이를 수행하는 Java 코드는 Listing 15와 같이 매우 단순하다.


Listing 15. GWT에서 텍스트 설정하기
public void onSuccess(String result) {     dialogBox.setText("Remote Procedure Call");     serverResponseLabel.removeStyleName("serverResponseLabelError");     serverResponseLabel.setHTML(result);     dialogBox.center();     closeButton.setFocus(true); } 

이제 다양한 브라우저에 대해 GWT 컴파일러에서 생성되는 코드를 살펴보자. 각 브라우저 순열에 대해 컴파일되는 파일을 보려면 .nocache.js 파일을 열고 Listing 16과 비슷한 형태의 코드 섹션을 찾는다.


Listing 16. GWT의 브라우저 인식 코드
if (!strongName) {   try {     unflattenKeylistIntoAnswers(['opera'],  'D1B884746B9C511E12378A55F9FD97E2.cache.html');     unflattenKeylistIntoAnswers(['safari'],  '12DC532DA52018F17FA7F84F7137102A.cache.html');     unflattenKeylistIntoAnswers(['gecko1_8'],  '0986E60F243CC620FA7138AB06F221EB.cache.html');     unflattenKeylistIntoAnswers(['gecko'],  'CF1F7CBAF43D18B03F82260D99CB1803.cache.html');     unflattenKeylistIntoAnswers(['ie8'],  '1EE88964C0A866A7F2887C02F69F64D3.cache.html');     unflattenKeylistIntoAnswers(['ie6'],  '5395DF4A8135D37430AAE1347158CE76.cache.html');     strongName = answers[computePropValue('user.agent')];   }   catch (e) {     return;   } } 

이제 각 키('opera', 'safari' 등)를 생성된 파일에 일치시킬 수 있다. 이 기능을 사용하면 Internet Explorer V6용으로 컴파일되었던 Listing 15의 onSuccess 메소드의 버전을 확인할 수 있다(Listing 17 참조).


Listing 17. Internet Explorer V6용으로 컴파일된 코드
function $onSuccess(this$static, result){   ($clinit_11() , this$static.val$dialogBox.caption.element) .innerText = 'Remote Procedure Call';   setStyleName(this$static.val$serverResponseLabel.element,  'serverResponseLabelError', false);   this$static.val$serverResponseLabel.element.innerHTML = result || '';   $center(this$static.val$dialogBox);   $setFocus(this$static.val$closeButton, true); } 

Internet Explorer V6의 경우, GWT는 Internet Explorer V6에 최적화된 API 즉, 요소의 innerText 특성을 사용한다. 이제 이 코드를 Listing 18의 Gecko V1.8+ 순열과 비교해 보자.


Listing 18. Firefox V3+용으로 컴파일된 코드
function $onSuccess(this$static, result){   ($clinit_11() , this$static.val$dialogBox.caption.element) .textContent = 'Remote Procedure Call';   setStyleName(this$static.val$serverResponseLabel.element,  'serverResponseLabelError', false);   this$static.val$serverResponseLabel.element.innerHTML = result || '';   $center(this$static.val$dialogBox);   $setFocus(this$static.val$closeButton, true); } 

최신 버전의 Firefox의 경우 GWT는 Java 코드를 요소의 textContent 특성을 사용하는 JavaScript로 컴파일한다. 이 예제가 간단하기는 하지만 애플리케이션 코드에서 innerText와 같은 특성을 여러 번 사용할 수 있음을 쉽게 상상할 수 있을 것이다.

GWT로 개발을 많이 해 본 경우에는, 지연된 바인딩을 빠르게 익힐 수 있겠지만 지연된 바인딩이 항상 최선의 방법이 되지는 않는다. 지금까지 살펴본 대로 GWT는 애플리케이션의 각 순열에 대해 다양한 버전의 JavaScript를 컴파일한다. 그리고 이러한 순열은 GWT가 코드를 지역화하는 방법을 보여 준다. 기본적으로 6가지 브라우저 변형과 하나의 언어가 있다. 하나의 언어 대신 세 가지 언어를 지원해야 하는 경우에는 18개의 순열과 18가지 버전의 JavaScript가 사용된다. 이 경우 컴파일 시간이 길어지기 때문에 생산성이 저하될 수 있다. 물론 JavaScript로 컴파일하지 않는 Hosted Mode에서 대부분의 작업을 수행하면 이 문제를 해결할 수 있다. 이는 가장 쉽게 코드를 디버깅하는 방법이다. 하지만 컴파일할 필요가 있는 경우에는 하나의 브라우저(테스트에 사용할 브라우저)에 대해서만 컴파일하도록 GWT에 지시하여 컴파일 시간을 크게 단축할 수 있다. 이를 위해서는 Listing 19와 같이 애플리케이션에 대한 모듈 XML 구성 파일을 수정하기만 하면 된다.


Listing 19. 하나의 브라우저에 대해서만 GWT 구성하기
                                           

여기에서 핵심은 끝에서 두 번째 행에 있는 set-property 태그이다. 이 태그에서는 user.agent 특성을 gecko1_8로 설정했으므로 GWT가 Firefox V3+를 대상으로 하는 JavaScript를 생성하는 하나의 컴파일만을 수행한다. 지금까지 GWT를 통해 사용자의 브라우저에서 가장 빠르게 실행되는 JavaScript를 생성하는 여러 가지 방법 중 일부를 살펴보았다.

고속 Ajax

Ajax는 이제 웹에서 보편적으로 사용되고 있으며 웹 애플리케이션의 필수 부분이 되었다. Ajax라는 용어가 만들어질 때 Ajax의 X는 XML을 의미했었으며 이는 브라우저와 서버 사이에 전송되는 데이터의 형식으로 XML이 사용될 것으로 가정했었기 때문이었다. 하지만 실제로 많은 Ajax 애플리케이션에서는 HTML을 사용하여 서버와 통신하고 있다. 이렇게 된 이유는 HTML이 가장 구현하기 쉽기 때문이다. 하지만 HTML은 최적화와는 거리가 멀다.

일부 Ajax 애플리케이션 서버에서는 XML 형식으로 데이터를 돌려 보낸다. 이는 HTML에 비해 향상된 방법이기는 하지만 최적화의 관점에서는 부족한 면이 있다. XML은 부피가 큰 형식이며 JavaScript를 사용하여 구문 분석하기가 까다로울 수 있다. 이 경우 매우 많은 용량의 데이터가 유선으로 전송되어야 하고 매우 많은 JavaScript가 실행될 때까지 사용자가 많은 시간 동안 기다려야 한다. 따라서 많은 웹 애플리케이션에서는 XML 대신 JSON을 사용하고 있다. 이 또한 또 하나의 기능 향상이다.

GWT에는 Ajax를 위한 클라이언트 측 및 서버 측 구성 요소가 포함되어 있기 때문에 GWT에서 Ajax용으로 사용하는 데이터 형식이 무엇인지 궁금해할 수도 있겠지만 당연히 GWT에서는 고도로 최적화된 고유 형식을 사용한다. 유용한 Firebug를 사용하는 이 형식을 다음 그림 3에서 확인할 수 있다.


그림 3. Firebug를 사용하여 Ajax 트래픽 모니터링하기
Firebug를 사용하여 Ajax 트래픽 모니터링하기

Firebug에서는 서버에서 보내고 받은 데이터를 보여 준다. Listing 20에서 자세한 내용을 살펴보자.


Listing 20. GWT 요청 및 응답 데이터
Request:  5|0|6|http://localhost:8080/gwtperf/|29F4EA1240F157649C12466F01F46F60| org.developerworks.gwt.client.GreetingService|greetServer|java.lang.String| IBM developerWorks|1|2|3|4|1|5|6| Response: //OK[1,["Hello, IBM developerWorks!

I am running Google App Engine Development/1.2.2.

It looks like you are using:
Mozilla/ 5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/ 3.5.2"],0,5]

물론 개발자가 작성하는 Java 코드는 매우 단순하다. GWT는 매우 쉽게 설계할 수 있는 단순한 프로그래밍 모델이면서도 고도로 최적화된 런타임 구현을 제공한다.

요약

이 기사에서는 GWT의 여러 가지 성능 최적화 기능과 Google Plug-in for Eclipse Galileo를 활용하는 방법에 대해 살펴보았다. GWT를 사용하면 높은 성능을 제공하는 동적 웹 애플리케이션을 쉽게 작성할 수 있다. GWT는 앞으로도 계속 발전할 것이며 향후 발표될 GWT V2.0 릴리스에는 GWT를 사용하여 작성된 웹 애플리케이션의 성능을 향상시키기 위한 코드 분할 및 리소스 번들과 같은 여러 가지 새 기능이 포함되어 있다. 이러한 기능은 GWT 트렁크 소스 코드를 빌드하여 초기에 액세스할 수 있다.


다운로드 하십시오

설명이름크기다운로드 방식
Source codeos-eclipse-googlegalileo-source.zip36KBHTTP

다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기

토론

  • Eclipse에 관해 궁금한 점이 있으면 가장 먼저 Eclipse Platform 뉴스그룹을 살펴보자. (이 링크를 선택하면 기본 Usenet 뉴스 리더 애플리케이션이 실행되면서 eclipse.platform이 열린다.)

  • Eclipse 뉴스그룹에는 Eclipse 사용 및 확장에 관심이 있는 사용자를 위한 리소스가 많이 있다.

  • developerWorks 포럼 & 블로그를 통해 developerWorks 커뮤니티에 참여하자.

필자소개

Michael Galpin's photo

Michael Galpin은 1990년대 말부터 웹 애플리케이션을 개발하고 있으며 California Institute of Technology에서 수학과를 졸업하고 현재는 캘리포니아 산호세에 있는 eBay에서 아키텍트로 근무하고 있다.

No comments: