본문 바로가기
프로그래밍 놀이터/디자인 패턴, 리펙토링

[책 정리] 22. 클린 아키텍처 - Clean Architecture

by 돼지왕 왕돼지 2022. 11. 3.
반응형

 

-

육각형 아키텍처(Hexagonal Architecture), DCI(Data, Context and Interaction), BCE(Boundary-Control Entity) 모두 세부적인 면에서는 다소 차이가 있더라도 그 내용은 상당히 비슷하다.

이들의 목표는 모두 관심사의 분리(separation of concerns)다.

이들 모두 소프트웨어를 계층으로 분리함으로써 관심사의 분리라는 목표를 달성할 수 있었다.

각 아키텍처는 최소한 업무 규칙을 위한 계층 하나와, 사용자와 시스템 인터페이스를 위한 또 다른 계층 하나를 반드시 포함한다.

 

 

-

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

 

프레임워크 독립성

    아키텍처는 다양한 기능의 라이브러리를 제공하는 소프트웨어, 즉 프레임워크의 존재 여부에 의존하지 않는다. 도구로 사용하며, 프레임워크가 지닌 제약사항 안으로 시스템을 욱여 넣도록 강제하지 않는다.

 

테스트 용이성

    업무 규칙은 UI, DB, 웹 서버, 또는 여타 외부 요소가 없이도 테스트할 수 있다.

 

UI 독립성

    시스템의 나머지 부분을 변경하지 않고도 UI 를 쉽게 변경할 수 있다.

 

데이터베이스 독립성

    오라클이나 MS SQL 서버를 몽고DB, 빅테이블, 카우치DB 등으로 교체할 수 있다.

 

모든 외부 에이전시에 대한 독립성

    실제로 업무 규칙은 외부 세계와의 인터페이스에 대해 전혀 알지 못한다.

 

 

-

 

 

 

의존성 규칙

 

-

동심원은 서로 다른 영역을 표현하며, 보통 안으로 들어갈수록 고수준이 된다.

바깥쪽 원은 메커니즘이고 안쪽 원은 정책이다.

이러한 아키텍처가 동작하도록 하는 가장 중요한 규칙은 의존성 규칙(dependency rule)이다.

 

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

 

 

-

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

특히 내부의 원에 속한 코드는 외부의 원에 선언된 어떤 것에 대해서도 그 이름을 언급해서는 절대 안 된다.

 

 

-

외부의 원에 선언된 데이터 형식도 내부의 원에서 절대로 사용해서는 안 된다.

특히 그 데이터 형식이 외부의 원에 있는 프레임워크가 생성한 것이라면 더더욱 사용해서는 안 된다.

우리는 외부 원에 위치한 어떤 것도 내부의 원에 영향을 주지 않기를 바란다.

 

 

* 엔티티

 

-

엔티티는 전사적인 핵심 업무 규칙을 캡슐화한다.

엔티티는 메서드를 가지는 객체이거나 일련의 데이터 구조와 함수의 집합일 수도 있다.

기업의 다양한 앱에서 엔티티를 재사용할 수만 있다면, 그 형태는 그다지 중요하지 않다.

 

 

* 유스케이스

 

-

유스케이스 계층의 소프트웨어는 앱에 특화된 업무 규칙을 포함한다.

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

 

 

-

이 계층의 변경이 엔티티에 영향을 줘서는 안 된다.

또한 DB, UI 또는 여타 공통 프레임워크같은 외부 요소에서 발생한 변경이 이 계층에 영향을 줘서도 안 된다.

하지만 운영 관점에서 앱이 변경된다면 유스케이스가 영향을 받으며, 따라서 이 계층의 소프트웨어에도 영향을 준다.

 

 

* 인터페이스 어댑터

 

-

인터페이스 어댑터(interface adapter) 계층은 일련의 어댑터들로 구성된다.

어댑터는 데이터를 유스케이스와 엔티티에게 가장 편리한 형식에서 DB나 웹 같은 외부 에이전시에게 가장 편리한 형식으로 변환한다.

이 계층은 MVC 아키텍처 같은 것들을 모두 포괄한다.

프레젠터(Presenter), 뷰(View), 컨트롤러(Controller)는 모두 인터페이스 어댑터 계층에 속한다.

모델은 그저 데이터 구조 정도에 지나지 않으며, 컨트롤러에서 유스케이스로 전달되고, 다시 유스케이스에서 프리젠터와 뷰로 되돌아간다.

 

 

* 프레임워크와 드라이버

 

-

원의 가장 바깥쪽 계층을 일반적으로 DB 나 웹 프레임워크 같은 프레임워크 도구들로 구성된다.

일반적으로 이 계층에서는 안쪽 원과 통신하기 위한 접합 코드 외에는 특별히 더 작성해야 할 코드가 그다지 많지 않다.

프레임워크와 드라이버 계층은 모든 세부사항이 위치하는 곳이다.

웹, DB 는 모두 세부사항이다.

 

 

* 원은 네 개여야만 하나?

 

-

그렇지 않다. 네 개보다 더 많은 원이 필요할 수도 있다.

하지만 어떤 경우에도 의존성 규칙은 적용된다.

소스 코드 의존성은 항상 안쪽을 향한다.

안쪽으로 이동할수록 추상화와 정책의 수준은 높아진다.

가장 바깥쪽 원은 저수준의 구체적인 세부사항으로 구성된다.

그리고 안쪽으로 이동할수록 소프트웨어는 점점 추상화되고 더 높은 수준의 정책들을 캡슐화한다.

따라서 가장 안쪽 원은 가장 범용적이며 높은 수준을 가진다.

 

 

* 경계 횡단하기

 

-

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

예를 들어 자바 같은 언어에서는 인터페이스와 상속 관계를 적절하게 배치함으로써, 제어흐름이 경게를 가로지르는 바로 그 지점에서 소스 코드 의존성을 제어흐름과는 반대가 되게 만들 수 있다.

 

 

* 경계를 횡단하는 데이터는 어떤 모습인가

 

-

경계를 가로지르는 데이터는 흔히 간단한 데이터 구조로 이루어져 있다.

기본적인 구조체나 간단한 데이터 전송 객체(data transfer object)등 원하는 대로 고를 수 있다.

또는 함수를 호출할 떄 간단한 인자를 사용해서 데이터로 전달할 수도 있다.

 

중요한 점은 격리되어 있는 간단한 데이터 구조가 경계를 가로질러 전달된다는 사실이다.

꾀를 부려 엔티티 객체나 db 행을 전달하는 일은 원치 않는다.

우리는 데이터 구조가 어떤 의존성을 가져 의존성 규칙을 위배하게 되는 일은 바라지 않는다.

 

 

 

전형적인 시나리오

 

-

의존성의 방향에 주목하라.

모든 의존성은 경계선을 안쪽으로 가로지르며, 따라서 의존성 규칙을 준수한다.

 

 

 

결론

 

-

소프트웨어를 계층으로 분리하고 의존성 규칙을 준수한다면 본질적으로 테스트하기 쉬운 시스템을 만들게 될 것이며, 그에 따른 이점을 누릴 수 있다.

DB 나 웹 프레임워크와 같은 시스템의 외부 요소가 구식이 되더라도, 이들 요소를 야단스럽지 않게 교체할 수 있다.

 

 

반응형

댓글