hexdrinker

클린 아키텍처

-3 min read

지난 수십 년간 우리는 시스템 아키텍처와관련된 여러 아이디어를 봐왔다. 헥사고날 아키텍처(Hexagonal Architecture), DCI(Data, Context and Interaction), BCE(Boundary-Control-Entity) 등 이들 아키텍처는 모두 세부적인 면에서 다소 차이가 있더라도 내용은 비슷하다.

이들의 목표는 모두 관심사의 분리(separation of concerns)다. 이들은 모두 소프트웨어의 계층을 분리함으로써 관심사의 분리라는 목표를 달성할 수 있었다. 각 아키텍처는 최소한 업무 규칙을 위한 계층 하나와, 사용자와 시스템 인터페이스를 위한 또 다른 계층 하나를 반드시 포함한다.

이들 아키텍처는 모두 시스템이 다음과 같은 특징을 지니도록 만든다.

  • 프레임워크 독립성
    아키텍처는 프레임워크 존재 여부에 의존하지 않는다. 프레임워크가 가진 제약사항을 시스템에 욱여 넣도록 강제하지 않는다.
  • 테스트 용이성
    업무 규칙은 UI, DB, 웹 서버, 기타 외부 요소 없이도 테스트할 수 있다.
  • UI 독립성
    시스템의 나머지 부분 변경 없이도 UI를 쉽게 변경할 수 있다.
  • DB 독립성 업무 규칙은 DB에 결합되지 않는다. 고로 DB를 교체할 수 있다.
  • 모든 외부 에이전시에 대한 독립성
    업무 규칙은 외부 세계와의 인터페이스에 대해 전혀 알지 못한다.
클린 아키텍처
클린 아키텍처

의존성 규칙

보통 안으로 들어갈수록 고수준의 소프트웨어가 된다. 바깥쪽 원은 메커니즘이고 안쪽 원은 정책이다. 이러한 아키텍처가 동작하도록 하는 가장 중요한 규칙은 의존성 규칙(Dependency Rule) 이다.

소스 코드 의존성은 반드시 안쪽으로, 고수준의 정책을 향해야 한다.

내부의 원에 속한 요소는 외부의 원에 속한 어떤 것도 알지 못한다.

엔티티

엔티티는 전사적인 핵심 업무 규칙을 캡슐화한다. 메소드를 가지는 객체거나 일련의 데이터 구조와 함수의 집합일 수도 있다. 재사용할 수만 있다면 형태는 중요하지 않다.

전사적이지 않은 단순한 단일 애플리케이션을 작성하고 있다면 엔티티는 해당 애플리케이션의 업무 객체가 된다. 이 경우엔 가장 일반적이며 고수준인 규칙을 캡슐화한다.

유스케이스

유스케이스 계층은 애플리케이션에 특화된 업무 규칙을 포함한다. 또한 시스템의 모든 유스케이스를 캡슐화하고 구현한다.

유스케이스는 엔티티로 들어오고 나가는 데이터 흐름을 조정하며, 엔티티가 자신의 핵심 ㅇ버무 규칙을 사용해서 유스케이스의 목적을 달성하도록 이끈다.

인터페이스 어댑터

인터페이스 어댑터(Interface Adapter) 계층은 일련의 어댑터들로 구성된다. 데이터를 유스케이스와 엔티티에게 가장 편리한 형식에서 DB나 웹 같은 외부 에이전시에게 가장 편리한 형식으로 변환한다.

예를 들어 GUI의 MVC 아키텍처의 요소들(Presenter, View, Controller)는 모두 이 계층에 속한다.

프레임워크와 드라이버

가장 바깥쪽 계층은 이 계층은 모든 세부사항이 위차하는 곳으로 일반적으로 DB, 프레임워크 같은 도구들로 구성된다. 이 계층엔 안쪽과 통신하기 위한 접합 코드 외에는 특별히 더 작성해야 할 코드가 많지 않다.

원은 네 개여야만 하나?

원들은 개념을 설명하기 위한 하나의 예시다. 더 많은 원이 필요할 수도 있고 항상 네 개만 사용해야 한다는 규칙도 없다. 하지만 어떤 경우에도 의존성 규칙은 적용된다.

경계 횡단하기

위 이미지를 다시 보자. 컨트롤러와 프레젠터가 유스케이스 계층과 통신하는 모습을 볼 수 있다. 데이터는 컨트롤러에서 시작하여 유스케이스를 지나고 프레젠터에서 마무리된다.

소스 코드 의존성도 주목하자. 각 의존성은 유스케이스를 향해 안쪽을 가리킨다.

이처럼 제어흐름과 의존성 방향이 명백히 반대인 경우, 대체로 의존성 역전 원칙을 사용하여 해결한다.

아키텍처 경계를 횡단할 때 언제라도 동일한 기법을 사용할 수 있다. 우리는 동적 다형성을 이용하여 소스 코드 의존성을 제어흐름과는 반대로 만들 수 있고, 이를 통해 제어흐름이 어느 방향으로 흐르더라도 의존성 규칙을 준수할 수 있다.