byungil
30장. 데이터베이스는 세부사항이다.
관계형 데이터베이스
관계형 데이터베이스는 데이터를 저장하고 접근하는데 탁월한 기술이지만 결국 그저 기술일 뿐이며, 세부사항임을 뜻함
데이터를 테이블에 행 단위로 배치한다는 자체는 아키텍처적으로 전혀 중요하지 않음
유스케이스는 이러한 방식을 알아서는 안되며 관여해서도 안됨
데이터가 테이블 구조를 가진다는 사실은 오직 아키텍처의 외부 원에 위치한 최하위 수준의 유틸리티 함수만 알아야 함
하지만 성능은?
성능은 당연히 아키텍처적인 관심사이지만, 데이터 저장소의 측면에서는 완전히 캡슐화하여 업무 규칙과 분리할 수 있는 관심사
데이터 저장소에서 데이터를 빠르게 넣고 뺄 수 있어야 하는 것은 맞지만, 이는 저수준의 관심사
이는 저수준의 데이터 접근 메커니즘 단에서 다룰 수 있고, 성능은 전반적인 아키텍처와는 아무런 관련이 없다
결론
체계화된 데이터 구조와 데이터 모델은 아키텍처적으로 중요함
하지만 데이터를 회전식 자기 디스크 표면에서 이리저리 옮길 뿐인 기술과 시스템(데이터베이스)은 아키텍처적으로 중요하지 않음
데이터를 테이블 구조로 만들고, SQL로만 접근하도록 하는 관계형 데이터베이스 시스템은 전자보다는 후자에 훨씬 가까움
데이터는 중요하지만 데이터베이스는 세부사항임
31장. 웹은 세부사항이다.
웹은 입출력장치이자 GUI이며 GUI는 세부사항이므로, 이를 핵심 업무 로직에서 분리된 경계 바깥에 두어야 함
UI와 애플리케이션 사이에는 추상화가 가능한 또 다른 경계가 존재함
비즈니스 로직은 다수의 유스케이스로 구성되며, 각 유스케이스는 사용자를 대신해서 일부 함수를 수행하는 것으로 볼 수 있음
각 유스케이스는 입력 데이터, 수행할 처리 과정, 출력 데이터를 기반으로 기술할 수 있음
32장. 프레임워크는 세부사항이다.
혼인 관계의 비대칭성
우리는 프레임워크를 위해 대단히 큰 헌신을 해야 하지만, 프레임워크 제작자는 우리를 위해 아무런 헌신도 하지 않음
프레임워크를 사용할 경우 우리는 프레임워크 제작자가 제공하는 문서를 꼼꼼히 읽음
이 문서에서는 우리가 만들 소프트웨어와 프레임워크를 어떻게 통합할 수 있을지 조언함
대개의 경우 이들은 프레임워크를 중심에 두고, 우리의 아키텍처는 그 바깥을 감싸야 한다고 말함
프레임워크 제작자는 당신의 애플리케이션이 가능하면 프레임워크에 공고하게 결합될 것을 강하게 역설함
프레임워크 제작자 입장에서는 프레임워크에 대해 절대적인 제어권을 쥐고 있으므로 오히려 결합되기를 바람
한번 결합하면 그 관계를 깨기가 매우 어렵기 때문이며, 이러한 관계는 일방적임
해결책
프레임워크를 사용할 수 있지만 프레임워크와 결합해서는 안되고, 적당히 거리를 둬야 함
프레임워크가 자신의 클래스로부터 파생을 요구한다면 프록시를 만들고, 업무 규칙에 플러그인할 수 있는 컴포넌트에 위치시켜야 함
프레임워크를 아키텍처의 바깥쪽 원에 속하는 세부사항으로 취급하고 아키텍처의 안쪽 원으로 들어오지 못하게 해야 함
핵심 코드에 플러그인 할 수 있는 컴포넌트에 프레임워크를 통합하고, 의존성 규칙을 준수해야 함
스프링은 훌륭한 의존성 주입 프레임워크이지만 ,업무 객체는 @Autowired 등을 포함해 절대로 스프링에 대해 알아서는 안됨
33장. 사례 연구: 비디오 판매
예시로 살펴볼 제품은 웹사이트에 비디오를 판매하는 소프트웨어로, 비디오들을 개인과 기업에게 웹으로 판매함
개인은 단품 가격을 지불해 스트리밍으로 보거나, 더 높은 가격을 내고 비디오를 다운로드해서 영구소장할 수 있음
기업용 라이센스는 스트리밍 전용이며, 대량 구매를 하면 할인을 받을 수 있음
일반적으로 개인은 시청자인 동시에 구매자이지만, 기업은 비디오를 구매하는 사람이 따로 있음
비디오 제작자는 비디오 파일과 비디오 해법에 대한 설명서, 부속 파일(시험, 문제, 해법, 소스 코드 등)을 제공해야 함
관리자는 신규비디오 시리즈물을 추가하거나 기존 시리즈물에 비디오를 추가/ 삭제하며, 다양한 라이센스에 맞춰 가격을 책정함
시스템의 초기 아키텍처를 결정하는 첫 단계는 액터와 유스케이스를 식별하는 일임
유스케이스 분석
4개의 주요 액터는 시스템이 변경되어야 할 네 가지 주요 근원임
신규 기능을 추가하거나 기존 기능을 변경해야 한다면, 그 이유는 반드시 이들 액터 중 하나에게 기능을 제공하기 위함임
따라서 시스템을 분할하여, 특정 액터를 위한 변경이 나머지 액터에게는 전혀 영향을 미치지 않게 만들어야 함
중앙의 점선으로 된 유스케이스는 추상 유스케이스임
추상 유스케이스는 범용적인 정책을 담고 있으며 다른 유스케이스에서 이를 더 구체화함
시청자 입장의 카탈로그 조회하기와 구매자 입장의 카탈로그 조회하기는 모두 추상 유스케이스를 상속받음
이는 꼭 생성해야만 했던 것은 아니며, 이를 다이어그램에서 없애더라도 전체 제품의 기능을 조금도 손상시키지 않음
그러나 이들은 너무 비슷하기 때문에, 유사성을 식별해서 분석 초기에 통합하는 방법을 찾는 편이 더 현명하다고 판단했음
컴포너틑 아키텍처
터와 유스케이스를 식별했으므로, 예비 단계의 컴포넌트 아키텍처를 만들어볼 수 있음
늘 그렇듯이 이중으로 된 선은 아키텍처 경계를 나타냄
뷰, 프레젠터, 인터랙터, 컨트롤러로 분리된 전형적인 분할 방법을 확인할 수 있음
또한 대응하는 액터에 따라 카테고리를 분리했다는 사실도 확인할 수 있음
각 컴포넌트는 단일 jar 파일에 해당한며, 이들 컴포넌트는 자신에게 할당된 뷰, 프레젠터, 인터랙터, 컨트롤러를 포함함
CatalogView와 Catalog Presenter는 특수한 컴포넌트임
이는 카탈로그 조회하기라는 추상 유스케이스를 처리하는 나만의(로버트 마틴 만의) 방식임
이 뷰와 프레젠터는 해당 컴포넌트 내부에 추상 클래스로 코드화 될 것임
그리고 상속받는 컴포넌트에서는 이들 추상 클래스로부터 상속받은 뷰와 프레젠터 클래스들을 포함함
시스템을 여러 컴포넌트로 분할해서 여러 개의 .jar로 전달해야 할까?
이는 그럴수도 있고 아닐수도 있음
대신 컴파일과 빌드 환경은 분명히 이 형태로 나눌 것이며, 컴포넌트를 독립적으로 전달할 수 있게 빌드하는 것도 가능할 것임
또한 전달해야 할 이 모든 단위를 더 적은 개수로 합칠 수 있는 권한도 가지고 있다.
선택지를 열어두면, 후에 시스템이 변경되는 양상에 맞춰 배포 방식을 조정할 수 있음
34장. 빠져있는 장
계층 기반 패키지
가장 단순한 첫 번째 설계 방식은 전통적인 수평 계층형 아키텍처임
기술적인 관점에서 해당 코드가 하는 일에 기반해 코드를 분할하며, 이를 계층 기반 패키지라고 함
전형적인 계층형 아키텍처에는 웹, 업무 규칙, 영속성 코드를 위한 계층이 하나씩 존재함
기능 기반 패키지
기능 기반 패키지 구조는 연관된 기능, 도메인 개념 또는 에그리거트 루트에 기반하여 수직의 얇은 조각으로 코드를 나누는 방식임
전형적으로 모든 타입이 하나의 자바 패키지에 속하며, 패키지 이름은 그 안에 담긴 개념을 반영해서 지음
포트와 어댑터
코드 베이스는 내부(도메인)와 외부(인프라)로 구성됨을 흔히 볼 수 있음
내부는 도메인 개념을 모두 포함하는 반면, 외부는 외부 세계(UI, DB 등)와의 상호작용을 포함함
여기서 핵심 규칙은 바로 외부가 내부에 의존하며, 절대로 그 반대로는 안된다는 점임
컴포넌트 기반 패키지
계층형 아키텍처의 목적은 기능이 같은 코드끼리 분리하는 것으로 웹은 업무 로직으로부터, 업무 로직은 데이터 접근으로부터 분리함
엄격한 계층형 아키텍처에서는 의존성 화살표가 항상 아래로 향해야 하며, 각 계층은 반드시 아래 계층에만 의존해야 함
하지만 의도치 않은 방식으로 의존성을 추가하더라도, 잘못되었지만 보기에는 여전히 좋은 비순환 의존성 그래프가 생성됨
예를 들어 OrdersController에서 OrdersRepositry를 주입하여 코드가 동작하도록 만든 결과는 다음과 같음
결론
이 장은 최적의 설계를 꾀했더라도, 구현 전략에 얽힌 복잡함을 고려하지 않으면 설계가 순식간에 망가질 수도 있음을 강조함
설계를 어떻게 해야만 원하는 코드 구조로 매핑할 수 있을지, 그 코드를 어떻게 조직화할지 고민해야 함
또한 런타임과 컴파일타임에 어떤 결합분리 모드를 적용할지를 고민해야 함
가능한 선택사항을 열어두되 실용주의적으로 행하고, 팀의 규모와 기술 수준, 해결책의 복잡성을 제약(일정과 예산)과 고려해야 함
또한 선택된 아키텍처 스타일을 강제하는데 컴파일러의 도움을 받을 수 있을지를 고민해야 함
그리고 데이터 모델과 같은 다른 영역에 결합되지 않도록 주의해야 하는데, 구현 세부사항에는 항상 문제가 있는 법임
Last updated