하이버네이트 우수 실천법

하이버네이트 레퍼런스 문서의 뒷부분에 있는 24장 Best Practices를 번역했습니다. 하이버네이트 한글 레퍼런스가 있을 줄 알았는데 번역된 것을 찾지 못하겠네요.

하아버네이트를 배우고 쓰면서 생소한 환경에 어려움을 격게 되는데 사용법을 익히고나서 보면 많이 도움이 되는 글입니다.


세분화된 클래스를 작성하고 <component>로 매핑한다.


street, suburb, state, postcode를 Address 클래스로 캡슐화 한다. 이렇게 하면 코드 재사용성이 올라가고 리팩토링하기 쉬워진다.

영속 객체에 ID 속성을 선언한다.

하이버네이트에서 ID 속성을 꼭 만들어야 하는 건 아니지만 ID 속성을 써야만 하는 여러가지 이유가 있다. ID는 업무상 의미가 없도록 인위적으로 생성된 모조 키가 좋다.

자연 키(natural key)를 식별한다.

모든 엔티티에서 자연 키를 식별하고 <natural-id>로 매핑한다. 자연 키에 해당하는 속성들을 비교하도록 equals()와 hashCode()를 구현한다.

각 클래스 매핑은 개별 파일에 저장한다.

한 파일에 매핑 정보를 몰아 넣지 않는다. com.eg.Foo 클래스는 com/eg/Foo.hbm.xml 파일에서 매핑한다. 팀으로 일하는 환경이라면 이 방식이 특히 합리적이다.

매핑 파일을 자원으로 적재한다.

매핑 파일은 매핑 대상 클래스와 함께 배포한다.

질의 문자열을 외부에 두는 것을 고려한다.

질의문이 비 ANSI 표준 SQL 함수를 호출한다면 이렇게 하는 게 좋다. 질의 문자열을 외부 매핑 파일에 두면 응용 S/W가 더 유연해진다.

바인드 변수를 사용한다.

JDBC에서처럼 비 상수 값을 "?" 문자로 대체한다. 질의문에 비 상수 값을 넣으려고 문자열 조작을 하지 말아라. 질의문에 이름을 붙힌 매개변수(named parameter)를 쓰는 것도 고려할 수 있다.

JDBC 연결을 따로 관리하지 않는다.

하이버네이트는 응용 S/W가 JDBC 연결을 관리하도록 허용하지만 이 방식은 마지막 수단으로 생각해야 한다. 내장 연결 제공자를 사용할 수 없다면 org.hibernate.connection.ConnectionProvider의 독자 구현을 제공하는 것도 검토해보도록 한다.

자작 타입(custom type)을 고려한다.

라이브러리에서 가지고 온 자바 타입이 있고 이것을 영속화해야 하는데 컴포넌트로서 매핑하려해도 필요한 접근자가 없다고 하자. 이럴 때는 org.hibernate.UserType을 구현해 볼 만하다. 이 방식을 쓰면 하이버네이트 타입으로 변환하는 작업을 응용 프로그램 코드에서 따로 구현하지 않아도 된다.

병목지점에 JDBC를  사용한다.

시스템 중 성능이 중요한 부분에서 어떤 작업은 직접 JDBC를 쓰는 것이 유리할 수 있다. 그렇지만 JDBC가 필요하다고 너무 빨리 가정하지 말라. 어떤 지점이 병목인지 알 때까지 판단을 유보해라. 직접 JDBC를 써야 한다면 하이버네이트의 Session을 열고 여기에서 JDBC 연결을 받아 사용하도록 한다. 이렇게 해서 여전히 같은 트랜젝션 전략과 연결 제공자를 사용할 수 있다.

세션 비우기(session flushing)을 이해해라.


이따금 Session은 자신의 영속 상태를 데이터베이스와 동기화 한다. 이 작업이 너무 자주 일어난다면 성능에 영향을 줄 것이다. 때로는 자동 비우기를 꺼서 필요 없는 비우기를 최소화 할 수 있다. 또는, 특정 트랜젝션내의 질의문이나 여타 작업의 순서를 바꿔서 그렇게 하기도 한다.

삼중 계층(3-tier) 구조에서는 이탈(detached) 객체를 고려한다.


서블릿/세선 빈 아키텍쳐를 쓸 때는 세션 빈에서 읽은 영속 객체를 서블릿/JSP 단에 보내거나 받을 수 있 수 있다. 매 요청을 처리할 때 마다 새 Session을 사용해라. Session.merge()나 Session.saveOrUpdate()를 써서 객체를 데이터베이스와 동기화 해라.

이중 계층(2-tier) 구조에서는 긴 영속 문맥(long persistence contexts)를 고려한다.

성능 확장성을 최대한 높이려면 데이터베이스 트랜잭션은 가능한 짧아야 한다. 그렇지만, 종종 오랫동안 운영되는 응용 트랜잭션이 필요하다. 응용 트랜잭션이란 사용자의 관점에서 본 단위 작업 하나를 말한다. 응용 트랜잭션 하나가 여러 클라이언트 요청/답변 주기에 걸쳐있을 수도 있다. 응용 트랜잭션을 구현할 때에 이탈 객체를 쓰는 것이 일반적이다. 2-티어 아키택처에 적당한 대안은 단일 개방 영속 접촉 세션을 응용 트랜잭션의 전체 생애 주기 동안 유지하는 것이다.  요청이 끝나면 단순히 JDBC 연결을 끊고 이어지는 요청이 시작할 때 재접속한다. 한 세션을 여러 응용 트랜잭션이 공유하지 말아야 한다. 그렇지 않으면 노후한 데이터로 일을하게 될 것이다.

예외(Exception)를 복구할 수 있는 것처럼 다루지 말아라.

이것은 우수 실천법이라기 보다는 필수 실천법에 더 가깝다. 예외가 발생하면 Transaction을 되돌리고 Session을 닫아라. 이렇게 하지 않으면, 하이버네이트는 메모리 상의 상태가  영속 상태를 정확히 표현한다고 보장할 수 없다. 예를 들어, 데이터베이스에 특정 ID가 있는지 확인할 때 query 대신 Session.load()를 쓰지 말아라.

연관(association)에는 유보적 취득(Lazy fetching)을 택하라.

모든 연관 객체를 미리 다 읽어 놓지 말고 연관 대부분을 클래스에 플락시(proxy)와 유보적 수집을 적용하여 처리하도록 한다. 이렇게 하면 2차 캐시에 모든 것을 다 담아두지 않을 수 있다. 연관된 클래스가 캐시되어 있다면 캐시 적중율은 극적으로 올라갈 것이다. lazy='false' 사용하면 명시적으로 유보적 취득 기능을 끌 수 있다. 조인으로 취득해야 하는 일이 그리 많지 않고 한두 쓰임새에서만 쓰인다면  질의문에 left join fetch을 사용한다.

미취득 데이터 문제를 예방하려면 뷰 단까지 세션 개방하기(Open session in view) 패턴이나 잘 통제된 조립 단계를 사용한다.

하이버네이트는 데이터 전송 객체(Data Transfer Objects, DTO)을 작성하는 지루한 작업에서 개발자를 자유롭게 한다. 전통적인 EJB 아키텍처에서 DTO 두 가지 목적으로 쓰였다. 우선은 엔티티 빈을 직렬화 할 수 없는 문제를 해결한다. 두 번째로는 암묵적으로 조립 단계를 정의한다. 조립 단계에서는 제어권을 표현 단으로 넘기기 전에 뷰에서 사용될 모든 데이터를 취득하고 DTO에 정리한다. 하이버네이트를 쓰면 첫번째 목적은 의미 없다. 영속화 문맥(persistence context; 세션)을 뷰 생성 단계에까지 열어둘 준비가 되어있지 않다면 조립 단계는 여전히 필요하다. 비즈니스 절차를 어떤 데이터가 이탈 객체로서 표현 단에 제공될지에 대한 엄격한 제약을 갖는 것으로 여기도록 한다. 이것은 하이버네이트의 제약이 아니고 안전한 데이터를 주고 받기 위한 기본적인 요건이다.

하이버네이트에서 비즈니스 로직을 추상화하도록 고려한다.

하이버네이트 데이터 접근 코드를 인터페이스 뒤에 숨기도록 해라. DAO와 쓰레드 지역 세션(Thread Local Session) 패턴을 조합해라. 심지어 어떤 클래스는 UserType으로 하이버네이트에 연결돤 JDBC로 직접 코드를 작성해 영속화 할 수 있다. 하지만, 이 조언은 충분히 큰 응용 S/W를
고려한 것이지 달랑 테이블 다섯개인 응용 S/W에는 적당하지 않다.

특이한 연관 매핑을 쓰지 말라.

진짜로 다대다 연관이 필요한 실용적 테스트 케이스는 흔치 않다. 대부분 연계 테이블(link table)에 부가 정보를 저장해야만 하는데 이럴 때는 두 일대다 관계로 분리하고 중간에 연계 클래스(link class)를 두는 것이 훨씬 좋다. 사실, 대부분의 연관은 일대다이거나 다대일이다. 이 때문에, 다른 연관 유형을 사용할 때에는 조심해서 처리해야 한다.

양방향 연관을 활용하라.

단방향 연관은 질의하기 어려운 편이다. 대규모 응용 S/W에서는 질의 시 연관 대부분이 양쪽 방향으로 탐색 가능해야 한다.

by 박성철 | 2009/11/26 19:39 | 프로그래밍 이야기 | 트랙백(1) | 덧글(0)

픽사 단편 모음

늘 영감을 주는 픽사 작품들이지만 그 중에서도 단편 작품들은 눈물이 날 정도로 감동적입니다.
미투의 서드타입님이 몇가지 픽사 단편을 올리셨는데 ( http://me2day.net/thirdtype/2009/11/16#10:55:19 ) 이에 동기부여가 되어(일도 하기 싫고) 검색을 좀 해봤습니다.

픽사 홈페이지의 단편 모음 : http://www.pixar.com/shorts/index.html
픽사 단편 모음짐 : http://en.wikipedia.org/wiki/Pixar_Short_Films_Collection_%E2%80%93_Volume_1
픽사 단편 목록 : http://en.wikipedia.org/wiki/List_of_Pixar_shorts

이 중에서 픽사 단편 목록에 있는 것들을 기초로 유튜브에서 화질 좋은 것만 한번 찾아 봤습니다.

The Adventures of André and Wally B., Luxo Jr., Red's Dream, Tin Toy, Knick Knack 같은 초기 작품은 제가 모시던 사장님이 미국 출장 갔다가 복사해오신 SIGGRAPH 작품집 비디오를 통해 봤었는데 당시에 얼마나 충격을 받았는지 모릅니다. Tron과 더불어 CG에 한동안 빠져들 게 했던 작품들이죠. Tron이 리메이크 된다는 소식이 있는데 많이 기대됩니다.

The Adventures of André and Wally B.



Luxo Jr.




Red's Dream




Tin Toy




Knick Knack




Geri's Game




For the Birds




Mike's New Car




Boundin'



Jack-Jack Attack



One Man Band



Mater and the Ghostlight




Lifted




Your Friend the Rat




Presto




BURN-E




Partly Cloudy




Dug's Special Mission



*) 이런 날로 먹는 포스팅도 좋네요. ㅎㅎ

by 박성철 | 2009/11/16 13:47 | 사는 이야기 | 트랙백(1) | 핑백(1) | 덧글(2)

[번역] 제어 역전 컨테이너와 의존성 주입 패턴 (4/4)

[번역] 제어 역전 컨테이너와 의존성 주입 패턴 [1][2][3][4]
어떤 것을 쓸 것인가?

지금까지는 제가 이 패턴과 변종들을 어떻게 이해하는지를 집중적으로 설명했습니다. 이제, 언제 어떤 것을 쓸면 좋을지 판단하는 데 도움이 될 만한 장단점을 이야기할 수 있게 되었습니다.

서비스 위치탐색기 대 의존성 주입

서비스 위치탐색기와 의존성 주입 사이에서 어떤 것을 선택하느냐가 가장 근본적입니다. 이 두 구현체 모두 기본적으로 객체 간의 결합을 끊어 줍니다. 결합은 '빈약한 예제'의 결함이었습니다. 두 기술을 적용한 사례 모두 사용하는 쪽 코드가 서비스 인터페이스의 구현물에 의존하지 않았습니다. 서비스를 사용하는 응용 클래스에 구현물을 제공하는 방법이 두 패턴의 중요한 차이점입니다. 서비스 위치탐색기 방식에서는 응용 클래스가 명시적으로 위치탐색기를 호출하여 서비스를 요청합니다. 주입 방식에서는 명시적인 요청이 없습니다. 사용하기 원하는 서비스가 응용 클래스에 들어갑니다. 그래서 제어 역전이라고 합니다.

제어 역전은 프레임워크들의 일반적인 특징이지만 비용을 내해야 합니다. 프레임워크는 대체로 이해하기 어렵고 디버깅을 하려고 할 때 문제가 생기기도 합니다. 그래서 전 보통 필요하지 않으면 프레임워크를 쓰지 않는 편입니다. 그렇다고 프레임워크가 나쁘다는 뜻은 아닙니다. 단지 프레임워크들이 보다 직접적인 방식의 대안들에 대해 자신의 가치를 스스로 증명해야 할 필요가 있다는 생각이다.

서비스를 사용하는 모든 객체가 위치탐색기에 의존한다는 것이 서비스 위치탐색기의 가장 큰 차이점입니다. 위치탐색기로 다른 구현물들에 대한 의존성을 숨길 수 있지만 위치탐색기에는 의존해야 합니다. 그래서 위치탐색기와 주입 사이에서의 결정은 의존성이 문제가 되는지 여부에 따릅니다.

의존성 주입을 쓰면 컴포넌트가 무엇에 의존하고 있는지 파악하기 쉽습니다.  의존성 주입에서는 단순히 생성자 같은 주입 메커니즘만 살피면 의존성을 알 수 있습니다. 서비스 위치탐색기에서는 위치탐색기를 호출하는 부분의 소스코드를 찾아 읽어봐야 합니다. 최신 IDE의 참조 찾기 기능을 쓰면 이런 작업을 쉽게 할 수 있지만, 여전히 생성자나 변경 메소드를 보기 만큼 쉬운 건 아닙니다.

서비스를 사용하는 객체의 특징에 따라 대부분이 결정됩니다. 서비스 하나를 사용하는 여러 유형의 클래스로 된 응용 소프트웨어를 만들 때라면 응용 클래스가 위치탐색기에 의존하는 게 큰 문제가 안 됩니다. 친구들에게 준 예의 MovieLister에서는 서비스 위치탐색기가 아주 잘 작동했습니다. 친구들이 해야 할 일이라고는 올바른 서비스 구현물을 집어오도록 위치탐색기를 설정하는 것뿐입니다. 설정을 코드로 하든 아니면 파일로 하든 상관없이 말입니다. 이런 시나리오에서는 주입기의 역전이 그리 매력적으로 보이지 않습니다.

MovieLister가 컴포넌트로서 다른 사람이 작성하는 응용 프로그램에 사용된다면 좀 다릅니다. 이 경우에는 고객들이 사용하려는 서비스 위치탐색기의 API에 대해 그리 잘 알지 못합니다. 고객은 각각 서로 호환이 안 되는 자신만의 서비스 위치탐색기를 가지고 있을 것입니다. 격리된 인터페이스(segregated interface)를 쓰면 어느 정도 이 문제를 해결할 수 있습니다. 고객들이 직접 이 인터페이스로 자신들의 위치탐색기에 맞는 어댑터를 만들 수 있습니다. 그렇지만 어떤 경우라도 여전히 특정 격리 인터페이스를 찾으려면 첫 번째 위치탐색기를 살펴봐야 합니다. 그리고, 일단 어댑터가 등장하면 위치탐색기를 직접 다루는 단순성은 약해지기 시작합니다.

주입에서는 컴포넌트가 주입기에 의존하지 않기 때문에 컴포넌트가 한번 설정되고 나면 주입기에서 추가적인 서비스들을 얻을 수 없습니다.

사람들은 보통 테스트를 더 쉽게 할 수 있어서 의존성 주입을 선호합니다. 여기서 핵심은 테스트하려면 실 서비스 구현을 스텁(stub)이나 목(mock)으로 쉽게 바꿀 수 있어야 한다는 것입니다. 그렇지만 의존성 주입과 서비스 위치탐색기 사이에는 이런 면에서 진짜 어떤 차이도 없습니다. 양쪽 모두 스텁을 쓰기 아주 좋습니다. 서비스 위치탐색기를 쉽게 교체할 수 있도록 노력하지 않은 프로젝트에서 나온 관찰 결과는 의심스럽습니다. 이런 데는 지속적 테스트가 도움이 됩니다. 테스트를 하면서 서비스를 스텁으로 바꾸기 쉽지 않다면 설계에 심각한 문제가 있다는 뜻입니다.

물론 테스트 문제는 자바 EJB 프레임워크 같이 심하게 침투적인(intrusive) 컴포넌트 환경 때문에 악화됩니다. 이런 종류의 프레임워크는 응용 프로그램 코드에 주는 영향이 최소화되어야 한다고 봅니다. 특히, 코드를 수정하고 실행하는 주기가 느려지게 하는 일은 해서는 안 됩니다. 무거운 컴포넌트를 대체하는 플러그인을 쓰면 이런 작업에 큰 도움이 됩니다. 이는 테스트 주도 개발 같은 기법에는 성패가 달린 결정적 조건입니다.

이처럼 핵심은 외부의 응용 프로그램에 쓰일 것으로 예상하는 코드의 작성자와 관련되어 있습니다. 이런 프로그램에는 컴포넌트 제작자가 어떤 제어를 할 수가 없습니다. 이 경우에는 서비스 위치탐색기 도입을 아무리 최소한으로만 하려 한다 해도 문제가 됩니다.

생성자 주입 대 변경자 주입

서비스를 조합하는 데에는 서비스들을 서로 연결하는 항상 어떤 규약이 있어야 합니다. 주입은 매우 간단한 규약만 있으면 되는데 이것이 주입의 본질적인 강점입니다. 최소한 생성자 주입과 변경 주입은 그렇습니다. 컴포넌트에 잡스런 어떤 작업도 하지 않아도 되고 주입기 입장에서도 모든 설정 작업을 상당히 직접적이고 단순하게 할 수 있습니다.

인터페이스 주입은 설정 작업에 필요한 많은 인터페이스를 만들어야 하기 때문에 상대적으로 침투적입니다. 아발론의 방식처럼 몇몇 인터페이스만 있어도 된다면 그렇게 나쁘지만은 않습니다. 그렇지만 인터페이스 주입은 컴포넌트와 의존 객체들을 조립하는데 많은 작업을 해야 합니다. 이런 이유로 요즘 등장하는 경량 컨테이너들은 변경자와 생성자 주입을 합니다.

변경자와 생성자 주입 사이에서 선택하는 문제는 객체지향 프로그래밍의 일반적인 논쟁을 반영하기 때문에 흥미있습니다. 즉 객체의 필드에 값을 생성자에서 채울 것이냐 변경자에서 할 것이냐는 문제이다.

객체와 관련해서 오래전부터 전 기본적으로 가능한 생성 시에 객체를 유효하게 만듭니다. 이 조언은 켄트백의 "스몰톡 우수 기법 패턴(Smalltalk Best Practice Patterns)"에 실린 생성자 메소드와 생성자 매개변수 메소드 패턴까지 거슬러 올라갑니다. 매개변수가 있는 생성자는 적합한 장소에서 유효한 객체를 만들라는 뜻을 명백하게 표현합니다. 객체 초기화 방식이 하나 이상이라면  다른 조합을 표현하는 여러 생성자를 만듭니다.

단순히 변경자 없앰으로써 불변 필드를 확실히 숨길 수 있는 것도 생성자 초기화의 장점입니다. 이 점은 중요합니다. 무엇인가 바뀌지 말아야 할 때도 변경자는 변경사항을 고스란히 전달하는 결함이 있습니다. 초기화에 변경자를 쓰면 이런 특징 때문에 고민하게 됩니다. (실제로 이런 상황에 저는 변경자를 쓰는 방식을 배제하곤 합니다. 전 initFoo 같은 메소드를 써서 생성될 때에만 수행되어야 할 무엇이라는 것을 강조하는 편입니다.)

하지만 모든 상황에는 예외가 있습니다. 생성자 매개변수가 너무 많으면 무척 보기 지저분합니다. 키워드 매개변수가 없는 언어에서는 특히 그렇습니다. 생성자가 길면 대개 객체가 너무 많은 일을 하고 있다는 것을 뜻하기 때문에 나눠야 하는 것이 맞지만 의도적으로 생성자를 길게 만들어야 할 때도 있습니다.

객체를 유효하게 생성하는 방법이 여러 가지 있다면 생성자가 매개변수의 숫자와 타입만으로 구분할 수 있는 이상 생성자로 구분해서 표현하기 어려울 수 있습니다. 이때가 팩토리 메서드가 활약할 때입니다. 팩토리 메서드는 private 생성자와 변경자의 조합으로 유효한 객체를 생성합니다. 컴포넌트 조합에 쓰는 전통적 팩토리 메서드는 보통 정적 메서드(static method) 형태이기 때문에 인터페이스에 둘 수가 없습니다. 팩토리 클래스를 만들 수도 있지만 그러면 주입해야 할 또 다른 서비스 인스턴스가 생길 뿐입니다. 팩토리 서비스가 가끔 좋은 전략일 수 있지만 팩토리를 생성하려면 이 글에서 다루는 IoC 기술 중 하나를 써야만 합니다.

문자열같이 단순한 매개변수를 가진 생성자도 골치입니다. 변경자 주입에서라면 각 변경자의 이름으로 문자열 매개변수가 무엇에 쓰는 것인지 나타낼 수 있습니다. 생성자는 매개변수의 위치에 의존할 뿐이어서 용도를 알기 어렵습니다.

생성자가 여러 개이고 상속을 했다면 특히 곤란해질 수 있습니다. 모든 것을 초기화를 하려면 자신만의 매개변수를 추가하면서도 부모 클래스의 생성자 하나하나를 호출하는 생성자들을 만들어야 합니다. 자칫하면 생성자가 폭발적으로 많아질 수도 있습니다.

이런 단점이 있어도 전 생성자 주입부터 시작하기 좋아합니다. 그렇지만 지금까지 지적한 문제가 진짜 문제가 되기 시작하면 즉시 변경자 주입으로 바꿀 수 있도록 준비를 합니다.

생성자 주입과 변경자 주입을 비교하는 문제 때문에 의존성 주입 기능이 있는 프레임워크의 제작팀 사이에서 많은 논쟁이 있었습니다. 그렇지만, 이들 프레임워크를 만드는 대부분의 사람은 비록 어느 한 쪽을 선호한다 하더라도 두 가지 방식을 모두 지원하는 것이 중요하다는 것을 이해하는 듯합니다.

코드 대 설정 파일

서비스들을 엮을 때 설정 파일을 쓸 것인지 아니면 코드로 API를 써서 할 것인지 선택하는 문제는 개별적이면서도 종종 혼용할 수도 있는 문제입니다. 여러 곳에 배포될 것으로 예상하는 애플리케이션 대부분은 별도 설정 파일 쪽이 대체로 타당합니다. 대부분의 경우 XML 파일일 것이고 XML은 이런 일에 잘 맞습니다. 하지만 프로그램 코드로 서비스를 조립하기가 더 쉬울 때도 있습니다. 한가지 사례로 배포 환경이 비슷비슷한 단순한 응용프로그램을 들 수 있습니다. 이 경우 분리된 XML 파일보다 코드가 조금 더 깨끗할 수 있습니다.

조건에 따라 분기하는 단계가 포함되어 조합이 매우 복잡한 경우에는 차이가 분명합니다. 한번 프로그래밍 언어에 친숙해지기 시작하면 XML은 서서히 쓰지 않을 것이고 진짜 언어를 쓰는 것이 더 나을 겁니다. 프로그래밍 언어는 깨끗한 프로그램을 짜는 데 필요한 모든 문법을 가지고 있습니다. 코드로 조립한다면 빌더 클래스를 만들 것입니다. 독특한 여러 구축 계획이 있다면 빌더 클래스들을 여러 개 마련하고 간단한 파일을 써서 어떤 것을 선택할지 설정할 수 있습니다.

종종 사람들이 필요 이상으로 설정 파일을 정의하는데 열심인 것으로 보입니다. 프로그래밍 언어는 보통 직접적이고 강력한 설정 메커니즘을 만듭니다. 최신 언어들은 대규모 시스템의 일부로 조립해 쓸 수 있는 작은 조립기를 쉽게 컴파일할 수 있습니다. 컴파일하는 게 문제라면 같은 작업을 수행할 수 있는 스크립트 언어도 있습니다.

프로그래머가 아닌 사람이 수정할 수 있어야 하기 때문에 설정에 프로그래밍 언어를 쓰면 안 된다는 말을 듣곤 합니다. 그렇지만 이런 경우가 얼마나 될까요? 사람들이 진짜 복잡한 서버 응용 프로그램의 트렌젝션 격리 수준(transaction isolation level)을 비 프로그래머가 조정하기 원할까요? 프로그래밍 언어가 아닌 설정 파일을 써야만 단순하게 작업할 수 있는 걸까요? 설정 파일이 복잡해지면  적당한 프로그래밍 언어를 사용해볼 것을 생각하기 시작해야 할 시점입니다.

지금 이 순간 자바 세상에는 설정 파일 사이에 불협화음이 있습니다. 컴포넌트마다 다른 것들과 다른 자신만의 고유 설정파일을 가지고 있습니다. 만약 이런 컴포넌트 수십 개를 가지고 있다면 설정파일 수십 개를 서로 맞추느라 금방 질리고 말 것입니다.

여기서 저는 항상 프로그래밍 인터페이스를 써서 쉽게 모든 설정을 할 수 있도록 할 것을 제안합니다. 그러고 나면 별도 설정 파일을 다루는 일은 선택사항이 됩니다. 프로그래밍 인터페이스를 써서 설정 파일을 다루도록 하는 건 쉽습니다. 컴포넌트를 작성한다면 프로그래밍 인터페이스를 쓸지, 정해진 형태의 설정 파일을 쓸지, 자작 설정 양식을 만들고 프로그래밍 인터페이스에 이것을 붙일지 여부를 컴포넌트의 사용자에게 남겨두십시오.

사용과 설정의 분리

서비스를 사용하는 곳에서 설정을 분리하도록 하는 것이 그 무엇보다 중요합니다. 실제로 이는 구현에서 인터페이스를 분리하라는 기본적인 설계 원칙에 들어맞습니다. 이 원칙은 객체지향 프로그래밍에서 조건문으로 어떤 클래스를 생성할지 결정할 때에 볼 수 있습니다. 이렇게 생성을 한 후에는 중복된 조건문으로 조건을 평가하는 일이 다형성으로 대체됩니다.  

이런 분리가 단일 코드 베이스에서 유용하다면 서비스나 컴포넌트 같은 외래 요소를 쓸 때는 특히 절대적입니다. 먼저 특정 배포 환경에서 어떤 구현 클래스를 쓸지 선택하는 것을 나중으로 미루고 싶은지 질문해야 합니다. 만약 그렇다면 플러그인의 어떤 구현물을 사용해야 합니다. 일단 플러그인을 쓴다면 이 플러그인들을 조립하는 작업은 반드시 응용 프로그램의 다른 부분들과 분리해야 합니다. 이렇게 해야 다른 배포 환경에 맞는 설정을 쉽게 교체할 수 있습니다. 어떻게 이것을 하느냐는 것은 부차적인 문제입니다. 설정 메커니즘은 서비스 위치탐색기를 설정하는 것일 수도 있고 직접 객체를 설정하도록 주입을 사용하는 것일 수도 있습니다.

그 외 주제들

이 글에서는 의존성 주입과 서비스 위치탐색기로 서비스를 설정하는 기본 문제에 집중했습니다. 여전히 주목해서 다룰만한 주제가 더 있지만 아직 파고들 기회가 없었습니다. 특히 생애 주기 행태(life-cycle behavior)와 관련된 토론 주제가 있습니다. 어떤 컴포넌트는 (멈춤이나 시작 같은) 고유의 생애 주기 이벤트를 가지고 있습니다. 경량 컨테이너드에서 관점 지향을 사용하는 것도 점점 많은 관심을 받는 또 다른 토론 주제입니다. 비록 이 글에서는 관점 지향을 다루지 않았지만 이에 대해 내용을 추가하거나 따로 쓰거나 할 생각입니다.

경량 컨테이너 관련 웹 사이트를 찾아보면 지금까지 다룬 주제에 대해서는 더 많이 찾을 수 있을 것입니다. 피코 컨테이너와 스프링 웹 사이트를 방문하면 이들 주제와 관련된 더 많은 논의와 새로운 주제의 시작을 접할 수 있습니다.

마치면서...

요즘 쇄도하는 경량 컨테이너는 모두 서비스를 조립하는 방법과 관련하여 의존성 주입이라는 공통 패턴에 근거를 두고 있습니다. 의존성 주입은 서비스 위치탐색기의 유용한 대안입니다. 응용 클래스를 만들 때 이 둘은 거의 같습니다. 그렇지만 서비스 위치탐색기가 더 직접적이기 때문에 약간은 앞선다고 생각합니다. 그렇지만 여러 응용 프로그램에서 쓰이는 클래스를 만든다면 의존성 주입을 선택하는 것이 더 낫습니다.

서비스 위치탐색기와 의존성 주입 간의 선택은 응용 프로그램 안에서 서비스를 사용하는 부분과 서비스를 설정하는 부분을 분리한다는 원칙보다 중요하지는 않습니다.
[번역] 제어 역전 컨테이너와 의존성 주입 패턴 [1][2][3][4]

by 박성철 | 2009/10/31 16:38 | 프로그래밍 이야기 | 트랙백(1) | 덧글(0)

◀ 이전 페이지다음 페이지 ▶