byungil
21장. 소리치는 아키텍처
아키텍처의 테마
소프트웨어 애플리케이션의 아키텍처는 유스케이스에 대해 소리쳐야 함
아키텍처는 프레임워크에 대한 것이 아니며, 프레임워크는 사용하는 도구일 뿐임
아키텍처를 프레임워크 중심으로 만들어버리면, 유스케이스가 중심이 되는 아키텍처는 절대 나올 수 없음
아키텍처의 목적
좋은 아키텍처는 유스케이스가 중심이므로, 프레임워크나 도구 등에 전혀 구애받지 않고 유스케이스를 지원하는 구조를 가짐
좋은 아키텍처는 프레임워크, 데이터베이스, 웹 서버, 여타 개발 환경 문제나 도구에 대한 결정을 미룰 수 있음
좋은 아키텍처는 프로젝트의 훨씬 후반까지 결정을 하지 않아도 되도록 도와줄 뿐만 아니라 결정을 쉽게 번복할 수 있음
좋은 아키텍처는 유스케이스에 중점을 두며, 지엽적인 관심사에 대한 결합은 분리시킴
프레임워크는 도구일 뿐, 삶의 방식이 아니다.
프레임워크는 매우 강력하고, 상당히 유용할 수 있음으며, 누군가는 “프레임워크가 모든 것을 하게 하자”라는 태도를 취함
하지만 이는 우리가 취하고 싶은 태도가 아님
우리는 어떻게 하면 아키텍처를 유스케이스에 중점을 둔 채 그대로 보존할 수 있을지를 생각해야 함
테스트하기 쉬운 아키텍처
아키텍처가 유스케이스를 최우선으로 한다면, 프레임워크 없이도 필요한 유스케이스 전부를 단위 테스트 할 수 있어야 함
테스트를 돌리는데 반드시 웹서버나 데이터베이스가 필요한 상황이어서는 안됨
엔티티는 반드시 POJO여야 하며, 프레임워크나 데이터베이스 및 다른 것들에 의존해서는 안되고 유스케이스가 엔티티를 조작해야 함
최종적으로 프레임워크로 인한 어려움을 겪지 않고도 반드시 이 모두를 있는 그대로 테스트할 수 있어야 함
22장. 클린 아키텍처
프레임워크 독립성
테스트 용이성
UI 독립성
데이터베이스 독립성
외부 에이전시에 대한 독립성
의존성 규칙
각각의 동심원은 서로 다른 영역이며, 안으로 들어갈수록 고수준의 소프트웨어가 됨
이러한 아키텍처가 동작하도록 하는 가장 중요한 것은 의존성 규칙임
바깥은 메커니즘 안은 정책인데, “소스 코드 의존성은 반드시 안쪽으로, 고수준의 정책을 향해야 한다." 임
우리는 외부 원에 위치한 어떤 것도 내부의 원에 영향을 주지 않기를 바람
내부의 원에 속한 요소는 외부의 원에 속한 어떤 것(함수, 클래스, 변수 등의 모든 소프트웨어 엔티티)도 알지 못함
엔티티
운영 관점에서 특정 애플리케이션에 무언가 변경이 필요하더라도 엔티티에는 절대로 영향을 주면 안됨
ex) 엔티티는 핵심 비즈니스 로직을 다루므로, UI 단의 페이징 처리 등이 필요해도 변경이 일어나서는 안됨
유스케이스
유스케이스의 변경이 엔티티에 영향을 주면 안되며, 외부 요소의 변경이 이 계층에 영향을 주는 것도 안됨
하지만 운영 관점에서 애플리케이션이 변경된다면 유스케이스가 영향을 받고, 유스케이스 세부사항이 변하면 일부 코드는 영향을 받음
인터페이스 어댑터
프레젠터나 컨트롤러 등과 같은 어댑터들로 구성되며, 컨트롤러에서 유스케이스로 전달된 요청은 다시 컨트롤러로 되돌아 감
어댑터는 유스케이스와 엔티티에 맞는 데이터에서 DB나 웹 등과 같은 외부 요소에 맞는 데이터로 변환함
또한 데이터를 외부 서비스에 맞는 형식에서 유스케이스나 엔티티에서 사용되는 내부적인 형식으로 변환하는 또 다른 어댑터가 필요함
프레임워크와 드라이버
모든 세부사항이 위치하는 곳으로, 웹과 데이터베이스도 세부사항이므로 이를 외부에 위치시켜 피해를 최소화함
경계를 횡단하는 데이터는 어떤 모습인가?
데이터 구조가 어떤 의존성을 가져 의존성 규칙을 위배되게 하는 일은 원치 않음
따라서 경계를 가로 질러 데이터를 전달할 때, 데이터는 항상 내부의 원에서 사용하기에 가장 편리한 형태여야 함
23장. 프레젠터와 험블 객체
험블 객체 패턴
험블 객체 패턴은 디자인 패턴으로, 테스트하기 어려운 행위와 쉬운 행위를 단위 테스트 작성자가 쉽게 분리하는 방법으로 고안됨
험블 객체 패턴은 행위들을 두 개의 모듈 또는 클래스로 나누는데, 이 중 하나가 험블임
기본적인 본질은 남기고, 테스트하기 어려운 행위를 모두 험블 객체로 옮김
나머지 모듈에는 험블 객체에 속하지 않은, 테스트하기 쉬운 행위를 모두 옮김
프레젠터와 뷰
뷰
험블 객체이며, 테스트하기 어려움
프레젠터
애플리케이션으로부터 데이터를 받아 화면에 표현할 수 있는 포맷으로 만드는 것
이를 통해 뷰는 데이터를 화면으로 전달하는 간단한 일만 처리하도록 만듬
테스트와 아키텍처
테스트 용이성은 좋은 아키텍처가 지녀야 할 속성으로 오랫동안 알려짐
험블 객체 패턴이 좋은 예인데, 테스트하기 쉬운 부분과 어려운 부분으로 분리하면 아키텍처가 정의되기 때문임
프레젠터와 뷰는 이러한 경계 중 하나이며, 이 밖에도 수 많은 경계가 존재함
24장. 부분적 경계
아키텍처 경계를 완벽하게 만드는 데는 비용이 많이 들며, 유지하는데도 엄청난 노력이 필요함
쌍방향의 다형적 Boundary 인터페이스
Input/Output 데이터구조
두 영역을 독립적으로 컴파일하고 배포할 수 있는 컴포넌트로 격리하는데 필요한 모든 의존성 관리
마지막 단계를 건너뛰기: 독립적으로 컴파일 및 배포 가능한 컴포넌트로 만들고, 단일 컴포넌트에 그대로 모아둠
일차원 경계: 양방향 Boundary 인터페이스가 아닌 한방향만 경계를 인터페이스로 격리함
파사드: Facade 클래스에 모든 서비스 클래스를 메소드 형태로 정의하고, 호출이 발생하면 해당 서비스 클래스로 전달함
25장. 계층과 경계
시스템이 3가지 컴포넌트(UI, 업무 규칙, DB)로만 구성된다고 생각하기 쉬움
몇몇 단순한 시스템에서는 이 정도로 충분하지만, 대다수의 시스템에서 컴포넌트는 이보다 많음
아키텍처 경계는 어디에나 존재하며, 아키텍처 경계가 언제 필요한지를 신중하게 파악해내야 함
이러한 경계를 제대로 구현하려면 비용이 많이 든다는 사실도 인지하고 있어야 함
동시에 이러한 경계가 무시되었다면 나중에 다시 추가하는 비용이 크다는 사실도 알아야 함
매우 똑똑한 일부 사람들이 수년 동안 말해왔듯이, 추상화가 필요하리라고 미리 예측해서는 안됨(YAGNI)
YAGNI(You Aren’t Going to Need It)에는 지혜가 담겨 있는데, 오버 엔지니어링이 언더 엔지니어링보다 나쁠때가 훨씬 많음
반대로 어떤 아키텍처 경계도 존재하지 않는 상황에서 경계가 정말로 필요하다는 사실을 발견할 수 있음
하지만 그때서야 경계를 추가하려면 비용이 많이 들고 큰 위험을 감수해야 함
그러므로 소프트웨어 아키텍트는 미래를 내다보고 현명하게 추측해야 함
26장. 메인 컴포넌트
모든 시스템에는 최소한 하나의 컴포넌트가 존재하고, 이 컴포넌트가 나머지 컴포넌트를 생성하고 조정하며 관리함
이 컴포넌트를 메인 컴포넌트(Main)이라고 부름
궁극적인 세부사항
메인 컴포넌트는 궁극적인 세부사항으로, 가장 낮은 수준의 정책임
메인은 시스템의 초기 지입점으로, 운영체제를 제외하면 어떤 것도 메인에 의존하지 않음
메인은 모든 팩토리와 전략 및 나머지 기반 설비를 생성한 후, 시스템에서 더 높은 수준을 담당하는 부분으로 제어권을 넘김
의존성 주입 프레임워크를 이용해 의존성을 주입하는 일은 바로 이 메인 컴포넌트에서 이뤄져야 함
메인은 고수준의 시스템을 위한 모든 것을 로드한 후, 제어권을 고수준의 시스템에게 넘김
결론
메인은 초기 조건과 설정을 구성하고, 외부 자원을 모두 수집한 후 제어권을 애플리케이션의 고수준 정책으로 넘기는 플러그인임
메인은 플러그인이므로 메인 컴포넌트를 애플리케이션의 설정 별로 하나씩 둬서 둘 이상의 메인 컴포넌트를 만들 수도 있음
메인을 플러그인 컴포넌트로 여기고 아키텍처 경계 바깥에 위치한다고 보면, 설정 관련 문제를 훨씬 쉽게 해결할 수 있음
Last updated