- Front Servlet
웹 브라우저의 모든 요청을 받아 분석한 후, 이를 알맞은 컨트롤러로 전달하는 창구 역할을 수행한다. Spring MVC의DispatcherServlet이 여기에 해당된다.- Controller
Spring의@Controller어노테이션이 붙은 클래스에 해당된다.
컨트롤러는 실제 웹 브라우저가 요청한 기능을 실행하고, 응답 결과를 생성하는데 필요한 Model을 만든 다음, 응답 결과를 생성할 View를 선택하여 응답 결과를 전달한다. 하지만 컨트롤러는 어플리케이션이 제공하는 기능과 사용자 요청을 매개하는 역할만 수행한다.- Service
서비스(Service)는 핵심 기능의 로직을 구현한 클래스로, 컨트롤러로부터 사용자의 요청 처리 역할을 위임받아 실질적인 요청 처리 작업을 수행한다.- DAO(Data Access Object)
DB와 웹 어플리케이션 간 데이터 이동을 담당하는 객체로, 이를 통해 어플리케이션은 DB의 데이터를 변경하거나 조회할 수 있다.
Service가 제공하는 핵심 기능은 그 기능을 수행하는 환경에 관계없이 항상 동일한 로직을 수행하며, 이러한 로직은 1개 혹은 여러 개의 단계를 거친다.
만약 서비스의 기능을 실행하던 중 그 중간 단계에서 오류가 발생한다면 현재까지의 변경 사항을 기능 수행 이전으로 되돌려야 하고, 오직 모든 단계를 성공적으로 진행했을 때만 서비스의 기능 수행에 의한 변경사항이 반영되어야 한다. 이로 인해 서비스 메서드는 @Transactional 어노테이션을 이용해서 트랜잭션 범위에서 실행하게 된다.
1개의 서비스 클래스를 구현할 때, 서비스 클래스 1개당 메서드 1개를 구현하거나 동일한 데이터를 사용하는 여러 개의 메서드를 1개의 서비스 클래스에 모아서 구현하는 방식을 취할 수 있다.
첫번째 방법을 채택할 경우, 코드 길이를 일정 수준 이내로 유지할 수 있어 코드가 간결해지므로 기능의 변경과 확장이 쉽다는 장점이 있다.
서비스 메서드의 실행 결과와 그에 관한 처리는 다음의 2가지로 구분할 수 있다.
- 리턴값을 이용한 정상 결과
: 서비스 메서드의 리턴 타입으로 지정한 객체를 반환하거나 Exception 없이 메서드의 실행을 종료한다.- Exception을 이용한 비정상 결과
: Exception이 발생한 경우, 서비스 메서드의 실행에 실패한 것으로 간주하여 발생한 Exception에 관한 메서드를 실행한다.
일반적인 경우, 컨트롤러는 서비스 영역을 거쳐야 DAO에 접근할 수 있다. 이를 위해 서비스 클래스에 별도의 로직 수행 없이 DAO의 메서드만 호출하는 서비스 메서드를 구현할 수도 있다. 한편 컨트롤러에서 곧바로 데이터 접근 계층의 DAO를 사용하는 방식도 활용할 수 있다. 이 때는 컨트롤러 클래스의 메서드에서 직접 DAO의 메서드를 호출하게 된다.
제공 기능 수의 증가와 로직의 추가로 인해 웹 어플리케이션이 복잡해지면 컨트롤러-서비스-DAO 구조의 코드 역시 복잡해진다. 이로 인해 중요한 로직을 구현한 코드가 분산되어 특정 기능의 분석이 어려워지거나, 쿼리 또는 코드에서의 중복이 늘어나면서 웹 어플리케이션의 유지보수가 어려워진다는 문제가 발생한다.
도메인 주도 설계는 UI-서비스-도메인-인프라의 4가지 영역으로 어플리케이션을 구성한다. 이 중 UI는 컨트롤러에, 인프라는 DAO 영역에 대응되며, 서비스 영역이 아닌 도메인 영역에 주요 도메인 모델과 업무 로직이 위치하게 된다. 또한 도메인 영역에서는 정해진 패턴에 따라 모델을 구현하기 때문에 업무가 복잡해져도 복잡도를 일정한 수준으로 유지할 수 있다.