2008년 3월 27일 목요일

적응형 소프트웨어로서의 웹 어플리케이션

다양한 브라우저에서 "동일하게 보이고 동일하게 동작하는" 웹 어플리케이션을 만들기란 쉽지 않다. 브라우저라는 환경이 너무나 다양한 탓이다. 다양한 환경을 다루는 솔루션은 단일한 환경을 다루는 솔루션에 비해 복잡해지기 마련이다.

같은 이유로 적응형 소프트웨어를 만드는 것도 어려운 일이다. 사실, "다양한 환경에서 제대로 기능하는 것"이 적응형 소프트웨어의 목표라고 할 때, 웹 어플리케이션은 브라우저라는 다양한 환경에서 제대로 동작하려고 애쓰는 적응형 소프트웨어라고도 할 수 있다.

여러 개의 솔루션을 종합해서 하나로 만든 솔루션은 복잡하기 때문에 유지보수가 어렵다. 다음 예를 보자.

#sidebar {
padding: 10px;
border: 5px solid black;
width: 230px; /* for Internet Explorer */
voice-family: “\“3\””;
voice-family: inherit;
width: 200px; /* real value */
}

html>body #sidebar {
width: 200px;
} /* for Opera */

이 코드는 인터넷 익스플로러와 오페라, 기타 브라우저에서 모두 똑같은 모양의 웹 페이지를 보여주기 위한 CSS 코드이다. 인터넷 익스플로러가 너비 값을 해석하는 방식의 차이 때문에 인터넷 익스플로러를 위한 너비값을 먼저 지정한 후, voice-family 속성을 사용해 인터넷 익스플로러가 선언이 끝난 것처럼 인식하게 하고, 그 후에 다른 브라우저를 위한 너비 값을 선언한 것이다. 하지만 오페라 브라우저도 인터넷 익스플로러처럼 voice-family 속성을 만나면 해석을 멈추기 때문에 아래 쪽에 오페라 브라우저만을 위해 추가적인 선언을 해 주었다. 이 코드는 서로 다른 브라우저 환경에서 동일한 모양을 보여준다는 목표를 달성하기 위해 일종의 CSS 트릭을 이용하고 있다. 이런 방식은 코드를 복잡하게 만들 뿐 아니라 브라우저들의 버전이 바뀌어 CSS를 해석하는 규칙이 변한다면 더 이상 유효하지 않게 된다. 하지만 CSS 기법을 담고 있는 많은 책들이 서로 다른 브라우저 문제를 해결하기 위해 이와 비슷한 트릭들에 의존하고 있다.

위 코드를 주석 없이 본다면 사실상 어떤 부분이 인터넷 익스플로러를 위한 부분이고 어떤 부분이 나머지 브라우저를 위한 부분인지, 맨 아래 오페라를 위해 삽입한 코드는 왜 들어가 있는건지, 알기가 어렵다. 하지만 각각의 CSS 코드를 분리해서 상황에 맞게 로드할 수 있다면 다음과 같이 될 것이다.

/* Internet Explorer */
#sidebar {
width: 230px;
padding: 10px;
border: 5px;
}

/* the others */
#sidebar {
width: 200px;
padding: 10px;
border: 5px;
}

이 편이 코드를 읽기는 훨씬 쉽다. 따라서 환경에 대응하는 각각의 솔루션을 분리하는 것이 복잡도를 줄이는 방법이다. 하지만 S라는 솔루션을 Sa, Sb, ... Sz 으로 분리했을 경우, 요구사항이 변하거나 다른 해결 방법을 사용하고자 하여 Sa가 Sa'으로 변경되면 Sb, ... Sz 도 같이 변경해 주어야 한다는 번거로움이 생긴다.

따라서 이상적인 방법은 Sa와 나머지 솔루션 사이의 차이를 Vab, Vac, ... Vaz로 정의한 다음, Sa만을 변경해 나가고 나머지 솔루션은 Sa에 Vab ... Vaz를 적용해 자동으로 생성하는 것이다.

이와 같은 생각을 웹 어플리케이션에 적용해보자. 하나의 브라우저에 대해서만 CSS나 자바스크립트 코드를 작성한 후 브라우저 사이의 차이를 정의한 룰을 적용해서 다른 브라우저들에 적합한 CSS와 자바스크립트 코드를 생성해내는 것이 가능할 것이다. 일단 각 브라우저에 적합한 코드들을 만들어 냈다면, 리퀘스트의 정보를 살펴보고 해당 브라우저에 맞는 코드를 로드하게 만드는 것은 쉬운 일이다.

솔루션 사이의 차이를 어떻게 기술할 수 있을까? 필요한 것은 코드에서 "관심의 대상이 되는 부분"을 정의하고 그 부분에 "규칙에 의한 변화"를 가해서 다른 솔루션을 만들어내는 것이다. AOP의 pointcut과 advice가 의도는 다를지언정 이와 비슷한 역할을 한다고 할 수 있다. 따라서 솔루션 사이의 variation을 정의하기 위해, pointcut과 advice 같은 형식을 이용할 수 있다.

이와 같은 생각을 variation-applier라는 도구로 구현해보았다. 이 도구는 CSS 파일을 대상으로 한다. 사용 방법은 기본 솔루션에 해당하는 디렉토리와, variation 룰들(IE.var opera.var 등등)이 들어 있는 디렉토리, 솔루션들이 생성될 디렉토리를 지정하고 apply를 누르면, variation 룰 당 하나씩 새로운 솔루션이 생성된다.


variation rule은 pointcut과 advice의 개념을 사용했지만 최대한 CSS 문법과 비슷하게 기술하도록 하였다. 사용 예는 다음과 같다.

/* base file */
#sidebar
{ width: 200px; margin: 0;}

case 1
/* var file */
#sidebar
{ width: ((calculate + 30px)); }
=>
/* result file */
#sidebar
{ width: 230px; margin: 0; }

case 2
/* var file */
#sidebar
{ width: ((before border 5px) (calculate * 1.1 + 10) (after padding 10px)); }
=>
/* result file */
#sidebar
{ border: 5px; width: 230px; padding: 10px; margin: 0;}

case 3
/* var file */
global
{ width: ((around border 0)) margin: ((delete)) }
=>
/* result file */
#sidebar
{ border: 0; }

기본적으로 selector가 같을 때만 variation 규칙이 적용되지만 variation의 selector를 global로 선언한 경우에는 selector에 관계없이 모두 적용된다.

variation-applier는 Common Lisp으로 작성되었으며 weblocks 웹 프레임워크 위에서 실행된다. 실행을 위해서는 Common Lisp과 weblocks를 설치하고, 소스 코드의 build-and-test.lisp 파일을 SLIME으로 로드(ctrl+c ctrl+l)한 후, SLIME에서 (variation-applier:start-variation-applier)를 치면 된다. 브라우저의 주소창에 localhost:8080 을 쳐 넣으면 입력 화면이 나타나는 것을 볼 수 있다.

Blogger에는 파일을 첨부할 수가 없기에 티스토리 블로그에 소스 코드를 올려놓았다.
소스 코드 다운로드

댓글 1개:

익명 :

안녕하세요. 새로운 웹 서비스 창업을 준비하고 있는 이성암이라고 합니다. 얼마전 님께 용건이 있어서 메일을 보냈었는데, 확인을 안 하신것 같아 이렇게 글을 남깁니다.댓글에 남기기에는 부담이 가는 부분이 있어서 메일로 다시한번 보내 보겠습니다. 꼭 확인 부탁드립니다. 광고 아니니 염려하셔도 됩니다.^^ 감사합니다.(sallbull@naver.com)