프로그래밍 기초

클린 아키텍처 번역

hs-archive 2023. 3. 28. 19:35

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

 

Clean Coder Blog

The Clean Architecture 13 August 2012 Over the last several years we’ve seen a whole range of ideas regarding the architecture of systems. These include: Though these architectures all vary somewhat in their details, they are very similar. They all have

blog.cleancoder.com


클린 아키텍처

 

클린 아키텍처

시스템 아키텍처에 관한 다양한 아이디어들이 있습니다. 이를테면 Hexagonal Architecture, Onion Architecture, Screaming Architecture 등이 대표적입니다. 이러한 아키텍처들의 세부 사항은 다소 다르지만 그들 모두 "관심의 분리"라는 동일한 목표를 가지고 있습니다. 아키텍처들은 소프트웨어를 다양한 계층으로 나누어 "관심의 분리"를 달성합니다. 이러한 아키텍처는 다음과 같은 시스템을 생성합니다.

 

Independent of Frameworkds.

프레임워크와 독립적입니다. 아키텍처는 라이브러리에 의존하지 않습니다. 이를 통해 시스템을 제한된 제약 조건에 집어넣지 않고 이러한 프레임워크를 도구로 사용할 수 있습니다.

 

Testable.

테스트 가능해야 합니다. 비즈니스 규칙은 UI, 데이터베이스, 웹 서버 또는 기타 외부 요소 없이 테스트할 수 있습니다.

 

Independent of UI.

UI와 독립적입니다. 시스템의 나머지 부분을 변경하지 않고도 UI를 쉽게 변경할 수 있습니다. 예를 들어 비즈니스 규칙을 변경하지 않고 웹 UI를 콘솔 UI로 바꿀 수 있습니다.(웹 UI란 웹 사이트나 웹 애플리케이션의 UI를 의미합니다. 사용자가 웹 브라우저를 사용하여 상호작용할 수 있는 UI입니다. 반면, 콘솔 UI는 명령줄 인터페이스(CLI)를 의미합니다. 콘솔 UI는 사용자가 명령어를 입력하여 시스템과 상호작용할 수 있는 방법을 제공합니다. 이 문장에서는 Clean Architecture의 핵심 원칙 중 하나인 "Independent of UI"를 설명하고 있습니다. 이 원칙은 비즈니스 룰은 앞서 설명한 UI와 독립적이어야 한다는 것을 의미합니다. 즉, UI를 변경하더라도 시스템의 나머지 부분에 영향을 미치지 않아야 한다는 것입니다. 이를 통해 새로운 UI를 쉽게 도입하거나 기존 UI를 쉽게 교체할 수 있도록 시스템을 유연하게 만드는 것이 목적입니다.)

 

Independent of Database.

데이터베이스와 독립적입니다. Oracle 또는 SQL Server를 Mongo, BigTable, CouchDB 등으로 교체할 수 있습니다. 비즈니스 규칙은 데이터베이스에 바인딩되지 않습니다. (DB가 바뀌더라도 시스템의 나머지 부분에 영향을 미치지 않아야 한다는 것입니다.)

 

Independent of any external agency.

외부 기관과 독립적입니다. 비즈니스 규칙은 외부 세계에 대해 전혀 알지 못합니다.

 

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

 

종속성 규칙 - The Dependency Rule

동심원은 소프트웨어의 다양한 영역을 나타냅니다. 일반적으로 더 깊이 들어갈수록 소프트웨어의 수준이 높아집니다. 외부 원은 메커니즘입니다. 내부 원은 정책입니다. (Clean Architecture의 다이어그램을 보시면, 외부 원은 프레임워크, 드라이버, 도구, 외부라이브러리 등과 같은 구체적인 구현 기술을 나타냅니다. 반면 내부 원은 애플리케이션의 핵심 비즈니스 로직, 즉 애플리케이션의 정책을 나타냅니다. 더 깊이 들어갈수록 소프트웨어의 수준이 높아진다는 것은, 외부 원에서는 "구현 기술에 대한 문제"를 해결하고, 내부 원에서는 핵심 "비즈니스 로직에 대한 문제"를 해결한다는 의미입니다. 즉, 내부 원은 애플리케이션의 핵심 비즈니스 로직에 집중하며, 구현 기술에 대한 의존성을 최대한 분리하는 것이 중요하다는 것을 나타냅니다. 의존성 규칙(Dependency Rule)은 내부 원에 위치한 정책에 대한 코드가 외부 원에 위치한 메커니즘에 의존하지 않도록 하는 것을 의미합니다. 이러한 분리는 유연하고 확장 가능한 애플리케이션 개발을 가능케 하며, 테스트, 유지보수, 리팩토링 등의 과정에서도 이 점을 제공합니다.) ("구현 기술에 대한 문제"란 예를 들어 데이터베이스, 웹 프레임워크, 네트워크 통신 등 특정 기술을 사용하여 시스템을 구현할 때 발생할 수 있는 문제 혹은 처리해야 할 일을 의미합니다. 구체적인 예를 들자면 데이터베이스의 경우 데이터베이스 최적화 등의 문제. 웹 프레임워크의 경우 컨트롤러/액션 처리, 미들웨어 처리, 세션 관리 등의 문제. 네트워크 통신의 경우 프로토콜, 포트 등의 문제. 라이브러리의 경우 버전 호환성, 의존성 관리 등의 문제가 있습니다. 반면, 핵심 "비즈니스 로직에 대한 문제"란 시스템이 제공하는 기능과 관련된 문제를 의미합니다. 예를 들어, 주문 시스템에서 주문을 처리하는 방식, 상품을 조회하는 방식 등과 같이 비즈니스에 필요한 로직에 대한 문제 혹은 처리해야 할 일을 의미합니다.) 이 아키텍처가 작동하도록 만드는 최우선 규칙은 "종속 규칙"입니다. 이 규칙에 따르면 "소스 코드 종속성"은 안쪽만 가리킬 수 있습니다. 내부원의 어떤 것도 외부 원의 어떤 것에 대해 전혀 알 수 없습니다. 특히 외부 원에서 선언된 이름은 내부 원의 코드에서 언급되어서는 안 됩니다. 여기에는 함수, 클래스, 변수 또는 기타 명명된 소프트웨어 엔티티가 포함됩니다. 마찬가지로 외부 원에서 사용되는 데이터 형식은 내부 원에서 사용하면 안 됩니다. 특히 이러한 형식이 외부 원의 프레임워크에서 생성된 경우에는 더욱 그렇습니다. 우리는 외부 원의 어떤 것도 내부 원에 영향을 미치지 않기를 원합니다.

 

엔티티 - Entities

엔티티는 전사적 비즈니스 규칙을 캡슐화합니다. (우선 기업은 여러 애플리케이션과 시스템을 운영한다는 것을 인지합시다. 이러한 맥락에서 "전사적 비즈니스 규칙"이란 기업 전반에 걸쳐, 기업의 모든 애플리케이션에 걸쳐, 적용되는 비즈니스 규칙을 의미합니다. 다시 말해, 특정 부서나 프로젝트, 제품 등에 국한되는 비즈니스 규칙이 아니라, 전체 범위에서 적용되는 규칙을 말합니다. 예를 들어, 회사의 모든 고객은 고유한 식별자를 가지고 있어야 한다는 규칙이 "전사적 비즈니스 규칙"에 해당합니다.) 엔티티는 메서드가 있는 객체이거나 데이터 구조 및 함수 집합일 수 있습니다. 엔티티는 가장 일반적이고 높은 수준의 규칙(전사적 규칙)을 캡슐화한 것이므로 외부의 어떤 것이 변할 때 해당 엔티티도 변할 가능성은 매우 적습니다. (예를 들어, 대한민국 국민은 주민번호를 갖는다는 규칙은 대한민국이라는 국가 내에서 매우 일반적이고 높은 수준의 규칙입니다. 이러한 규칙(주민번호)을 통해 여러 사회 서비스가 작동합니다. 그중 일부 사회 서비스가 변경되거나 폐지된다고 해서 갑자기 대한민국 국민은 주민번호를 갖는다는 규칙이 변경되거나 폐지되지는 않습니다. 이것은 엔티티가 독립적이고 외부의 어떤 것이 변할 때 해당 엔티티도 변할 가능성은 매우 작다는 것을 보여줍니다.)

 

사용 사례 - Use Cases

이 계층의 소프트웨어에는 애플리케이션별 비즈니스 규칙이 포함되어 있습니다. 시스템의 모든 사용 사례를 캡슐화하고 구현합니다. 이러한 사용 사례는 엔티티 간 데이터 흐름을 조율하고 해당 엔티티가 전사적 비즈니스 규칙을 사용하여 사용 사례의 목표를 달성하도록 지시합니다. 앞서 말한 것처럼 이 레이어의 변경 사항이 엔티티에 영향을 미치지 않을 것으로 예상합니다.(엔티티는 사용 사례보다 안쪽에 있는 원이므로.) 또한 이 계층이 데이터베이스, UI 또는 공통 프레임워크와 같은 외부 요소의 변경에 의해 영향을 받지 않을 것으로 예상합니다. 그러나 우리는 응용 프로그램 작동에 대한 변경 사항이 사용 사례와 이 계층의 소프트웨어에 영향을 미칠 것으로 예상합니다. 사용 사례의 세부 사항이 변경되면 이 계층의 일부 코드가 확실히 영향을 받습니다.

 

인터페이스 어댑터 - Interface Adapters

이 계층의 소프트웨어는 사용 사례 및 엔티티에 가장 편리한 형식에서 데이터베이스 또는 웹과 같은 일부 외부 에이전시에 가장 편리한 형식으로 데이터를 변환하는 어댑터 집합입니다. (안(사용 사례, 엔티티)에서 사용하기 좋은 데이터 형식에서 바깥(DB, Web 등)에서 사용하기 좋은 데이터 형식으로 변환하는 것들의 모음을 말하고 있습니다.) 예를 들어 GUI의 MVC 아키텍처를 완전히 포함하는 것은 이 계층입니다. Presenters, Views, Controller가 모두 여기에 속합니다. 모델은 컨트롤러에서 사용 사례로 전달된 다음 사용 사례에서 프리젠터 및 뷰로 다시 전달되는 데이터 구조일 가능성이 높습니다. 마찬가지로 데이터는 이 계층에서 엔티티 및 사용 사례에 가장 편리한 형식에서 사용 중인 지속성 프레임워크에 가장 편리한 형식으로 변환됩니다. 이 계층보다 안에 있는 계층의 코드는 데이터베이스에 대해 전혀 알지 못합니다. 데이터베이스가 SQL 데이터베이스인 경우 모든 SQL은 이 계층, 특히 데이터베이스와 관련이 있는 이 계층의 부분으로, 제한되어야 합니다. (Clean Architecture에서는 외부와의 인터페이스를 추상화하고, 내부적인 비즈니스 로직은 독립적으로 관리하기 위해 의존성 역전 원칙을 따릅니다. 이는 외부의 변경으로부터 내부의 변경을 피하기 위한 것입니다. 같은 논지로, 인터페이스 어댑터 계층은 외부 시스템과의 인터페이스를 담당하며, 외부 시스템에 대한 세부 정보와 의존성을 내부 계층과 분리하기 위해 추상화를 사용합니다. 이렇게 함으로써 인터페이스 어댑터 계층은 내부 비즈니스 로직과 외부 시스템 간의 결합도를 줄입니다. 아래 사진을 참고하세요.)

 

전통적인 레이어 패턴
의존성 역전 패턴

 

프레임워크 및 드라이버 - Frameworkds and Drivers

가장 바깥쪽 레이어는 일반적으로 데이터베이스, 웹 프레임워크 등과 같은 프레임워크와 도구로 구성됩니다. 일반적으로 이 레이어에는 내부의 다음 원과 통신하는 글루 코드 외에 많은 코드를 작성하지 않습니다. 이 레이어는 모든 세부 사항이 있는 곳입니다. 웹은 세부 사항입니다. 데이터베이스도 세부 사항입니다. 우리는 이러한 것들을 다른 것에 최대한 해를 끼치지 못하도록 외부에 보관합니다.

 

모든 경우에 있어 오직 네 개의 원이 전부인가요?

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

 

경계를 넘다.

다이어그램의 오른쪽 하단에는 원 경계를 어떻게 교차하는지에 대한 예가 있습니다. 다음 계층에서 사용 사례와 통신하는 컨트롤러 및 발표자를 보여줍니다. 제어 흐름에 유의하십시오. 컨트롤러에서 시작하여 사용 사례를 통해 이동한 다음 Presenter에서 실행됩니다. 소스 코드 종속성에도 유의하십시오. 그들 각각은 사용 사례를 향해 안쪽을 가리킵니다. 우리는 일반적으로 "종속성 역전 원칙"을 사용하여 이러한 명백한 모순을 해결합니다. 예를 들어 자바와 같은 언어에서는 소스 코드 종속성이 경계를 넘어 올바른 지점에서 제어 흐름에 반대하도록 인터페이스와 상속 관계를 배열합니다. 예를 들어 사용 사례에서 발표자를 호출해야 한다고 가정합시다. 그러나 이 호출은 종속성 규칙을 위반하므로 직접 호출해서는 안 됩니다. 외부 원의 이름은 내부 원에서 언급할 수 없습니다. 따라서 우리는 유스 케이스가 내부 원에서 인터페이스(여기서는 유스 케이스 출력 포트로 표시됨)를 호출하고 외부 원의 발표자가 이를 구현하도록 합니다. 동일한 기술이 아키텍처의 모든 경계를 교차하는 데 사용됩니다. 우리는 동적 다형성을 활용하여 제어 흐름에 반대되는 소스 코드 종속성을 생성하므로 제어 흐름이 어떤 방향으로 진행되든 종속성 규칙을 준수할 수 있습니다.

 

경계를 넘는 데이터

일반적으로 경계를 넘는 데이터는 단순한 데이터 구조입니다. 원하는 경우 기본 구조체 또는 간단한 데이터 전송 객체(Data Transfer Object, DTO)를 사용할 수 있습니다. 또는 데이터는 단순히 함수 호출의 인수일 수 있습니다. 또는 해시맵으로 압축하거나 개체로 구성할 수 있습니다. 중요한 것은 격리되고 단순한 데이터 구조가 경계를 넘어 전달된다는 것입니다. 우리는 엔티티 또는 데이터베이스 행을 속이고 전달하고 싶지 않습니다. 우리는 데이터 구조가 종속성 규칙을 위반하는 어떤 종류의 종속성도 가지기를 원하지 않습니다. 예를 들어 많은 데이터베이스 프레임워크는 쿼리에 대한 응답으로 편리한 데이터 형식을 반환합니다. 이것을 RowStructure라고 부를 수 있습니다. 경계를 넘어 안쪽으로 해당 RowStructure를 전달하고 싶지 않습니다. 이는 내부 원이 외부 원에 대해 알도록 강제하기 때문에 종속성 규칙을 위반하는 것입니다. 따라서 경계를 넘어 데이터를 전달할 때 항상 내부 원에 가장 편리한 형식이어야 합니다.(외부 원이 사용하는 데이터 구조를 내부 원이 알아야 한다는 것은 종속성 규칙을 위반하는 것이므로 항상 데이터를 내부로 보낼 때에는 데이터를 내부 원이 사용하는 데이터 구조로 변환하여 보내야 한다는 말입니다.)

 

결론

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

 

 

 

 

 


https://en.wikipedia.org/wiki/Dependency_inversion_principle

 

Dependency inversion principle - Wikipedia

From Wikipedia, the free encyclopedia Software programming object-oriented design methodology In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software modules. When following this principle, the

en.wikipedia.org

'프로그래밍 기초' 카테고리의 다른 글

깃허브 액션  (2) 2023.05.15
CI/CD  (2) 2023.05.14
int와 Integer의 차이  (0) 2022.11.05
커플링(coupling), 디커플링(decoupling) - 번역  (0) 2022.10.22
의존성 주입(dependency injection) - 번역  (0) 2022.10.22