2023년 11월 28일 작성

Clean Architecture - 계층 분리

관심사에 따라 계층을 분리하여, system을 유지 보수하기 쉽게 만들 수 있습니다.

Architecture 계층 분리하기

  • Hexagonal Architecture, DCI(Data, Context, Interaction), BCE(Boundary-Control-Entity)와 같은 system architecture에 관련된 여러 생각들은 모두 계층 분리를 통한 관심사의 분리를 목표로 하며, 비슷한 특징을 가지고 있습니다.
계층 분리의 장점 설명
Framework 독립성 framework를 도구로 사용하며, framework가 지닌 제약 사항으로 system을 강제하지 않습니다.
Test 용이성 업무 규칙은 UI, DB, Web server 및 다른 외부 요소 없이도 test할 수 있습니다.
UI 독립성 system의 나머지를 변경하지 않고도 UI를 쉽게 변경할 수 있습니다.
Database 독립성 Oracle이나 MS-SQL server 등을 다른 DB로 교체할 수 있고, 업무 규칙은 DB에 결합되지 않습니다.
외부 Agency에 대한 독립성 업무 규칙은 외부의 interface에 대해 전혀 알지 못합니다.

계층 경계를 횡단하는 Data

  • 경계를 가로질러 data를 전달할 때, data는 항상 내부의 계층에서 사용하기에 가장 편리한 형태여야 합니다.
    • 경계(계층)를 횡단하는 data는 간단한 data 구조로 이루어지며, 구조체나 DTO 등 원하는 형태를 선택할 수 있습니다.
    • 중요한 점은 격리되어 있는 간단한 data 구조가 경계를 가로질러 전달된다는 사실입니다.
    • data 구조가 의존성을 가져서 의존성 규칙을 어기게 해선 안 됩니다.

의존성 규칙

  • source code 의존성은 항상 내부 계층을 향하며, 내부로 이동할수록 추상화와 정책의 수준이 높아집니다.
    • 가장 외부에 있는 계층은 저수준의 세부 사항이며, 내부로 이동할수록 점점 더 추상화되고 더 높은 수준의 정책들을 캡슐화(encapsulation)합니다.
    • 가장 내부 계층은 가장 범용적이며, 높은 수준의 정책을 가지고 있습니다.
  • 외부 계층에 위치한 어떤 것도 내부 계층에 영향을 주지 않아야 합니다.
    • 내부 계층에 속한 요소는 외부 계층에 속한 어떤 것(예를 들어, 함수, class, 변수 등의 모든 software entity)도 알지 못합니다.

Architecture Layer Diagram

  • 상황에 따라서 더 많은 계층이 필요할 수도 있으며, 아래의 diagram은 예시입니다.
flowchart TD

framework_and_driver[장치, DB, Web, UI, 외부 Interface]
interface_adapter[Controller, Gateway, Presenter]
application_business_logic[UseCase]
enterprise_business_logic[Entity]

subgraph framework_and_driver_layer[Framework와 Driver 계층]
    framework_and_driver
    subgraph interface_adapter_layer[Interface Adapter 계층]
        interface_adapter
        subgraph application_business_logic_layer[Application 업무 규칙 계층]
            application_business_logic
            subgraph enterprise_business_logic_layer[Enterprise 업무 규칙 계층]
                enterprise_business_logic
            end
        end
    end
end

framework_and_driver --> interface_adapter --> application_business_logic --> 
enterprise_business_logic

Enterprise 업무 규칙 계층 : Entity

  • Entity는 전사적인 핵심 업무 규칙을 캡슐화(encapsulation)하며, method를 갖는 객체일 수도, data와 함수의 집합일 수도 있습니다.
    • 다양한 application에서 재사용만 가능하다면 형태는 중요하지 않습니다.
  • 특정 application에 어떠한 변경이 필요하더라도 Entity에는 영향을 주면 안 됩니다.
    • 외부 계층의 무언가가 변경되더라도, Entity는 변경되어선 안 됩니다.
    • 예를 들어, Entity는 핵심 업무 규칙(business logic)을 다루므로, UI 단의 paging 처리 등이 필요해도 변경이 일어나서는 안 됩니다.

Application 업무 규칙 계층 : UseCase

  • UseCase는 application에 특화된 업무 규칙을 포함하며, system의 모든 UseCase를 캡슐화(encapsulation)하고 구현합니다.

  • UseCase는 Entity로 들어오고 나가는 data 흐름을 조정합니다.
    • 또한 Entity가 자신의 핵심 업무 규칙을 사용해서 UseCase의 목적을 달성하도록 이끕니다.
  • UseCase의 변경이 Entity에 영향을 줘선 안 되며, 외부 요소의 변경이 이 계층에 영향을 주는 것도 안 됩니다.
    • 하지만 운영 관점에서는 application이 변경된다면 UseCase가 영향을 받을 수 있기 때문에, UseCase 세부 사항이 변하면 일부 code는 영향을 받을 수 있습니다.

Interface Adapter 계층 : Controller, Gateway, Presenter

  • presenter나 controller 등과 같은 adapter들로 구성되며, controller에서 UseCase로 전달된 요청은 다시 controller로 되돌아 갑니다.

  • adapter는 UseCase와 Entity에 맞는 data에서 DB나 Web 등과 같은 외부 요소에 맞는 data로 변환합니다.
    • 반대로, data를 외부 service에 맞는 형식에서 UseCase나 Entity에서 사용되는 내부적인 형식으로 변환하는 또 다른 adapter도 필요합니다.
  • 특정 기술에 종속되는 역할(객체 변환)은 adapter가 맡게 하여, UseCase까지 세부 기술 의존성이 도달하지 않도록 합니다.
    • 만약 UseCase 계층에서 변환을 한다면 UseCase가 세부 기술에 의존하게 됩니다.

Framework와 Driver : 장치, DB, Web, UI, 외부 Interface

  • 가장 바깥쪽 계층은 database나 Web framework 같은 것들로 구성됩니다.
  • 이 계층에서는 안쪽 원과 통신하기 위한 접합 code 외에는 특별히 더 작성할 것이 없습니다.
  • 모든 세부 사항이 위치하는 곳으로, Web과 database도 세부 사항이므로 이를 외부에 위치시켜 피해를 최소화합니다.

(번외) Component 기반의 분리

  • 계층 분리가 아닌 component 기반으로 분리할 수도 있습니다.
flowchart LR

ui[UI]
controller[Controller]
usecase[UseCase]
entity[Entity]
databsae[Databsae]

subgraph controller_layer[ ]
    controller
    subgraph usecase_layer[ ]
        usecase
        subgraph entity_layer[ ]
            entity
        end
    end
end

ui --> controller --> usecase --> entity
databsae --> entity

Reference


목차