달력

5

« 2024/5 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Domain 객체에 Repository를 inject해야 하나 ?

먼저 DAO와 Repository의 차이를 알아보자.

presentation <--> service <--> domain <--> data access

이런 관계에서 DAO는 data access layer에 속한다.
DAO는 CRUD 연산을 encapsulate하는데, ORM이 없는 상황에서는 RDB와 OO Technique 간의 impedence를 처리한다.

Eric Evans는 "객체는 더 이상 <자신의 의미나 상호작용에서의 역할 지원>과 관련된 코드가 없을 때 까지 정제되어야 한다"라고 한다.

@Configurable("organization")
class Organization {
// implementation needs to be injected
private EmployeeDAO employeeDao;
// ..
// ..
public List<Employee> getOutstationEmployees() {
List<Employee> emps = employeeDao.getEmployeesByAddress(corporateOffice);
List<Employee> allEmps = employeeDao.getAllEmployees();
return CollectionUtils.minus(allEmps, emps);
}
// ..
}

위의 코드에서 employeeDao를 통해 데이터를 준비하는 것은 Oraganization의 역할이 아니다. 이런 상세한 로직은 data access layer에 가까운 다른 추상화에 속해야 한다.

가장 이상적인 추상화 수준은 EmployeeRepository이다.

Repository의 역할은
- data accessors(Dao)와 상호작용을 추상화하는 분리된 레이어
- 도메인 모델에 "business interface"를 제공한다.

이런 경우 Employee aggregate(Employee 클래스는 Employee aggregate를 구성하는 Adress, Office 등과 같은 클래스와 연관을 갖을 수 있다)에 대해 하나의 Repository를 사용한다.

Aggregate의 리파지토리는 도메인 언어로 도메인 모델에게 data access 서비스를 제공하기 하기 위해 필요한 모든 Dao들과 상호작용하는 책임을 갖는다. 도메인 모델은 리파지토리 덕에 데이터 레이어로부터의 결과를 수집하는 것과 같은 상세 구현과 분리/유지될 수 있게된다.

public interface EmployeeRepository {
List<Employee> getOutstationEmployees(Address address);
// .. other business contracts
}

public class EmployeeRepositoryImpl implements EmployeeRepository {

private EmployeeDAO employeeDao;

public List<Employee> getOutstationEmployees(Address address) {
List<Employee> emps = employeeDao.getEmployeesByAddress(corporateOffice);
List<Employee> allEmps = employeeDao.getAllEmployees();
return CollectionUtils.minus(allEmps, emps);
}
}

리파지토리와 Dao의 주요 차이점은 아래와 같다.

  • Dao는 리파지토리 하위의 추상화 단계로써 데이터베이스로부터의 데이터를 읽어오기 위한 배관 코드(plumbing code)를 가질 수 있다. 데이터베이스 테이블 마다 하나의 Dao를 사용하고, 하나의 도메인 타입이나 aggregate에 대해 하나의 리파지토리를 사용한다.
  • 리파지토리가 제공하는 인터페이스/계약(contract)은 순수 "도메인 중심적"이고 같은 도메인 언어를 사용한다.
리파지토리는 도메인 구조물이다.

리파지토리는 도메인의 ubiquitous 언어를 사용한다. 그래서 리파지토리가 제공하는 인터페이스는 도메인 모델에 속한다. 하지만 리파지토리의 구현은 테이블 종속적인 메소드나 Dao를 사용하기 위한 배관코드를 갖는다. 그래서 순수 도메인 모델은 리파지토리 인터페이스에만 종속적이어야 한다. 마틴 파울러는 이를 위해 "Separated Interface" 패턴(http://www.martinfowler.com/eaaCatalog/separatedInterface.html - 리파지토리 인터페이스는 도메인 패키지 정의하고 구현은 다른 패키지. 클라이언트는 상세 구현을 완전히 몰라도 된다. Separated Interface는 Gateway를 위한 훌룡한 plug point가 된다.)을 추천했다.

도메인 모델에 리파지토리를 Inject하는 것은 아래와 같이 단순하다.

@Configurable("organization")
class Organization {
private String name;
private Address corporateOffice;
// .. other members

// implementation needs to be injected
private EmployeeRepository employeeRepo;

// ..
// ..

public List<Employee> getOutstationEmployees() {
return employeeRepo.getOutstationEmployees(corporateOffice);
}
// ..
}

하이버네이트 같은 ORM을 사용하게 되면 transparent persistence로 인해 Dao가 불필요해진다.

이러한 방식으로 구현된 어플리케이션을 수행하기 위해서는 아래와 같이 jvm에 옵션을 추가해야 한다.

-javaagent:/Users/msbaek/.m2/repository/org/springframework/spring-agent/2.5.2/spring-agent-2.5.2.jar

eclipse에서 아래 화면과 같이 설정하면 테스트 수행시마다 설정을 할 필요가 없어진다.

Javaagent-Options

질의응답
Q1. 리파지토리 대신 Dao에서 Aggregate를 처리하면 되지않나 ?
A1. Dao는 높은 재사용성을 제공하는 fine grained 메소드를 제공. 리파지토리는 도메인 구조물로써 도메인 언어를 사용하고 Aggregation에 대한 coarse grained 메소드를 제공. Dao는 "outstation(출장소)"라는 도메인 언어의 해석을 포함면 안된다.

참고자료

  • http://debasishg.blogspot.com/2007/02/domain-driven-design-inject.html
:
Posted by codetemplate