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