상세 컨텐츠

본문 제목

[Architecture] 5부 아키텍처 : 17장 경계 - 선 긋기

프로그래밍/Architecture

by jisooo 2024. 1. 14. 17:45

본문

 

 

소프트웨어 아키텍처에서 경계란?

소프트웨어 아키텍처는 "선을 긋는 기술", 즉 경계의 기술이다.

경계는 소프트웨어 요소를 서로 분리하고,

경계 한편에 있는 요소가 반대편에 있는 요소를 알지 못하도록 막는다.

프로젝트 초기에 그어지는 이 경계선은 가능한 한 오랫동안 결정을 연기시키기 위해,

그래서 이들 결정이 핵심적인 업무 로직을 오염시키지 못하게 만들려는 목적으로 쓰인다.

아키텍트의 목표는 필요한 시스템을 만들고 유지하는 데 드는

인적 자원을 최소화하는 것이 최족 목표라는 사실을 상기해야 한다.

프로그래밍 실무를 담당하면서 가장 위의 목표에서 경계하게 되는 것은

바로 컴포넌트 간의 결합이다.

(특히 너무 일찍 내려진 결정에 따른 결합)

이 결정은 시스템의 업무 요구사항, 유스케이스와 아무런 관련이 없는 "결정"이다.

앞 장에서 계속 강조했던 업무 규칙과 상반되는 개념의 "세부사항"에 대한 내용이다.

프레임워크, 데이터베이스, 웹 서버, 유틸리티 라이브러리, 의존성 주입에 대한 결정 등이 여기에 포함된다.

좋은 아키텍처란 이러한 세부사항들에 대한 결정은 부수적이며, 결정을 연기할 수 있는 아키텍처이다.

좋은 시스텐 아키텍처는 이러한 세부사항의 결정에 의존하지 않는다.

좋은 시스템 아키텍처는 이러한 결정을 가능한 한 최후의 순간에 내릴 수 있게 해주며,

결정에 따른 영향이 크지 않게 만든다.


결정에 대한 비극과 희극

책에서는 이러한 세부사항에 대한 빠른 결정으로 인한 비극을 겪은 사례와,

세부사항에 대한 결정을 최대한 늦춤으로써 성공한 사례를 대비하여 설명한다.

비극에 대한 사례는, 3티어로 구성된 리치 아키텍처를 선택하여

GUI를 위한 서버, 미들웨어 서버, 데이터베이스 서버를 구성하여

모든 도메인 객체가 세 가지 인스턴스를 가져야한다는 빠른 결정을 내렸다.

이들 인스턴스는 서로 다른 머시에 상주했기 때문에,

프로세스 간 그리고 티어 간 통신이 필요했고, 결국 리치 시스템이 구성되었다.

이상황에서 기존 레코드에 대해 필드를 추가해야하거나, 간단한 기능 추가와 같은 변경사항이 향후 발생했을 때

발생할 수 있는 수많은 부작용들을 나열한다.

추가되는 필드는 세 티어에 있는 클래스 모두와 티어간 메시지 다수에 추가해야 하고..

메시지 프로토콜은 네 개를 설계해야 하고..

간단한 기능을 수행하기 위해 위 세개의 서버가 실행 파일들이 해야하는 일을 나열해본다.

모든 객체의 초기화, 직렬화, 마샬링과 언마샬링, 메시지에 대한 구성 및 파싱,

소켓 통신들, 타임아웃 관리, 재시도 시나리오 등등.......

이러한 비극은 아키텍트가 너무 이르게 결정을 내림으로써

추후 변경에 대한 개발 비용을 엄청나게 가중시킨 사례이다.

반면 이러한 세부사항의 결정을 최대한 미룸으로써 성공한 케이스도 함께 설명한다.

FitNesse를 만들기 위해 저자는, FitNesse의 요구에 특화된 그들만의 웹서버를 직접 작성했다.

기본 뼈대만 갖춘 웹 서버는 단순한 단일 소프트웨어이기에

구현이 간단할 뿐만 아니라,

어떤 웹 프레임워크를 사용할지에 대한 결정을

훨씬 나중으로 연기할 수 있또록 해주었기 때문이다.

또한 초기에 데이터베이스에 대한 결정을 최대한 미루도록 하였다.

소프트웨어에서 어떤 데이터베이스를 사용하더라도 상관없는 형태로 설계함으로써

의도적으로 데이터베이스에 대한 결정을 미루었다.

모든 데이터 접근 영역과 데이터 저장소 영역 사이에 인터페이스를 추가하여

느슨한 결합을 하도록 하는 간단한 설계방식을 사용했다.

FitNesse 개발 초기에 그들은

업무 규칙과 데이터베이스 사이에 경계선을 그었다.

경계선을 통해 업무 규칙은 데이터 접근 메서드 외에는 데이터베이스에 관해서 어떤 것도 알지 못하게 되었다.

그를 통해 일년이 훨 넘는 기간 동안 데이터베이스를 선택하고 구현하는 일을 연기할 수 있었다.

이 결정으로 그들은 파일 시스템을 선택하여 시도해볼 수 도 있었고,

더 나은 해결책이 보이면 방향을 바꿀 수도 있었다.

이렇게 컴포넌트 간 경계선을 긋는 행위는

결정을 늦추고 연기하는 데 도움이 되었고,

궁극적으로는 시간을 엄청나게 절약해주었다.


어떻게, 언제 경계선을 그을까?

GUI는 업무 규칙과 관련 없으므로 이 사이에 경계선이 필요하다.

데이터베이스와 업무 규칙, 데이터베이스와 GUI 역시 관련이 없으므로

이들 사이에 경계선이 필요하다.

데이터베이스는 업무 규칙이 간접적으로 사용할 수 있는 도구다.

업무 규칙은 스키마, 쿼리언어, 또는 데이터베이스와 관련된 나머지 세부사항에 대해

어떤 것도 알아서는 안된다.

업무 규칙이 알아야 할 것은

단지 데이터를 가져오고 저장할 대 사용할 수 있는 함수 집합이 있다는 사실이 전부이다.

이러한 함수 집합을 통해서 우리는 데이터베이스를 인터페이스 뒤로 숨길 수 있다.

위 도표에서 클래스와 인터페이스를 눈여겨보자.

실제 애플리케이션에서는 업무 규칙과 관련된 수많은 클래스들이 존재하고,

데이터베이스 인터페이스와 관련된 수많은 클래스들,

그리고 데이터베이스 접근을 구현한 수많은 구현체가 존재한다.

그렇더라도 모두는 이 패턴을 거의 동일하게 따른다.

 

경계선은 상속 관계를 횡단하면서 Database Interface 바로 아래에 그어진다.

Database Access에서 출발하는 두 화살표의 방향을 주목하자.

이들 두 화살표는 DatabaseAccess 클래스로부터 바깥쪽으로 향하고 있다.

이 도표에서 DatabaseAccess가 존재한다는 사실을 알고 있는 클래스는 없다.

17.3 도표는 이를 좀더 거시적인 관점에서 보여준다.

많은 업무 규칙이 포함된 컴포넌트(Business Rule)은 Database의 존재를 알지 않는다.

반면 Database는 Business Rule를 향해 화살표를 뻗어 있으므로 Business Rule에 대해 알고 있다.

이는 DatabaseInterface 클래스는 BusinessRules 컴포넌트에 속하며,

DatabaseAccess 클래스는 Database 컴포넌트에 속한다는 사실을 의미한다.

위 도표에서 화살표의 방향을 다시 한번 강조한다.

BusinessRule에 있어 Database는 문제가 되지 않지만,

Database는 BusinessRules 없이는 존재할 수 없다는 사실을 이 방향을 통해 알 수 있따.

BusinessRule에서는 어떤 종류의 데이터베이스 구현체로 교체될 수 있으며,

BusinessRule은 그 변경에 조금도 개의치 않는다.

이와 같은 사실은 데이터베이스에 대한 결정은 연기할 수 있으며,

데이터베이스를 결정하기에 앞서, 업무 규칙을 먼저 작성하고 테스트하는 데

집중할 수 있음을 의미한다.

세부사항의 대표 예시로 데이터베이스를 예시로 들었지만,

"입출력"을 담당하는 GUI 컴포넌트도 위에서 설명한 데이터베이스의 컴포넌트와 유사한 위치에 있다.

사용자 인터페이스는 모델에 있어 중요하지 않고,

업무 규칙이 중요하다.

GUI 역시 데이터베이스 예시와 마찬가지로,

GUI와 업무 규칙 컴포넌트 사이에 경계선에 의해 분할되어야 하고,

화살표의 방향을 통해 우리는 관련성이 낮은 컴포넌트(세부사항)가

관련성이 높은 컴포넌트(업무 규칙)에 의존한다는 사실을 알 수 있다.

화살표는 어느 컴포넌트가 어떤 컴포넌트를 알고 있는지를,

그래서 어느 컴포넌트가 어느 컴포넌트를 신경 쓰는지를 보여준다.


플러그인 아키텍처

앞에서 업무 규칙과 세부사항 사이에 그려진 패턴은

시스템에서 서드파티 플러그인을 사용할 수 있게 한 바로 "플러그인 아키텍처" 패턴과 동일하다.

소프트웨어 개발 기술의 역사는

플러그인을 손쉽게 생성하여, 확장 가능하고 유지보수가 쉬운 시스템 아키텍처를 확립할 수 있게 만드는 방법에 대한 이야기다.

선택적이거나 또는 수많은 다양한 형태로 구현될 수 있는 나머지 컴포넌트로부터

핵심적인 업무 규칙은 분리되어 있고, 또한 독립적이다.

사용자 인터페이스 및 데이터베이스는 플러그인 형태로 고려되었기에,

수많은 종류의 데이터베이스, 사용자 인터페이스 구현체를

업무 규칙 컴포넌트에 플러그인 형태로 연결할 수 있게 한다.

그럼으로써, 세부사항 컴포넌트나 모듈의 변경이

나머지 업무 규칙의 모듈에 영향받지 않기를 원한다.

시스템에서 한 부분이 변경되더라도 관련 없는 나머지 부분이 망가지길 원치 않는다.

이러한 변경으로부터 망가지는 주 원인은 우리가 제일 경계해야 할 "결합"이며,

시스템을 플러그인 아키텍처로 배치함으로써 변경이 전파될 수 없는 방화벽을 생성할 수 있다.

경계는 변경의 축이 있는 지점에 그어진다.

경계의 한쪽에 위치한 컴포넌트는 경계 반대편의 컴포넌트와는 다른 속도로,

그리고 다른 이유로 변경된다.

이 패턴의 원리 역시 순전히 단일 책임 원칙에 해당한다.

단일 책임 원칙은 경계를 어디에 그어야할지를 알려준다.

결론

소프트웨어 아키텍처에서 경계선을 그으려면 먼저 소프트웨어를 컴포넌트 단위로 분할해야 한다.

컴포넌트들 중 핵심 업무 규칙을 담은 컴포넌트와, 그 외 부가적인 세부사항 컴포넌트를 구분해야 한다.

그리고 핵심 업무 규칙 외의 컴포넌트는 플러그인 아키텍처를 취하여,

세부사항 컴포넌트의 변경이 업무 규칙 컴포넌트에 영향을 주지 않도록 배치한다.

또한 컴포넌트 간 의존성을 그릴 때, 세부사항이 업무 규칙을 향하도록 컴포넌트를 배치 한다.

즉 의존성 화살표가 세부사항이 업무 규칙을 의존하도록 하여,

세부사항은 업무 규칙에 의존하되, 업무 규칙은 세부사항의 존재를 알지 못하도록 한다.

이는 의존성 역전 원칙과 안정된 추상화 원칙을 응용한 것임을 눈치챌 수 있다.

의존성 화살표는 저수준의 세부사항에서 고수준의 추상화를 향하도록 배치한다.

#클린아키텍처 #cleanArchitecture #경계 #의존성역전원칙 #안정된추상화원칙 #단일책임원칙 #컴포넌트

관련글 더보기

댓글 영역