계층형 아키텍쳐에 관하여

위승현·2024년 10월 25일

CS

목록 보기
2/6

이 블로그 작성글은 필자가 계층형 아키텍처란 무엇이고 또 각 계층이 실제 코드에서
맡는 역할은 무엇인지 상세히 기록해놓고 싶어 작성하는 글이다.

문제점에 대해서는 다루지 않는다. 그래도 참고할만한 글은 링크를 올려놓았다.

계층형 아키텍처란?

소스코드의 역할과 관심사에 따라 계층으로 그룹화해 분리하는 아키텍처를 의미한다.
그룹화로 분리함에 따라 코드 가독성 / 유지 보수의 용이성 개선의 효과를 얻을 수 있다.
소프트웨어 개발에서 가장 일반적으로 널리 알려져 사용되고 있는 아키텍처이다.

특정 계층의 구성요소가 해당 계층에 관련된 기능만을 수행하고
이로 인해 높은 유지보수성을 가지며 쉬운 테스트를 할 수 있다는 장점이 있다.

계층형 아키텍쳐(이하 레이어 아키텍처)에는 필수로 존재해야 할 레이어나 최소 요구 레이어수는 존재하지 않지만 보통 아래와 같은 3계층 혹은 4계층으로 나누어 진다.


4-Tier Architecture

일반적으로는 4계층으로 이루어진다.

(1) Presentation Layer

사용자와의 요청 및 응답 등 상호작용 처리에 관심사를 둔 계층이다.
프레젠테이션 계층은 도메인이나 데이터베이스와 직접 연결되지 않으며,
주로 사용자 경험에 중점을 둔다.
대표적인 구성요소는 View와 Controller가 있다.

  • 주요 역할: 사용자 입력 및 출력 처리, HTTP 요청 및 응답 처리

(2) Business Layer (Domain Layer)

소프트웨어의 비즈니스/도메인 로직 처리를 주 관심사로 둔다.
다시말해 화면에 데이터를 출력하는 방법이나
데이터를 어디서 어떻게 가져오는지에 대한 내용은 관심이 없다.

Persistence Layer에서 데이터를 가져와서 비즈니스 로직을 수행하고
그 결과를 Presentation Layer로 전달하면 된다.
대표적인 구성요소는 Service와 Domain Model이 있다.

실제로 경우에 따라 Service와 Domain Model을 별개의 계층으로 나누거나
아예 Domain Model을 Layered Architecture와 별개로 분리하는 경우도 있다고 한다.

(1) Domain Layer

  • 소프트웨어가 해결하고자 하는 문제 영역으로서 도메인 처리에 초점을 둔 계층

  • 오직 도메인 처리에만 관심을 두며, 도메인 이외에 외부 인프라와의 통신이나 의존을 지양하는 계층

  • 도메인 레이어는 서비스(어플리케이션) 레이어에 의존하지 않도록 구현하는 것이 좋다.(한 어플리케이션에 의존하면, 다른 어플리케이션에서는 활용할 수 없기 때문이다.)

  • 주요 역할: 비즈니스 규칙 처리, 도메인 객체 관리

  • 예시: 엔티티 클래스, 도메인 서비스

(2) Application Service Layer

  • 서비스 계층 혹은 어플리케이션 계층이라고 불리기도 한다.

  • 도메인 처리를 위해 필요한 제반 작업 처리에 초점을 둔 계층

  • 주요 역할: 비즈니스 로직 흐름 제어, 서비스 간 조율, 트랜잭션 관리

  • 예시: Service 클래스, Facade 패턴


(3) Persistence Layer (Data Access Layer)

데이터베이스에 직접적으로 요청을 전달하는 등 데이터베이스에 접근하는데 관심사를 둔 계층이다. 다시말해 데이터베이스와 매핑되는 객체로서의 엔티티를 영구히 관리하는 계층이라고 할 수 있다. 대표적인 구성요소로는 ORM, Repository, DAO가 있을 수 있다.

  • 주요 역할: 데이터베이스 접근, 영속성 관리

(4) Database Layer

실제 데이터베이스 서버가 운영되는 계층이다.
서비스에서 사용하고 있는 DB가 이 계층에 속할 수 있다.

  • 주요 역할: 데이터의 저장 및 조회, 데이터 관리

  • 예시: MySQL, PostgreSQL, MongoDB


프로젝트 구조를 통한 예시

프로젝트명/
│
├── src/
│ └── main/
│ └── java/
│ └── com/
│ └── example/
│ └── library_management/
│ ├── Main.java # 메인 클래스
│ │
│ ├── presentation/ # 프레젠테이션 계층
│ │ ├── controller/
│ │ │ ├── BookController.java # Book 관련 HTTP 요청 처리
│ │ │ └── MemberController.java # Member 관련 HTTP 요청 처리
│ │ │
│ │ └── view/
│ │ ├── BookPresenter.java # Book 관련 응답 프레젠테이션
│ │ └── MemberPresenter.java # Member 관련 응답 프레젠테이션
│ │
│ ├── application/ # 애플리케이션 계층
│ │ ├── service/
│ │ │ ├── BookService.java # Book 관련 비즈니스 로직
│ │ │ └── MemberService.java # Member 관련 비즈니스 로직
│ │ │
│ │ └── dto/ # Data Transfer Objects
│ │ ├── BookDto.java # Book 관련 데이터 전송 객체
│ │ └── MemberDto.java # Member 관련 데이터 전송 객체
│ │
│ ├── domain/ # 도메인 계층
│ │ ├── model/
│ │ │ ├── Book.java # Book 도메인 객체
│ │ │ └── Member.java # Member 도메인 객체
│ │ │
│ │ └── repository/ # 도메인 관련 인터페이스
│ │ ├── BookRepository.java # Book 관련 영속성 인터페이스
│ │ └── MemberRepository.java # Member 관련 영속성 인터페이스
│ │
│ └── infrastructure/ # 인프라 계층
│ └── persistence/
│ ├── BookRepositoryImpl.java # BookRepository 구현체
│ └── MemberRepositoryImpl.java # MemberRepository 구현체

이러한 예시 구조도가 존재한다고 할 때 각각이 무슨 역할을 맡게될지 정리해보자

계층별 역할과 예시 설명

Presentation Layer (프레젠테이션 계층)

  • 역할: 사용자 또는 외부 클라이언트와의 상호작용을 관리하는 계층으로,
    요청을 수신하고 응답을 반환한다.

  • 구성요소:

    • controller/: 사용자 요청을 받아들여 적절한 서비스로 전달하는 역할
    • view/: 데이터를 포맷팅하거나 특정 형태로 가공하여 사용자에게 표시한다.
  • 예시:

    • BookController: 책에 대한 사용자 요청을 처리.
    • BookPresenter: 사용자에게 반환될 데이터를 가공.

Business Layer

Application Layer (애플리케이션 계층)

  • 역할: 비즈니스 로직 흐름을 제어하는 역할로,
    서비스 클래스에서는 프레젠테이션 계층에서 받은 요청을 처리하기 위해
    도메인 계층의 로직을 호출하고, 여러 도메인 로직을 조합하여 최종 비즈니스 로직을 완성한다.
    이는 프레젠테이션 계층과 도메인 계층 간의 의존성을 줄이고
    각 계층을 깔끔하게 분리하는 데 기여한다.

  • 구성요소:

    • service/: 비즈니스 로직을 처리하고 트랜잭션을 관리
    • dto/: 데이터 이동을 위한 객체로, 각 계층 간 데이터 교환 시 사용
  • 예시:

    • BookService: 비즈니스 로직을 담당하여, 프레젠테이션 계층의 요청을 기반으로 데이터를 처리하고 결과를 반환

Domain Layer (도메인 계층)

  • 역할: 애플리케이션의 핵심 비즈니스 로직과 데이터 모델을 정의하는 계층으로,
    소프트웨어가 수행해야 하는 실제 비즈니스 문제 해결의 핵심을 담고 있다.
    모델 패키지에 있는 클래스들은 주요 데이터를 나타내는 도메인 객체일 뿐만 아니라,
    비즈니스 핵심 로직을 직접 구현하여 책임을 분명하게 하고, 이를 재사용할 수 있게 한다.

  • 구성요소:

    • model/: 도메인 객체로서 애플리케이션의 주요 데이터를 표현
    • repository/: 리포지토리 인터페이스가 존재하며, 도메인 객체의 영속성 관련 메서드를 정의. 리포지토리 인터페이스는 도메인 데이터 영속성 인터페이스를 정의하여 데이터 접근 방식에 대한 추상화를 제공
  • 예시:

    • Book: 책 데이터를 담는 도메인 객체이며, 대출 여부 확인, 연체료 계산 등의 핵심 로직을 포함
    • BookRepository: 이 데이터를 저장하고 조회하는 메서드를 정의하는 인터페이스

Persistence Layer (퍼시스턴스 계층)

  • 역할: 데이터베이스, 외부 시스템 등과의 연결을 담당한다.
    도메인 계층에서 정의한 인터페이스를 구현하여 실제 영속성 작업을 수행한다.

  • 구성요소:

    • persistence/: 데이터베이스 접근 로직을 구현하는 클래스들로, 주로 Repository 인터페이스의 구체적인 구현체가 포함되어 실제 DB와의 상호작용을 담당. (DAO)
  • 예시:

    • BookRepositoryImpl: 데이터베이스와 상호작용하여 BookRepository의 메서드를 구현합니다.

살짝 들 수 있는 의문

왜 Repository가 도메인 계층에 존재하고, 퍼시스턴스 계층에서 구현체를 만드는가?

답변: 리포지토리 인터페이스가 도메인 계층에 존재하며,
이는 도메인 로직에서 필요로 하는 CRUD 메서드를 정의한다.
실제 데이터 접근 로직은 퍼시스턴스 계층에 구현된 DAO(Data Access Object)에서 처리된다.

따라서 BookRepository는 도메인 객체에 대한 메서드를 정의하는 인터페이스이고, BookRepositoryImpl은 이 인터페이스의 실제 구현체,
즉 DAO로써 데이터베이스와 상호작용을 수행한다.

이러한 분리는 유연성, 테스트 용이성, 코드 재사용성을 높이는 데 도움이 된다.



Layered Architecture의 장점과 단점

장점

  1. 계층별 관심사가 분리되기 때문에 코드 가독성과 유지 보수성이 높다.
  2. 모듈 교체가 용이하다. (결합도가 낮기 때문이다.)
  3. 각 계층은 자신의 관심사에만 초점을 두기에 한 계층을 테스트할 때 그 환경을 조성하는 것이 수월하다.

단점과 해결방안

https://velog.io/@weskii/%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%99%80-%EC%A2%85%EB%A5%98

여기서 부터는 내가 정리한 다른 블로그 글이 있으니 참고하면 될 듯 하다.

https://velog.io/@jay/%EC%89%BD%EA%B2%8C-%EB%A7%90%ED%95%98%EB%8A%94-%EA%B3%84%EC%B8%B5%ED%98%95-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%9D%98-%EB%AC%B8%EC%A0%9C

아니면 문제점에 대해서 자세히 설명해놓으신 dante Yoon 님의 블로그를 참고해도 좋을 것 같다.

profile
개발일기

0개의 댓글