메인 컴포넌트는 모든 시스템에 최소한 하나 이상 존재하고, 다른 나머지 컴포넌트를 생성하고 조종하고 관리하는 역할을 한다. 궁극적인 세부사항 메인 컴포넌트는 궁극적인 세부사항으로, 가장 낮은 수준의 정책이다. 메인 컴포넌트는 시스템의 진입점으로 어떤 것도 메인 컴포넌트에 의존하지 않는다. 메인 컴포넌트는 시스템 전반을 담당하는 기반 설비를 생성하고 시스템에서 더 높은 수준을 담당하는 부분으로 제어권을 넘기는 역할을 한다. 주로 의존성 주입 프레임워크를 이용해 의존성을 주입하는 역할을 하고, 클린 아키텍처에서 가장 바깥쪽에 위치하는 컴포넌트로, 가장 지저분한 컴포넌트라고 생각하면 좋다. 결론 메인 컴포넌트는 애플리케이션의 플러그인이라고 생각하고 설계하면 된다. 언제든지 갈아끼우던가, 새롭게 만들 수 있는 ..
CleanArchitecture
시스템은 주로 UI, 비즈니스 로직, 데이터베이스 세 가지 컴포넌트로 구성된다고 생각할 수 있지만, 대개 더 많은 컴포넌트로 구성될 수 있다. 마지막에 말하지만 쪼개려면 얼마든지 더 작은 컴포넌트들로 분리할 수 있다. 움퍼스 사냥 게임 움퍼스 사냥 게임은 간단히 GO EAST 와 SHOOT WEST 같은 명령어를 사용한다. 플레이어는 명령어를 입력하고, 컴퓨터는 명령어 기반으로 동작을 수행한다. 만약 영어로 되어 있는 현재 상태에서 한글 서비스를 추가하고 싶을 경우 어떻게 만들어야 할지 상상해보자. 명령을 내리는 부분과 게임을 구분하여 영어 UI, 한글 UI 에서 게임을 사용하면 된다. 추가로 기존에 메모리에 저장했던 것을 클라우드에 저장하고 싶은 요건이 생겼다면 클라우드 데이터가 게임을 호출하도록 하면..
아키텍처 경계를 분리하는 데는 비용이 많이 든다. 독립적으로 컴파일하고 배포할 수 있는 컴포넌트를 만들고 관리하기 위해서는 의존성 관리가 필수인데 많은 노력이 들어간다. 애자일 커뮤니티에 속한 사람 중 많은 사람들은 YAGNI 원칙에 위배된다고 말하며 경계를 만드는 것에 반대하기도 하지만, 아키텍처는 부분적 경계가 어쩌면 필요할지도 모른다고 생각한다. 마지막 단계를 건너뛰기 소스코드 레벨에서 모두 분리를 하지만, 컴포넌트를 분리하지 않으면 동시에 컴파일하고 배포할 수 있다. 하지만 완전히 독립되지 않은 형태이므로 의존성이 잘못된 방향으로 선을 넘을 가능성이 크다. 일차원 경계 인터페이스와 구현체를 분리해 일차원 경계를 만드는 것이다. Controller(C) -> Service(I)
22장에서 다룬 클린 아키텍처는 험블 객체 구현체들로 가득 차 있다. 험블 객체 패턴 험블 객체 패턴은 디자인 패턴으로 테스트하기 어려운 행위와 테스트하기 쉬운 행위를 단위 테스트 작성자가 분리하기 쉽게 하는 방법으로 고안되었다. 행위들을 테스트하기 쉬운 것은 남기고 테스트하기 어려운 것들을 모두 험블 객체로 옮긴다. GUI의 경우 각 요소가 필요한 위치에 위치하는 것은 테스트하기 어렵기 때문에 이를 Humble object 로 옮기고 쉽게 테스트할 수 있는 것만 뷰에 남기면 Humble object 는 뷰, 나머지는 프레젠터가 된다. 프레젠터와 뷰 뷰는 험블 객체이고 테스트하기 어렵다. 이 객체에 포함된 코드는 가능한 간단하게 유지한다. 뷰는 데이터를 GUI로 이동시키고 데이터를 직접 처리하지는 않는다..
육각형 아키텍처 포트와 어댑터라고도 알려져 있는 아키텍처로 외부에서 내부로 의존성이 향하고 각 계층에는 포트와 어댑터가 존재함 DCI: Data, Context and Interaction BCE: Boundary-Control-Entity 세 개의 아키텍처 모두 세부적인 면에서는 차이가 있어도 이들 모두의 목표는 관심사의 분리이다. 세 아키텍처 모두 소프트웨어를 계층으로 분리해 관심사 분리의 목표를 달성한다. 아키텍처의 목표 프레임워크 독립성 테스트 용이성 UI 독립성 데이터베이스 독립성 모든 외부 에이전시에 대한 독립성 의존성 규칙 모든 의존성은 프레임워크와 드라이버 -> 인터페이스 어댑터 -> 애플리케이션 업무 규칙 (유스케이스) -> 엔터프라이즈 업무 규칙 (엔티티) 방향을 따라야 한다. 엔티티 ..
우리가 만드는 아키텍처는 우리가 무엇인지 소리쳐야 한다. 소리쳐야 하는 부분은 디렉터리 구조, 패키지에 담긴 소스파일이다. 그것이 무엇이라고 소리치는지 보자. 나는 헬스 케어 시스템이야 또는 재고 관리 시스템이야 라고 소리친다면 올바른 아키텍처지만, 만약 나는 스프링이야, 나는 ASP야 라고 소리친다면 이를 수정하는게 좋다. 아키텍처의 테마 애플리케이션 아키텍처는 유스케이스에 대해 소리쳐야 한다. 프레임워크에 대해 소리치고 있다면 유스케이스에 대해 소리치도록 바꿔보자. 프레임워크는 우리를 돕는 주체이지 우리가 맞춰야 하는 주체가 아니다. 아키텍처의 목적 좋은 아키텍처는 유스케이스를 그 중심에 두기 때문에, 프레임워크나 도구, 환경에 전혀 구애받지 않고 유스케이스를 지원하는 구조를 아무런 문제 없이 기술할..
업무 규칙은 수익을 얻거나 비용을 줄일 수 있는 규칙이다. 이는 컴퓨터로 구현됐을 수도 있고, 사람이 수동으로 하는 작업들이 될 수도 있다. 예를 들어 은행에서 대출에 N%의 이자를 붙인다는 것은 사람이 하던, 컴퓨터가 하던 업무 규칙이다. 대출에 이자를 붙인다는 것을 핵심 업무 규칙이라고 하고, 이러한 핵심 업무 규칙에는 대출 잔액, 이자율, 지급 일정과 같은 핵심 업무 데이터가 필요하다. 핵심 업무 규칙과 핵심 업무 데이터를 객체로 만든 것이 엔티티다. 엔티티 엔티티는 컴퓨터 시스템 내부 객체로 핵심 업무 데이터를 기반으로 동작하는 핵심 업무 규칙을 구체화한다. 엔티티의 인터페이스는 핵심 업무 데이터를 기반으로 동작하는 핵심 업무 규칙을 구현한 함수로 구성된다. 엔티티는 입출력 장치 등과 같은 외부 ..
좋은 시스템일수록 저수준 컴포넌트가 고수준 컴포넌트에 의존하도록 설계되어 있다. 수준 수준은 입력과 출력까지의 거리이다. 시스템의 입력과 출력과의 거리가 멀어질수록 정책의 수준은 높아진다. 입력과 출력을 다루는 정책은 시스템의 최하위 수준에 위치해야 한다. 따라서 고수준의 정책(비즈니스 로직)이 입출력 시스템에 영향을 받게 되어 있다면 잘못 설계된 경우일 가능성이 크다. 아래의 코드가 그렇다. function encrypt() { while (true) { writeChar(translate(readChar())); } } 고수준의 encrypt 함수가 저수준(입력과 출력을 담당하는)의 writeChar 와 readChar 에 의존성을 가지고 있다. 이러한 경우 입출력 시스템의 정책에 변화가 생긴다면 e..
시스템 아키텍처는 일련의 소프트웨어 컴포넌트와 그 컴포넌트들을 분리하는 경계에 의해 정의된다. 경계 횡단하기 '런타임에 경계를 횡단한다' 는 뜻은 경계 한쪽에 있는 기능이 반대편의 기능을 호출하는 것이다. 적절하게 경계를 횡단하는 방법은 소스코드 의존성 관리이다. 두꺼운 단일체 모놀리틱 구조에서는 대부분 다형성에 의존해 내부 의존성을 관리한다. 따라서 특히 객체 지향 패러다임이 중요해진다. 가장 단순한 형태의 경계 횡단은 저수준 클라이언트에서 고수준 서비스로 향하는 함수 호출이다. 이 경우 런타임 의존성과 컴파일 의존성 모두 저수준 컴포넌트에서 고수준 컴포넌트로 향한다. 배포형 컴포넌트 아키텍처의 경계가 물리적으로 드러나는 경우 배포형 컴포넌트다. 배포형 컴포넌트는 별도의 실행 파일이 존재해 배포 과정에..
소프트웨어 아키텍처는 선을 긋는 기술이다. 이 선은 소프트웨어를 분리하고 이 선을 사이에 두고 한 쪽은 다른 쪽을 알지 못한다(반대는 알 수 있다). 결합을 줄이고 일찍 결정하지 않아도 되는 요소들을 나중으로 미루는 것이 선 긋기의 목표다. 어떻게 선을 그을까? 그리고 언제 그을까? 관련이 있는 것과 없는 것 사이에 선을 긋는다. GUI 와 비즈니스 로직은 관련이 없기 때문에 GUI 와 비즈니스 로직 사이에는 선이 그어져야 한다. 그리고 비즈니스 로직과 DB 사이에도 선이 그어져야 한다. 어떤 DB 를 사용하더라도 비즈니스 규칙이 그에 따라 변화되어서는 안된다. 이렇게 정하고 보면 인터페이스가 어떤 계층에 있어야 하는지 알게 된다. 기본적으로 스프링 컨트롤러 - 서비스 - 레포지토리 구조에서 DB 인터페..