IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
한국 developerWorks   >  dW Column  > developerworks

JSON-Object-Element mapper로 웹 애플리케이션 내 역할 분담하기



강규영강규영 jania902@gmail.com

오픈마루 스튜디오에서 웹 서비스 기획과 개발을 담당하고 있으며, 소프트웨어 공학, 인터페이스 디자인, 진화심리학 등 다양한 분야에 관심을 두고 있다. 개인 블로그 “Alan’s Blog”를 운영하고 있다.

2008년 9월 9일


Ajax 애플리케이션의 자바스크립트 코드를 살펴보면 1) HTML 문자열, 2) DOM 엘리먼트, 3) JSON 객체 사이의 변환을 수행하는 단순 반복적인 부분이 많다. DOM에서 데이터를 뽑아 JSON 객체로 만들고, 이를 서버로 전송하고, 서버에서 보내준 JSON 객체를 받아 DOM을 갱신하고, 간혹 HTML 문자열을 조합해내어 innerHTML에 대입하는 것 등이다.

그러다 보면 자바스크립트 코드와 HTML이 마구 얽히고 디자인 개편 한번 하려고 하면 자바스크립트 코드도 여기저기 손봐줘야 한다. 구조와 표현을 HTML과 CSS로 분리하고 자바스크립트에는 순수하게 로직만 담아보려고 해도 이게 말처럼 쉽지 않은 경우가 많다.

Joe(JSON-Object-Element mapper)는 이러한 코드 중복을 줄이고, 각 기술(HTML, CSS, 자바스크립트) 사이의 이상적인 역할 분담을 장려하기 위해 개발된 작은 jQuery 플러그인이다.


HTML과 자바스크립트 객체의 매핑

서버 측 스크립트가 DB에 저장된 데이터를 기반으로 아래와 같은 HTML을 그려줬다고 치자.


<div id="names">
   <p class="name"><span class="first">Alan</span> <span class="last">Kang</span></p>
   <p class="name"><span class="first">Cate</span> <span class="last">Kim</span></p>
</div>


사용자가 첫 번째 사람 이름(Alan Kang)을 변경하면 동적으로 HTML이 갱신되고, 이를 저장하기 위해 서버로 Ajax 요청을 보내야 한다(아주 전형적인 시나리오다). 이 때, 클라이언트 사이드에서 이런 일이 가능하다면 좋을 것이다.


$.joe.def('Name', {first: '.first', last: '.last'});


위 코드는 Name이라는 클래스를 정의한다. Name 클래스에는 first와 last라는 속성이 있는데 각각 CSS 선택자 “.first”와 “.last”에 대응된다. 클래스를 정의했으니 이제 인스턴스를 만들어보자.


var names = $('#names p.name').toObj('Name');


위 코드에서는 jQuery의 CSS 선택자 문법을 통해 원하는 엘리먼트를 선택하고(두 개의 p.name 엘리먼트) 이를 위에서 정의한 Name 클래스의 인스턴스와 매핑한다. 이렇게 해서 얻어진 names 변수는 length가 2인 배열을 담고 있고, 이 배열의 원소는 자동으로 생성된 Joe 객체다.


alert(names[0].first()); // Alan
names[0].first('Allen');
alert(names[0].first()); // Allen


속성에 대한 getter와 setter의 이름은 똑같고 인자 개수에 의해 다형적으로(polymorphic) 실행된다. 즉, names[0].first()는 인자를 넘기지 않았으므로 getter로 수행되고, names[0].first(‘Allen’)은 인자를 하나 넘겼으므로 setter로 수행된다.

위 코드에서는 첫 번째 원소의 first 속성을 ‘Alan’에서 ‘Allen’으로 변경한다. 이 코드가 수행되면 HTML의 해당 부분도 화면에서 자동으로 갱신된다. 이제 Ajax 요청을 보내기 위해 JSON 객체를 만들어야 한다.


var json = names[0].toJson();


JSON도 쉽게 얻어졌다. 이 JSON의 내용은 {first: 'Allen', last: 'Kang'}이다. 서버로 이를 전송하는 코드는 생략하겠다. 한편, 서버에서 보내준 JSON 객체를 이용하여 화면을 동적으로 갱신해야 한다면 어떨까?


var element = // …
var name = $.joe.Name.fromJson(json)
name.attach(element);


$.joe.Name.fromJson(json) 부분은 JSON 객체로부터 Joe 객체를 만들어내고, Joe 객체인 name의 attach() 함수는 객체의 각 속성을 엘리먼트에 반영하는 역할을 수행한다.



위로


컴포지션, 타입 지정, 속성 매핑

이제 예제를 조금 더 복잡하게 바꿔보자. Person은 name, age, profile image url을 갖는다. 여기에서 name은 위에서 정의한 Name 클래스의 인스턴스다. HTML은 아래와 같다.


<div class="person">
  <p class="name"><span class="first">Alan</span><span class="last">Kang</span></p>
  <p class="age">18</p>
  <p><img class="profile" src="alan.jpg" /></p>
</div>


Name 클래스는 위에서 이미 정의했으니, Person을 정의해보자.


$.joe.def('Person', {
  name: '.name {{Name}}',
  age: '.age {{number}},
  profile: '.profile [[src]]',
});


위 정의에서:

  • name 속성은 .name에 매핑되고, 타입은 Name이다.
  • .age 속성은 .age에 매핑되고, 타입은 number다.
  • .profile 속성은 .profile에 매핑되고, 타입은 생략되었으므로 string이다. 다만 [[src]]를 통해 innerHTML이 아닌 img.src 속성에 매핑되도록 지정하였다.

이제 아래와 같이 인스턴스를 만들고 사용할 수 있다.


var person = $(‘.person’).toObj(‘Person’);
person.name().first('Allen'); // 이름을 Alan에서 Allen으로 변경
person.age(person.age() + 1); // 나이 한 살 더 먹기
person.profile('alan.png'); // img.src 값을 alan.jpg에서 alan.png로 변경




위로


동적 콘텐츠와 정적 콘텐츠를 똑같이 다루기

눈치 빠른 독자들은 이미 알아챘겠지만 Joe는 서버에서 페이지 로딩 시점에 보내준 HTML과 중간에 동적으로 생성한 JSON 객체를 최대한 같은 방식으로 취급할 수 있게 해준다. 별도 데이터를 자바스크립트 객체나 배열에 넣어놓고 쓰는 것이 아니라 브라우저의 DOM 자체를 데이터 소스로 사용하기 때문이다.

예를 들어 현재 로그인한 사용자의 이름과 아이디를 자바스크립트에서 알아야 하는 경우가 있다. 이 때 지금까지 보통 쓰던 방식은 var currentUser = {id: …, name: …}; 등과 같이 객체를 만들어 어딘가에 박아놓고 필요할 때 불러 쓰는 식이었다. 하지만 로그인한 사용자의 이름과 ID는 이미 HTML에 담겨 있을 것이다. 따라서 이 정보를 자바스크립트 객체로 또 갖고 있는 것은 중복이다.

이로 인해 생길 수 있는 대표적인 문제는 HTML이 수정되었는데 currentUser 객체는 수정되지 않아 로직이 꼬이는 것이다. 페이지가 복잡해지면 복잡해질수록, 동적으로 변하는 요소가 많으면 많을수록 점점 더 큰 문제가 된다. 반면, Joe 방식에서라면 별도의 currentUser를 만드는 것이 아니라 다음과 같다.

  1. 화면에 나타나는 User 객체에 대한 마크업에 의미를 부여하여 최대한 구조를 통일하고
  2. 화면 상단에 표현되는 현재 로그인한 사용자 정보도 같은 마크업을 사용하여 그려준다.
  3. 이 때, 표현은 CSS로 분리되어 있으므로 디자인 자유도는 충분히 살려둘 수 있다.
  4. $.joe.def를 통해 User 객체를 정의하고 currentUser를 자동으로 얻어낸다.

이 방식은 웹 애플리케이션의 이상적인 역할 분담(separation of concerns)에 가깝다. 즉 구조와 의미(혹은 데이터)는 HTML에 몰아넣고 표현은 CSS가 담당하며, 자바스크립트는 로직만을 담당한다.


맺음말

이밖에도 객체와 엘리먼트 분리하기, 메서드 정의하기, 객체로부터 HTML 그려내기, 배열과 매핑하기 등 실제 프로젝트를 수행하고자 할 때 꼭 필요한 기능들이 구현되어 있으나 지면 관계 상 생략하였다. 자세한 소개는 필자의 블로그 글(http://alankang.tistory.com/137)과 다운로드 파일에 포함되어 있는 예제(BDD 스팩에 담긴 예제)를 참고하기 바란다.




위로


예제 및 코드 다운로드

http://jania.pe.kr/aw/moin.cgi/JsonObjectElementMapper



참고자료


  1. JOE 다운로드 페이지
  2. JSSpec
  3. John Resig의 자바스크립트 마이크로템플릿 엔진



이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us



위로


[지난 developerWorks Column 보기]

사이트 여행

dW 커뮤니티
포럼 | 블로그 | Spaces
dW Student Community

로컬 컨텐츠

행사 및 세미나

기획 기사

개발자 입문

튜토리얼 및 교육

TOP 10 인기자료

SW 다운로드

RSS 피드

뉴스레터
 
  
자바스크립트가 작동이 중지되었습니다. 이 기능을 수행하시려면 브라우저에서 자바스크립스트를 작동시켜 주시거나 이곳을 클릭해주세요.

Special offers
Screencast
IBM SOA Sandbox 시험판
dW Student Community
로보코드
코드 트레이닝


    IBM 소개 개인정보 보호정책 문의