이번글은 www.javajigi.net에서 진행중인 스터디에 참여하면서 발표를 하기 위해 준비한 자료이다. 스터디의 주제는 오픈소스 프레임워크 또는 툴의 프로젝트 적용 방안 등에 대한 주제로 진행되고 있으며 현재는 Hibernate에 대해 스터디를 진행하고 있다.
(자바지기 스터디)

1. ORM을 사용하는 이유
2. 도메인 모델
3. 도메인 모델 vs. Transaction Script
4. 도메인 모델 사례

1. ORM을 사용하는 이유
프레임워크나 기타 툴을 바라보는 관점에 있어 그것을 잘 활용하는 것도 중요하지만 왜 그런 툴들이 나타날 수 밖에 없었던가 하는 상황을 이해하는 것이 더욱 중요하다고 생각한다. 최근 개발자 커뮤니티 게시판의 질문을 보면 프레임워크의 선택에 대한 질문이 많이 나오고 있는데 이것도 기본을 이해하면 자신의 프로젝트 환경에 맞는 프레임워크를 선택할 수 있다.
과거 EJB를 처음 도입하던 시기에 Session Bean 만 사용하는 것이 좋은지 Entity Bean을 사용해야 하는지, 혹은 BMP(Bean Managed Persistency), CMP(Container Managed Persistency) 에 대한 논쟁이 많았는데, 이것은 EJB를 제대로 이해하지 못한 상태에서의 질문이라 할 수 있다.
ORM을 바라볼 때도 이런 관점에서 봐야 한다. ORM 자체보다는 각 프로젝트의 아키텍처 상에서 ORM이 어디에 위치하는지? 왜 프로젝트에서 ORM을 사용해야 하는지? 등을 먼저 고민해봐야 한다.
그럼 왜 프로젝트에서 ORM을 사용하는 것일까? 일단 두 가지 관점에서 볼 수 있다. 첫 번째는 EJB의 Entity Bean과 같은 역할을 보다 쉽게 수행해주기 때문에 사용하는 경우이다. Entity Bean의 경우 persistency 계층, 즉 데이터베이스로의 객체 로딩, 저장 등을 처리하지만 EJB의 경우 기본적으로 분산환경을 제공해야 하기 때문에 간단한 정보를 관리하기 위해서는 많은 작업과 파일이 필요하기 때문에 개발자들로부터 외면을 받았다. 하지만 ORM 툴을 사용하면 일반 자바 클래스(POJO, Plain Old Java Object)를 이용하여 아주 쉽게 기존의 Entity Bean이 수행하던 Persistency 계층과의 bridge 역할을 처리할 수 있기 때문에 ORM을 이러한 용도로 사용하고 있다.

두 번째는 ORM이 진정한 힘을 발휘하는 부분인데 객체모델로 설계된 내용을 RDBMS로 쉽게 매핑하는 역할에 사용하는 것이다. 얼핏 생각하면 첫 번째 용도와 같아 보이지만 여기서는 데이터베이스와의 관계 보다는 객체모델이 더욱 중요하다고 할 수 있다. 이번 칼럼의 내용도 대부분은 객체 모델(도메인모델)에 초점을 맞추고 있다.
따라서 ORM을 제대로 사용하기 위해서는 구축 대상이 되는 시스템의 모델을 잘 설계하는 것이 과거의 방식에 비해 훨씬 더 중요해졌다고 할 수 있다. ORM에 대한 중요도나 ORM의 사용이 쉽지 않은 것은 아직까지 국내 개발자들이 엔터프라이즈 애플리케이션에서의 객체 모델 설계 경험이나 기술이 부족하기 때문이다. 일반적으로 객체 모델은 객체지향 설계 기법을 사용하여 클래스와 클래스간의 관계로 표현한 것을 객체모델이라고 하는데 최근에는 객체라는 개념을 벗어나서 도메인 모델이라는 용어를 더 많이 사용한다.



2. 도메인 모델
일반적으로 모델이라고 하는 것은 현실 세계의 사물을 적절하게 추상화 또는 일반화 작업을 거쳐 관심 있는 부분만 표현한 것이라고 할 수 있다. 이러한 모델을 이용하여 우리는 실제 사물을 보지 않고도 사물에 대한 여러 가지 정보를 얻을 수 있기 때문에 모델은 많은 산업 분야 활용되고 있다. 대표적인 분야가 건축 분야이다. 건축물을 만들기 전에 건축 설계자들은 필요에 따라 다양한 모델을 만드는데 “조감도”, “모델 하우스”, “설계도” 등이 있다.
모델의 정의를 이용하여 “도메인 모델”이라는 용어를 다시 정의하면 개발 대상이 되는 업무를 파악하여 적절한 추상화 과정(모델링 과정)을 거쳐 눈에 보일 수 있는 형태(산출물)로 만들어 내는 것이라 할 수 있다.
도메인 모델은 비즈니스 영역에서 사용되는 객체를 판별하고, 객체가 제공해야 하는 기능을 추출하며, 각 객체간의 관계를 정립하는 과정을 거친다.
소프트웨어의 개발에서 모델링의 결과로는 모델 하우스 등과 같이 완성된 제품의 축소 본을 나타나는 것이 아니라 단순한 설계도인 문서 형태로만 나타나게 된다(소프트웨어는 완성된 후에도 실제 사물로 존재하는 것이 아니기 때문). 물론 좀 더 나아가 파일럿 프로젝트 형태로 실제 시스템의 특정 부분을 구축할 수도 있지만 이것을 보고 일반적인 소프트웨어 모델링의 결과물이라고 말하지는 않는다.
소프트웨어 모델에서 대표적인 모델로 데이터 모델이 있는데 도메인에서 관리하는 정보(데이터)를 파악하여 다이어그램으로 나타낸 ERD(Entity Relation Diagram)가 있다. 대부분의 개발자들은 ERD에 아주 익숙할 것이다.
모델이 현실 세계를 추상화하여 표현한 것이라고 했는데 시스템 대상이 되는 기업의 업무에는 데이터만 있는 것이 아니라 데이터를 이용하는 프로세스가 반드시 존재하게 된다. 데이터만 모델링 하는 경우라면 프로세스를 표현하지 못하기 때문에 기존의 개발 방식에서는 프로세스 모델링이라고 하여 데이터 모델링과는 별도로 프로세스에 대한 모델링을 하였다. 데이터와 프로세스에 대해 별도로 모델링을 하는 경우에는 모델링의 결과로 나타난 산출물을 이용하여 모델을 검증하거나 실제 개발을 진행하는데 있어 프로세스와 데이터를 연결시켜주는 부분에서 많은 혼동이 발생할 수 있다.
모델은 근본적으로 실제 현상이나 사물을 단순화 시킨 것이다. 실물과 정확히 똑같은 모델을 만들었다고 하면 그것은 이미 모델이 아니다. 또 한가지, 만들어진 모델이 잘된 것인지 아닌지 판별하기가 어렵다. 모델에는 모델링 작업을 수행한 모델러(Modeler)의 가치관이 반영되기 때문에 객관적으로 이를 평가하기란 결코 쉬운 일이 아니다. 다수의 사람들에게 자동차의 모형을 요구하면, 그들은 각각 서로 다른 모형을 만들어낼 것이다. 자동차의 외관에 관심이 많은 사람은 디자인과 색상 등을 정확하게 묘사하기 쉽고, 내부 구조에 관심이 많은 사람은 내부 구성도를 그려낼 수도 있다. 그렇지만, 이들 중 어떤 것이 잘된 것이라고 평가하는 일은 쉬운 것이 아니다.
모델링을 하는데 있어서 위의 두 가지 특성 즉, 태생적인 단편성이나 주관적 특성을 잘 이해하고 있어야 한다. 복잡한 소프트웨어를 개발하는 프로젝트일수록 모델의 단순함을 극복하기 위해 다양한 뷰를 제공하는 다수의 모델이 필요할 수 있다. 또한, 해당 소프트웨어의 사용자가 다수이고, 개발자 역시 많다고 하면, 참여자의 필요에 맞는 특정 모델이 요구된다. 따라서, 많은 이해 관계자가 결부된 프로젝트의 경우에는 다양한 관점을 반영한 모델이 제시되어야 하는 것이다.

도메인 모델의 장점은 역시 객체지향에 기반한 재사용성, 확장성, 그리고 유지 보수의 편리함에 있다. 일단 도메인 모델을 구축하고 나면 (필요에 따라 약간의 수정이 필요하겠지만) 언제든지 재사용할 수 있다. 예를 들어, 한번 커뮤니티(클럽, 게시판 등) 도메인 모델을 구축하고 나면 비슷한 커뮤니티 시스템에 대해서 도메인 모델을 재사용할 수 있게 된다. 또한, 상속/인터페이스, 더 나아가 컴포넌트 개념을 바탕으로 도메인 모델을 개발하게 되면 무한한 확장성을 갖게 된다.

도메인 모델의 단점은 하나의 도메인 모델을 구축하는 데 많은 노력이 필요하다는 것이다. 객체를 판별해내야 하고 객체들 간의 관계를 정립해야 하며, 더 나아가 객체와 데이터베이스 사이의 매핑에 대해서 고민해야 하기 때문이다. 이는 이론과 경험을 함께 겸비하지 않으면 쉽게 풀 수 없는 문제이기 때문에, 도메인 모델에 능숙한 개발자가 팀에 없을 경우 도메인 모델을 구축하는 것 자체가 힘들어질 수도 있다.

최근에 이런 도메인 모델에 대한 이슈가 자주 등장하는 것은 필자의 경우 두 가지로 생각하고 있다. 첫 번째는 기업 업무를 지원하는 애플리케이션의 복잡성의 증가이고, 두 번째는 디자인패턴, 컴포넌트 등 객체지향 기술의 일반화와 ORM 도구와 같은 안정적인 프레임워크의 출현이다.
엔터프라이즈 애플리케이션의 복잡성의 증가는 최근 기업의 대부분의 업무가 애플리케이션상에서 운영되는 경우가 많다. 이것은 과거에 비해 소프트웨어가 처리해야 되는 업무의 양과 복잡도가 그만큼 증가했다는 것이다. 소프트웨어의 복잡도는 증가 했는데 이를 만드는 기법, 툴 등이 과거와 같다면 비용증가, 납기지연과 소프트웨어 위기와 같은 상황이 초래할 것이다. 도메인 모델은 이러한 소프트웨어의 복잡도를 해결하기에 아주 적합한 기술이라 할 수 있습니다. 그리고 이와 같은 객체지향 기술을 기본으로 하여 Component Based, Service Oriented와 같은 더욱 진보된 개념을 쉽게 적용할 수 있다.
객체지향 관련 기술이 과거에도 없던 것이 아닌 것 임에도 불구하고 최근 이렇게 많이 이슈가 되고 있는 이유의 두 번째는 객체지향 기술의 일반화이다. 객체지향이 시스템을 유연하게 해주고 확장성을 좋게 해준다고 주장하지만, 잘못된 클래스의 상속은 유연성을 더 떨어뜨려 유지보수를 더욱 어렵게 만든다. 하지만 최근 몇 년 사이에 디자인 패턴을 중심으로 하여 리팩토링, EJB, 자바와 같은 객체지향 언어, 컴포넌트 등과 같이 개발자들이 인식하지 못하는 사이에 일반화가 많이 되었다고 할 수 있다. 여기에 Struts 등과 같은 프레임워크를 사용한 엔터프라이즈 애플리케이션이 일반화 되고 있는 상황에서 Hibernate와 같은 ORM 오픈소스 프레임워크가 출현하면서 이런 변화에 가속도를 붙여다 라고 할 수 있다.



3. 도메인 모델 vs. Transaction Script
마틴 파울러는 Enterprise Application Architecture Pattern이라는 책에서 시스템의 기능구현 방법을 도메인 모델 방식과 Transaction Script 방식으로 분류하고 있다.
도메인 모델은 앞에서 설명했듯이 객체모델을 이용하여 객체들간의 관계를 이용하여 기능 요구사항을 수행하는 방식이라 할 수 있다. 그리고 대부분의 프로젝트에서 사용하는 데이터의 CRUD 처리에 의해 기능을 구현하는 방식을 Transaction Script 방식이라고 한다. 물론 이런 분류는 마틴 파울러라는 개인이 주장하는 것이지만 객체지향을 엔터프라이즈 애플리케이션에 적용하는 분야에서의 마틴파울러의 인지도를 보았을 때 개인이 사용하는 용어로만 치부할 수는 없다.
다음은 도메인 모델을 이용한 방식과 Transaction Script를 이용한 처리의 예제이다.

Transaction Script 방식

EmpService.java

Emp emp = loadEmp("홍길동");
Dept dept = loadDept("총무과");
if(emp.getDeptName().equals(dept.getDeptName()))
{
System.out.println("총무과 소속)";
}


도메인 모델 방식

EmpService.java

Emp emp = loadEmp("홍길동");
Dept dept = loadDept("총무과");

if(emp.isBelongTo(dept))
{
System.out.println("총무과 소속");
}


이 예제는 객체지향의 가장 강점이라고 할 수 있는 다형성 등은 사용하지 않고 있지만 "객체에 일을 시킨다.", "객체는 책임을 가진다." 등과 같은 객체지향적인 개념을 포함한 코드라고 할 수 있다.
두 코드를 비교 했을 때 차이점은 거의 없는 것 같다. 하지만 사원이 특정 부서에 소속되었는지에 대한 기능 명세가 변경되었을 때 Transaction Script 방식에서는 emp.getDeptName().equals(dept.getDeptName())게 구현된 많은 부분을 찾아서 수정해야 하지만 객체모델을 사용하는 경우에는 Emp의 isBelongTo() 메소드의 내부 구현만 변경하면 된다. 물론 Transaction Script 방식에서도 공통 함수로 도출하여 사용할 수 있지만, 설계 단계가 아닌 구현단계의 이슈이기 때문에 객체모델과 비교하여 짜임새 있게 구성할 수 없다.

ORM을 사용해야 하는 이유로부터 출발하여 도메인 모델까지 설명하였다. 이제 다시 ORM을 왜 사용해야 하는가에 대한 질문은 "당연히 도메인 모델을 이용하여 복잡한 비즈니스 로직을 가지고 있는 엔터프라이즈 애플리케이션을 구현하는데 있어 객체의 저장과 관련된 계층을 transparent하고, 쉽게 구현하기 위해 사용한다." 라는 답을 도출할 수 있다.



4. 도메인 모델 사례
이번 장에서는 설계된 도메인 모델의 구현에 대해서 살펴보도록 하자. 도메인 모델의 설계는 주로 클래스 다이어그램으로 표현된다. 클래스 다이어그램에서 표현된 클래스의 속성과 메소드, 클래스간의 관계는 구현 시 그대로 적용되기 때문에 기존의 Transaction script 방식에 비해 설계 -> 구현간의 gap을 많이 줄이는 효과도 있다. Transaction script 방식에서는 설계가 주로 필요한 정보(Value Object)와 Service 계층의 메소드 call 수준이라면 도메인 모델에서의 설계는 요구사항을 쉽게 구현하는 클래스와의 관계를 설계하는 것이라 할 수 있기 때문이다.
이제 사례를 통해 도메인 모델을 만들어 보기로 하자. 여기서 만들 사례는 대부분의 개발자들이 잘 알고 있는 사용자 권한 관리 기능이다. 다음은 사용자 요구사항이다.

사용자의 권한에 따라 사용 가능한 메뉴만 보여야 하며 사용자의 등급은 필요에 따라 추가되거나 삭제될 수 있으며, 사용자의 등급 변경에 따른 시스템의 권한은 시스템이 운영중인 상태에서 적용되어야 한다.


일반적으로 프로젝트에서는 고객으로부터는 이 정도의 요구사항도 나오지 않는다. 이것은 어쩌면 개발팀 자체의 요구사항일 수 있다. 이런 요구사항을 기본으로 하여 필자는 다음과 같은 사용자 권한 관리 서브 모듈을 설계하였다.



이렇게 최초 작성된 모델을 가지고 사용자 요구사항을 만족하는지 시뮬레이션 해볼 수 있다. 위의 설계 대로라면 "홍길동" 이라는 사용자가 인사담당자에서 영업담당자로 변경되었을 경우에는 홍길동이라는 사원을 검색하여 "홍길동" 사용자에서 인사업무 관련 프로그램의 "Menu", "Program"을 삭제하고 다시 영업담당자가 사용하는 항목을 추가하는 작업을 해야 한다. 이런 구현은 사용자의 편의를 생각하지 않은 구현이기 때문에 좀 더 다른 방식의 모델이 필요하다. 좀 더 고민하여 다음과 같은 모습을 만들었다.



User와 Program 가운데 Role이라는 객체를 더 도출하여 사용자는 시스템내에서 역할을 가지고 역할은 역할이 수행 가능한 항목들을 가지고 있는 모습이다. 이렇게 설계를 하면 앞의 문제는 자연스럽게 해결된다. "홍길동" 사용자를 검색하여 "인사담당자" Role을 삭제하고 "영업담당자" Role을 추가하기만 하면 되기 때문이다.
여기까지는 지금까지 우리에게 익숙한 엔티티 모델(Entity Model)과 별로 차이점이 없어 보인다. 물론 User – Role 관계에서 N:M 관계가 표현되어 있지만 말이다. 위의 모델에 대해 다음과 같은 요구사항을 적용시켜 보자.

특정 화면의 경우 사용자 권한 따라 특정 버튼이 보여지거나 감춰지거나 해야 한다. 물론 버튼의 visibility 뿐만 아니라 버튼에 연결되어 있는 프로그램까지 visibility와 동일하게 적용되어야 한다.

위의 요구사항을 만족시키기 위해 다음과 같이 모델을 변경하는 것이 일반적인 ER 모델에서의 방법이다. 물론 객체 모델에서도 이렇게 할 수 있다.



이런 모델의 변경은 Role 클래스의 구조를 변경해야 한다. 그리고 다음과 같이 Service 계층에서의 구현에도 if절이 하나더 추가되어야 한다.


AclService.java

public boolean hasRole(User user, String id, String idType) {
if(idType.equals("Program")) {
//Program에 대한 처리
} else if(idType.equals("Menu")) {
//Menu에 대한 처리
} else if(idType.,equals("Button")) {
//Button에 대한 처리
} else {
//idType 오류
}
}


그리고 시스템에서 권한 통제가 필요한 새로온 항목이 추가될 때 마다 Role 클래스를 변경해야 하고 type check를 하는 구현에서 if..else 절이 추가되어야 한다. 이것은 기존 ER 모델을 사용했을 때와 비슷한 상황이라고 할 수 있다. 다음은 완성된 모습의 클래스 다이어그램이다.



시스템에 접근 가능한 모든 항목을 "Resource" 라는 인터페이스 또는 abstract 클래스로 정의하고 Program과 같은 구체화된 항목들은 이를 상속받게 하였다. 그리고 Role은 Resource만 관계를 가지고 있고 Resource의 하위 클래스들과는 관계가 없도록 하였다. 앞의 코드는 다음과 같이 변경된다.


AclService.java

public boolean hasRole(User user, String id) {
Resource resource = findResource(id);
return user.hasRole(resource);
}



User.java

public boolean hasRole(User user, String id) {
Resource resource = findResource(id);
return user.hasRole(resource);
}


이런 모델에서 "Document"라는 새로운 권한 관리 항목을 추가시키는 경우 Document 클래스만 생성하기만 하면 된다. AclService의 hasRole(), User 클래스의 hasRole() 메소드의 구현은 변경할 필요가 없다. 이것이 도메인 모델을 사용하는 이유이다.



* 참고문서
- Enterprise Application Architecture Pattern
- 도메인모델을 이용한 J2EE(POJO) 컴포넌트 만들기
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 김형준


Trackback URL : http://www.jaso.co.kr/trackback/60

Comments List

  1. 짱가 2006/03/20 02:25 # M/D Reply Permalink

    형.. 역시...
    명쾌한 글..
    잘 읽었습니다.
    도메인 모델에 관해서 형에게 많은 것을 물어보고 습득해야 할것인뎅.. ^^

Leave a comment
« Previous : 1 : ... 345 : 346 : 347 : 348 : 349 : 350 : 351 : 352 : 353 : ... 388 : Next »