banner

banner

2. 프로젝트 구조

프로젝트
2024.09.04. by   sanam

프로젝트 구조

해당 프로젝트는 controller -> service -> repository(이하 기존 구조) 로 이어지는 일차원적인 구조를 따르지 않았습니다. 해당 구조가 나쁜건 아니지만 지난 몇 개월간 학습하며 해당 구조에 단점이 보였습니다.

기존 구조의 문제

서비스 레이어

문제점을 나열하기 전에 우선 서비스 레이어의 역할이 무엇인지에 대해 생각해보겠습니다. 서비스 레이어은 흔히 도메인 서비스 로직을 담고 있어야한다고 합니다.

기존 구조에서 서비스 레이어는 아래의 역할을 하고 있습니다.(이건 제가 이렇게 구현했기 때문에 다른 분께는 해당되지 않을 수 있습니다.)

  1. 요청(request dto) 알맞은 형태로 변환하고
  2. 도메인 로직에 따른 valid 를 검증하고
  3. repository 에서 데이터를 불러오고
  4. 액션을 수행하고
  5. 데이터를 변환(response dto)해서 반환한다.

1~5 의 전부가 비즈니스 로직은 아닙니다. 기능을 동작시키기 위한 코드의 나열일 뿐입니다. 여기서 비즈니스 로직은 2번 밖에 없습니다.

따라서, 서비스 레이어에서는 비즈니스 로직과 기능을 동작시키기 위한 코드를 분리시켜야 할 필요가 있어보입니다.

컨트롤러 레이어

백엔드 개발자는 서비스를 만든다.

하나의 서비스는 여러 기능의 집합체다. 이 여러 기능 하나하나를 usecase 라고 하자.

따라서 백엔드 개발자는 클라이언트에게 usecase 를 제공해야 한다. 기존 구조를 생각해보자. 기존 구조에서는 컨트롤러의 핸들러가 하나의 기능을 제공한다.

만약 하나의 기능을 컨트롤러가 아닌 다른 곳에서 사용해야 하는 경우를 생각해보자.

예를 들면, 어드민이 캐싱을 초기화 할 수 있도록 만들어 놓은 api 가 있다. 서비스가 고도화됨에 따라 하루에 한 번 이 캐싱 초기화가 스케줄러를 통해 수행되어야한다고 생각해보자.

현재의 구조에서 스케줄러가 캐싱을 초기화하기 위해서는 restTemplate 등을 통해 우리의 서버에 요청을 하는 수 밖에 없다. 왜냐면 핸들러가 하나의 기능을 담당하기 때문이다.

DDD 와 Layered Architecture

DDD 는 너무나 유명한 주제라 설명을 생략하겠습니다.

저는 위에서 언급한 문제 때문에 꽤나 오래 골머리를 앓았습니다. 이 구조에 대한 문제를 해결해 준건 도메인 주도 설계 철저 입문 이라는 책입니다. 책에서는 DDD 라는 개발론에 대해 자세히 설명하고 마지막에는 이 개발론을 적용할 수 있는 여러 구조를 소개해줍니다. 그 부분에서 4계층 구조의 Layered Architecture 를 발견했고 그동안 가졌던 모든 문제를 해결할 수 있겠다라고 생각했습니다. (기존 구조도 사실 Layered Architecture 입니다. 다만 3계층으로 간략화 된 상태일 뿐입니다.)

자세한 구조는 아래와 같습니다.

각 계층의 역할에 대해 알아보겠습니다.

1. Presentation Layer

presentation layer 는 크게 특별한 건 없다. Application Layer 의 클라이언트가 되는 부분을 정의한다. 아마 web controller 가 대부분일듯.

2. Application Layer

어플리케이션 레이어는 클라이언트에게 기능 을 제공합니다. 즉, 위에서 언급한 usecase 를 제공합니다.

하나의 기능으로 정의 된 모든 것들은 이 application layer 에 정의됩니다. 보통 DDD 에서는 usecase 를 application service 라고 지칭합니다. 그런데 service 는 이후 Domain 계층에서도 등장하므로 저는 usecase 라고 지칭하겠습니다.

3. Domain Layer

도메인 계층은 비즈니스 로직을 구현합니다. 비즈니스 로직의 조합으로 하나의 기능은 usecase가 완성됩니다. 비즈니스 로직은 크게 두 형태로 존재할 수 있습니다.

  1. 도메인 모델
  2. 도메인 서비스

도메인 모델은 말 그대로 모델입니다. 저는 DB 테이블을 객체화 시킨 엔티티를 도메인 모델로 정의했습니다.  해당 모델은 각종 비즈니스 로직을 수행할 메서드가 정의되어 있습니다. update 용 등 다양한 모델이 존재합니다. 아래처럼 될 수 있습니다.

  • Post (DB)
  • PostUpdateCmd (업데이트용 모델)
  • PostSearchCond (검색용)
  • ...

도메인 서비스에는 도메인 모델이 수행하기 어색한 비즈니스 로직을 넣습니다.

마지막으로 repository 의 인터페이스 또한 해당 레이어에 정의합니다. 구현체가 아닌 인터페이스만을 정의합니다. 구현체는 아래의 Infrastructure Layer 에서 구현합니다.

4. Infrastructure Layer

Infrastructure Layer 에서는 구현체 및 설정을 제공합니다.

예를 들면, Repository 를 도메인 계층에서 인터페이스만을 정의하고 해당 레이어에서 구현합니다. Repository 의 구현체에서는 SimpleJpaRepository 뿐만 아니라 QueryDSL 도 같이 사용해서 만들 수 있습니다. 또한 이벤트도 인터페이스를 도메인 레이어에서 정의하고 해당 레이어에서는 이벤트의 구현체를 정의할 수 있습니다.

정리

이렇게 기존 3단계의 구조의 문제점을 살펴보고 이 문제를 해결하기 위한 새로운 구조를 정리해봤습니다. 참고할만한 내용이 많지 않았기 때문에 프로젝트를 진행하면서 개인적으로 생각을 하며 많은 정리를 했습니다.. 이 내용을 이 글에 작성하기는 너무 많기 때문에 언젠가 기회가 되면 정리해보겠습니다.

References

0