Layered Architecture

3 분 소요


0. 들어가면서

레이어 아키텍처(layered arhcitecture)는 학원에서 배우는 초급자부터 현장의 개발자들까지 많은 곳에서 사용되고 널리 알려진 아키텍처 패턴입니다. 익숙한만큼 쉽다고 생각되지만, 어플리케이션이 커짐에 따라 레이어 아키텍처는 본연의 목적을 잃고 제 역할을 못하는 경우가 발생합니다. 레이어 아키텍처를 적용하여 얻고자하는 목표를 이해하고, 아키텍처 사상이 흔들리지 않도록 고려할 것들이 무엇이 있는지 알아보겠습니다.

1. Layered Architecture

이름처럼 계층 구조를 지닌 아키텍처입니다. 구성되는 계층에 따라 N-계층 아키텍처라고 불립니다. 비교적 단순한 어플리케이션은 3계층, 일반적으로 4계층을 가집니다. 레이어 아키텍처를 적용하는 가장 큰 이유는 관심사의 분리입니다. 각 계층들은 각자 맡은 책임이 있고, 이에 맞는 역할을 수행합니다.

레이어 아키텍처에서 의존성의 방향은 중요합니다. 하나의 계층이 모든 일을 처리할 수 없으므로 자신이 수행할 수 없는 일은 하위 계층에 의존합니다. 그러나 하위 계층은 상위 계층에 대한 어떤 지식이나 정보가 없어야 합니다.

레이어 아키텍처를 통해 다음과 같은 목적을 이룰 수 있습니다.

  • 서로 다른 계층으로 분리하여 전체적인 시스템 결합도를 낮춥니다.
    • 하위 계층은 인터페이스를 통해 접근하고, 실 구현 코드를 직접 사용하지 않습니다.
    • 각 계층을 모듈(module)로 관리하고, 인터페이스로 접근하여 해당 계층의 변경 사항을 최소화할 수 있습니다.
  • 재사용성을 높입니다.
    • 뷰(view)를 표현을 위한 조인 쿼리는 조회 로직의 재사용성을 낮춥니다.
    • 화면 설계가 인프라스트럭처 계층까지 침투한 것으로 화면이 변경될 때마다 쿼리가 함께 변경되어야 합니다.
    • 재사용성의 트레이드 오프(trade-off)가 적절한 수준의 쿼리를 작성하고, 도메인 객체들을 통해 화면에 필요한 데이터를 만듭니다.
  • 유지 보수성을 높입니다.
    • 각 계층은 격리되도록 설계합니다.
    • 하위 계층의 의존성이 필요한 경우 인터페이스를 사용하여 다른 계층의 변경에 대한 영향이 전파되지 않도록 최소화합니다.

1.1. 4-Layered Architecture

참고한 자료마다 계층의 이름이나 계층의 개수가 다르지만, 본질적으론 같은 내용이므로 하나를 예로 들어 설명하겠습니다. 다음은 4계층 레이어 아키텍처이며 각 계층 별로 맡은 책임과 해야하는 일 입니다.

  • 사용자 인터페이스 계층(User Interface Layer)
    • 사용자 화면을 구성하는 것에 관심이 있습니다.
    • 사용자 인터페이스를 어떻게 구성하고 상호 작용은 어떻게 수행할지에 대한 책임을 가지고 있습니다.
    • 화면을 직접 서비스하지 않는다면 클라이언트로부터 요청을 받고, 응답하는 API를 정의합니다.
  • 어플리케이션 계층(Application Layer)
    • 도메인 계층의 비즈니스 로직과 인프라스트럭처 계층의 데이터 접근 로직을 조율하는 것에 관심이 있습니다.
    • 실제 비즈니스 로직보단 고수준(high-level)에서 추상화 된 어플리케이션 기능을 표현합니다.
  • 도메인 계층(Domain Layer)
    • 핵심 비즈니스 로직을 수행하는 것에 관심이 있습니다.
    • 세부적인 기술이나 외부 관심사에 의존하지 않고, 격리된 상태에서 순수한 비즈니스 로직을 수행합니다.
    • Java 어플리케이션인 경우에 POJO(Plain Old Java Object) 객체를 사용해 비즈니스 로직을 구성합니다.
  • 인프라스트럭처 계층(Infrastructure Layer)
    • 상위 계층에게 기술적인 부분을 지원하는 것에 관심이 있습니다.
    • 기술 종속성이 강한 구현체를 제공하는 계층입니다.
    • 영속성 프레임워크, 프레임워크 설정, 외부 API 요청 기능, 이벤트 리스너(listener) 등이 있습니다.

http://pds19.egloos.com/pds/201106/28/18/Open_Session_In_View_Pattern.pdf

2. Open And Closed Layer

엄격한 레이어 아키텍처는 반드시 바로 아래 계층만 의존합니다. 이와 달리 완화된 레이어 아키텍처는 자신의 하위 레이어라면 모두 의존할 수 있습니다. 이를 계층이 “닫혔다(close)” 혹은 “열렸다(open)”라고 표현합니다.

  • 하위 계층이 닫혀있다면 이를 그대로 통과하지 못하고 반드시 바로 아래 닫힌 계층을 의존합니다.
  • 하위 계층이 열려있다면 이를 그대로 통과하여 더 하위 계층에 직접 의존합니다.
  • 아래 예시를 보면 비즈니스 계층은 서비스 계층을 통과하고 영속성 계층을 직접 의존합니다.

https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch01.html

2.1. Sinkhole Anti Pattern

엄격한 레이어 아키텍처처럼 모든 계층이 닫힌 경우 하위 계층에 별다른 로직 없더라도 반드시 바로 아래 계층을 호출해야 합니다. 요청을 전달받은 하위 계층은 아무런 로직 없이 요청을 다음 계층으로 바이패스(bypass)하는데 이 경우를 싱크홀 안티 패턴이라고 합니다. 이는 불필요한 리소스(resource) 낭비를 만듭니다.

레이어 아키텍처를 적용한 모든 어플리케이션들에서 싱크홀 패턴을 발견할 수 있습니다. 80-20 규칙(rule)을 통해 시스템에 퍼진 싱크홀 패턴이 적정 수준인지 확인할 수 있습니다. 전체 코드에서 안티홀 패턴이 적용된 코드가 20% 수준이라면 괜찮습니다. 만약 이 비율이 역전되거나 대부분의 요청이 안티 싱크홀 패턴을 따른다면 해당 계층을 여는 것도 고려해봐야 합니다.

3. Pros And Cons

우선 레이어 아키텍처의 장점들을 정리해보겠습니다.

  • 각 계층들로 나누었기 때문에 결합도가 느슨한 구조를 만들 수 있습니다.
  • 대상 계층의 컴포넌트를 제외하고 다른 계층의 의존성들은 테스트 더블(test double)로 만들기 때문에 테스트가 쉽습니다.
  • 배우기 쉽고 구현이 간단하여 거의 모든 어플리케이션들의 개발 시작점으로 적합합니다.

다음 레이어 아키텍처의 단점들입니다.

  • 어플리케이션 구조를 다르게 바꾸기 어렵습니다.
  • 계층을 수평적으로 나누어 배포하는 것이 어렵기 때문에 모든 계층을 하나의 노드로 배포, 확장(scale)하므로 무겁습니다.

4. Consideration

레이어 아키텍처를 적용할 때 다음과 같은 사항들을 고려합니다.

  • 모델(model)과 뷰(view)를 분리합니다.
    • 모델은 도메인 설계에 따라 우리가 기대하는 시스템의 동작 모습이며 도메인 계층에 존재합니다.
    • 뷰는 사용자에게 보여지는 모습이며 사용자 인터페이스 계층에 존재합니다.
    • 모델은 화면 출력과 관련된 로직을 포함하지 않고, 뷰는 비즈니스 로직을 포함하지 않습니다.
    • 도메인 계층은 사용자 인터페이스 계층에 직접 접근하지 않습니다.
  • 깔끔하고 얇은 뷰(clean and thin view)를 가져야 합니다.
    • 뷰는 오직 마크업(markup)과 화면 출력 로직만 포함합니다.
    • 시스템의 상태를 변경시킬 수 있는 비즈니스 로직은 포함하지 않습니다.
  • 도메인 계층을 기술적 의존성으로부터 고립시켜야 합니다.
    • 도메인 계층은 비즈니스를 구성하는 핵심 개념, 중요한 정보와 준수해야하는 규칙들을 표현합니다.
    • 도메인 계층에 기술 의존성이 침투하는 것은 비즈니스가 기술적 변경에 강하게 결합되는 것을 의미합니다.
    • 비즈니스 로직에 침투한 기술적 이슈는 시스템을 변경하고 이해하기 어렵게 만듭니다.
    • 시스템을 단순하고 유연한 상태로 유지하기 위해선 도메인 계층을 기술적인 이슈로부터 고립시켜야 합니다.
    • 도메인 계층을 기술적인 이슈와 격리하기 위해 독립적인 POJO로 개발합니다.
    • 실제 기술적 요소를 지닌 구현체들은 인터페이스를 통해 캡슐화하여 사용합니다.

REFERENCE

댓글남기기