ETC/Software Development Methodology

클린 아키텍쳐(Clean Architecture) 에 대해

범데이 2022. 12. 8. 01:10

클린 아키텍쳐에대해 공부하기 위해 포스팅을 찾던 중,

잘 정리된 외국 포스팅이 있어서 이를 번역하여 포스팅하고자 한다.

 


 

The Clean Architecture Diagram

 

지난 몇 년 동안 우리는 시스템 아키텍처에 관한 다양한 아이디어를 보았다. 여기에는 다음이 포함된다.

  • Hexagonal Architecture (a.k.a. Ports and Adapters) by Alistair Cockburn, Steve Freeman, Nat Pryce가 멋진 책 Growing Object Oriented Software에서 채택
  • Jeffrey Palermo의 Onion Architecture
  • Screaming Architecture
  • James Coplien 및 Trygve Reenskaug의 DCI.
  • Ivar Jacobson의 저서 Object Oriented Software Engineering (A Use-Case Driven Approach에서 BCE 작성)

이러한 아키텍처는 모두 세부 사항이 다소 다르지만 매우 유사하다. 그들은 모두 관심의 분리라는 동일한 목표를 가지고 있다. 그들은 모두 소프트웨어를 계층으로 나누어 이러한 분리를 달성한다. 각각에는 비즈니스 규칙에 대한 계층과 인터페이스에 대한 계층이 하나 이상 있다.

 

이러한 각 아키텍처는 다음과 같은 시스템을 생성한다.

  1. 프레임워크와 독립적이다. 아키텍처는 일부 기능이 포함된 소프트웨어 라이브러리의 존재에 의존하지 않는다. 이를 통해 시스템을 제한된 제약 조건에 집어넣지 않고 이러한 프레임워크를 도구로 사용할 수 있다.
  2. 테스트가 가능하다. 비즈니스 규칙은 UI, 데이터베이스, 웹 서버 또는 기타 외부 요소 없이 테스트할 수 있다.
  3. UI와 독립적이다. 시스템의 나머지 부분을 변경하지 않고도 UI를 쉽게 변경할 수 있다. 예를 들어 비즈니스 규칙을 변경하지 않고 웹 UI를 콘솔 UI로 바꿀 수 있다.
  4. 데이터베이스와 독립적이다. Oracle또는 SQL Server를 Mongo, BigTable, CouchDB등으로 교체할 수 있다. 비즈니스 규칙은 데이터베이스에 바인딩 되지 않는다.
  5. 외부 기관과 독립적이다. 사실 비즈니스 규칙은 외부 세계에 대해 전혀 알지 못한다.

이 문서 상단의 다이어그램은 이러한 모든 아키텍처를 실행 가능한 단일 아이디어로 통합하려는 시도이다.

 

 

The Dependency Rule

동심원은 소프트웨어의 다양한 영역을 나타낸다. 일반적으로 더 깊이 들어갈수록 소프트웨어의 수준이 높아진다. 외부 원은 메커니즘이다. 내부 원은 정책이다.

 

이 아키텍처가 작동하도록 만드는 우선 규칙은 종속성 규칙(Dependency Rule) 이다. 이 규칙에 따르면 소스 코드 종속성은 안쪽만 가리킬 수 있다.내부 원의 어떤 것도 외부 원의 어떤 것에 대해 전혀 알 수 없다. 특히 외부 원에서 선언된 이름은 내부 원의 코드에서 언급되어서는 안된다. 여기에는 변수 또는 기타 명명된 소프트웨어 엔티티, 함수, 클래스가 포함된다.

 

마찬가지로 외부 원에서 사용되는 데이터 형식은 내부 원에서 사용하면 안된다. 특히 이러한 형식이 외부 원의 프레임워크에서 생성되는 경우에는 더욱 그렇다. 우리는 외부 원의 어떤 것도 내부 원에 영향을 미치기를 원하지 않는다.

 

 

Entities

엔티티(Entities) 는 Enterprise wide 비즈니스 규칙을 캡슐화한다. 엔티티는 메서드가 있는 객체이거나 데이터 구조 및 함수 집합일 수 있다. 엔티티가 엔터프라이즈의 여러 다른 응용 프로그램에서 사용될 수 있는 한 중요하지 않다.

 

기업이 없고 단일 애플리케이션을 작성하는 경우 이러한 엔티티는 애플리케이션의 비즈니스 개체이다. 가장 일반적이고 높은 수준의 규칙을 캡슐화한다. 그들은 외부의 어떤 것이 변할 때 변할 가능성이 가장 적다. 예를 들어 이러한 개체가 페이지 탐색 또는 보안 변경에 의해 영향을 받지 않을 것이라고 예상할 수 있다. 특정 애플리케이션에 대한 운영상의 변경은 엔티티 계층에 영향을 미치지 않아야 한다.

 

 

Use Cases

이 계층의 소프트웨어에는 애플리케이션별 비즈니스 규칙이 포함되어 있다. 시스템의 모든 사용 사례(Use Cases) 를 캡슐화하고 구현한다. 이러한 사용 사례는 엔티티 간 데이터 흐름을 오케스트레이션하고 해당 엔티티가 전사적 비즈니스 규칙을 사용하여 사용 사례의 목표를 달성하도록 지시한다.

 

이 레이어의 변경 사항이 엔티티에 영향을 미치지 않을 것으로 예상한다. 또한 이 계층이 데이터베이스, UI 또는 공통 프레임워크와 같은 외부 요소의 변경에 의해 영향을 받지 않을 것으로 예상한다. 이 계층은 이러한 우려로부터 격리되어 있다.

 

그러나 우리는 응용 프로그램 작동에 대한 변경사항이 사용 사례와 이 계층의 소프트웨어에 영향을 미칠 것으로 예상한다. 사용 사례의 세부 사항이 변경되면 이 계층의 일부 코드가 확실히 영향을 받는다.

 

 

Interface Adapters

이 계층의 소프트웨어는 사용 사례 및 엔티티에 가장 편리한 형식에서 데이터베이스 또는 웹과 같은 일부 외부 에이전시에 가장 편리한 형식으로 데이터를 변환하는 어댑터 집합이다. 예를 들어 GUI의 MVC 아키텍처를 완전히 포함하는 것은 이 계층이다. Presenters, Views및 Controllers가 모두 여기에 속한다. 모델은 컨트롤러에서 use case로 전달된 다음 use case 에서 presenters 및 views로 다시 전달되는 데이터 구조일 가능성이 높다.

 

마찬가지로 데이터는 이 계층에서 엔티티 및 사용 사례에 가장 편리한 형식에서 사용 중인 지속성 프레임워크에 가장 편리한 형식으로 변환된다. 즉, 데이터베이스. 이 원 안에 있는 코드는 데이터베이스에 대해 전혀 알지 못한다. 데이터베이스가 SQL 데이터베이스인 경우 모든 SQL은 이 계층, 특히 데이터베이스와 관련이 있는 이 계층 부분으로 제한되어야 한다.

 

또한 이 계층에는 외부 서비스와 같은 일부 외부 형식의 데이터를 사용 사례 및 엔티티에서 사용하는 내부 형식으로 변환하는 데 필요한 다른 어댑터가 있다.

 

 

 

Frameworks와 Drivers

가장 바깥쪽 레이어는 일반적으로 데이터베이스, 웹 프레임워크 등과 같은 프레임워크와 도구로 구성된다. 일반적으로 이 레이어에는 내부의 다음 원과 통신하는 글루 코드 외에 많은 코드를 작성하지 않는다.

 

이 레이어는 모든 세부 사항이 있는 곳이다. 웹은 세부 사항이다. 데이터베이스는 세부 사항이다. 우리는 이러한 것들을 거의 해를 끼치지 않는 외부에 보관한다.

 

 

오직 네 개의 원만 허용하나?

아니다. 원은 개략적이다. 우리는 이 네 가지 이상의 것이 필요하다는 것을 알게 될 것이다. 항상 이 4개만 있어야 한다는 규칙은 없다. 그러나 종속성 규칙은 항상 적용된다. 소스 코드 종속성은 항상 안쪽을 가리킨다. 안쪽으로 이동하면 추상화 수준이 높아진다. 가장 바깥쪽 원은 낮은 수준의 콘크리트 디테일이다. 내부로 이동함에 따라 소프트웨어는 더욱 추상화되고 더 높은 수준의 정책을 캡슐화 한다. 가장 안쪽 원이 가장 일반적인 원이다.

 

 

 

경계를 넘다.

다이어그램의 오른쪽 하단에는 원 경계를 어떻게 교차하는지에 대한 예가 있다. 다음 계층에서 Use Cases와 통신하는 Controllers및 Presenters를 보여준다. control의 흐름에 유의하자. controller에서 시작하여 use case를 통해 이동한 다음 Presenter에서 실행된다. 소스 코드 종속성에도 유의하자. 그들 각각은 use cases 를 향해 안쪽을 가리킨다.

 

우리는 일반적으로 종속성 역전 원칙을 사용하여 이러한 명백한 모순을 해결한다. 예를 들어 Java와 같은 언어에서는 소스 코드 종속성이 경계를 넘어 올바른 지점에서 제어 흐름에 반대하도록 인터페이스와 상속 관계를 배열한다.

 

예를 들어 use case 에서 presenter를 호출해야 한다고 가정한다. 그러나 이 호출은 종속성 규칙을 위반하므로 직접 호출해서는 안된다. 외부 원의 이름은 내부 원에서 언급할 수 없다. 그래서 우리는 use case 가 내부 원에서 인터페이스(여기서는 use case 출력 포트로 표시됨)를 호출하고 외부 원의 발표자가 이를 구현하도록 한다.

 

동일한 기술이 아키텍처의 모든 경계를 교차하는 데 사용된다. 우리는 동적 다형성을 활용하여 제어 흐름에 반대되는 소스 코드 종속성을 생성하므로 제어 흐름이 어떤 방향으로 진행되든 종속성 규칙을 준수할 수 있다.

 

 

 

경계를 넘는 데이터.

일반적으로 경계를 넘는 데이터는 단순한 데이터 구조이다. 원하는 경우 기본 구조체 또는 간단한 데이터 전송 객체를 사용할 수 있다. 또는 데이터는 단순히 함수 호출의 인수일 수 있다. 또는 해시맵으로 압축하거나 개체로 구성할 수 있다. 중요한 것은 격리되고 단순한 데이터 구조가 경계를 넘어 전달된다는 것이다. 우리는 엔티티 또는 데이터베이스 행을 속이고 전달하고 싶지 않다. 우리는 데이터 구조가 종속성 규칙을 위반하는 어떤 종류의 종속성도 가지기를 원하지 않는다.

 

예를 들어 많은 데이터베이스 프레임워크는 쿼리에 대한 응답으로 편리한 데이터 형식을 반환한다. 이것을 RowStructure라고 부를 수 있다. 경계를 넘어 안쪽으로 해당 행 구조를 전달하고 싶지 않다. 이는 내부 원이 외부 원에 대해 알도록 강제하기 때문에 종속성 규칙을 위반하는 것이다.

 

따라서 경계를 넘어 데이터를 전달할 때 항상 내부 원에 가장 편리한 방식이다.

 

 

 

결론

이러한 간단한 규칙을 따르는 것은 어렵지 않으며 앞으로 많은 골칫거리를 덜어 줄 것이다. 소프트웨어를 계층으로 분리하고 종속성 규칙을 준수하면 내포된 모든 이점과 함께 본질적으로 테스트 가능한 시스템을 만들 수 있다. 데이터베이스나 웹 프레임워크와 같은 시스템의 외부 부분이 쓸모없게 되면 최소한의 소란으로 그러한 쓸모없는 요소를 교체할 수 있다.

 

 

 


#Reference

https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

반응형