일반 다섯 가지의 Ajax 우수 사례

황제낙엽 2011.04.07 08:29 조회 수 : 219

sitelink1  
sitelink2  
sitelink3 http://1 
extra_vars4 ko 
extra_vars5 http://www.ibm.com/developerworks/kr/library/wa-aj-5best/index.html 
extra_vars6 sitelink1 

이 기사에서는 웹 애플리케이션에서 Ajax 개발을 수행하는 과정에서 채택할 수 있는 다음과 같은 다섯 가지 우수 사례를 소개한다.

  1. 호출 최소화
  2. 데이터 규모 축소
  3. 컴포넌트 사전로드
  4. 원활한 오류 처리
  5. 기존 도구의 사용

이러한 우수 사례를 이용하면 Ajax 코드를 더욱 빠르게 실행하는 보다 견고한 Javascript 코드를 작성할 수 있으며 이렇게 하는 것이 사용자에게도 유익하다.

Ajax 개요

Ajax는 비교적 새로운 용어로 오랫동안 존재해왔던 기술(예: HTTP상에서 비동기 호출을 할 수 있는 오브젝트, Javascript 코드 및 XML)을 설명하는 데 사용된다. Ajax는 전체 HTML 페이지를 제출하고 나서 다시 로드하지 않아도 되도록 하기 위해 자주 사용되며, 특히 전체 페이지를 다시 로드할 필요가 없는 조치를 사용자가 수행하는 경우에 사용된다.

지난 몇 년 동안 Ajax는 Ajax를 사용하는 개선된 사이트를 개발하는 데 필요한 도구로서 보다 광범위하게 사용되었다. 이 기사에 있는 우수 사례를 이용하여 Ajax와 Javascript 코드를 사용하는 우수한 웹 애플리케이션을 빌드하도록 하자.

호출 최소화

당연한 얘기지만 Ajax를 사용하는 웹 애플리케이션의 성능을 강화하기 위해 할 수 있는 한 가지 방법은 Ajax 호출 수를 최소화하는 것이다.

호출 수를 최소화할 수 있는 한 가지 방법은 여러 개의 호출을 소수의 호출로 한데 모의는 것이다. 데이터가 비교적 작은 경우("데이터 규모 축소" 참조), 대부분의 네트워크에서는 대기 시간이 문제가 된다. 대기 시간은 브라우저가 실제로 서버와 서비스에 연결되는 데 걸리는 시간을 말하며 때로는 연결에 중요한 부분이 될 수 있다. 사용자가 경험하는 총 대기 시간은 사용자의 실제 접속뿐만 아니라 브라우저의 캐싱 설정과 DNS 클라이언트와 같은 여러 가지 요인에 따라 달라진다.

웹 애플리케이션에서 호출을 최소화하는 방법을 배우기 위해 읽을 수 있는 하나의 코드 스니펫이나 간단한 공식은 없다. 그러나 클라이언트에서 서버로의 Ajax 호출 수를 조정하는 효과적인 방법을 간단한 연습을 통해 확인할 수 있다. 사용자가 중고 오토바이를 구입하는 예제 웹 애플리케이션을 생각해보자(그림 1 참조).


그림 1. 중고 오토바이를 검색할 간단한 웹 페이지
make, model, year 드롭 다운 단추와 postal code 필드가 표시된 스크린샷 

먼저, 사용자는 오토바이의 년식을 선택한다. 그런 다음, 오토바이의 형식을 선택한다. 마지막으로 오토바이의 모델을 선택한다. 그 동안 Ajax는 백그라운드에서 실행하면서 웹 애플리케이션에서 드롭 다운 상자를 업데이트하여 사용자 목록을 필터링함으로써 사용자가 항목을 더욱 쉽게 선택할 수 있게 한다.

클라이언트용 상자와 서버용 상자가 각각 하나씩 있는 간단한 다이어그램을 작성하여 연습을 시작한다. 그림 2에 표시한 바와 같이 서버에서 사용자 데이터를 가져오기 위해 브라우저에서 Ajax를 호출하는 선을 그린다.


그림 2. Ajax 호출 차트 작성
점선이 브라우저와 서버에서 확장되어 있고 브라우저와 서버 간에 make, model 및 inventory에 해당하는 실선이 표시되어 있다. 

한 번의 호출로 형식과 모델을 가져오도록 Ajax 호출을 결합하여 설계를 개선할 수 있다. Ajax를 호출하여 형식을 가져온 후, 추가로 Ajax를 호출하여 모델을 가져오는 대신 사용자가 형식을 선택할 때 모델을 캐시하여 새 코드가 캐시에서 사용 가능한 모델 목록을 간단히 검색할 수 있도록 한다. 같은 데이터를 로컬에 캐시된 자원에서 가져오는 것이 서비스를 통해 가져오는 것보다 훨씬 더 빠르다. 추가로 서비스를 호출하지 않게 되면 서비스 호출에 따른 대기 시간을 없앨 수 있다. 개선된 통신 과정은 그림 3과 같다.


그림 3. 형식과 모델을 가져오는 호출을 결합한 이후의 Ajax 호출
점선이 브라우저와 서버에서 확장되어 있고 브라우저와 서버 간에 2개의 실선이 표시되어 있다. 하나는 makes와 models를 처리하기 위한 것이며 다른 하나는 inventory를 처리하기 위한 것이다.  

지금까지 재설계 과정을 통해 브라우저와 서버 간의 통신에서 하나의 호출을 제거했다. 목록 1에 있는 코드를 사용하여 호출 수를 더 줄일 수 있다. 이 코드의 일부 주요 행에서는 나중에 검색하기 위해 배열에서 가져온 데이터를 저장한다.


목록 1. 로컬에서 데이터를 캐시에 저장하기
var choices = new Array();

function fillChoiceBoxes(year) {

    // see resources for links to dojo toolkit...
    if (dojo.indexOf(choices, year) == -1) {
        // go get the         
    } else {
        // make the ajax call and fill the choices.    
        choices[year] = result; // result of ajax call.
    }

    // calling a function to fill the values...
    fillSelect(dojo.byId('makes'), choices[year]);

}

사용자가 서로 다른 두 개의 모델을 고려하면서 오락가락하고 있는 경우, 웹 애플리케이션은 추가로 서비스를 호출 하는 대신 로컬에 캐시된 데이터를 사용한다. 캐시 전용 데이터는 적어도 사용자 세션이 지속되는 시간 동안에는 정적이다. 캐시하지 않아도 되는 데이터를 캐시하여 많은 문제를 일으키지 않도록 한다.

이 예제에서 살펴본 바와 같이 가능한, 데이터 캐싱과 클라이언트에서 서버로의 라운드 트립을 줄여서 호출을 최소화한다.

데이터 규모 축소

데이터 처리 성능을 높이려면 서버에서 클라이언트로 전송하는 데이터를 가능한 작게 해야 한다. 이 작업을 효과적으로 수행하기 위해서는 서버에서 클라이언트로 전송되는 메시지의 형식을 규정할 수 있는 위치를 서비스 계층에서 제어해야 한다.

XML은 여러 가지 타당한 이유로 인해 클라이언트와 서버 간의 일반적인 메시지 형식으로 사용된다. XML 직렬화 기능을 제공하는 프레임워크나 라이브러리가 부족하다는 점도 이러한 이유에 해당된다.

그러나 XML은 보다 간결한 메시지 형식인 JSON(JavaScript Serialized Object Notation)과 비교했을 때 복잡한 메시지 형식이라고 할 수 있다. 간단히 메시지를 작성하여 서비스에서 클라이언트로 JSON 형식의 오브젝트를 전송할 수 있게 하는 라이브러리가 현재 많이 있다.

Dojo Toolkit와 같은 다수의 클라이언트측 라이브러리를 이용하면 서비스에서 사용할 전송 형식을 정의할 수 있다. 서비스 응답에서 JSON을 사용하는 경우에는 매개변수를 제공하여 동일한 클라이언트 오브젝트를 사용할 수 있다.

목록 2에 있는 코드를 생각해보자. 이 코드에서는 XML을 사용하여 motorcycle 오브젝트를 표현한다.


목록 2. XML로 된 motorcycle 데이터
<motorcycle>
  <year>2010</year>
  <make>Motocool</make>
  <model>Uberfast</model>
</motorcycle>

이제 목록 3을 생각해보자. 이 코드에는 같은 데이터가 JSON으로 표시되어 있다. 공백을 제거하고 나면 코드가 25% 정도 작아진다.


목록 3. JSON으로 된 motocycle 데이터
{ 
"motorcycle" : { 
    "year" : "2010", 
    "make" : "Motocool", 
    "model" : "Uberfast"
    }
}

데이터가 더 작아져서 서비스에서 클라이언트로(또는 그 반대로) 데이터를 전송하는 데 걸리는 시간이 줄어들 뿐만 아니라 문자열이 작아져서 구문 분석하는 데 걸리는 시간도 줄어든다.

가능한 소수의 문자로 구성되도록 전송할 데이터를 설계한다.

컴포넌트 사전로드

Ajax 호출과 함께 사용할 이미지 및 Javascript 파일과 같은 컴포넌트를 로드하여 브라우저 캐싱을 활용할 수 있다. Javascript 파일과 이미지를 사전로드해도 캐싱을 켠 사용자만 그 혜택을 누릴 수 있지만, 사용자 대부분은 캐싱을 켜고 있다는 사실을 인식하는 것이 중요하다.

외부 Javascript 파일을 사전로드하려면 워크플로우 초기에 Javascript 파일을 페이지에 삽입해야 하지만, 이 페이지가 최적화하려고 하는 페이지보다 더 작고 자원도 적은 경우에는 이렇게 하는 것으로 충분하다. 예를 들면, 비교적 경량인 페이지를 이용하여 사용자에게 워크플로우를 소개하는 경우에는 사전로딩이 유용하다. 호출 최소화 섹션의 오토바이 구입 예제를 생각해보자. Ajax 코드를 모두 포함하고 있는 더욱 규모가 큰 Javascript 코드를 사전로드하여 워크플로우의 초기 페이지에서 드롭 다운 상자가 포함된 페이지를 처리할 수 있다.

Ajax를 호출한 결과로 이미지를 업데이트하는 경우에는 이미지를 사전로드하는 것이 유용하다. 이미지를 사전로드하면 사용자가 요소 위로 마우스를 이동하여 드롭 다운 상자를 선택하거나 단추를 클릭할 때, 브라우저가 이미지를 가져올 때까지 사용자가 기다릴 필요가 없다. Ajax가 비동기적으로 수행된다고 하더라도 이미지를 서버에서 클라이언트로 전송하려면 시간이 걸리고 이미지가 완전히 다운로드될 때까지는 사용자의 브라우저에 이미지가 표시되지 않는다.

목록 4에 있는 예제에서는 사용자가 목록에서 오토바이 유형을 선택할 때 사용된 이미지를 표준 Javascript 코드를 사용하여 사전로드한다.


목록 4. 표준 Javascript 코드를 사용하여 이미지 사전로드하기
<html>
<head><title>Preload example</title></head>
<body>
<!-- web page... -->
<script type="text/javascript" language="javascript">
    var img = new Image();
    img.src = "http://path/to/motocool.jpg";
</script>
</body>
</html>

해당 페이지의 이미지를 사전로드할 때는 Javascript를 배치하는 위치가 중요하다. HTML에 Javascript 코드를 삽입했다고 해서 웹 페이지 로딩에 영향이 있어서는 안 된다. HTML 페이지에 Javascript 코드를 삽입하면 페이지 로딩 속도가 느려질 수 있다. 브라우저에는 한 번에 다운로드할 수 있는 자원이 비교적 제한되어 있기 때문에 일반적으로 <script> 요소 안에 있는 Javascript 코드를 해당 HTML 페이지의 마지막 부분에 삽입해야 한다. 가능한 스크립트를 HTML 페이지 마지막 부분에 삽입해야 브라우저가 이미지와 기타 자원을 더 빠르게 로드할 수 있다.

HTML 5에서는 새로운 async 속성을 <script> 태그에서 사용할 수 있다. 이 속성을 사용하면 브라우저가 Javascript 코드를 비동기적으로 실행하게 되어 웹 페이지에서 다른 작업이 수행되고 있는 동안에도 Javascript 코드를 실행할 수 있게 된다.

원활한 오류 처리

try... catch문을 사용하여 오류를 처리하는 것보다는 방어적 코드를 수행하는 편이 더 좋으므로 Javascript 코드에서 정의한 모든 함수는 적대적이라고 가정해야 한다. 다시 말해서 사용자 입력을 기반으로 하는 Javascript 함수를 사용하여 계산을 해야 하는 경우에는 목록 5에서와 같이, 계산을 하기 전에 입력을 확인해야 한다.


목록 5. 사용자 입력 확인
function caculateDistance(source,dest) {
    if (! isNaN(source) || ! isNan(dest)) {
        dojo.byId("errors").innerHTML = "Please provide a valid number.";
    }
}

코드를 방어적으로 작성한 경우에도 가능한 try... catch문과 오류 콜백을 사용하는 것이 좋다. 목록 6에서는 Javascript 코드에서try... catch문을 사용하여 오류를 확인한다.


목록 6. try... catch문을 사용한 오류 처리
function calculateDistance(source,dest) {
    try {
        // do some calculations...
    } catch (error) {
        dojo.byId("errors").innerHTML = "An error occurred while adding the numbers";
    }
}

목록 7에서는 Dojo Toolkit에서 제공하는 xhrGet() 메소드를 호출하는 과정에서 오류 콜백을 사용한다. 오류 인수는 선택사항이어서 오류 핸들러를 정의하는 과정을 건너뛰기 쉽다.


목록 7. xhrGet() 메소드와 함께 오류 콜백 사용하기
var args = {
    url: "/moin_static185/js/dojo/trunk/dojo/../dojo/NoSuchFile",
    handleAs: "text",
    preventCache: true,
    load: function(data) {
        // do something when successful...
    },
    error: function(error) {
        dojo.byId("errors").innerHTML = "An error occurred while getting the data..";
    }
}
var ajx = dojo.xhrGet(args);

웹 페이지에서 오류를 처리하는 방법은 기술적 문제에 상당하는 비즈니스 문제를 일으킬 수 있다. 사용자에게 표시되는 메시지가 비즈니스에 영향을 줄 수 있으므로 뭔가 잘못되는 경우에 사용자에게 어떤 메시지를 표시할 것인지 클라이언트에게 확인해야 한다. 예외가 발생하는 경우에 가능한 의미 있는 기본적인 작동을 제공할 수 있게 클라이언트가 도와줄 수 있다.

마지막으로 목록 8에서와 마찬가지로 Javascript 경보 상자에는 오류에 대한 설명을 표시하지 않는다. 사용자는 소프트웨어 엔지니어가 아니므로 경보 상자에서 사용자에게 표시하는 정보는 사용자에게는 아무런 의미가 없다. 사용자가 아무런 조치도 취할 수 없는 메시지를 제공한다는 문제가 있을 뿐만 아니라 경보 상자는 사용자가 해당 웹 페이지로 돌아가려면 경보 상자를 닫는 조치를 추가로 수행해야 한다는 문제가 있다.


목록 8. Javascript 경보 상자를 사용하지 않고 오류 처리하기
function calculateDistance(source,dest) {
	try {
		// do some calculations...
	} catch (error) {
                // Bad:
		// alert(error.message);
                // Better:
                dojo.byId("errors").innerHTML = 
                    "An error occurred while calculating data...";
	}
}

기존 도구의 사용

마지막 우수 사례는 가능한 NIH(Not Invented Here) 증후군을 탈피하는 것이다. 기존 도구(프레임워크와 플랫폼)를 사용함으로써 이러한 도구의 자원을 활용할 수 있다. 일반적으로 사용하는 완성된 도구는 성능과 크로스 브라우저 호환성이 전체적으로 테스트되었다. 또한, 이러한 도구에는 자체 프로젝트에서 구현할 수 있는 기능보다 더 많은 기능이 있다.

애니메이션과 같은 기능과 기타 많은 함수를 지원할 뿐만 아니라 Ajax 호출에 필요한 메소드를 제공하는 유용한 도구가 많다. 이러한 도구 중 일부를 표 1에 표시해 놓았다.


표 1. Ajax 호출에 필요한 메소드를 제공하는 Javascript 도구
도구 설명
Dojo Toolkit Dojo Toolkit는 무료로 사용할 수 있는 Javascript 도구로 구성된 제품이다. 이 도구는 REST(Representational State Transfer) 서비스뿐만 아니라 보통의 웹 페이에 Ajax 호출에 필요한 여러 가지 메소드를 제공한다. Dojo Toolkit의 메소드는 XML, JSON 및 평문 메시지 형식을 지원한다.
GWT(Google Web Toolkit) Designer Google은 최근에 Instantiations Developer Tools를 인수했으며 이 제품을 무료 도구로 구성된 제품으로 다시 공개했다. GWT Designer는 그 중 하나로 사용자는 기존의 Eclipse 설치판 위에 이 도구를 설치할 수 있다. GWT Designer를 사용하면 GWT를 사용하는 인터페이스를 빌드하는 데 도움이 된다. GWT를 이용하면 Ajax를 사용하는 복잡한 웹 애플리케이션을 빌드할 수 있으며 웹 애플리케이션을 본래의 애플리케이션만큼이나 복잡하게 할 수도 있다. RAP(Rich Ajax Platform)과 마찬가지로 GWT는 Javascript 프레임워크라고 하기보다는 오히려 Ajax를 사용하는 HTML에 컴파일된 Java 기반 툴킷이라고 할 수 있다.
jQuery jQuery는 전체 Ajax 함수를 제공하는 또 다른 Javascript 라이브러리이다. 또한, jQuery는 Javascript 파일을 다운로드(컴포넌트 사전로드 우수 사례에서 유래)하여 실행하는 다른 Ajax 기반 메소드(예: getScript())와 다양한 메시지 형식을 지원한다.
Prototype Prototype 또한, 편리하게 Ajax를 호출하기 위해 사용하는 Javascript 프레임워크이다. Ajax.PeriodicalUpdater와 같은 메소드를 사용하여 주기적으로 Ajax 페이지에 있는 값을 업데이트할 수 있으며 오랫동안 실행되는 서비스 프로세스의 다른 상태나 진행 표시줄과 같은 제어를 구현할 수 있다.
RAP(Rich Ajax Platform)

이 표에 있는 다른 프레임워크와 달리, RAP은 SWT(Swing or Standard Widget Toolkit) 애플리케이션을 빌드하는 것과 마찬가지로 Eclipse IDE(Integrated Development Environment)와 Java 및 비Java 코드를 사용하여 더 나은 Ajax 사용 사이트를 빌드할 수 있게 하는 완전한 플랫폼이다. 복잡한 HTML, CSS 및 Javascript 코드를 다루고 싶지 않은 Java 프로그래머에게는 RAP과 같은 플랫폼 도구가 좋은 대안이 된다.

RAP 문서에서는 RAP을 기존 Eclipse 설치판에 플러그인으로 설치하지 않도록 경고하고 있다. 따라서 Eclipse 사이트에서 Eclipse for Rich Client Platform(RCP) and RAP Developers 번들을 다운로드하여(참고자료 확인) 각각 별도의 위치에 설치해야 한다. 치트 시트에는 샘플 프로젝트를 가져오는 방법이 표시되어 있다.

요약

웹 애플리케이션에서 Ajax를 사용하면 더욱 매끄러운 웹 애플리케이션 인터페이스를 사용자에게 제공할 수 있다. 완전한 HTML 페이지를 전송하는 것과 관련하여 이미 Ajax에는 몇 가지가 기능이 개선되었지만, 이 기사에 있는 우수 사례를 채택하면 더 나은 Ajax 애플리케이션을 빌드하는 데 도움이 된다.


참고자료

교육

  • Dojocampus.org에서 Dojo Toolkit API 문서와 예제를 읽어보자. 

  • New to Web Development 페이지를 확인하여 동적 웹 애플리케이션 등에 관해 배우자. 

제품 및 기술 얻기

토론