피터팬 컴플렉스의 드러머 김경인씨와 스튜디오 촬영을 진행 했습니다.

오늘 사내 사진 동호회 '찰나'의 정기 출사로 목동소재 모 스튜디오에 다녀 왔습니다.
모델이 되어주신분은 피터팬컴플렉스의 드러머이신 김경인씨가 수고 해 주셨습니다.

소문대로 키크고 매력적인 미인이시더군요.. *.*b
경인씨, 오늘 수고 많으셨습니다. 앞으로도 멋진 활동 부탁드리겠습니다.

소속사도 걸려있고 김경인씨의 초상권이 있는 사진들이기에 서비의  Photo Gallery와  이곳 서비의 다락방 외에
다른 곳에는 게시 할 수 없습니다.

피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인 피터팬 컴플렉스 김경인

minolta @7, 17-35mm, 50mm, 100mm macro, kodak portra 160vc
2007/05/19 22:48 2007/05/19 22:48
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. Blog Icon
    정우성

    =ㅂ=!
    신작가님!!!! 벌써 올리셨군요.
    네이버에서 "김경인"으로 검색했는데 신작가님의 블로그가 걸릴줄은..ㄷㄷㄷ;;;
    너무 멋져요!!
    +_+)b

  2. 헉..그런가요?
    생각지도 못했는데.. 저도 ㄷㄷㄷ 인데욤 ;;

스타크래프트 2 시연 동영상이 떴군요..

역시 블리자드 차기작은 스타크래프트2였군요..
화면은 화려합니다.

밸런스를 잘 맞춰 나와 줬으면 좋겠습니다.



Starcraft2 intro



21분짜리 풀타임 영상

2007/05/19 18:40 2007/05/19 18:40
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Sony Alpha 신형 디지탈바디 2종 조작부 및 명칭

이미지는 소미동 Kroiz™ /크로이츠님 이 작성 하신 자료입니다.

소니의 새 DSLR. 세로그립에도 십자컨트롤러가 들어가는군요.. 필름시절 미놀타에이어 이번에도 전 카메라 브랜드를 통틀어 최강의 세로그립이 태어나겠는걸요...

소니 차세대 플래그십

소니 차세대 플래그십



SLR 클럽 군사잡지™님의 소니신제품 취재기..


필름 바디 사용하고 있는 저이지만 이번 DSLR은 많이 땡기네욤..
2007/05/18 22:04 2007/05/18 22:04
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Ajax와 XML: 다섯 가지 Ajax 안티 패턴(anti-pattern)

원문출처 : http://www.ibm.com/developerworks/kr/library/x-ajaxxml3/

Ajax 코드의 일반적인 함정 피하기

난이도 : 중급

Jack D Herrington, Senior Software Engineer, Leverage Software Inc.

2007 년 5 월 15 일

어플리케이션들이 어떻게 잘못 되었는지를 이해함으로써 어플리케이션들을 올바르게 수행하는 방법을 배울 수 있습니다. Asynchronous JavaScript™ + XML (Ajax) 애플리케이션들을 작성하는 것에도 올바른 방식과 그릇된 방식이 있습니다.


사람들이 처음부터 모든 것을 잘 했다면 이 세상은 완전히 달라졌을 것이다. Ajax도 마찬가지다. 필자는 Ajax 개발자를 위해서 코딩, 기고, 강연, 지원 등 많은 일들을 해왔다. 이러한 일련의 활동들을 통해서 Ajax를 올바르게 다루는 방법과 잘못 다루는 방법에 대해 배웠다. 지난 기술자료인, 다섯 개의 일반적인 Ajax 패턴: 유용한 Ajax 디자인 패턴들에서, Ajax 애플리케이션을 올바르게 작성하는 다섯 가지 패턴들을 제시했다. 이 글에서는 Ajax 코드에서 자주 볼 수 있는 다섯 가지 안티 패턴(anti-pattern)에 대해 설명하겠다.

안티 패턴이란 무엇인가? 안티 패턴은 문제가 될 가능성이 짙은, 모든 사람들이 주의해야 할 애플리케이션 디자인의 결함이다. 이 글에서는 고급 주제에 대해 이야기 하겠다. 신택스 에러와 링커(linker) 문제는 언급하지 않겠다.

대부분의 개발자들은 안티 패턴의 대표적인 예라 할 수 있는, 웹 사이트에서 "SQL Injection attack" 이라는 결과를 만들어 내는 Structured Query Language (SQL) 라이브러리의 오용에 대해 알고 있을 것이다. 이러한 안티 패턴은 기업의 매출에 타격을 가하고, 고객의 기록을 노출 하기도 하며, 모든 프로그래밍 언어에서 발생할 수 있다. 따라서, 왜 이러한 일이 발생하는지, 어떻게 발생하는지, 이러한 문제를 어떻게 피하는지를 이해하는 것이 중요하다.

이 글에서는 Ajax 안티 패턴에 대해 살펴볼 것이다. 필자는 지금 기업에 수십억 달러 정도의 매출의 손실이 있다는 것을 이야기하려는 것은 아니다. 이러한 안티 패턴들이 서버를 충돌시키거나 형편없는 사용자 경험을 제공하고, 이 두 가지 모두 실망스럽고 비용이 많이 들 수 있다는 것을 이야기 하려는 것이다.

무엇인가 잘못 될 수 있다는 것을 이해한다면 많은 것을 배울 수 있다. 가끔 사람들은 Ajax을 페이지가 로딩된 후에 서버에서 XML을 보내는 유일한 방법으로 생각하고 있다. 이것은 매우 제한된 시각이며, 이것이 잘못 적용된다면 애플리케이션에 성능 문제를 일으킬 수 있다. 이 글에서, 왜 이것이 잘못 되었으며 이를 수정하는 방법을 설명하겠다.

굳이 그럴 필요가 없는데도 타이머에 폴링(poll)하기

필자가 생각하기에 많은 Ajax 문제들은 JavaScript 언어에 있는 타이머 기능의 오용과 관련이 있다. 핵심 메소드는 window.setInterval()이다. 이 메소드를 볼 때마다 여러분의 마음속에 작은 경각심이 생긴다. 왜 이 사람은 타이머를 사용하고 있을까? 틀림없이, 타이머에는 예를 들어 애니메이션과 같은 타이머의 본래 목적이 있을 것이다.

window.setInterval() 메소드는 특정 간격(매 초(second))마다 특정 함수를 콜백(call back)하도록 페이지에 명령한다. JavaScript 언어가 단일 쓰레드이기 때문에, 대부분의 브라우저들은 이러한 타이머를 거의 실행하지 않는다. 여러분이 1초를 요청하면 1초 또는 1.2초 또는 9초 또는 다른 시간으로 콜백을 얻게 된다.

타이머가 확실히 필요하지 않는 한 부분은 완료 할 Ajax 요청을 찾는 부분이다. Listing 1의 예를 보자.


Listing 1. Antipat1a_polling.html
                
<html><script>
var req = null;

function loadUrl( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.open('GET', url, true);
    req.send('');
  }
}

window.setInterval( function watchReq() {
    if ( req != null && req.readyState == 4 && req.status == 200 ) {
      var dobj = document.getElementById( 'htmlDiv' );
      dobj.innerHTML = req.responseText;
      req = null;
   }
 }, 1000 );

var url = window.location.toString();
url = url.replace( /antipat1a_polling.html/, 'antipat1_content.html' );
loadUrl( url );
</script><body>
Dynamic content is shown between here:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div>And here.</body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1a_polling.html 보기 링크 antipat1a_polling.html의 온라인 버전을 참조하라.

setInterval 호출에 도달할 때까지 모든 것이 좋아 보인다. 이 호출은 요청의 상태를 관찰 할 타이머를 설정하고 다운로드 된 자료에서 페이지의 내용을 설정한다.

요청이 짧게 완료될 때를 규명할 수 있는 문제에 대한 솔루션을 설명하겠다. Listing 2는 이 페이지가 요청하는 파일을 보여주고 있다.


Listing 2. Antipat1_content.html
                
<b>Hello there</b>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1_content.html 보기 링크 antipat1_content.html의 온라인 버전을 참조하라.

그림 1은 필자의 브라우저에 나타나는 페이지 모습이다.


그림 1. HTML 문서
HTML 문서

"그런데 이것은 잘 작동하지 않습니까? 깨짐 현상도 없는데 픽스가 왜 필요한가요?"라고 물을 수도 있겠다. 실제로 이것은 깨졌다. 매우 느리기 때문이다. 타이머 설정을 1초 간격으로 하면 요청은 잘 진행된다. 따라서 먼저, 비어있는 박스와 함께 페이지가 나타나고, 1초를 기다리면 내용이 나타난다.

솔루션은 무엇인가? Ajax는 본질적으로 비동기식(asynchronous)이다. 요청이 언제 끝났는지를 보기 위해 폴링 루프가 필요하지 않을까?

그렇게 필요한 것은 아니다. Listing 3에서 보듯, 모든 XMLHTTPRequest 객체가 제공하는 것은 onreadystatechange라고 하는 콜백 메커니즘이다. (얼마나 아름다운 이름인가, VAX PDP/11s를 연상시키는 이름이다.)


Listing 3. Antipat1a_fixed.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) {
  ...
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /antipat1a_fixed.html/, 'antipat1_content.html' );
loadUrl( url );
</script>
...

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1a_fixed.html 보기 링크 antipat1a_fixed.html의 온라인 버전을 참조하라.

이 새로운 코드는 onreadystatechange 콜백에 대한 응답으로 요청 객체가 변했는지의 여부를 본다. 그런 다음, 이것이 완료되면 페이지를 업데이트 한다.

결과는 매우 빨라진 페이지 로드이다. 페이지가 나타나면, 거의 동시에 새로운 콘텐트로 박스가 채워진다. 왜? 요청이 완료되자마자, 이 코드가 호출되고 필자는 페이지를 채우기 때문이다. 바보 같은 타이머 때문에 혼란스러워 할 필요가 없다.

또 다른 폴링 안티 패턴은 한 페이지가 요청을 서버로 반복해서 바운스(bounce) 할 때이다. 심지어 요청이 변경되지 않았음에도 그렇게 하는 경우이다. Listing 4의 검색 페이지 예제를 보자.


Listing 4. Antipat1b_polling.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) {
  ...
}

window.setInterval( function watchSearch() {
  var url = window.location.toString();
  var searchUrl = 'antipat1_content.html?s='+searchText.value;
  url = url.replace( /antipat1b_polling.html/, searchUrl );
  loadUrl( url );
 }, 1000 );

</script><body><form>
Search <input id="searchText" type="text">:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div></form></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1b_polling.html 열기 링크 antipat1b_polling.html의 온라인 버전을 참조하라.

그림 2에서는 필자의 브라우저에서 이 페이지가 실행되는 모습이다.


그림 2. 동적인 응답 영역을 가진 검색 영역
동적인 응답 영역을 가진 검색 영역

얼마나 아름다운가? 이 페이지는 이치에 맞는다. 필자가 검색 텍스트를 바꾸면, 결과 영역은 새로운 기준에 근거하여 바뀐다. (실제로는 그렇지 않지만 막후에 실제 검색 엔진이 있었다면 그렇게 했을 것이다.)

문제는 JavaScript 코드가 window.setInterval을 사용하여 계속해서 요청을 만든다는 것이다. 심지어 검색 필드의 콘텐트가 바뀌지 않았음에도 말이다. 이는 네트워크 대역폭을 잠식하고 서버 시간을 잠식한다. 대중적인 사이트의 경우 이것은 치명적이다.

솔루션은 검색 박스에 이벤트 콜백을 사용하는 것이다. (Listing 5)


Listing 5. Antipat1b_fixed.html
                
<html><script>
var req = null;
function processReqChange() { ... }
function loadUrl( url ) { ...  }

var seachTimer = null;
function runSearch()
{
  if ( seachTimer != null )
    window.clearTimeout( seachTimer );
  seachTimer = window.setTimeout( function watchSearch() {
    var url = window.location.toString();
    var searchUrl = 'antipat1_content.html?s='+searchText.value;
    url = url.replace( /antipat1b_fixed.html/, searchUrl );
    loadUrl( url );
    seachTimer = null;
   }, 1000 );
}
</script><body><form>
Search <input id="searchText" type="text" onkeyup="runSearch()">:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div></form></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat1b_fixed.html 열기 링크 antipat1b_fixed.html의 온라인 버전을 참조하라.

여기에서 필자는 runSearch() 함수를 검색 박스의 onkeyup() 메소드로 연결했다. 이러한 박식으로 사용자가 검색 박스에 무엇인가 입력하면 콜백을 받도록 한다.

runSearch()가 수행하는 것은 매우 똑똑하다. 1초 간의 단일 타임아웃을 설정하고 이 시간안에 서버를 호출하고 검색을 실행하도록 한다. 그리고 이것을 설정하기 전에 시간이 경과되지 않았다면 그 타임아웃을 삭제한다. 왜? 이것은 사용자가 많은 텍스트를 입력하도록 허용하기 때문이다. 그런 다음, 사용자가 마지막 키를 누른 후 1초 만에 검색이 실행된다. 이러한 방식으로 사용자는 계속적으로 깜박거리는 디스플레이 때문에 신경 쓰지 않아도 된다.






콜백에서 리턴 결과 검사하지 않기

많은 Ajax 안티 패턴은 XMLHTTPRequest 객체의 메커니즘에 대한 오해에서 기인한다. 필자가 종종 목격하게 되는 것 중 하나는 사용자가 콜백에서 객체의 readyState 또는 status 필드를 검사하지 않을 때이다. Listing 6을 보자.


Listing 6. Antipat2_nocheck.html
                
<html><script>
var req = null;
function processReqChange() {
  var dobj = document.getElementById( 'htmlDiv' );
  dobj.innerHTML = req.responseText;
}
...

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat2_nocheck.html 열기 링크 antipat2_nocheck.html의 온라인 버전을 참조하라.

모든 것이 멀쩡한 것처럼 보인다. 작은 요청이지만, 일부 브라우저에서는 이것으로 족하다. 하지만, 대부분의 요청들은 onreadystatechange 핸들러로 여러 호출을 요청해야 할 정도로 크다. 따라서 여러분의 콜백은 불완전한 데이터로 작동하게 된다.

이를 수행하는 올바른 방법은 Listing 7에 나타나 있다.


Listing 7. Antipat2_fixed.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}
...

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat2_fixed.html 열기 링크 antipat2_fixed.html의 온라인 버전을 참조하라.

더 많은 코드가 생긴 것은 아니지만 모든 브라우저에서 작동한다.

Windows® Internet Explorer® 7에서 이러한 문제가 다른 브라우저에서 보다 중요하다는 것을 깨달았다. Internet Explorer 7은 onreadystatechange로 많은 콜백을 한다. 심지어는 작은 요청에도 정말 많다. 따라서, 핸들러를 올바르게 작성하는 것이 중요하다.






HTML이 더 나은 선택임에도 불구하고 복잡한 XML 실행하기

필자가 일했던 한 회사에서, "intelligence at the edge of the network"라는 말을 자주 사용했다. 서버에서 모든 일을 수행하는 대신 데스크탑에서 브라우저 기능을 사용하라는 의미이다.

하지만, 페이지에 많은 정보를 넣으면 그곳에는 많은 JavaScript 코드가 놓이게 된다. 이것은 큰 단점이 된다. 바로 브라우저 호환성이다. 실제로 모든 대중적인 브라우저에서 JavaScript 코드의 모든 중요한 라인을 테스트 해야 한다. 적어도 고객이 사용할 것 같은 브라우저에서도 그렇게 해야 한다. 그래야 의미가 통한다. 복잡한 Ajax 예를 보자. (Listing 8)


Listing 8. Antipat3_complex.html
                
<html><head><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 && req.responseXML ) {
    var dtable = document.getElementById( 'dataBody' );
    var nl = req.responseXML.getElementsByTagName( 'movie' );
    for( var i = 0; i < nl.length; i++ ) {
      var nli = nl.item( i );
      var elYear = nli.getElementsByTagName( 'year' );
      var year = elYear.item(0).firstChild.nodeValue;
      var elTitle = nli.getElementsByTagName( 'title' );
      var title = elTitle.item(0).firstChild.nodeValue;

      var elTr = dtable.insertRow( -1 );

      var elYearTd = elTr.insertCell( -1 );
      elYearTd.innerHTML = year;

      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = title;
} } }

function loadXMLDoc( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /antipat3_complex.html/, 'antipat3_data.xml' );
loadXMLDoc( url );
</script></head><body>
<table cellspacing="0" cellpadding="3" width="100%"><tbody id="dataBody">
<tr>
  <th width="20%">Year</th>
  <th width="80%">Title</th>
</tr>
</tbody></table></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat3_complex.html 열기 링크 antipat3_complex.html의 온라인 버전을 참조하라.

이 코드는 Listing 9에 나타난 XML에서 데이터를 읽고 이를 테이블로 포맷팅 한다.


Listing 9. Antipat3_data.xml
                
<movies>
  <movie>
    <year>1993</year>
    <title>Jurassic Park</title>
  </movie>
  <movie>
    <year>1997</year>
    <title>The Lost World: Jurassic Park</title>
  </movie>
  <movie>
    <year>2001</year>
    <title>Jurassic Park III</title>
  </movie>
</movies>

그림 3과 같은 결과를 보게 된다.


그림 3. 복잡한 영화 리스팅 페이지
복잡한 영화 리스팅 페이지

이것은 절대로 나쁜 코드가 아니다. 실제로는 비교적 단순한 태스크를 수행하는 많은 코드일 뿐이다. 결과 페이지는 전혀 복잡하지 않다. 클라이언트 측에서는 정렬되거나 검색될 수 없다. 사실, XML과 HTML간 이러한 복잡한 변환을 할 이유가 전혀 없다.

서버가 XML 대신 HTML을 리턴 하도록 하는 것이 더 간단하지 않을까? (Listing 10)


Listing 10. Antipat3_fixed.html
                
<html><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'tableDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) { ... }

var url = window.location.toString();
url = url.replace( /antipat3_fixed.html/, 'antipat3_content.html' );
loadUrl( url );
</script><body><div id="tableDiv"></div></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat3_fixed.html 열기 링크 antipat3_fixed.html의 온라인 버전을 참조하라.

정말로 더 간단해졌다. 모든 복잡한 테이블 행과 셀 생성 코드는 <div> 태그의 innerHTML로 대체된다. à!

서버에서 리턴된 HTML은 Listing 11을 참조하라.


Listing 11. Antipat3_content.html
                
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody">
<tr>
  <th width="20%">Year</th>
  <th width="80%">Title</th>
</tr>
<tr>
  <td>1993</td>
  <td>Jurassic Park</td>
</tr>
<tr>
  <td>1997</td>
  <td>The Lost World: Jurassic Park</td>
</tr>
<tr>
  <td>2001</td>
  <td>Jurassic Park III</td>
</tr>
</tbody>
</table>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat3_content.html 열기 링크 antipat3_content.html의 온라인 버전을 참조하라.

모든 것이 그렇듯, 서버와 클라이언트 중 어디에서 처리할 것인지를 선택하는 것은 작업의 특성에 달려있다. 이 경우, 작업은 비교적 단순했다. 영화 테이블을 채우는 것이다. 작업이 더 복잡했다면, 다시 말해서, 정렬, 검색, 추가 또는 삭제, 영화를 클릭하면 더 많은 정보로 가게 되는 동적 인터랙션 같은 기능이 있다면 클라이언트에 보다 복잡한 코드가 실행되는 것을 볼 수 있다. 사실, 이 글 후반에 가서는 클라이언트에서의 정렬(sorting)을 설명할 것이다. 여기에서 서버에 너무 많은 부하를 주는 요소에 대해서 이야기 할 것이다.

이것에 대한 가장 완벽한 예제는 아마도 Google Maps일 것이다. Google Maps는 서버 측에서 리치 클라이언트 측 코드와 지능형 매핑 엔진을 혼합하는 고급스러운 작업을 수행한다. 필자는 이 서비스를 거기에서 어떤 프로세싱을 수행할 것인지를 결정하는 방법 예제로서 사용해 보겠다.






JavaScript 코드를 전달해야 할 때 XML 전달하기

웹 브라우저가 XML 데이터 소스를 읽고 이를 동적으로 실행한다는 모든 가설을 기반으로, 여러분은 이것이 사용할 수 있는 유일한 메소드라고 생각할 것이다. 하지만, 여러분의 생각은 틀리다. 매우 똑똑한 엔지니어들은 Ajax 전송 기술을 사용하여 XML 대신 JavaScript 코드를 보내기 때문이다. Listing 12에서 영화 테이블 예제를 보도록 하자.


Listing 12. Antipat4_fixed.html
                
<html><head><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dtable = document.getElementById( 'dataBody' );
    var movies = eval( req.responseText );
    for( var i = 0; i < movies.length; i++ ) {
      var elTr = dtable.insertRow( -1 );
      var elYearTd = elTr.insertCell( -1 );
      elYearTd.innerHTML = movies[i].year;
      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = movies[i].name;
} } }

function loadXMLDoc( url ) { ... }

var url = window.location.toString();
url = url.replace( /antipat4_fixed.html/, 'antipat4_data.js' );
loadXMLDoc( url );
</script></head><body>
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody"><tr>
  <th width="20%">Year</th>
  <th width="80%">Title</th>
</tr></tbody></table></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat4_fixed.html 열기 링크 antipat4_fixed.html의 온라인 버전을 참조하라.

서버에서 XML을 읽는 대신, JavaScript 코드를 읽는다. 이 코드는 JavaScript 코드에 있는 eval() 함수를 사용하여 데이터를 얻는데, 이는 테이블 구현에 사용할 수 있다.

JavaScript 데이터는 Listing 13에 나타나 있다.


Listing 13. Antipat4_data.js
                
[ { year: 1993, name: 'Jurassic Park' },
  { year: 1997, name: 'The Lost World: Jurassic Park' },
  { year: 2001, name: 'Jurassic Park III' } ]

이러한 기능은 JavaScript 언어로 서버와 통신하도록 해야 한다. 하지만, 그렇게 큰 일은 아니다. 대부분의 대중적인 웹 언어들은 이미 JavaScript Object Notation (JSON) 아웃풋을 지원한다.

효과는 명확하다. 이 예제에서 JavaScript 언어를 사용함으로써 클라이언트로 다운로드 된 데이터의 크기가 52%나 줄었다. 성능 역시 증가했다. JavaScript 버전을 읽는 것도 9%나 빨라졌다. 9%는 그렇게 큰 비율은 아니지만, 이 예제는 매우 기본적인 예제라는 것을 기억하라. 더 큰 데이터 블록이나 더 복잡한 구조는 더 많은 XML 파싱 코드를 요구할 것이지만, JavaScript 코드는 바뀌지 않는다.






서버에서 너무 많은 일을 수행하기

서버에서 적은 일을 수행해야 할 카운터 인자가 서버에서 너무 많은 일을 수행한다. 앞서 언급했지만, 이것은 균형을 맞추기 위한 작동이다. 하지만, 서버에서 작업을 분산하는 방법에 대한 설명으로서 클라이언트에서 영화 테이블을 정렬하는 방법을 설명하겠다.

Listing 14에는 정렬 가능한 영화 테이블이 나타나 있다.


Listing 14. Antipat5_sort.html
                
<html><head><script>
var req = null;
var movies = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    movies = eval( req.responseText );
    runSort( 'year' );
} }

function runSort( key )
{
  if ( key == 'name' )
    movies.sort( function( a, b ) {
      if ( a.name < b.name ) return -1;
      if ( a.name > b.name ) return 1;
      return 0;
    } );
  else
    movies.sort( function( a, b ) {
      if ( a.year < b.year ) return -1;
      if ( a.year > b.year ) return 1;
      return 0;
    } );
  var dtable = document.getElementById( 'dataBody' );
  while( dtable.rows.length > 1 ) dtable.deleteRow( 1 );
  for( var i = 0; i < movies.length; i++ ) {
    var elTr = dtable.insertRow( -1 );
    var elYearTd = elTr.insertCell( -1 );
    elYearTd.innerHTML = movies[i].year;
    var elTitleTd = elTr.insertCell( -1 );
    elTitleTd.innerHTML = movies[i].name;
  }
}

function loadXMLDoc( url ) { ... }

var url = window.location.toString();
url = url.replace( /antipat5_sort.html/, 'antipat4_data.js' );
loadXMLDoc( url );
</script></head><body>
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody"><tr>
  <th width="20%"><a href="javascript: void runSort('year')">Year</a></th>
  <th width="80%"><a href="javascript: void runSort('name')">Title</a></th>
</tr></tbody></table></body></html>

실제 환경에서는 어떻게 보이는지 알고 싶다면 새 창에서 antipat5_sort.html 열기 링크 antipat5_sort.html의 온라인 버전을 참조하라.

이것은 매우 간단한 예제이다. 이 페이지에 나타날 것 같은 특별히 긴 영화 리스트에는 작동하지 않는다. 하지만, 페이지 리프레시 없이도, 서버가 많은 일을 수행하지 않아도 빠르게 정렬하는 테이블을 만들 수 있다.






결론

필자는 Ajax에 대한 많은 글을 써왔고 많은 Ajax를 수행했다. 필자는 Ajax forum on IBM developerWorks의 Ajax 포럼을 운영한다. 따라서 Ajax에 대한 한 두 가지의 일쯤은 알고 있고 이것이 어떻게 사용되고 어떻게 오용되는지도 알고 있다. 필자가 자주 목격하게 되는 것 중 하나는 개발자들이 Ajax의 복잡성을 오해하고 있다는 것이다. 개발자들은 Ajax가 XML, JavaScript, HTML 코드를 브라우저로 보내는 것 정도로 생각하고 있다. 필자는 Ajax 플랫폼을 완전한 브라우저로 보고 있다. 사실, 대중적인 브라우저들의 전체라고 볼 수 있다.

결론은 다음과 같이 내릴 수 있겠다. Ajax에 대해 배워야 할 것은 많이 있고 이와 관련한 실수들도 많이 한다. 바라건데, 이 글이 빠지기 쉬운 함정을 피하는데 지침이 되었기 바란다. 성공을 통해 많은 것을 배울 수도 있지만 실수를 통해서도 많은 것을 배우기 마련이다.

기사의 원문보기


필자소개

Jack D. Herrington은 20년 경력을 지닌 소프트웨어 엔지니어이다. Code Generation in Action, Podcasting Hacks, PHP Hacks 의 저자이다. 30개 이상의 기술자료를 기고했다. (jherr@pobox.com)

2007/05/17 23:11 2007/05/17 23:11
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

AJAX와 XML: 다섯 개의 일반적인 Ajax 패턴

원문출처 : http://www.ibm.com/developerworks/kr/library/x-ajaxxml2/

유용한 Ajax 디자인 패턴들

난이도 : 중급

Jack D Herrington, Senior Software Engineer, Leverage Software Inc.

2007 년 4 월 10 일

Asynchronous JavaScript + XML (Ajax)은 단연 2006년의 화두였고, 2007년에도 이러한 기조를 이어갈 전망입니다. 하지만 이것이 여러분의 애플리케이션에는 어떤 영향을 미칠까요? Ajax 애플리케이션에 사용되는 일반적인 아키텍처 패턴에는 무엇이 있을까요? 이 글에서는 다섯 가지 Ajax 디자인 패턴을 소개합니다.

확실히, Ajax는 모든 사람들이 자신들의 사이트에 채택하고 싶어하는 Web 2.0 용어이다. 하지만, 이것이 진정으로 의미하는 것은 무엇일까? 엔지니어들은 아키텍처 레벨에서 이것을 자신들의 사이트에 어떻게 통합할까? 이 글에서, Ajax의 기초를 설명하고, Ajax 개발에서 베스트 프랙티스로 입증된 몇 가지 Ajax 디자인 패턴을 소개하겠다.

Ajax는 Dynamic HTML (DHTML)과 XMLHTTPRequest 객체를 포함한 일련의 기술들을 포괄하는 기술이다. DHTML은 세 가지 엘리먼트들, Hypertext Markup Language (HTML), JavaScript 코드, Cascading Style Sheets (CSS)의 결합이다. 웹 페이지에서 JavaScript 코드를 사용하면서, 콘텐트를 추가, 제거, 수정하기 위해 페이지를 동적으로 수정할 수 있다. 바로 이것이 DHTML의 동적인 요소이다. JavaScript 코드는 XMLHTTPRequest 객체를 사용하여 페이지가 로딩된 후에 서버에서 데이터를 요청한다.

서버에서 데이터를 요청하는 것과, 그 데이터를 사용하기 위해 페이지를 수정하는 것, 이 두 가지 요소들의 결합이 Ajax의 정수이자 Web 2.0 사이트의 동적인 본성이다.

하지만, 이러한 기능들이 실제 세계에서 어떻게 사용되고, 사이트에서 이들을 어떻게 사용하는지에 대해서는 정확히 알 수 있다. 따라서 간단한 디자인 패턴(design patterns.)이 필요하다. 이 용어가 생소하다면, 같은 이름의 책을 참조하기 바란다. (참고자료) 이 책에서는 엔지니어들이 접하는 공통의 태스크에 대한 구현 패턴을 설명하고 있다. 이 책에서는 시스템을 디자인하는 방법에 대한 베스트 프랙티스 뿐만 아니라, 엔지니어들이 사용할 수 있는 용어도 설명한다.

이 글에서는 다섯 가지 일반적인 Ajax 디자인 패턴을 소개한다. HTML, XML, JavaScript 코드를 사용하여 서버에서 데이터를 얻는 방법이 다양하다. 서버에서 새로운 HTML로 페이지를 업데이트 하는 가장 단순한 패턴부터 시작하겠다.

Pattern 1. HTML 세그먼트 대체하기

아마도 가장 일반적인 Ajax 태스크는 서버에서 업데이트 된 HTML을 요청하여, 이것을 사용하여 페이지의 한 부분을 업데이트 하는 것이다. 예를 들어, 주식 시세를 업데이트 하기 위해 이를 주기적으로 수행할 수 있다. 또는, 검색 요청에 대한 응답으로, 온 디맨드(on demand) 방식으로 업데이트 할 수 있다.

Listing 1의 코드는 서버에서 페이지를 요청한 다음 콘텐트를 페이지의 바디에 있는 <div> 태그에 배치하는 부분이다.


Listing 1. Pat1_replace_div.html
				
<html>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'htmlDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /pat1_replace_div.html/, 'pat1_content.html' );
loadUrl( url );
</script>
<body>
Dynamic content is shown between here:<br/>
<div id="htmlDiv" style="border:1px solid black;padding:10px;">
</div>
And here.<br/>
</body>
</html>

Listing 2는 코드가 요청하고 있는 콘텐트이다.


Listing 2. Pat1_content.html
				
HTML encoded content goes here.

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat1_replace_div.html의 온라인 버전을 참조하라.pat1_replace_div.html 새 창으로 보기 링크

이 페이지를 Firefox에 로딩할 때, 그림 1과 같은 결과를 볼 수 있다.


그림 1. <div> 태그가 있는 페이지
태그 페이지

Listing 1의 코드로 가서 몇 가지를 살펴보자. 첫 번째로 알아야 할 것은 loadUrl() 함수인데, 이것은 서버에서 URL을 요청한다. 이 함수는 XMLHTTPRequest 객체를 사용하여 서버에 새로운 콘텐트를 요청한다. 또한, 브라우저가 콘텐트를 받을 때 호출되는 콜백 함수(이 경우, processReqChange)도 지정한다.

processReqChange 함수는 객체를 검사하여 요청이 완료되었는지 여부를 확인한다. 완료되었다면, 이 함수는 페이지의 <div> 태그의 innerHTML을 응답 텍스트에 설치한다.

동적 콘텐트용 플레이스홀더로서 <div> 태그를 사용하는 것은 Ajax 코드의 주요한 특징이다. 이 태그는 (여러분이 보더 같은 것을 추가하지 않는 한) 눈에 띠는 특징은 없지만 콘텐트가 어디로 가야 할 지를 알려주는 좋은 마커로서 작동한다. 엔지니어들은 대체 가능한 세그먼트에 <span> 태그를 사용한다. 나중에 설명하겠다. <div><span> 태그의 차이점은 전자가 라인 브레이크(패러그래프)를 사용하는 반면, 후자는 인라인 텍스트의 섹션을 정확하게 구분한다는 점이다.

잠시, processReqChange 함수로 가서, 함수가 statusreadyState 값을 체크하는 것이 중요하다. 일부 브라우저는 요청이 완료될 때에만 함수를 호출하지만, 다른 브라우저는 요청이 실행 중이라는 것을 나타내면서 지속적으로 콜백한다.

Tab 디스플레이 변수

이 패턴의 또 다른 변종은 Tab 스타일의 디스플레이를 생성하는 것이다. Listing 3은 Tab Ajax 인터페이스이다.


Listing 3. Pat1_tabs.html
				
<html>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( 'tabDiv' );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( tab ) {
  var url = window.location.toString();
  url = url.replace( /pat1_tabs.html/, tab );
  ...
}

function tab1() { loadUrl( 'pat1_tab1_content.html' ); }
function tab2() { loadUrl( 'pat1_tab2_content.html' ); }
tab1();
</script>
<body>
<a href="javascript: void tab1();">Tab 1<a> 
<a href="javascript: void tab2();">Tab 2<a>
<div id="tabDiv" style="border:1px solid black;padding:10px;">
</div>
</body>
</html>

Listing 4는 첫 번째 탭의 콘텐트이다.


Listing 4. Pat1_tab1_content.html
				
Tab 1 content

Listing 5는 두 번째 탭의 콘텐트이다.


Listing 5. Pat1_tab2_content.html
				
Tab 2 content

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat1_tabs.html의 온라인 버전을 참조하라.pat1_tabs.html 새 창으로 보기 링크

이 페이지를 브라우저에 로딩하면, 그림 2와 같은 첫 번째 탭을 볼 수 있다.


그림 2. 첫 번째 탭의 콘텐트
첫 번째 탭의 콘텐트

두 번째 탭 링크를 클릭한다. 브라우저는 두 번째 탭의 콘텐트를 가져와서, 이를 탭 영역에 보여준다. (그림 3)


그림 3. 두 번째 탭의 콘텐트
두번째 탭의 콘텐트

사용자에게서 요청을 가져와서 새로운 내용으로 디스플레이의 일부를 업데이트 하는 것, 이 경우에는 Tab 디스플레이를 만드는 것이야 말로 이 디자인 패턴의 전형적인 사용법이다. 애플리케이션 측에서 얻을 수 있는 가치는 사용자에게 훨씬 가벼운 페이지를 제공할 수 있고, 사용자는 자신들이 원하는 자료들에 온 디맨드 방식으로 액세스 할 수 있다.

Ajax 이전의 일반적인 기술은 페이지에 두 개의 탭을 두고, 온 디맨드 방식으로 이들을 숨기거나 보여주는 것이었다. 다시 말해서, 두 번째 탭용 HTML은 결코 보이지 않더라도 생성되었으며, 서버 시간과 대역폭의 낭비만 초래했다. 이제 새로운 Ajax 방식으로, 두 번째 탭용 HTML은 사용자가 요청할 때에만 생성된다.

Read more 변형

실제 환경에서는 어떻게 보이는지 알고 싶다면 의 온라인 버전을 참조하라. pat1_readmore.html pat1_readmore.html 새 창으로 보기 링크

또 하나의 예로 Read more 링크를 들 수 있다. (그림 4)


그림 4. 내 지루한 블로그 엔트리의 Read more 링크
Read more 링크

강아지 산책에 대해 더 읽고 싶다고 가정해 보자. Read more 링크를 클릭하고 그 링크를 전체 스토리로 대체할 수 있다. (그림 5)


그림 5. Read more 링크를 클릭한 후의 페이지 모습
Read more 클릭 후

사용자들은 페이지 리프레시 없이도 더 많은 자료들을 볼 수 있다.

Listing 6은 이 페이지에 대한 코드이다.


Listing 6. Pat1_readmore.html
				
<html>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dobj = document.getElementById( "moreSpan" );
    dobj.innerHTML = req.responseText;
  }
}

function loadUrl( url ) { ... }

function getMore()
{
  var url = window.location.toString();
  url = url.replace( /pat1_readmore.html/, 'pat1_readmore_content.html' );
  loadUrl( url );
}
</script>
<body>
<h1>Walking the dog</h1>
I took my dog for a walk today. 
<span id="moreSpan">
<a href="javascript: void getMore()">Read more...</a>
</span>
</body>
</html>

Listing 7은 "read more" 섹션에 대한 콘텐트이다.


Listing 7. Pat1_readmore_content.html
				
It was a nice day out. Warm and sunny. My dog liked getting out for a stretch.

이 코드는 <div> 태그 대신 <span> 태그의 사용법을 보여준다. 사용 방법은 사용자 인터페이스(UI)의 요구 사항에 따라 다르다. 여러분도 보다시피 어떤 방법이든 사용하기 쉽다.

이 페이지에 새로운 HTML을 만드는 것은 해결되었고, JavaScript가 데이터를 사용하여 보다 지능적인 작업을 수행하도록 하려면? 구조적인(structured) 방법으로 데이터를 브라우저에 어떻게 가져올 것인가? 당연히, XML이 필요하다.






Pattern 2. XML 데이터 읽기

몇 가지 이유로, Ajax는 XML의 동의어처럼 되어버렸다. XML은 절대로 그렇지 않은데 말이다. 위 예제에서 보듯, 텍스트 또는 HTML 조각 또는 Extensible HTML (XHTML) 코드를 리턴할 수 있다. 하지만 XML을 보내도 응답을 받을 수 있다.

Listing 8은 서버에서 책에 대한 기록을 요청하고, 페이지 내의 테이블에 그 데이터를 디스플레이 하는 Ajax 코드이다.


Listing 8. Pat2_xml.html
				
<html>
<head>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 && req.responseXML ) {
    var dtable = document.getElementById( 'dataBody' );
    var nl = req.responseXML.getElementsByTagName( 'book' );
    for( var i = 0; i < nl.length; i++ ) {
      var nli = nl.item( i );
      var elAuthor = nli.getElementsByTagName( 'author' );
      var author = elAuthor.item(0).firstChild.nodeValue;
      var elTitle = nli.getElementsByTagName( 'title' );
      var title = elTitle.item(0).firstChild.nodeValue;

      var elTr = dtable.insertRow( -1 );

      var elAuthorTd = elTr.insertCell( -1 );
      elAuthorTd.innerHTML = author;

      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = title;
} } }

function loadXMLDoc( url ) {
  if(window.XMLHttpRequest) {
    try { req = new XMLHttpRequest();
    } catch(e) { req = false; }
  } else if(window.ActiveXObject) {
    try { req = new ActiveXObject('Msxml2.XMLHTTP');
    } catch(e) {
    try { req = new ActiveXObject('Microsoft.XMLHTTP');
    } catch(e) { req = false; }
  } }
  if(req) {
    req.onreadystatechange = processReqChange;
    req.open('GET', url, true);
    req.send('');
  }
}

var url = window.location.toString();
url = url.replace( /pat2_xml.html/, 'pat2_xml_data.xml' );
loadXMLDoc( url );
</script>
</head>
<body>
<table cellspacing="0" cellpadding="3" width="100%">
<tbody id="dataBody">
<tr>
  <th width="20%">Author</th>
  <th width="80%">Title</th>
</tr>
</tbody>
</table>
</body>
</html>

Listing 9는 이 페이지의 데이터이다.


Listing 9. Pat2_xml_data.xml
				
<books>
  <book>
    <author>Jack Herrington</author>
    <title>Code Generation in Action</title>
  </book>
  <book>
    <author>Jack Herrington</author>
    <title>Podcasting Hacks</title>
  </book>
  <book>
    <author>Jack Herrington</author>
    <title>PHP Hacks</title>
  </book>
</books>

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat2_xml.html의 온라인 버전을 참조하라.pat2_xml.html 새 창으로 보기 링크

이 페이지를 브라우저에 로딩하면, 그림 6과 같은 결과를 볼 수 있다.


그림 6. XML 디스플레이 페이지
XML 디스플레이 페이지

이 페이지와 이전 패턴의 페이지와의 큰 차이는 processReqChange 함수에 있다. responseText를 보는 대신, 이제는 서버에서 온 응답이 XML로 올바르게 인코딩 될 경우에만 사용할 수 있는 XML Document Object Model (DOM)인 responseXML을 본다.

responseXML을 사용하여, XML 문서에서 <book> 태그들의 리스트를 요청한다. 이들 각각에 대해 <title><author> 엘리먼트를 받는다. 그런 다음, 각 책의 테이블에 행을 추가하고, 각 행에 셀을 추가하여 저자와 제목 데이터를 포함시킨다.

이는 전형적인 XML 데이터의 사용법이다. 보다 고급의 JavaScript 코드는 리턴된 데이터에 기반하여 클라이언트 측 소팅(sorting) 또는 검색을 수행한다.

안타깝게도, XML 데이터를 전송할 때의 단점은 브라우저가 XML 문서를 파싱하는데 시간이 걸린다는 점이다. 또한, XML에서 데이터를 찾는 JavaScript 코드는 복잡해 질 수 있다. (Listing 8) 대안은 서버에서 JavaScript 코드를 요청하는 것이다.






Pattern 3. JavaScript 데이터 읽기

서버에서 JavaScript 데이터를 요청하는 것은 JavaScript Object Notation (JSON)으로 통용되는 기술이다. JavaScript 데이터를 리턴하면 브라우저가 효율적으로 JavaScript 데이터 구조를 파싱하고 생성할 수 있고, 사용이 훨씬 쉬워진다.

서버에서 XML 데이터를 읽는 Listing 8의 코드를 서버에서 JavaScript 데이터를 읽는 것으로 수정했다. 새로운 코드는 Listing 10과 같다.


Listing 10. Pat3_js.html
				
<html><head><script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var dtable = document.getElementById( 'dataBody' );
    var books = eval( req.responseText );
    for( var b in books ) {
      var elTr = dtable.insertRow( -1 );

      var elAuthorTd = elTr.insertCell( -1 );
      elAuthorTd.innerHTML = books[b].author;

      var elTitleTd = elTr.insertCell( -1 );
      elTitleTd.innerHTML = books[b].title;
} } }

...

모든 HTML 코드는 같다. processReqChange 함수는 JavaScript 데이터가 서버에서 리턴했던 eval을 읽기 위해 변경된다. 이 함수는 eval에서 나온 JavaScript 객체들을 데이터 소스로서 사용하고, 이것은 테이블에 추가된다.

Listing 11은 서버에서 온 JavaScript 데이터이다.


Listing 11. Pat3_js_data.js
				
[ { author: 'Jack Herrington', title: 'Code Generation in Action' },
{ author: 'Jack Herrington', title: 'Podcasting Hacks' },
{ author: 'Jack Herrington', title: 'PHP Hacks' }
]

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat3_js.html의 온라인 버전을 참조하라. pat3_js.html 새 창으로 보기 링크

왜 많은 Ajax 애플리케이션 엔지니어들이 데이터를 인코딩할 때 XML 대신 JavaScript를 선호하는지를 쉽게 알 수 있다. JavaScript 코드는 읽기와 관리하기가 더 쉽고 브라우저가 처리하기에도 더 쉽다.

데이터 수집과 디스플레이도 중요하지만, Ajax의 핵심은 현재 데이터의 디스플레이이다. 여기에서는 현재(current.)가 중요하다. 여러분은 서버에서 늘 새로운 데이터를 가져오고 있다고 어떻게 확신할 수 있는가?






Pattern 4. 브라우저 캐시 피하기

브라우저는 웹 트래픽을 최적화하려고 하므로, 같은 URL을 두 번 요청하면, 페이지를 다시 요청하는 대신, 브라우저 캐시에 저장된 페이지를 사용하게 될 것이다. 따라서, Ajax 애플리케이션의 또 다른 패턴은 URL에서 무작위 엘리먼트를 사용하여 그 브라우저가 캐싱된 결과를 리턴하지 않도록 하는 것이다.

내가 좋아하는 방법은 현재 시간의 숫자 값을 URL에 추가하는 것이다. Listing 12는 그 방법이다.


Listing 12. Pat4_cache.html
				
<html>
<script>
...

function loadUrl( url ) {
  url = url + "?t="+((new Date()).valueOf());
  ...
}

...

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat4_cache.html의 온라인 버전을 참조하라.pat4_cache.html 새 창으로 보기 링크

이 것은 Listing 1에서 참조한 코드이지만, URL 스트링에서 JavaScript 텍스트가 추가되었다. 시간 값을 갖고 있는 t라고 하는 새로운 매개변수를 URL에 추가했다. 서버가 그 값을 인지하는지 여부는 상관 없다. 이것은 브라우저가 URL 기반 페이지 캐시를 무시하는지를 확인하는 방법일 뿐이다.






Pattern 5. 여러 HTML 세그먼트 대체하기

마지막 패턴은 첫 번째 패턴의 고급 버전이라고 볼 수 있다. <div> 태그를 서버에서 가져온 콘텐트로 대체하는 것이다. 웹 애플리케이션의 일반적인 문제는 사용자 인풋에 응답할 때, 여러 디스플레이 영역들이 업데이트되어야 한다는 점이다. 예를 들어, 주식 시세 애플리케이션에서, 디스플레이의 한 부분이 최신 시세를 보여주고, 또 다른 부분은 최신 가격 리스트를 보여준다.

디스플레이의 여러 부분들을 업데이트 하기 위해, 두 섹션에 대한 데이터를 포함하고 있는 서버에서 XML 응답을 사용한다. 정규식을 사용하여 응답에서 개별 섹션들을 분리한다. Listing 13은 그 방법이다.


Listing 13. Pat5_multi_segment.html
				
<html>
<head>
<script>
var req = null;
function processReqChange() {
  if (req.readyState == 4 && req.status == 200 ) {
    var one = req.responseText.match( /\<one\>(.*?)\<\/one\>/ );
    document.getElementById( 'divOne' ).innerHTML = one[1];
    var two = req.responseText.match( /\<two\>(.*?)\<\/two\>/ );
    document.getElementById( 'divTwo' ).innerHTML = two[1];
} }

function loadXMLDoc( url ) { ... }

var url = window.location.toString();
url = url.replace( /pat5_multi_segment.html/, 'pat5_data.xml' );
loadXMLDoc( url );
</script>
</head>
<body>

This is the content for segment one:<br/>
<div id="divOne" style="border:1px solid black;padding:10px;">
</div>
And segment two:<br/>
<div id="divTwo" style="border:1px solid black;padding:10px;">
</div>

</body>
</html>

Listing 14는 서버에서 가져온 데이터이다.


Listing 14. Pat5_data.xml
				
<segments>
  <one>Content for segment one</one>
  <two>Content for segment <b>two</b></two>
</segments>

실제 환경에서는 어떻게 보이는지 알고 싶다면 pat5_multi_segment.html의 온라인 버전을 참조하라. pat5_multi_segment.html 새 창으로 보기 링크

이 코드를 브라우저에 로딩하면 그림 7과 같은 결과를 볼 수 있다.


그림 7. 서버에서 온 데이터로 업데이트 된 두 세그먼트
두 세그먼트 디스플레이

페이지 코드에서, 서버에서 리턴된 자료는 유효 XML이기 때문에 XML 응답을 사용할 수도 있었따. 하지만, XML 코드에서 개별 세그먼트를 크래킹 하는 대신 정규식을 사용하는 것이 더 쉬웠다.


결론

Ajax는 강력한 만큼, 오용 및 오해의 여지도 많이 있다. 이 글에서 내가 설명한 패턴들은 웹 애플리케이션에서 Ajax를 사용하는데 좋은 지침이 될 것이다. 이 글에서 제공한 코드를 사용하는 것 외에도, Ajax에서 파생된 Ajax와 Web UI 라이브러리도 사용해 보는 것도 좋다. 이중 가장 중요한 것은 Prototype.js 라이브러리로서, 서버에서 데이터를 쉽게 가져올 수 있으며, 크로스 브라우저 호환 방식을 사용하여 웹 페이지 콘텐트를 업데이트 한다. 이 라이브러리를 사용하면 전담 엔지니어들은 다양한 브라우저와 플랫폼에서 이들을 관리 및 테스트 할 수 있다.

Ajax에는 여러분의 애플리케이션에 동적인 작동을 추가할 수 있는 분명 무엇인가가 있다.

기사의 원문보기

필자소개

Jack D. Herrington은 20년 경력을 지닌 소프트웨어 엔지니어이다. Code Generation in Action, Podcasting Hacks, PHP Hacks 의 저자이다. 30개 이상의 기술자료를 기고했다. (jherr@pobox.com)

2007/05/17 23:10 2007/05/17 23:10
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

손담비 일본 MSN 영상자료

* 본 영상은 저의 저작물이 아니며 그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않습니다. *

손담비



2007/05/17 10:33 2007/05/17 10:33
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

R.F.I.D = 666

* 본 영상은 저의 저작물이 아니며 그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않습니다. *

RFID기술에 대해 많은 사람들이 기대와 우려를 표하고 있다. 기술의 발전에 따른 편의성 증대와
그에 따른 개인 프라이버시의 무방비 노출 문제가 그것이다.
혹자는 RFID를 '악마의 표식'이란 극단적인 표현까지 하고 있는데, 이같은 시각에서 바라본 영상물 몇개를 소개 한다.




2007/05/17 07:02 2007/05/17 07:02
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 저도 RFID를 이용하여 미들웨어를 개발하는 입장에서.. 구경 잘 하고 갑니다...

    제가 찾아본 바로는 SYBASE 사에서 OPEN된 iAnywhere 가 있습니다. 여기 ALE자체가 라이브러리로 제공이 되고있어서.. 개발에 부담이 덜 될것 같다고 생각하지만.. 아직 사용법등을 본적은 없어서.. 도움이 되신다면 한번 검토해 보시고.. 제게도 좋은 소식이 있으면 알려주시면 좋겠네요.. ^^ 수고하세요~

  2. Sybase에도 rfid 솔루션이 있었군요.
    몰랐던 정보입니다. 감사합니다. ^^

IBM RFID Checkout in Supermarket

* 본 영상은 저의 저작물이 아니며 그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않습니다. *

2007/05/17 05:42 2007/05/17 05:42
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

RFID - Technology Video

* 본 영상은 저의 저작물이 아니며 그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않습니다. *

rfid를 이용한 물류관리에 대한 전반적인 이해를 돕기위한 동영상

2007/05/17 05:35 2007/05/17 05:35
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

나도 새로운 광고수익 모델에 참여해 볼까? :: 아글로코 ( AGLOCO )


현재 블로그 사용자들은 새로운 광고 프로그램 혹은 새로운 수입을 올릴수 있는 시스템이 생겨나기를 기대할것이다. 물론 구글의 '애드센스'는 현재 대 히트를 치며 전세계 블로그안에 자리를 차지 하고있다. 하지만 아직 많은 사람들에게 알려지지 않은 또한가지의 수입원이 있다.

이미 전세계의 블로거나 인터넷유저들의 주목하고있는 회사가 하나있는데, 이제는 소개를 해야할 시간이 온것같아 이렇게 소개한다. 아마 이것은 또하나의 인터넷 시장을 뒤흔들어 놓을만한 아이템이 될지 모르니 지금 이 글을 읽고 있다는것이 당신에게는 행운일지 모른다.

자, 이제 내가 소개하려는것이 무엇인지 알아보자.

AGLOCO?

A Global Community의 앞자를 따서 만든 이회사는, 스탠포드의 MBA과정을 밟고 있는 8명의 학생과 그외 4명의 사람들 총12명의 사람들이 모여서 만든회사로. 'Own The Internet' 인터넷을 자기것으로 만들라! 라는 슬로건을 내건 회사이다. 이미 Agloco에 대해서 들어본 블로거나 유저들은 상당히 있을것이다, 물론 처음 듣는사람이 훨씬 많겠지만..

어쨋든, 이 회사는 현재 오픈한지 8개월 정도가 되었으며 이미 외국의 블로거들 사이에서는 엄청나게 유명해졌다. 그렇다면 왜 아직한국에는 알려지지 않았는가? 일단은 영어이기 때문에, 그리고 또한가지는 한국사람들의 오해때문이다. 그이야기는 조금 뒤에 하도록 하겠다.

AGLOCO를 통해 어떻게 수입을 올릴수있는가?

원리는 간단하다. Agloco는 Viewbar라고 하는 일종의 툴바를 제공하는데, 그 툴바를 다운로드받아서 켜놓고 인터넷을 평상시처럼 사용하면, 사용한 시간만큼 시간을 적립해 돈을 제공하는것이다.

AGLOCO가 어째서 유저에게 돈을 주지??

사용자 삽입 이미지


위의 사진을 보면알겠지만, 잘이해해보면 구글의 원리와 비슷하다
Agloco가 우리에게 '광고'가 삽입된 작은 툴바를  제공함으로서 스판서들과 광고주들을 통해 수입을 얻는다. 유저들이 뷰바를 사용하기때문에  Agloco는 자신들의 수입을 다시 우리 즉 뷰바 유저들에게 돌려주겠다는 것이다.

그럼 다운받아서 켜놓고 인터넷 하면 돈을준다??
그렇다. 획기적이다. 너무 획기적이여서 사기처럼 들린다. 구글처럼 광고를 클릭해야 돈을 버는것도 아니고 우리가 물건을 사는것도 아닌 단순한 사용대가로 돈을 받는것이다..

그럼 돈을 얼마나, 어떻게 벌지?
일단 수입의 기준은 사용 시간으로 계산되는데 시간적립은 한달에 5시간으로 제한한다. 한달에 5시간만 뷰바를 켜놓고 사용하면 된다는 뜻이다. 그이후에는 뷰바를 꺼놓고 써도 상관없다. 시간이 5시간까지 밖에 적립이 안되는 이유는 예전에 닷컴붐이 한참일어났을때 AllAdavantage라는 회사가 있었다. 물론 Agloco의 멤버들이 이안에 포함되어있다. 그회사역시 같은컨셉으로 툴바를 제공했는데 성공했었다가 몇년후 문을 닫았다.

이유는? 너무많은 유저들이 사용해서 회사가 버는 돈보다 사용자에게 돌아가는 돈이 더 많았기 때문이다. 그래서 이번엔 5시간이라는 제한과 더 발전된 기술로 몇년만에 사람들앞에 다시 나타난것이다.

한가지 알아야할것은 회원수가 증가할수록 회사의 수입은 늘어나고 회사의 수입이 늘어날수록 각 사용시간에 따라 유저에게 분배되는 돈의 가격은 계속 증가할것이다.

한달에 5시간.,하루에 10분만 뷰바를 켜놓고 인터넷을 하면 매달 돈을 벌수있다... 믿겨지는가..?
아직 놀라긴 이르다.. 더엄청난 것이 있으니..

추천시스템
이 부분에서 대부분의 많은 사람들은 오해를 하기때문에 잘 이해해야한다.
구글 애드센스를 사용하는 사람이라면 이미 추천시스템에대해서 알것이다. 나를 통해서 누군가 애드센스를 가입하면 그사람이 일정 목표액에 도달했을때 나에게도 추가 수당이 지급되는것..
Agloco역시 추천 시스템이 있는데 이것은 어마어마하다.

간단한원리로 구글은 직추천, 즉 자기를 통해 추천받은사람 한테만 추가수당이 있다 하지만 Agloco는 내가 추천한사람 또 그사람이 추천한사람 또 그사람이 추천한사람.... 그 사람들이 뷰바를 사용하는 시간또한 나에게도 적립이된다. 물론 무한정은 아니고 최종 5단계까지만 적립된다. 무조건 가입한다고 돈을 받는것은 아니고 툴바를 사용했을 경우이다.


방금 이런생각을 했을것이다. 엥? 모야 사기네, 피라미드, 인터넷 다단계네..라고
이미 수도없이 들어왔기 때문에 별로 걱정하지도 신경쓰지도 않는다. 그런종류의 비방글이라면 댓글을 달지 말기를 바란다.

글세 과연그럴까? 그들은 어떤 물건을 사라고 강요하는것도 아니고 우리가 가입할때 돈을 낼필요도 없다. 또 5단계까지의 제한이 있어서 구지 피라미드라고 할수도 없다. 구글의 추천시스템에서 약간 발전한것이며 또한 미국의 많은 인터넷 Affilate Program의 한종류와 다를바가 없다.

이것이 다단계다 사기다에대해서는 논하고 싶지않다. 어차피 Agloco가 생긴 지난 8개월간 외국에서도 신나게 논쟁을 해왔고 현재도 믿지않는 사람들은 많다. 나는 이글을 읽는 사람보고 이걸 꼭 가입해야 한다고 강요하고 싶은 생각도 없으며 단지 기회를 제공하는 역할을 할뿐이다.

지난번에 블로깅으로 10000$ 이상을 벌고있다는 John Chow의 이야기를 기억하는가? 그는 현재 자신의 Agloco네트워크에 15,000명의  회원이 등록되어 있으며 회사 전체 랭크 3위에 기록되어있다.
이미 미국에선 유명인사이며 구글에서 Make Money Online의 키워드로 검색하면 두번째에 그의 블로그가 올라와있다.

솔직해지자.
이 회사의 논쟁은 '뷰바'이다. 왜냐하면 아직 뷰바는 다운로드가 가능하지 않기 때문이다. 나도 인간이고 물증이 없기 때문에 뷰바가 실제로 릴리즈 되기 전까지는 되도록이면 말하지 않으려 했었다. 하지만 뷰바의 제공없이도 현재 전세계에는 하루에도 몇천명씩 가입자가 증가하고 있기때문에 하루하루가 아쉬울뿐이었다. 하지만 이논란도 뷰바가 나오고 나면 다 사라질것이다, 그리고 또 한가지는 이들이 운영했었다던 AllAdvantage는 이미 성공했었고 실제로 돈을 받았다는 물증도 있다.




나는 Agloco에 가입한지 벌써 3개월이 지나가고 있다. 뷰바가 나오기만을 손꼽아 기다렸고 4월달에 나온다던 뷰바는 기술적 문제로 계속 미루어져 왔다. 하지만 오늘 미국현지시간으로 (저는 미국에 거주중입니다) 오전 11시가 조금되기전 JohnChow의 블로그에 동영상이 올라왔다. 사진으로는 익히 봐왔지만 직접 동영상으로 보긴 처음이었다. Agloco회사 자체의 블로그에도 소식이 업데이트 되었기때문에 상당히 믿을만 하다고 생각된다.

동영상 꼭보세요 John Chow가 직접 뷰바사용기 -> 클릭

몇가지 유용한 사이트를 제공하겠다. 물론 영어로 되어있음. 네이버나 다음에서 검색해서 뜨는 사이들은 전부 개인들이 만든것이기때문에 나도 많이 둘러봤지만 과장되거나 너무 홍보적이거나 정확하지 않은 정보들이 포함되어있기 때문에 조심하라고 말해주고 싶다.



Agloco의 웹사이트 직접가기 및 가입하기 -> 클릭
Agloco의 공식 블로그 -> 클릭
Agloco의 공식 한글 블로그 -> 클릭
돈을 얼마나 벌수있는가에 대한 연구 -> 클릭

Agloco의 가입은 무료이며 정보를 많이 요구하지 않기때문에 5분도 걸리지 않는다. 그리고 Agloco는 직접 가입할수 없으며 오직 추천을 통해서만 가입이 가능하다.

그리고 Agloco의 가입방법 -> 클릭


원문 출처 : http://shinee.tistory.com/44
원문 출처의 게시자는 본 글을 CCL [저작자표시-비영리-동일조건변경허락] 2.0 대한민국
라이센스를 주장하고 있으므로 자연히 본 글은 원문의 CCL을 따릅니다.

2007/05/16 13:27 2007/05/16 13:27
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

NetBeans IDE 6.0 Milestone 9 배포

사용자 삽입 이미지


netbeans.org 에서 넷빈즈 6.0 프리뷰 기사가 올라왔습니다. 물론 다운로드도  가능하구요.
( http://www.netbeans.org/community/releases/60/index.htm )

이 기사에서 넷빈즈 6.0의 새로운 기능을 다음과 같이 소개 하고 있네요.

에티터 향상
 - 좀 더 스마트한 code completion
 - 하이라이트
 - 향상된 내비게이션과 인스펙션

   screenshot of a window being moved by drag and drop

   screenshot of debugger windows with the Local Variables window fronted


Ruby/JRuby/Ruby on Rails 지원
  - 루비 프로젝트 지원
  - 향상된 루비 에디팅
  - 루비온레일스 지원

   screenshot of a window being moved by drag and drop



손쉬운 인스톨과 업그레이드
  - 기존의 업데이트 센터와 모듈메니저가 플러그인 메니저로 통합되면서 손쉬운 업데이트와
    플러그인 활성/비활성을 지원

   Customize your installation with the new NetBeans installer.


Swing GUI 개발
  - Bean Binding
  - Swing Application Framework 지원 : JSR 296 의 내용을 지원 한다고 합니다.

   screenshot of a running desktop database application created with the help of beans binding and Swing Application Frameword support



프로파일링
  - 프로파일러와 넷빈즈의 통합
  - 새로운 프로파일링 태스크 선택 dialog
  - Heap Walker

   profiler start screen


Web 과 Java EE
  -  Visual Design for web application 내장 : Visual Web Pack이란 이름으로 제공되던 웹 개발 환경이 넷빈즈에 통합되었습니다.
  - Visual page flow editing
  - 향상된 javascript 지원
  - Ajax 기능 내장형 JSF(Java Server Faces) 컴포넌트
  - Java Studio Creator로부터의 손쉬운 마이그레이션
  - 향상된 CSS 에디팅





Mobility
  - CLDC및 MIDP, CDC 개발을 위한 새로운 통합 UI 제공
  - 새로운 게임 빌더 내장
  - 새로운 Visual Mobile Designer
  - Design Analysis
  - 새로운 커스텀 컴포넌트
  - 새로운 Flow Control
  - JSR 172 stub 컴파일러 재 작성
  - 프로젝트 설정 매니저 향상

  

  


SOA
  - 그래피컬 WSDL 에디터
  - 비지니스 이벤트 프로세싱
  - 바인딩 컴포넌트를위한 툴 제공












UML
  - 템플릿 기반 코드 생성 가능
  - 콜렉션 타입 관리 기능 향상
  - 정렬도구 제공
  - 배포 툴 제공
  - 새로워진 Window Layout
  - 다이어그램 노드에서 Save As 가능






NetBeans Platform API 향상
  - Visual Library API
  - NetBeans Preferances API
  - Lexer
  - Logger
  - 제너릭 인터페이스


그외..
  - 로컬 파일에 대한 히스토리 저장
  - J2SE 프로젝트에 대한 Java Web Start 기능 제공
2007/05/16 12:17 2007/05/16 12:17
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

2차 세계대전을 무대로 독일 로봇대 미국로봇의 대결

이 동영상은 제가 제작한 동영상이 아니므로 제가 저작권자가 아니며
그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않음을 밝혀둡니다.
---------------------------------------------------------------------------
2007/05/16 01:24 2007/05/16 01:24
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

철권 에디 캐릭터의 모션 캡처용 데모 영상

* 본 영상은 저의 저작물이 아니며 그런 이유로 제 블로그에 포스팅 하는 글에 대한 CCL의 영향을 받지 않습니다. *

2007/05/16 01:10 2007/05/16 01:10
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

오랜만에 千と千尋の神隱し - 센과 치히로의 행방불명을 다시 봤습니다.

센과 치히로의 행방불명

일문 포스터를 찾고 싶었지만 도저히 찾을수가..



 


센과 치히로의 행방불명 엔딩-いつも何度でも(언제나몇번이라도)

퇴근 후 할일없이 빈둥거리다 딱히 할일도 없고 무료하기도 해서 '센과 치히로의 행방불명'을 다시 한번 봤습니다.
센과 치히로의 행방불명을 이번에 본걸로 4번째 보는건데요..
마지막으로 보고난 후 한 3-4년은 너끈히 흐른것 같습니다.
이 작품이 2001년도 작이니 애니메이션에서는 고전이라면 고전일수도 있겠군요..

부끄럽게도 이번에 집에서 한적하게 이 애니를 보다가 마지막즈음에서는 눈물이 흐르더라구요..
왜인지는 모르겠지만 예전에는 하야오 감독의 톡특한 상상력과 '과연 지브리.'라는 말이 절로나오는 '재미있는' 애니였는데..
물론 지금도 재미있게 느껴지는 애니이긴 하지만
예전에 볼 때는 이번처럼 가슴을 후벼파는 무언가는 느끼지 못했거든요..

센과 하쿠가 나누는 감정의 흐름 때문이 아니라 다른 이유에서 흘린 눈물이었지만..

세상과 타협하느라 옳은일을 외면하고, 행동하는 젊음 이란 말 마저도 무색케 하는 제자신이 부끄러웠고
자신이 바라는 그 길을 향해 망설임 없이 걸음을 내딛는 치히로의 모습에서 부러움과 아름다움이 느껴 졌거든요.. 더불어  성우의 목소리도 그 성격에 너무나 어울려서.


나이가 들수록 애가 되어가나 봅니다. [하핫]

센과 치히로의 행방불명
2007/05/15 13:50 2007/05/15 13:50
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

JAVA 5 한글 api

2007/05/15 09:54

서비 JAVA ,

JAVA SDK 1.5 API 를 강혜원님이 한글 번역 해 주신 문서입니다.

JAVA_1.5_API_KO_다운로드
2007/05/15 09:54 2007/05/15 09:54
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다