'ITWeb/개발일반'에 해당되는 글 490건

  1. 2008.07.24 [펌]html meta tags
  2. 2008.07.21 php 모듈 추가하기 - Installation of PECL extensions
  3. 2008.07.21 css 로 문장 정렬하기 tip
  4. 2008.07.21 [펌]스프링 프레임워크와 DDD
  5. 2008.06.30 [펌]AOP
  6. 2008.06.16 Data Hiding...
  7. 2008.04.17 [PHP]bitwise operators ...
  8. 2008.04.14 [PHP]php 로 구현된 singleton 패턴
  9. 2008.02.20 JavaScript 강좌 references. 2
  10. 2008.02.20 JavaScript Tips

[펌]html meta tags

ITWeb/개발일반 2008. 7. 24. 12:03
아직도 html 코드에 기본이 되는 태그들을 안쓰시는 분들이 많더군요.
기본적으루 좀 넣어 주자구요.. ^^*
사용자를 위한 배려 아닐런지요..
특히 커뮤니티 서비스를 만드시는 분들은.. 기본 기본..

no cache 넣어 주고 keyword 넣어 주고 description 넣어 주고... 이게 어렵나.. 흠..
이도 저도 싫으면.. no cache 라도..

<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="EXPIRES" CONTENT="Mon, 22 Jul 1999 00:00:00 GMT">
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">


ref. http://www.i18nguy.com/markup/metatags.html


Tag NameExample(s)Description
Author<META NAME="AUTHOR" CONTENT="Tex Texin"> The author's name.
cache-control<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"> HTTP 1.1. Allowed values = PUBLIC | PRIVATE | NO-CACHE | NO-STORE.
Public - may be cached in public shared caches
Private - may only be cached in private cache
no-Cache - may not be cached
no-Store - may be cached but not archived

The directive CACHE-CONTROL:NO-CACHE indicates cached information should not be used and instead requests should be forwarded to the origin server. This directive has the same semantics as the PRAGMA:NO-CACHE.
Clients SHOULD include both PRAGMA:NO-CACHE and CACHE-CONTROL:NO-CACHE when a no-cache request is sent to a server not known to be HTTP/1.1 compliant.
Also see EXPIRES.
Note: It may be better to specify cache commands in HTTP than in META statements, where they can influence more than the browser, but proxies and other intermediaries that may cache information.

Content-Language<META HTTP-EQUIV="CONTENT-LANGUAGE"
CONTENT="en-US,fr">
Declares the primary natural language(s) of the document. May be used by search engines to categorize by language.
CONTENT-TYPE<META HTTP-EQUIV="CONTENT-TYPE"
CONTENT="text/html; charset=UTF-8">
The HTTP content type may be extended to give the character set. It is recommended to always use this tag and to specify the charset.
Copyright<META NAME="COPYRIGHT" CONTENT="&copy; 2004 Tex Texin"> A copyright statement.
DESCRIPTION<META NAME="DESCRIPTION"
CONTENT="...summary of web page...">
The text can be used when printing a summary of the document. The text should not contain any formatting information. Used by some search engines to describe your document. Particularly important if your document has very little text, is a frameset, or has extensive scripts at the top.
EXPIRES<META HTTP-EQUIV="EXPIRES"
CONTENT="Mon, 22 Jul 2002 11:12:01 GMT">
The date and time after which the document should be considered expired. An illegal EXPIRES date, e.g. "0", is interpreted as "now". Setting EXPIRES to 0 may thus be used to force a modification check at each visit.
Web robots may delete expired documents from a search engine, or schedule a revisit.

HTTP 1.1 (RFC 2068) specifies that all HTTP date/time stamps MUST be generated in Greenwich Mean Time (GMT) and in RFC 1123 format.
RFC 1123 format = wkday "," SP date SP time SP "GMT"

wkday = (Mon, Tue, Wed, Thu, Fri, Sat, Sun)
date = 2DIGIT SP month SP 4DIGIT ; day month year (e.g., 02 Jun 1982)
time = 2DIGIT ":" 2DIGIT ":" 2DIGIT ; 00:00:00 - 23:59:59
month = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)

Keywords<META NAME="KEYWORDS"
CONTENT="sex, drugs, rock & roll">
The keywords are used by some search engines to index your document in addition to words from the title and document body. Typically used for synonyms and alternates of title words. Consider adding frequent misspellings. e.g. heirarchy, hierarchy.
PRAGMA NO-CACHE<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE"> This directive indicates cached information should not be used and instead requests should be forwarded to the origin server. This directive has the same semantics as the CACHE-CONTROL:NO-CACHE directive and is provided for backwards compatibility with HTTP/1.0.
Clients SHOULD include both PRAGMA:NO-CACHE and CACHE-CONTROL:NO-CACHE when a no-cache request is sent to a server not known to be HTTP/1.1 compliant.
HTTP/1.1 clients SHOULD NOT send the PRAGMA request-header. HTTP/1.1 caches SHOULD treat "PRAGMA:NO-CACHE" as if the client had sent "CACHE-CONTROL:NO-CACHE".
Also see EXPIRES.
Refresh<META HTTP-EQUIV="REFRESH"
CONTENT="15;URL=http://www.I18nGuy.com/index.html">
Specifies a delay in seconds before the browser automatically reloads the document. Optionally, specifies an alternative URL to load, making this command useful for redirecting browsers to other pages.
ROBOTS <META NAME="ROBOTS" CONTENT="ALL">

<META NAME="ROBOTS" CONTENT="INDEX,NOFOLLOW">

<META NAME="ROBOTS" CONTENT="NOINDEX,FOLLOW">

<META NAME="ROBOTS" CONTENT="NONE">
CONTENT="ALL | NONE | NOINDEX | INDEX| NOFOLLOW | FOLLOW | NOARCHIVE"
default = empty = "ALL"
"NONE" = "NOINDEX, NOFOLLOW"

The CONTENT field is a comma separated list:
INDEX: search engine robots should include this page.
FOLLOW: robots should follow links from this page to other pages.
NOINDEX: links can be explored, although the page is not indexed.
NOFOLLOW: the page can be indexed, but no links are explored.
NONE: robots can ignore the page.
NOARCHIVE: Google uses this to prevent archiving of the page. See http://www.google.com/bot.html

GOOGLEBOT <META NAME="GOOGLEBOT" CONTENT="NOARCHIVE"> In addition to the ROBOTS META Command above, Google supports a GOOGLEBOT command. With it, you can tell Google that you do not want the page archived, but allow other search engines to do so. If you specify this command, Google will not save the page and the page will be unavailable via its cache.
See Google's FAQ.

:

php 모듈 추가하기 - Installation of PECL extensions

ITWeb/개발일반 2008. 7. 21. 12:59
제가 테스트한 샘플 코드 입니다.
APC 추가 하기 (php 5.2.6 이랑 apache 2.2.9 입니다.)

1. /home/php/bin/pecl download apc
2. tar -xvzf APC-3.0.19.tgz
3. cd APC-3.0.19
4. /home/php/bin/phpize
4. ./configure --enable-apc-mmap --with-apxs=/home/apache/bin/apxs --with-php-config=/home/php/bin/php-config
5. make
6. make install
    이렇게 하시면 기본적으로 php 의 extension 모듈 위치로 복사 됩니다.
7. 또는 이렇게 하셔도 됩니다. cp ././libs/apc.so /usr/local/lib
    이 부분도 역시 php extension 위치로 복사해서 넣으시면 됩니다.
8. php.ini 수정하기
    extension_dir=설정한위치로적용하세요.
       예) /home/php/lib/php/extensions/no-debug-zts-20060613/apc.so 가 있습니다.
          extension_dir=/home/php/lib/php/extensions
          extension="no-debug-zts-20060613/apc.so" 이렇게 넣으시면 됩니다.
          dir 은..적절히 조절 하시면 됩니다.
    enble_dl=on

    extension="apc.so"
    apc.enabled=1
    apc.shm_segments=1
    apc.shm_size=256
    apc.ttl=7200
    apc.user_ttl=7200
    apc.num_files_hint=1024
    apc.mmap_file_mask=/tmp/apc.XXXXXX
    apc.enable_cli=1
    apc.include_once_override=1



ref. http://kr2.php.net/manual/en/install.pecl.php

php 설치 과정과 비슷 합니다.
보시면 아시겠지만 make install 과정 빼고 동일하죠.
make 하면 실제 build 까지 다 해주니 우리는 그냥 필요한 확장 모듈을 extension 에 복사 해주고 설정만 잡아 준 후 apache restart 시키면.. 끝.. ^^*

1. $ pecl install extname-beta
2. $ cd extname
$ phpize
$ ./configure
$ make
# make install

3. $ cd /your/phpsrcdir/ext
$ pecl download extname
$ gzip -d < extname.tgz | tar -xvf -
$ mv extname-x.x.x extname

$ cd /your/phpsrcdir
$ rm configure
$ ./buildconf --force
$ ./configure --help
$ ./configure --with-extname --enable-someotherext --with-foobar
$ make
$ make install

- 잘모르겠다 싶으면.. help ㅎㅎ
$ ./configure --help | grep extname
:

css 로 문장 정렬하기 tip

ITWeb/개발일반 2008. 7. 21. 12:38
- css 로 문장 정렬하기..tip

word-break
    공백단위나 글자단위로 문장을 잘라(정렬해) 줍니다. (only ie)

word-wrap
    문장이 길어 질때 테이블이 깨지지 않도록 해 줍니다. (only ie)

line-break
    강제 줄바꿈 해 줍니다. (only ie)

text-align
    글 정렬 ( ie, ff )
    left,right,center.justify

참고 사이트)
- http://www.w3schools.com/css/css_reference.asp
- http://msdn.microsoft.com/en-us/library/ms531205(vs.85).aspx
- http://developer.mozilla.org/en/docs/CSS
- http://www.w3.org/Style/CSS/



:

[펌]스프링 프레임워크와 DDD

ITWeb/개발일반 2008. 7. 21. 10:30

ref. http://www.zdnet.co.kr/builder/dev/web/0,39031700,39170214,00.htm


[DDD ③] 스프링 프레임워크와 DDD

이일민(toby.epril.com 운영자)   2008/07/19
[지디넷코리아]스 프링프레임워크(SpringFramework, 이하 스프링)의 첫 번째 메이저 업그레이드 버전인 2.0이 처음 발표되었을 때 개발자들이 가장 관심을 가지고 주목했던 것은 스프링을 통한 DDD(Driven Driven Design)였다. 대부분의 개발자들에게 아직 생소했던 개념이었던 DDD를 과감하게 주요 기능으로 내세우면서 등장한 스프링은 과연 DDD와 어떤 관련이 있는 것일까? 스프링2.x를 통해서 DDD를 적용하는 전략은 어떤 것들이 있는지 살펴보자.

  스프링 2.0

스프링2.0 버전은 2005년 말에 열렸던 TheSpringExperience 컨퍼런스에서 처음 소개가 되었다. 그때까지 1.3버전으로 준비되고 있었던 스프링의 차기 버전이 컨퍼런스 기간에 2.0이라는 메이저버전으로 버전자체의 업그레이드가 일어났다.

그 결정의 배경은 스프링의 다음 버전에 등장하는 기능들의 중요도와 변화의 영향력이 메이저 업그레이드를 하는 것이 바람직할 만큼 중요하다는 공감이 있었기 때문이다.

스프링 2.0에 소개된 새로운 기능에는 XML 설정의 단순화나 스키마의 도입 또 자바5의 새롭게 소개된 언어특성의 적용 등 그동안 지속적으로 요구되어졌기 때문에 당연히 들어갈 것으로 기대했던 내용들이 대거 포함되어 있었다.

그런데 그 중에서 필자의 눈을 사로잡는 생소한 단어가 눈에 띄었는데 그것이 바로 DDD다. TDD는 많이 들어봤어도 DDD는 무엇인가 궁금해하면서 DDD에 대해서 찾아보니 이미 몇 년 전부터 엔터프라이즈 아키텍처 기술에 관한 이야기들이 나올 때마다 자주 등장했던 Eric Evans의 책 제목인 Domain Driven Design의 약자인 DDD였다.

스프링 2.0
AOP, IoC/DI, PSA같은 시대를 앞서나가는 새로운 컨셉트와 기능들을 과감하게 소개하고 이를 현장에 접목시키는데 앞서왔던 스프링이었던지라 많은 스프링 개발자들은 지속적으로 엔터프라이즈 개발에 필요로 한 유용한 기술과 전략이 스프링의 업그레이드과정을 통해서 소개될 것을 기대해왔다.

하지만 DDD라는 단어와의 만남은 그리 쉽게 예측할 수 없었던 것이라 스프링 커뮤니티와 관련 개발자들 사이에서도 적지 않은 화제를 불러일으키게 되었다. 대다수의 스프링 개발자들은 2.0에 대한 발표소식을 들으며, 함께 소개된 DDD에 대해서도 많은 관심을 가지기 시작했다.

2006년 가을에 스프링 2.0의 정식버전이 릴리즈 되고 나서 열렸던 첫 번째 스프링 컨퍼런스인 TheSpringExperience 2006에서는 컨퍼런스의 네 개 주요트랙중의 하나가 DDD였을 정도였으니 스프링과 DDD는 매우 깊은 관계를 가지고 있음을 짐작할 수 있다.

TSE 2006 DDD트랙의 첫 번째 세션의 발표를 바로 Domain Driven Design이라는 책을 통해서 DDD라는 개념을 소개하고 이를 보급시키는데 앞장서고 있는 Eric Evans이 맡았다. Eric은 2007년 유럽에서 열린 스프링원 컨퍼런스에서도 키노트 발표를 담당했을 정도로 스프링과 깊은 관계를 가지고 있다.

DDD란 무엇인가?
이처럼 스프링과 DDD의 깊은 관계가 발생한 이유는 무엇일까? 그것은 스프링이 지금까지 지향해온 핵심가치와 DDD의 그것이 유사하기 때문이라고 생각된다.

스프링의 등장배경과 원리를 소개한 책인 J2EE Development without EJB라는 책의 첫 장에서는 스프링이 지향하는 핵심가치를 소개한다. 그 중 가장 눈에 띄는 것이 있다면 바로 OO(Object Oriented)라는 것이다. 스프링이 추구하는 핵심가치는 바로 객체지향이다.

자바라는 객체지향언어를 사용하는 프레임워크인 스프링이니 당연히 OO적일텐데 왜 그것을 핵심가치라고 하면서 강조하고 등장한 것일까? 그것은 자바의 근본이라고도 할 수 있는 객체지향이 사실은 엔터프라이즈 환경에서 상당히 무시당하고 있다는 안타까운 현실에서 나온 것이다.

스프링은 그것을 사용하는 개발자들에게 자바가 객체지향 언어라는 가장 기초적인 사실을 다시 상기시켜주면서 그 기초에 충실할 때에 가장 복잡하게 생각되는 엔터프라이즈 개발이 사실은 쉽고 단순해진다는 것을 알려주려는 의도를 가지고 만들어 진 것이다.

DDD 또한 그와 유사하다. DDD는 어떤 천재적인 기술자에게서 갑자기 소개된 새로운 개념과 아이디어가 아니다. 소프트웨어 설계라는 것이 존재했던 가장 초기부터 추구하고 가져왔던 가장 기초가 되는 기본에 다시 충실하자는 이야기이다. 그래서 어떤 사람들에게는 매우 진부하고 당연하게 들리기도 한다.

Eric Evans의 DDD 책을 읽어본 많은 사람들이 의외로 실망하는 이유가 바로 거기에 있다. 이미 잘 알고 있다고 생각하는 당연한 내용들이 많기 때문이다.

하지만 그것에 충실하는 것이 의외로 현장에서 잘 이루어져 있지 않고, 세세한 전략들이 충분히 제시되고 있지 않다는 것이 현실임을 안다면 소프트웨어 설계의 기본으로 돌아가자는 DDD의 주장이 매우 강력하고 중요한 것이라는 점을 인식할 수 있을 것이다.

스프링프레임워크의 모체인 Interface21의 Ramnivas Laddad가 정리한 DDD의 세 가지 특징을 살펴보자.

첫째는 도메인 그 자체와 도메인 로직에 초점을 맞춘다는 것이다. 일반적으로 많이 사용하는 데이터중심의 접근법을 탈피해서 순수한 도메인의 모델과 로직에 집중하는 것을 말한다.

둘째는 보편적인(ubiquitous) 언어의 사용이다. 도메인 전문가와 소프트웨어 개발자 간의 커뮤니케이션 문제를 없애고 상호가 이해할 수 있고 모든 문서와 코드에 이르기까지 동일한 표현과 단어로 구성된 단일화된 언어체계를 구축해나가는 과정을 말한다. 이로서 분석 작업과 설계 그리고 구현에 이르기까지 통일된 방식으로 커뮤니케이션이 가능해진다.

셋째는 소프트웨어 엔티티와 도메인 컨셉트를 가능한 가장 가까이 일치시키는 것이다. 분석모델과 설계가 다르고 그것과 코드가 다른 구조가 아니라 도메인 모델부터 코드까지 항상 함께 움직이는 구조의 모델을 지향하는 것이 DDD의 핵심원리이다.

물론 DDD는 방법론이 아니다. 따라서 이런 경우 이렇게 하라는 식의 접근법 보다는 원칙과 핵심가치를 설명해주고 그것에 어떻게 집중할 것인가에 주목하게 하는 것이다. 모든 애플리케이션의 핵심은 결국 그 애플리케이션을 사용할 도메인과 그 로직이라고 본다면 소프트웨어 설계와 구현도 그 부분이 핵심이 되는 것이 마땅하다는 것이 DDD의 개념이라고 생각하면 된다.

DDD에서 스프링의 역할
그렇다면 스프링을 이용한 개발과 DDD는 무슨 직접적인 관련이 있는 것일까?

사실 스프링은 설계도구나 방법론이 아니다. 애플리케이션을 개발하는데 있어서 필요로 하는 기본 프레임워크일 뿐이다. 하지만 스프링은 처음부터 단순한 생산성과 품질향상을 위한 애플리케이션 프레임워크일 뿐만 아니라 개발자들에게 개발의 원칙과 지향해야 할 개발 원리를 설명하기 위해서 등장한 것이다.

따라서 스프링을 사용하면 자연스럽게 그 애플리케이션 코드는 스프링이 지향하는 개발원칙을 따라갈 수 있게 된다.

스프링의 핵심 가치는 위에서 언급한 객체지향(OO)과 단순함(Simplicity)이다.

자바는 처음 언어가 소개될 때 객체지향프로그래밍을 지원하는 강력한 언어라는 점을 가장 중요한 특징으로 내세웠다. 하지만 자바가 본격적으로 사용되는 엔터프라이즈 환경의 코드들을 가만히 살펴보면 과연 객체지향의 특성들이 잘 살아있는지, 그 장점을 잘 활용하고 있는지 생각하면 의문스럽기만 하다.

● Anemic Domain Model
이는 흔히 말하는 빈약한 도메인모델(anemic domain model)라는 말에 잘 나타나 있다. 객체지향에서 말하는 오브젝트는 상태(state)와 행위(behavior)로 구성되어 있어야 한다. 하지만 자바엔터프라이즈 개발에서 흔히 사용되는 방식은 단지 상태 값, 즉 데이터만 가지는 데이터홀더 개념의 단순 오브젝트이다.

이런 오브젝트로 구성된 도메인모델은 객체지향언어와 기술의 장점을 전혀 살릴 수 없는 한계를 가지고 있다. 따라서 구조적으로 불합리한 형태의 코드를 생산하게 한다.

문제는 이런 빈약한 도메인모델과 오브젝트 구조가 거의 엔터프라이즈 자바 개발의 전반에 걸쳐서 사용되고 있다는 점이다. 대부분의 서버사이드 아키텍처라고 제시되는 구조가 빈약한 도메인모델의 사용을 부추기고 있다는 점이 문제다.
빈약한 오브젝트는 자바빈 형태로 나타나는 <리스트 1>과 같은 형태를 가진다.


 <리스트 1> 빈약한 오브젝트(Anemic Object)의 예


class Customer {
Integer customerId
String name
String telephone
String address
Integer point
Date lastVisited

public Integer getCustomerId() {
return customerId
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
public String getName() {
return name
}
public void setName(String name) {
this.name = name;
}
public String getTelephone() {
return telephone
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getAddress() {
return address
}
public void setAddress(String address) {
this.address = address;
}
public Integer getPoint() {
return point
}
public void setPoint(Integer point) {
this.point = point;
}
public Date getLastVisited() {
return lastVisited
}
public void setLastVisited(Date lastVisited) {
this.lastVisited = lastVisited;
}
}



빈약한 오브젝트가 가져오는 문제는 단지 객체지향 기술의 순수주의자들의 주장처럼 모든 객체는 행위가 포함 되야 한다는 정도에 그치는 것이 아니다.

모든 도메인은 행위에 해당하는 로직을 가지고 있고, 그 로직을 어떠한 형태로든 나타내야 하는데 그것이 도메인의 상태 정보만 가지고 있는 빈약한 오브젝트 속에서 모두 빠져나와 다른 형태로 구성된다는 점이다.

대부분의 자바 엔터프라이즈 아키텍처가 가지고 있는 이런 구조적인 한계들은 결국 과도한 서비스 레이어의 사용을 부추긴다.

도메인오브젝트의 데이터홀더(data holder)화와 서비스레이어의 비대해짐은 결국 트랜잭션 스크립트 패턴의 형태의 코드를 양산하게 된다. 트랜잭션 스크립트는 각 업무 트랜잭션을 하나의 메소드에 한 번에 구성하는 형태의 패턴이다. 이런 형태의 코드는 결국 객체지향적인 도메인모델의 장점을 살릴 수 없는 결과로 나아가게 된다.

<리스트 2>는 트랜잭션 스크립트 스타일의 서비스레이어의 예이다. Customer와 PointRule이라는 두 개의 도메인 오브젝트가 존재하지만 각 도메인에 종속된 로직들이 서비스레이어의 메소드에 산재되어 있는 구조이다.

addPoint 메소드는 Customer, PointRule을 받아서 또 다른 서비스 메소드를 사용해서 다 도메인 오브젝트의 로직에 해당하는 코드를 처리한다. 또한 withInOneMonth 메소드나 isVipCutomer 메소드의 경우도 도메인 오브젝트에 포함해야 하는 내용을 서비스 레이어에 노출한 형태이다.


 <리스트 2> Big Service Layer의 예


class CustomerService {
CustomerDao customerDao;
PointRuleDao pointRuleDao;

public void addPoints() {
List customers = customerDao.getAllCustomers();
PointRule pointRule = pointRuleDao.getCurrentPointRule();

for(Customer customer : customers) {
if (withInOneMonth(customers.getLastVisited())) {
if (isVipCustomer(customer, pointRule)) {
customer.setPoint(customer.getPoint() + VIP_POINTS);
}
else {
customer.setPoint(customer.getPoint() + MEMBER_POINTS);
}
}
}
}

boolean withInOneMonth(Date lastVisited) {
...
}

boolean isVipCustomer(Customer customer, PointRule pointRule) {
...
}
}



이런 형태의 거대한 서비스 레이어(big service layer) 형태는 객체지향의 설계원칙에 맞지 않을 뿐더러 도메인로직을 여러 곳에 산재하게 만들 뿐더러 코드의 중복과 오브젝트의 재활용성을 극히 떨어뜨리게 한다.

데이터중심의 설계와 개발에 익숙한 개발자들은 적절한 도메인모델을 이용해서 개발하는데 경험이 없거나 익숙하지 않기 때문에 이런 방식을 선호하거나 별 문제의식 없이 사용하는 경우가 많다. 또 어떤 기술은 기술자체가 이런 구조적인 한계를 노출하고 있다.

대표적인 것이 EJB의 엔티티빈 기술이다. 스프링을 비롯한 새로운 프레임워크와 기술들이 POJO를 선호하는 이유가 있다면 이 또한 자바의 객체지향적인 특징의 기본으로 돌아갈 수 있는 가장 단순하면서도 이상적이기 때문이다.

<그림 1>은 전형적인 3-tier 구조의 J2EE 아키텍처이다. 도메인 로직이 서비스 레이어에 집중되어있고 도메인모델 오브젝트는 단지 DTO와 같은 역할을 하는 데이터홀더로 사용되는 형태이다. 사실 이런 형태가 자바 엔터프라이즈 개발에서 거의 표준과 같이 인식되고 있다는 것은 심각한 문제이다.

심지어는 초기 스프링의 예제나 스프링 개발자들에 의해서 쓰여진 스프링 서적의 샘플 코드도 이런 구조를 그대로 사용했다는 것은 이런 모델이 얼마나 자연스럽게 개발자들에게 받아들여지고 사용되어져 왔는지 짐작하게 해준다.

<그림-1> Anemic domain model + Big service layer 아키텍처


● Rich Domain Model
빈약한 도메인모델의 한계와 문제점을 인식한 개발자들은 점차로 풍성한 도메인 모델(rich domain model)이나 지능적인 도메인 모델(smart domain model)이라고 불리는 형태로의 전환을 시도한다.

지능적 도메인 모델의 특징은 도메인 오브젝트에 단순한 데이터 값의 저장을 위한 getter/setter가 아닌 도메인과 직접 관련이 되어있는 로직을 담았다는 것이다.

제한적이지만 도메인에 극히 종속적인 로직은 도메인 오브젝트에 담았기 때문에 포터블한 도메인 오브젝트로 발전할 뿐더러 상당수의 로직 부분이 서비스 레이어에서 제거 될 수 있게 하는 좋은 효과를 가져왔다.


 <리스트 3> 풍성한 도메인 오브젝트의 적용 예


class Customer {
Integer customerId
String name
String telephone
String address
Integer point
Date lastVisited
Date registered

public booean isVipCustomer(PointRule pointRule) {
return this.customerLevel > pointRule.getVipLevel(this.registered)
&& isValidRegiststedCustomer();
}

public voiddoVipPointUpgrade(PointRule pointRule) {
if (isVipCustomer(pointRule) && ...)
customer.setPoint(customer.getPoint() + pointRule.VIP_POINTS);
}
else {
customer.setPoint(customer.getPoint() + pointRule.MEMBER_POINTS);
}
}
...

}



<리스트 3>에서는 기존에 서비스 레이어에 있던 도메인 로직이 도메인 오브젝트 안으로 이동한 모습을 볼 수 있다. 이렇게 도메인의 로직이 이동을 하게 되면 서비스 레이어에 중복되고 산재해서 나타나던 도메인 로직이 사라지고 일관성 있게 도메인 오브젝트에 처리를 맞길 수 있는 형태로 발전하게 된다.

<리스트 4>는 풍성한 도메인 오브젝트를 사용하는 서비스레이어의 변화된 모습이다.


 <리스트 4> 풍성한 도메인 오브젝트를 사용하는 서비스 레이어의 예


class CustomerService {
CustomerDao customerDao;
PointRuleDao pointRuleDao;

public void addPoints() {
List customers = customerDao.getAllCustomers();
PointRule pointRule = pointRuleDao.getCurrentPointRule();

for(Customer customer : customers) {
customer.doVipPointUpgrade(pointRule);
}
}
}



● DDD 아키텍처
풍성한 도메인 모델을 사용하는 것만으로도 도메인 모델 중심의 구현과 일치가 어느 정도 가능해졌다. 하지만 DDD에서 지향하는 도메인 레이어라는 개념은 이보다 더 발전된 형태의 아키텍처이다.

<그림 2>는 기존의 3-tier아키텍처와는 다른 형태의 DDD에서 많이 사용하는 구조이다. 기존의 아키텍처와의 가장 큰 변화라면 도메인 레이어의 도입이다. 기존의 도메인 모델/오브젝트는 단지 DTO의 역할을 하거나 데이터 홀더로 사용되어져 왔다면 DDD의 도메인 모델은 독립적인 형태의 레이어를 이루고 있는 것을 볼 수 있다.

<그림 2> DDD아키텍처


도메인 레이어는 비즈니스 애플리케이션의 심장과 갈은 역할을 한다. 모든 도메인 정보와 기능과 로직과 룰이 이 레이어에 집중되고 관리된다. 도메인 전문가와 소프트웨어 개발자들이 지속적으로 함께 살펴보며 다듬어 나갈 수 있는 그 도메인모델을 그대로 반영할 수 있는 구조가 만들어지게 되는 것이다.

이 경우 서비스 레이어는 비즈니스 로직을 직접 가지고 있지 않으면서 소프트웨어의 기능들을 적절한 도메인 레이어와의 협력을 통해서 처리할 수 있는 코디네이터 역할을 담당하게 된다. 따라서 서비스 레이어는 매우 얇아지게 된다.

또 한 가지 큰 변화는 저장소(repository) 또는 데이터액세스 레이어와의 연동을 이제는 도메인 레이어가 직접하게 된다는 것이다. 기존의 풍성한 도메인 모델에서는 도메인모델에게 넘겨줄 필요한 도메인 객체의 생성을 서비스레이어가 담당하게 되었다. 따라서 모든 레이어간의 연동이 서비스 레이어에 집중되는 한계를 가질 수밖에 없었다.

하지만 DDD 아키텍처에서는 도메인모델이 자신이 필요로 하는, 퍼시스턴스 관리를 위한 리포지토리 또는 인프라스트럭처 서비스와 직접 연동하는 것이 가능하다.

<리스트 5>는 도메인 레이어의 형태로 재구성한 Customer 클래스이다. 풍성한 도메인 모델 구조에서는 서비스 레이어가 데이터 액세스 레이어에 요청을 해서 PointRule를 받아 이를 Customer 오브젝트에 넘겨줘야 했지만, 여기서는 직접 PointRuleRepository에 요청해서 필요한 것을 받아서 사용할 수 있다.

따라서 도메인 오브젝트는 서비스 레이어의 도움이 없이도 독립적으로 도메인 로직을 처리할 수 있는 독립된 레이어 형태로 구성이 가능하게 된 것이다.


 <리스트 5> 도메인 레이어의 Customer 클래스


class Customer {
PointRuleRepository pointRuleRepository;

Integer customerId
...
Date lastVisited
Date registered

public booean isVipCustomer(PointRule pointRule) {
return this.customerLevel > pointRule.getVipLevel(this.registered)
&& isValidRegiststedCustomer();
}

public voiddoVipPointUpgrade() {
pointRuleRepository.getCurrentPointRule();

if (isVipCustomer(pointRule))
customer.setPoint(customer.getPoint() + VIP_POINTS);
}
else {
customer.setPoint(customer.getPoint() + MEMBER_POINTS);
}
}




  DI/AOP와 DDD

그렇다면 과연 이런 DDD의 아키텍처 구조와 스프링은 무슨 상관이 있다는 것인가? 사실 스프링이 직접적으로 DDD 아키텍처를 강제하거나 그런 구조로 만들어져 있는 것은 아니다.

스프링은 매우 범용적인 자바엔터프라이즈 개발에 사용되어질 수 있도록 만들어진 프레임워크이다. 그러면서도 DDD아키텍처를 적용할 때에 꼭 필요하다고 생각되는 기능을 제공한다.

도메인 모델와 의존삽입(DI)
위와 같은 도메인 레이어를 만들 때 가지는 문제점에 대해서 생각해보자.

첫 번째 문제는 도메인 오브젝트에 리포지토리나 다른 인프라스트럭처 서비스를 어떻게 삽입 할 것인가의 문제가 있다. 스프링이 지원하는 의존삽입(DI)을 사용하면 간단하게 처리할 수 있을 것 같다. 하지만 도메인 오브젝트는 의존삽입을 적용하기에 적절하지 않다.

스프링에서 빈(bean)으로 등록할 수 있는 것과 또는 없는 것, 하지 말아야할 것을 구분할 때 항상 등장하는 예가 바로 도메인 오브젝트다. 도메인 오브젝트가 스프링의 빈으로 등록되지 말아야 하는 첫 번째 이유는 빈약한 도메인 모델처럼 단순한 데이터만을 가지는 형태이기 때문이다. 즉 의존관계가 없다는 것이다.

따라서 굳지 빈으로 등록할 이유가 없다. 그냥 new 키워드를 통해서 생성하면 된다.

두 번째 문제는 도메인 오브젝트의 생성이 애플리케이션 코드에서 직접 일어나지 않고 써드파티(3-rd party) 프레임워크 등에서 만들어지는 경우가 있기 때문이다. 대표적으로 O/R매핑 툴인 하이버네이트를 사용한다면 find나 get 등에 의해서 전달되는 도메인 오브젝트는 모두 하이버네이트 내부에서 직접 생성이 된다.

따라서 그 오브젝트의 라이프사이클을 스프링에 위임할 수 없기 때문에 빈으로 쓰는 것이 부적절하다.

문제는 빈약한 도메인 모델을 사용한다면 상관없지만, DDD에서의 요구되는 도메인 오브젝트를 사용하려면 외부의 서비스나 리포지토리의 삽입이 필수적으로 요구된다. 하지만 위의 두 가지 제약 때문에 따라서 단순히 빈으로 등록해서 사용하는 것은 불가능하다.

바로 이런 문제를 해결할 수 있는 방법으로 등장한 것이 스프링 2.0의 DDD지원기능이다. 엄밀히 말해서 스프링에 DDD기능이란 없다. 단지 위와 같은 특성을 가지고 있는 도메인 모델에 의존삽입이 가능하게 하기 위해서 스프링 2.0에 특별히 도입된 기능이 있을 뿐이다.

● @Configurable
사실 이를 위해서 스프링이 제공하는 기능은 무척 간단하다. @Configurable이라는 새롭게 도입된 어노테이션과 AspectJ의 도움으로 스프링이 직접 생성하지 않는 도메인 오브젝트에도 의존삽입이 가능하게 해주는 것이다.

원리는 간단하다. AspectJ가 지원하는 LTW(Load Time Weaving)기능을 이용해서 오브젝트가 생성되는 시점의 조인 포인트에서 오브젝트에 자동결합(autowiring) 방식으로 의존성을 삽입해주는 것이다.

스프링의 의존삽입 기능은 XML과 같은 형태로 외부에서 정의하는 방법 외에도 프로그래밍 적으로 사용할 수 있는 자동결합 방식도 가능하다. 이를 이용하면 빈의 이름과 일치하는 setter를 찾아서 자동으로 삽입을 시키는 것이 가능하다.

AspectJ 5의 LTW를 이용하면 별도의 AOP를 위한 컴파일 작업 없이도 클래스가 로딩되는 시점을 이용해서 어느 곳에서 생성되는지와 상관없이 자동으로 의존삽입을 시킬 수 있다. 따라서 @Configurable이 적용되어 있는 모든 도메인 오브젝트에 적절한 외부 의존성을 삽입시켜줄 수 있다.

<리스트 6>은 @Configurable을 정의한 Customer클래스이다. 사실 스프링 2.0의 DDD 지원기능은 막상 적용하려고 보면 무척 간단하다. 물론 그 내부에서 처리되어지는 것들은 매우 복잡한 방식으로 이루어지고 있지만 말이다.


 <리스트 6> @Configurable이 적용된 Customer클래스


@Configurable
class Customer {
PointRuleRepository pointRuleRepository;

public void setPointRuleRepository(PointRuleRepository pointRuleRepository) {
this.pointRuleRepository = pointRuleRepository;
}
...

}



● 도메인 모델과 AOP
의존삽입이 가능하다는 것은 모든 빈 형태로 존재하는 각종 서비스들을 다 이용할 수 있다는 것이다. 이 외에도 도메인 모델에 필요로 하는, AOP에서 자주 등장하는 횡단관심(Crosscutting Concerns)도 모두 적용할 수 있다. 트랜잭션 지원이나 로깅, 보안, 트레이싱 같은 것들을 도메인 오브젝트에 적용하는 것도 스프링 빈의 형태로 정의되기 때문에 모두 할 수 있다.

@Configurable을 정의하기 위해서는 스프링 설정파일에 다음과 같이 prototype 형태로 정의하는 것이 필요하다. 빈으로 등록된 이유는 일반적인 형태의 삽입 대상이 되기 위함은 아니다. 따라서 이 도메인 오브젝트 빈을 다른 빈의 의존관계로 만들면 안 된다.

&ltbean class="com.mycompany.Customer" scope="prototype">
&ltpropety ... />
&ltbean>

빈의 형태로 등록이 되었기 때문에 스프링 AOP의 기능을 모두 적용할 수 있다. 스프링 2.0의 의존삽입과 AOP는 DDD를 본격적으로 구현해서 사용하려면 반드시 필요한 기술이라고 여겨지고 있다. 이제까지 풍성한 도메인 모델 정도의 구현에 만족했던 개발자들에게 도메인 레이어의 구분이라는 본격적인 DDD 구현의 실마리를 찾아준 것이다.

  스프링 DDD의 적용전략

스프링이 제공해주는 DI/AOP를 이용하면 DDD의 도메인 레이어 구현을 위해서 필요로 하는 기술적인 요구사항은 충족될 수 있다. 하지만 이것만으로 바로 DDD방식의 구현에 도전하는 개발자들은 다들 한번쯤 좌절을 겪기 마련이다. 기존의 빈약한 도메인 모델구조에서는 경험하지 못했던 아키텍처상의 더 많은 변수들이 있기 때문이다.

첫 번째로 고민해 볼 것은 리포지토리의 사용방식이다.

스프링 시큐리티를 만든 Ben Alex나 스프링웹플로우의 Keith Donald는 하이버네이트와 같은 투명한영속성(transparent persistence) 방식의 ORM 기술을 선호하는 편이다.

그 이유는 투명한 영속성을 사용하는 방식은 명시적으로 리포지토리에 update문을 호출하지 않아도 퍼시스턴스 오브젝트에 발생하는 변화를 감지해서 자동이로 이를 데이터베이스와 싱크를 맞춰주기 때문이다.

또 도메인 오브젝트 그래프를 따라서 데이터를 자동으로 적절한 시점에서 가져오는 것도 가능하다. 따라서 도메인 로직에 빈번하게 리포지토리나 DAO를 호출하는 코드가 등장하지 않는다.

최초로 퍼시스턴스화 할 때와 초기조회, 삭제, 벌크 수정정도만이 사용되어지고 그 외의 퍼시스턴스 코드가 등장하지 않으니 이 방식을 사용한 코드는 순수한 자바 오브젝트만을 사용한 코드처럼 깔끔하고 명확하게 만들어질 수가 있다.

하지만 이 방식의 문제점을 지적하는 사람도 적지 않다. 대표적으로 역시 스프링의 핵심 개발자인 Ramnivas Raddad이다. 그는 하이버네이트나 JPA를 이용해서 투명한 영속성을 사용할 경우, 그 사용이 과도하게 되면 많은 데이터를 처리하는데 불필요한 오버헤드가 발생한다고 생각한다.

따라서 리포지토리의 데이터 로직을 좀 더 강화해서 매우 정교한 형태의 꼭 필요한 처리만 가능하게 하고 벌크처리는 DAO안에서 가능한 간략한 방식으로 일어나는 것이 좋다고 주장한다.

이렇게 될 경우 도메인 로직을 순수한 자바오브젝트로 표현하던 것을 일부 데이터베이스 스크립트 방식으로 만들게 되지만 전체 애플리케이션의 성능을 고려해 본다면 엔터프라이즈 환경에서는 충분히 타협할 수 있는 구조라는 것이다.

순수한 도메인 오브젝트 중심의 로직 구현방식과 데이터베이스와의 협조를 통한 중도적인 접근방법 중 어느 것이 항상 더 낫다고 볼 수는 없을 것 같다. 그럼에도 필자는 투명한 영속성을 지원하는 ORM을 사용하는 것이 DDD에서 가지는 장점이 매우 많다고 생각한다.

어쨌든 좀 더 오브젝트 중심의 코드가 만들어지기 때문이다. 다른 이유로 원천적으로 ORM 툴을 사용할 수 없는 경우가 아니라면, 그렇게 설계된 후에 필요에 따라서 성능을 위해서 개선하는 방식을 취하는 것이 바람직 할 것이다.

두 번째로 고려해야 할 것은 DTO이다.

ROO(Real Object Oriented)라는 애플리케이션 프레임워크를 만든 Ben Alex는 도메인 오브젝트는 도메인 레이어 밖에서는 존재해서는 안 된다고 주장한다.

따라서 그의 프레임워크에서는 도메인 레이어 밖으로 나오는 오브젝트는 DTO 형태로 복제가 되서 나온다. 서비스 레이어와 도메인 레이어 사이에 얇은 DTO를 위한 어셈블리 레이어를 가지고 있다.

또 모든 도메인 오브젝트는 근본적으로 수정가능하지 않아야(immutable) 한다고 주장하는 사람도 있다. 수정이 필요한 경우는 복제를 통해서 도메인 레이어에 요청해야 한다는 것이다.

필자와 같은 개발자들은 DTO를 쓰는 것을 바람직하지 않게 생각한다. 모든 레이어에 존재하는 도메인 모델(domain model everywhere) 방식을 선호한다. 이 경우 DTO를 지지하는 사람들이 문제로 지적하는 도메인 레이어 외부에서 변경이 일어난다는 문제가 발생한다.

예를 들어 프레젠테이션 레이어에서 임의로 도메인 오브젝트의 로직을 호출하거나 변경을 가할 수도 있다는 것이다. 이런 것을 원천적으로 차단하는 방법 중의 하나가 DTO이다. 하지만 도메인 오브젝트를 직접 사용한다고 할지라도 이런 문제를 해결할 방법이 있다.

역시 스프링 2.0에 등장하는 AspectJ를 이용한 SpringAOP를 적용하면 특정 레이어에서 특정 메소드에 접근하는 것을 강제적으로 차단할 수 있다. 이를 통해서 구지 매번 개발자들에게 개발정책을 교육하고 매번 점검하지 않더라도 이를 편리하게 강제할 수 있다.

  DDD의 미래

DDD는 많은 사람들의 주목을 받고 있는 것에 비해서 사실 상당히 인기가 없다. DDD에 대한 말은 많고 많은 개발자들이 이야기하고 있기는 하지만, 정작 이를 현장에 적용했다는 소식은 그다지 들리지 않는다.

이는 DDD에 대한 정확한 이해와 접근방법에 대한 학습이 부족한 원인도 있을 것이다. 하지만 더 큰 이유는 DDD가 단지 개발 기술이 아니기 때문이다. DDD 사실상 소프트웨어 설계에 관한 철학이다. 그 설계와 구현이 일치를 이뤄야 하기 때문에 스프링과 같은 툴들이 이를 지원하고 있을 뿐이다.

따라서 진정한 DDD를 적용하고 그 장점을 충분히 누리려면 사실 많은 연구와 훈련이 필요로 하다. 스프링과 같은 실전 개발을 위한 좋은 툴이 제공되고 있으니 이제 한번쯤 DDD에 대해서 깊이 연구해보고 도전해볼 때가 되지 않았을까? @


참고자료
1. Anemic Domain Model: http://martinfowler.com/bliki/AnemicDomainModel.html
2. Domian Driven Design with DI and AOP: Ramnivas Laddad
3. Spring 2.0 Reference Manual
4. Domain Driven Design: Eric Evans

* 이 기사는 ZDNet Korea의 제휴매체인 마이크로소프트웨어에 게재된 내용입니다.

:

[펌]AOP

ITWeb/개발일반 2008. 6. 30. 19:02
ref. http://www.ibm.com/developerworks/kr/library/mar06/pollice/index.html



Aspect-Oriented Programming: AOP에 대한 실제적 접근방식 (한글)

developerWorks
문서 옵션
이 페이지를 이메일로 보내기

이 페이지를 이메일로 보내기


제안 및 의견
피드백

난이도 : 초급

Gary Pollice, Professor of Practice, Worcester Polytechnic Institute

2006 년 4 월 24 일

Aspect-Oriented Programming에 대한 대부분의 소개서들은 신기술 측면만을 다루고 있습니다. 바로 이러한 점 때문에 AOP의 실제적인 가치를 전혀 배울 수 없었습니다 . 이 글에서 AOP 기술을 소프트웨어 개발 프로젝트에 적용하는 방법을 설명합니다.

illustration최 근에 나는 Software Engineering Research Group (SERG)에서 Aspect 지향 프로그래밍(AOP)에 대한 토론을 진행해 줄 것을 부탁 받았다. 토론회가 시작되기 몇 시간 전, 한 학생이 나에게 물었다. "Aspect가 도대체 어디에 좋은가요? 그런데 로깅 예제는 안주셔도 됩니다. 내가 Aspect에 대한 것을 읽을 때 마다 보는 것이니까요. "

그 학생의 질문으로 나는 소프트웨어 시스템에 AOP를 적용하는 효과적인 방법을 생각하게 되었다. 또한 새로운 방식을 채택할 방법과 시기를 고려해야 할 필요성도 느꼈다. AOP는 새로운 방식이다. AOP가 효과적으로 사용될 수 있는 방법에 대해 이야기 하고자 한다. 또한 최근 AOP가 어떻게 진화했는지도 볼 것이다.

나는 Aspect 지향 자바를 예제로 사용할 예정이다. 하지만 자바 외에도 다른 여러 언어들의 Aspect 구현이 있다. AspectC++과 AspectL이 그것인데 이것은 Aspect 지향 Lisp 구현이다.1

AOP 개념 리뷰

AOP가 생소하다면 관련 개요서를 참조하기 바란다. 내가 쓴 2004년 2월의 기술자료를 참조해도 좋다.2 AOP 소개서의 많은 부분이 Aspect의 개념을 설명할 때 로깅을 예제로서 사용하고 있다. (로깅은 많은 사람들이 이해하고 있는 것이고 AOP가 사용되는 방법을 보여주는 좋은 예제이다.) Aspect는 크로스커팅을 하는 영역이다. 다시 말해서, 하나의 클래스에 쉽게 캡슐화 되지 않는다. 하지만 객체 지향 패러다임을 엄격히 따라간다면 그와 같은 영역을 일관되고 관리가 가능한 방식으로 나타내야 한다. 종종 크로스커팅 책임을 개별 helper 클래스로 위임해야 하고 영역에 의해 표현되는 기능을 필요로 하는 모든 클래스에 의존하여 호출들이 적절한 장소에서 그 위임에 대한 호출을 포함시켜야 한다. 코드의 적절한 포인트에 로그인을 지속적으로 삽입하는 것을 확인하기란 어려운 일이다. Aspect는 불완전 하지만 이러한 상황을 향상시킬 수 있는 방식을 제공한다.

AOP의 논의에 참여하기 위해서는 몇 가지 개념을 알아야 한다. 핵심 개념은 조인 포인트(join point)이다. 이 개념은 프로그래머에게는 익숙한 개념이지만 다시 한번 짚고 넘어가자. 조인 포인트는 "프로그램 플로우에서 정의가 잘된 포인트"이다. 3 메소드 호출 또는 메소드 리턴 같은 많은 유형의 조인 포인트가 있다. 정상 리턴이나 예외가 될 수 있다.

AOP의 경우 한 프로그램에 조인 포인트를 규명할 방식이 필요하다. AspectJ는 포인트컷(pointcut)을 사용하여 한 개 이상의 조인 포인트를 설명한다. 포인트컷은 조인 포인트를 기술하는 식(expression)이다. 포인트컷을 조인 포인트 세트를 리턴하는 코드의 쿼리로 생각할 수 있다.

조인 포인트 세트를 선택할 때 여기에 대한 어드바이스(advice)를 제공한다. 어드바이스는 프로그램이 실행하는 동안 조인 포인트를 만나게 될 때 실행되는 코드이다. 조인 포인트, 포인트컷, 어드바이스는 소프트웨어의 동적 속성을 나타낸다. 어드바이스는 프로그램 코드의 실행 특성을 변화시킨다.

시스템의 정적인 본질을 다루는 한 가지 개념이 있다. 바로 inter-type declaration이다. inter-type declaration은 프로그램의 정적 구조를 변화시킬 수 있다. 메소드와 변수를 추가하고, 지정된 규칙에 따라 상속 계층을 변경할 수 있다.

자바에서 클래스가 모듈의 단위이듯, Aspect는 AspectJ의 추가 모듈 단위이다. Aspect는 크로스커팅 영역을 위해 조인 포인트, 포인트컷, inter-type declaration, 어드바이스를 캡슐화 한다. AOP는 객체 지향 분석과 디자인의 대체 개념이 아니다. OO 방식이 우리가 원하는 솔루션을 제공하지 못하는 상황 속에서 새롭게 생겨난 것이다.

AOP 예제

이제 AOP 예제를 살펴보도록 하자. 제품 시스템과 제품 및 개발 상황 속에서 예제를 가져왔다. 두 개의 예제부터 시작하다.

실행 트레이싱

많은 개발자들이 프로그램의 실행을 디버깅 하거나 트레이싱 하기 위해 코드에 일종의 print 문을 포함시킨다는 것에 놀랐다. 물론 디버거는 정보를 잘 제공한다. 하지만 지금 우리는 디버거를 논할 것은 아니다. 프로그램의 텍스트 트레이스가 만들어지기를 기다리는 이유가 있다. 현재 Eclipse의 AspectJ Development Tools (AJDT)는 프로그램 실행 트레이스를 구현하는 좋은 예제이다. Eclipse 도움말에서 자세한 내용을 참조하라. AspectJ Programming Guide에도 자세한 내용이 있다.

이 예제는 원과 사각형 같은 이차원 그림을 표현하는 클래스를 가진 작은 자바 애플리케이션이다. 두 개의 원과 사각형을 만들고, 영역, 길이, 중앙 포인트 간 거리를 프린트하는 메인 메소드도 있다. 이 프로그램을 실행하면 그림 1과 같은 아웃풋이 나온다.

Figure 1: Input from the shape program

그림 1: shape 프로그램의 인풋

호출된 메소드의 실제 시퀀스를 보고 싶다면 두 가지 방법이 있다. 첫 번째 방법은 메소드의 이름과 클래스를 가진 메시지를 프린트하는 각 메소드의 시작에 코드를 삽입하는 것이다. 이를 각 메소드 마다 수행해야 한다. 두 번째 방법은 정확히 같은 일을 수행할 Aspect를 만드는 것이다. 이때에는 애플리케이션 코드를 변경할 필요가 없다.

트레이싱 예제는 Aspect를 사용하는 여러 버전의 트레이싱 솔루션들로 구성된다. 우리는 마지막 버전만 보도록 하겠다. 기타 다른 버전들은 AspectJ Programming Guide를 참조하기 바란다.

강력한 트레이싱 메커니즘에 대한 솔루션은 두 개의 파일로 구성된다. 하나는 추상 Aspect이다. 프로그래머가 파생된 클래스에서 일부 코드를 구현해야 하는 곳의 추상 클래스와 비슷하다. 이 경우는 파생된 Aspect이다. Trace라고 하는 추상 Aspect는 메소드 또는 구조체의 시작과 종료에 대한 메시지를 프린팅하고 아웃풋을 포맷팅 할 여러 가지 표준 메소드들을 갖고 있다. Aspect를 사용하고 있지 않다면 이 메소드들은 트레이스 정보를 출력할 때 사용할 헬퍼 클래스에 있을 것이다. 또한 프로그래머가 TRACELEVEL이라는 속성을 설정하여 트레이싱 유형을 설정할 수도 있다. 세 가지 레벨이 있다. 메시지 없음(no messages), 들여쓰기가 되지 않은 메시지(messages that are not indented), 중첩된 호출을 보여주도록 들여쓰기 된 메시지(messages that are indented to show nested calls).

Trace는 세 개의 포인트 컷을 정의한다. 이중 두 개는 구체적인 것이고 하나는 추상적이다. (그림 2) 추상 포인트컷인 myClass는 Trace를 확장하는 Aspect에서 제공된다. 포인트컷의 목표는 어드바이싱 될 조인 포인트를 포함하고 있는 객체용 클래스를 선택하는 것이다. 따라서 개발자는 트레이스 아웃풋에 어떤 클래스를 삽입할 지를 결정할 수 있다.

Figure 2: Pointcuts in the trace aspect

그림 2: 트레이스 Aspect의 포인트컷

myConstructor 포인트컷은 myClass가 선택한 클래스에 있는 객체용 구조체의 시작 부분에서 조인 포인트를 선택한다. 조인 포인트는 실제 구조체 바디이다. myMethod는 myConstructor와 비슷하지만, 이것은 선택된 클래스에서 메소드의 실행을 선택한다. 어드바이스에서 사용되는 toString 메소드의 실행은 생략했다는 것에 주목하라.

이 Aspect에서 제공하는 어드바이스는 매우 단순하다. 각 조인 포인트 전에 삽입되는 어드바이스와 조인 포인트 후에 실행되는 어드바이스가 있다. (그림 3)

Figure 3: Advice in the Trace aspect

그림 3: Trace aspect의 어드바이스

Trace Aspect를 사용하려면 이것을 확장하여 추상 포인트컷에 구체적 구현을 제공해야 한다. 그림 4는 예제 프로그램의 TraceMyClasses Aspect의 바디 모습이다. 포인트컷은 TwoDShape, Circle, Square의 인스턴스인 객체들만 선택할 것을 명령한다. 메인 메소드는 TRCELEVEL을 설정하고 트레이스 스트림을 초기화 하며 예제의 메인 메소드를 실행한다.

Figure 4: Concrete tracing aspect

그림 4: 구체적인 트레이싱 객체

그림 5는 아웃풋의 일부이다. 이 아웃풋은 각 객체에 대한 정보를 출력하고 있다. 이것은 각 메소드의 toString 메소드의 일부이다. myClasses 포인트컷이 객체를 어드바이스에 퍼블리시 하기 때문에 어드바이스는 객체에 대한 정보를 쉽게 추가할 수 있다.

Figure 5: Example trace output

그림 5: 트레이스 아웃풋

트레이스 코드를 직접 삽입하는 것 보다 AOP를 사용하는 것이 더 좋은 이유는? 여러 가지가 있다.

  • 한 장소(두 개의 Aspect)에 트레이싱 영역에 속해있는 모든 소스 코드를 둘 수 있다.
  • 트레이싱 코드를 삽입 및 제거하기가 쉽다. 구현 설정에서 Aspect를 제거하면 된다.
  • 트레이스 코드는 원하는 곳 어디에나 있다. 심지어 새로운 메소드를 목표 클래스에 추가하더라도 말이다. 따라서 오류를 줄일 수 있다. 또한 모든 트레이스 코드가 제거된다는 것을 알 수 있고, 구현 설정에서 Aspect를 제거할 때 어떤 것도 간과하지 않게 된다.
  • 적용 및 강화될 수 있는 재사용 가능한 Aspect를 가진다.

Design by Contract 또는 방어적 프로그래밍

Bertrand Meyer는 Design by Contract개념을 도입했다.4 이 원리는 클래스의 디자이너와 클래스의 사용자가 클래스 구현에 대한 생각을 공유한다는 것이다. 이 콘트랙트에는 불변 값, 전제 조건, 사후조건이 포함되어 있다. Design by Contract로 인해 클래스 디자이너는 인자의 유효성을 신경 쓰지 않고 클래스 기능을 구현하는 로직에만 집중할 수 있다. 물론 이것은 콘트랙트가 인자에 대한 사전 조건을 명시할 경우이다. Design by Contract는 클래스의 모든 클라이언트가 콘트랙트를 지킨다면 한 과잉 코드를 방지하고 퍼포먼스를 높인다.

광범위하게 사용할 라이브러리를 구현 할 때 메소드로 전달되는 인자의 유효성에 대해 잘 모를 경우가 있다. 각 메소드의 로직으로 처리하기 전에 인자를 검사해야 한다. 이것이 디펜스 프로그래밍(defensive programming)이다. 잘못될 가능성이 있는 것을 예견하고 이를 효과적으로 처리하는 것이다.

간단한 형상 프로그램을 공개적으로 사용한다고 해보자. 첫 번째 Euclidean 쿼드란트에 모든 좌표가 있어야 한다. 다시 말해서 x와 y 좌표는 비음수 값이다. 이는 포인트가 윈도우의 좌표에 나타난다면 유효한 제약조건이다. 대부분의 윈도우 시스템들은 좌측 상단 점을 (0,0)으로 시작하고 x 좌표를 오른쪽으로 늘리고 y 좌표를 아래쪽으로 옮긴다. 내부적인 필요에 의해서 Design by Contract를 사용해야 한다. 이 클래스를 사용할 개발자들에 대한 제어권이 있기 때문이다. 이것을 외부 클라이언트로 퍼블리시 할 때 인자를 검사하고 인자가 무효할 경우 예외를 던져야 한다. Aspect는 필요한 것을 구현할 수 있는 좋은 방법을 제공한다.

퍼블릭 메소드에 모든 인자를 검사할 Aspect를 구현해야 한다. 첫 번째로 해야 할 일은 포인트컷을 구현하는 일이다. 이전 예제에서 myClass 포인트컷을 사용하고, 인자 체킹을 필요로 하는 구조체를 선택하기 위해 포인트컷을 추가한다. 그림 6은 우리에게 필요한 포인트컷 세트이다. 두 번째 포인트컷은 포인트컷의 목표가 TwoDShape의 인스턴스라는 것을 지정한다. 이 같은 객체에 있는 거리 메소드로의 유일한 호출은 이 포인트컷에 의해 선택된다는 것을 의미한다.

Figure 6: Pointcuts for argument checking

그림 6: 인자 검사를 위한 포인트컷

마지막으로 적당한 어드바이스를 추가한다. 간단히 하기 위해 무효 인자를 만났을 때 메시지를 프린트 하고 실제 값을 0으로 바꾸고 무효 값이 전달될 때 거리에 대한 호출을 무시한다. 그림 7은 두 개의 어드바이스 아이템이다.

Figure 7: Argument checking advice

그림 7: 인자 검사 어드바이스

다음을 실행하면,

Circle c3 = new Circle(3.0,2.0,-2.0);

c1.distance(null>);

우리 프로그램에서는 다음과 같은 아웃풋을 얻게 된다.

Negative argument encountered at: execution(tracing.Circle(double, double, 
	double)) All arguments changed to 0.0
Null value given to distance at: 
	call(double tracing.Circle.distance(TwoDShape))

정확한 라인 번호와 소스 파일 이름을 보여줄 수 있지만 이 예제에서는 기본적인 기술만 보도록 한다.

많은 클래스가 있고 여러 인터페이스를 노출하는 큰 프로젝트에서 인자 검사를 구현하는 Aspect를 위해 개별 디렉토리를 구성해야 한다. 쉽게 구분할 수 있고 관리할 수 있도록 Aspect를 구성하는 여러 가지 방법들이 떠오른다. 내부적으로 사용할 시스템을 구현할 때 내부 구현 설정을 사용하고, 외부적으로 사용할 것을 구현할 때에는 Aspect가 포함된 설정을 사용한다. EclipseAJDT를 사용하면 새로운 구현 설정이 간단해 진다.

Aspect와 디자인 패턴

AOP는 기존 패턴을 향상시키고 새로운 것을 발견할 수 있도록 해준다. 사실, 크로스커팅 영역으로의 코드 투입도 하나의 패턴이다. 현재, 일부 연구원들은 AOP 방식을 사용한 디자인 패턴의 구현을 평가하고 있다. University of British Columbia의 Jan Hannemann은 그의 박사 논문에서 이것을 연구한다. http://www.cs.ubc.ca/~jan/AODPs/를 참조하라.5 Nicholas Lesiecki 역시 IBM developerWorks에 Aspect와 디자인 패턴에 대한 글을 기고하고 있다. 6

AspectJ에서 표준 디자인 패턴인 Adapter 패턴을 구현하는 방법을 알아보자.

그림 8은 Adapter 패턴에 대한 Unified Modeling Language (UML) 다이어그램이다. 이 패턴을 보면, 클라이언트는 서비스를 필요로 하고 서비스 요청을 한다. 많은 서비스 공급자들이 있고 이들 각각은 다양한 서비스 이름이나 서비스 요청자가 지켜야 할 비 표준 요구 사항들을 갖고 있다. 객체 지향 디자인에서는 목표 인터페이스에서 서비스에 대한 요청을 캡슐화하고, 인터페이스에 대해 프로그래밍 하며, 클라이언트와 서비스 간 중재자로서 작동할 어댑터(이 다이어그램의 경우 Adaptee)를 구현하도록 하고 있다.

Figure 8: Adapter pattern

그림 8: Adapter 패턴

이 방식은 매우 합리적이다. 하지만 어댑터 같은 패턴으로 설계되지 않았던 레거시 시스템이 있다면? 또한 서비스로의 호출이 애플리케이션 전체로 퍼져나갈 수 있다. 새롭고 향상된 서비스를 어떻게 구현할까? Aspect가 없다면 시스템을 리팩토링 하고, 모든 호출을 서비스에 배치시키고, 어댑터를 설계하고, Adapter 패턴을 구현해야 할 것이다. 이는 매우 힘든 일이다. 코드 향상을 위한 리팩토링은 가치 있는 목표이다. 하지만 언제나 그럴 수는 없다.

이 경우 Adapter 패턴의 AOP 버전을 구현하여 문제를 해결하도록 한다.

그림 9에서 서비스를 사용하는 클라이언트를 보자. 이 서비스는 한 지점에서 현재의 Client 객체로 거리를 리턴할 것이다.

Figure 9: Simple client

그림 9: 클라이언트

이 서비스용 인터페이스는 하나의 메소드를 기술하고 있다.


double useService(Client clt, double x, double y);

새로운 서비스 공급자는 다른 이름이 붙여진 메소드를 갖고 있다. 매개변수도 다르다. 이것의 인터페이스는 아래와 같다.


double useNewService(double x0, double x1, double y0, double y1);

오래된 서비스를 호출하고, 새로운 서비스에 대한 알맞은 인자를 얻고, 새로운 서비스를 호출하고, 그 결과를 클라이언트에 리턴하는 어댑터를 구현하고 싶다. 클라이언트를 변경하지 않고 말이다. 우리의 Aspect가 바로 이러한 일을 한다. (그림 10)

Figure 10: Adapter aspect to invoke the new service

그림 10: 새로운 서비스를 호출하는 Adapter aspect

너무 간단하다. 포인트컷을 선언하여 원래 서비스의 useService 메소드에 대한 모든 호출을 구분하고 있다. 그런 다음 around 어드바이스를 사용하여 새로운 서비스에 대한 호출로 대체한다.

이 방식에도 장단점은 있다. 우선 하나의 단순한 Aspect를 사용하여 애플리케이션에 있는 모든 코드를 변경할 수 있다. 또한 서비스를 호출하는 영역을 한 장소에 캡슐화 할 수 있다. 새로운 서비스가 더 새로운 서비스로 대체된다면 Aspect의 코드만 변경하면 된다. 시스템이 더욱 강해질 것은 자명하다.

사용되지 않는 오래된 클라이언트가 여전히 새로운 시스템에 있다는 것이 큰 단점이다. 시간이 충분하다면 표준 Adapter 패턴을 사용하도록 시스템을 리팩토링 할 수도 있다. 하지만 현재로서는 원래 서비스의 useService 메소드를 0.0 같은 더미 값을 리턴하는 코드를 사용하여 변경할 수 있다.

산업 강화 사용

지금까지, 매우 제한되었지만 유용한 AOP 적용 예제를 보았다. 기술력을 향상시킬 수 있는 방법이 궁금할 것이다. 여기에서는 간단한 예제 한 가지를 설명하겠다.

Spring Framework을 다들 알 것이다.7 Spring Framework은 엔터프라이즈 애플리케이션의 개발을 지원하는 애플리케이션 프레임웍이다. 복잡한 엔터프라이즈 애플리케이션을 구현할 수 있는 레이어드 J2EE 프레임웍을 제공한다. Spring의 기반이 되는 기술 중 하나가 AOP이다. Spring은 런타임 시 크로스커팅 로직이 코드에 적용될 수 있도록 하는 자체적인 Aspect 구현을 개발했다. AspectJ를 Spring Framework으로 쉽게 통합할 수 있는 통합 기능도 제공한다.

Spring은 현재 많은 기업들이 사용하고 있고 더 낳은 애플리케이션을 구현하는데 사용되고 있다. 개발 시간이 적게 들고 설계도 잘 되어 있다. 실제 사례들에 Aspect를 적용할 수 있는 좋은 예제라 할 수 있다.8

전망

앞으로 AOP는 소프트웨어 개발자 툴킷의 일부가 될 것이다. AOP가 주요 디자인 메커니즘으로 간주되는 시스템을 구현하는 것 까지는 아니더라도 OO 디자인을 향상시킬 수 있다고 생각한다. 이를 위해서는 몇 가지 조건이 필요하다.

첫째, 안정적인 표준의 AOP 구현이 필요하다. 이 작업은 이미 시작되었다. EJB Version 5는 두 개의 대표적인 자바 AOP 언어인 AspectJ와 AspectWerkz를 합친 것이다. C++ 같은 기타 언어들의 표준 구현 역시 도움이 될 것이다.

둘째, AOP를 특정 시스템에 적용했을 때의 효용성을 입증할 메트릭스를 개발해야 한다. AOP를 사용하여 디자인 패턴을 재구현 한다면 과연 이것이 OO 패턴 보다 더 나을까? 더 나은 점은 무엇이고, 그렇지 않은 부분은 무엇인가? 이러한 메트릭스를 개발하기 위해 우리가 해야 할 일은 무엇일까? 우리는 경험적 증거에 입각하여 구현 및 디자인 결정을 내려야 한다. 9

세 번째, AOP를 지원하는 툴을 지속적으로 개발해야 한다. Eclipse용 AJDT는 훌륭한 툴이라고 감히 말하고 싶다. 이 툴은 우리가 필요로 하는 지원 부분을 계속 향상시키고 있다.

Aspect는 여기서 멈추지 않는다. 주류 애플리케이션의 일부가 되려면 멀었지만 더 가까이 다가선 것 만은 틀림없다.

1 http://www.aspectc.org/, http://common-lisp.net/project/closer/aspectl.html

2 The Rational Edge: http://www.ibm.com/developerworks/rational/library/2782.html

3 AspectJ Programming Guide: http://www.eclipse.org/aspectj/doc/released/progguide/index.html

4 Bertrand Meyer, Object-Oriented Software Construction, 2d ed. Prentice Hall 1998.

5 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides의 Design Patterns

6 http://www-128.ibm.com/developerworks/java/library/j-aopwork5/

7 http://www.springframework.org/

8 Pro Spring, Rob Harrop and Jan Machacek, Apress 2005.

9 AOP 메트릭스 개발

기사의 원문보기

:

Data Hiding...

ITWeb/개발일반 2008. 6. 16. 17:10

Data Hiding

  • public anyone can access it
  • protected only descendants can access it
  • private only you can access it
  • final no one can re-declare it
  • abstract someone else will implement this

OOP 하면서 많이 나오는 내용이죠.
변수를 사용하면서 이부분에 대해서 명확히 이해하고 작성하는게 좋겠죠.. ^^*
걍 지나가다 생각 나서 올려 봤어요..

:

[PHP]bitwise operators ...

ITWeb/개발일반 2008. 4. 17. 10:33

[bitwise operators]
이 연산자를 어디서 사용을 하고 계시나요?
쓰임새가 목적에 따라 다르겠지만 제가 지금 설명 하고자 하는 내용은 이것을 이용해서 컨텐츠(글)에 대한 옵션을 지정하는 방법입니다.

ref. http://www.php.net/manual/en/language.operators.bitwise.php
ref. http://www.vipan.com/htdocs/bitwisehelp.html

일반적으로 블로그 컨텐츠의 경우 글 작성을 하는 경우 여러가지 옵션이 존재 합니다.

- 공개, 비공개, 19금, 친구만 공개, 구독자만 공개, 검색에 노출/비노출 등등...

이렇게 많은 글에 대한 옵션이 등장하죠.
위에 예를 가지고 설명해보겠습니다.

공개/비공개 : 1
친구만 공개/비공개 : 2
구독자만 공개/비공개 : 4
검색에 공개/비공개 : 8

binary 로 표현 하면
1                     1                   1                    1
2^^3                2^^2               2^^1               2^^0

이케 되겠내요.

사용자가 옵션을 선택해 보죠..
글을 공개 하고 검색에 노출하고 싶다
binary : 1001
decimal : 9
그럼 실제 코딩 단계에서는 어떻게 이런 값을 얻을수 있을까요?
일반적으로 글에 대한 default 값이 존재 합니다.
default 를 공개로만 설정하고 나머지는 사용자가 선택 해야 한다고 가정 하도록 하죠.

bitOpen = 1
bitFriend = 2
bitReader = 4
bitSearch = 8

flag = 0

위와 같이 16가지의 옵션이 존재 할 수 있겠죠.. 이들에 대한 표현을 하기 위해서 bitwise operators 를 사용 하는 것이지요..
0000 : 전체 비공개
0001 : 공개
0010 : 친구만 공개
0011 : 공개및 친구도 공개 (사실 예가 좀 안좋내요..ㅡㅡ^ 이점 너그럽게 이해해 주시길.. ^^;)
1001 : 공개 하고 검색에도 등록 (이 예가 더 좋내요.. ^^;)
....
1111 : 전체 공개

flag |= bitOpen (0001)
flag |= bitFriend (0010)
flag |= bitReader (0100)
flag |= bitSearch (1000)
등등..

bitOpenY = flag | bitOpen
bitOpenN = flag & bitOpen
bitFriendY = flag | bitFriend
bitFriendN = flag & bitFriend
// 글 공개 이나 친구에게는 비공개로 선택
result = bitOpenY | bitFriendN (0001)
이거 뭐 그냥.. bitOpen 만 쓰면 되지 이걸 왜 연산까지 하냐 그러시겠지만 아주 초 간단 예를 들어서 그렇게 보일수 있는 거구요.
2^^N 개의 옵션이 있는 경우 이 bitwise operators 는 정말 유용하게 사용 됩니다.

그냥 기초 이니까.. 그 원리만 이해를 하시면 될듯 하내요.. ^^*

과거에도 쉽게 사용했던 방법은 주로 코드 테이블을 짜서 사용을 했었죠.. 아마도..
각 단위별로 의미를 부여 하고.. 코드를 생성 하거나 특정 값에 의미를 부여 하는 식으루다가요..

rdbms 랑 script 랑 잘 만들어서 사용하면 퍼포먼스 도 그렇고 유지보수에도 좋은 결과가 나올 겁니다..
(늘 그렇듯이 잘 만들면.. ㅋ)

:

[PHP]php 로 구현된 singleton 패턴

ITWeb/개발일반 2008. 4. 14. 21:19
php 로 구현된 singleton 패턴
- prototype 과 singleton
- javascript object, class & inheritance, sigletons

class singleton
// ensure that only a single instance exists for each class.
{
    function &getInstance ($class, $arg1=null)
    // implements the 'singleton' design pattern.
    {
        static $instances = array();  // array of instance names

        if (array_key_exists($class, $instances)) {
            // instance exists in array, so use it
            $instance =& $instances[$class];
           
        } else {
            // load the class file (if not already loaded)
            if (!class_exists($class)) {
                switch ($class) {
                    case 'date_class':
                        require_once 'std.datevalidation.class.inc';
                        break;

                    case 'encryption_class':
                        require_once 'std.encryption.class.inc';
                        break;

                    case 'validation_class':
                        require_once 'std.validation.class.inc';
                        break;

                    default:
                        require_once "classes/$class.class.inc";
                        break;
                } // switch
            } // if

            // instance does not exist, so create it
            $instances[$class] = new $class($arg1);
            $instance =& $instances[$class];
        } // if

        return $instance;

    } // getInstance
   
} // singleton

ref. http://www.tonymarston.net/php-mysql/singleton.html

뭐 위에 다른 글에서도 설명 되어 있지만 어떤 language 로 구현을 하던 최대 N 개로 제한 되어 지는 극한까지는 1개로 제한 되어 지는 객체를 생성 하는 패턴 방식입니다.

더 쉽게 설명 하자면 그냥 global class ,variable  또는 static 이라고도 할 수도 있겠죠.
물론 의미적으로 통할 수 있다는 설명 입니다.
근데 뭐 쉽게 이해 하는데 이 정도면 되지 않나 싶기도 하구요.. ^^*
전 어려운 용어나 개념은 별로 좋아라 하지 않아서.. ㅎㅎ
:

JavaScript 강좌 references.

ITWeb/개발일반 2008. 2. 20. 17:52
 
W3C
YUI
    yahoo.com YUI JavaScript ENG
ECMA
:

JavaScript Tips

ITWeb/개발일반 2008. 2. 20. 17:48

 
Semicolon insertion
-When the compiler sees an error, it attempts to replace a nearby linefeed with a semicolon and try again.
-This should alarm you.
-It can mask errors.
-Always use the full, correct forms, including semicolons.
Comma
-Good: [1, 2, 3]
-Bad:  [1, 2, 3,]

 
Required block
-Good:
§if (a) {
§    b();
§}
-Bad:
§if (a) b();
== and !=
-Bad
§if (a == null) { ... }
-Good:
§if (a === null) { ... }
§if (!a) { ... }

 
Common subexpression removal
Loop invariant removal
for (var i = 0; i < divs.length; i += 1) {
    divs[i].style.color = "black";
    divs[i].style.border = thickness + 'px solid blue';
    divs[i].style.backgroundColor = "white";
}

----->
 
var border = thickness + 'px solid blue',
    nrDivs = divs.length;
for (var i = 0; i < nrDivs; i += 1) {
    var ds = divs[i].style;
    ds.color = "black";
    ds.border = border;
    ds.backgroundColor = "white";
}

 
Strings
-Concatenation with +
§Each operation allocates memory
foo = a + b;
-Concatenate with array.join('')
§The contents of an array are concatenated into a single string
-Comparison
§a) foo = a + b; vs b) foo = [a, b].join('');
a)  <  b)
§a) foo = 'a' + 'b'; vs b) foo = ['a', 'b'].join('');
a)  >  b)


 
-Place <script src> tags as close to the bottom of the body as possible. (Also, place CSS <link> as high in the head as possible.)
-Minify and gzip script files.
-Reduce the number of script files as much as possible.
<script></script>
<!--  // -->
§Hack for Mosaic and Navigator 1.0.
language=javascript
§Deprecated.
src=URL
§Highly recommended.
§Don't put code on pages.
type=text/javascript
§Ignored.

 
document.write
-Allows JavaScript to produce HTML text.
-Before onload: Inserts HTML text into the document.
-After onload: Uses HTML text to replace the current document.
-Not recommended.

 
name
-Identifies values in form data
-Identifies a window/frame
id
-Uniquely identifies an element


 
document.all
-Microsoft feature, rejected by W3C and most other browsers.
-It acts as a function or array for accessing elements by position, name, or id.
-Avoid it.


 
Manipulating elements
-Old
§if (my_image.complete) {
§    my_image.src = superurl;
§}
-New
§if (my_image.getAttribute('complete')) {
§    my_image.setAttribute('src', superurl);
§}


 
Element id 통한 접근
var oElement = null;
if ( document.getElementById ) {
oElement = document.getElementById(ID);
} else if ( document.layers ) {
oElement = document.layers[ID];
} else if ( document.all ) {
oElement = document.all[ID];
}


 
var oHttp = false;
var aMsxmlType = [
'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP'
];
if ( window.XMLHttpRequest ) {
try {
oHttp = new XMLHttpRequest();
} catch(e) {
oHttp = false;
}
} else if ( window.ActiveXObject ) {
for ( i=0; i<this.aMsxmlType.length; i++ ) {
try {
oHttp = new ActiveXObject(this.aMsxmlType[i]);
if ( oHttp ) {
break;
}
} catch(e) {
oHttp = false;
}
}
}

 
JavaScritp XMLDOM
var oXmlDoc = null;
if ( window.ActiveXObject ) {
oXmlDoc = new ActiveXObject("Microsoft.XMLDOM");
} else if ( document.implementation && document.implementation.createDocument ) {
oXmlDoc = document.implementation.createDocument("", "", null);
}
IE/FF (xml file)
§Using XMLDOMObject. getElementsByTagName(..)
FF (xml string)
§var oDomParser=new DOMParser();
§var oDoc = oDomParser.parseFromString(XMLSTRING,"text/xml");


: