laughcryrepeat 2021. 3. 8. 01:19

16장 독립성

 

좋은 아키텍처가 시스템에서 지원해야 할 것.

 

  • 유스케이스
  • 운여
  • 개발
  • 배포

유스케이스

시스템의 아키텍처는 시스템의 의도를 지원해야 한다.

행위를 명확히 하고 외부로 드러내서 이를통해 시스템이 지닌 의도를 아키텍처 수준에서 알아볼 수 있게 만드는 것.

 

운영

운영지원 관점에서 아키텍처는 요구사항에 맞게 운영작업을 허용할 수 있는 형태로 구조화되야 한다.

아키텍처에서 각 컴포넌트를 적절히 격리하여 유지하고 컴포넌트 간 통신 방식을 특정 형태로 제한하지 않으면,

나중에 운영에 필요한 요구사항이 바뀌더라도 기술 스펙트럼 사이를 전화하는 일이 훨씬 쉽다.

 

개발

개발환경을 지원하는데 있어 아키텍처는 핵심적인 역할을 한다.

 

Conway 법칙
시스템을 설계하는 조직이라면 어디든지 그 조직의 의사소통 구조와 동일한 구조의 설계를 만들어 낼 것이다.

잘 격리되어 독립적으로 개발가능한 컴포넌트 단위로 시스템을 분할해야

각 컴포넌트를 독립적으로 작업할 수 있는 팀에 할당 가능하다.

 

배포

아키텍처는 배포 용이성을 결정하는데 중요한 역할.

목표는 즉각적인 배포. 시스템 빌드후 즉각 배포 가능한 형태.

마스터 컴포넌트는 시스템 전체를 하나로 묶고, 각 컴포넌트를 올바르게 구동하고 통합하고 관리.

 

선택사항 열어놓기

좋은 아키텍처는 컴포넌트 구조와 관련된 관심사들 사이에 균형을 맞추고, 각 관심사 모두를 만족시킨다.

시스템을 겨리된 컴포넌트 단위로 분리하고 선택사항을 가능한 많이 열어두어,

향후 변경에 필요한 경우를 대비한다.

 

계층 결합 분리

아키텍트는 단일 책임 원칙과 공통 폐쇄 원책을 적용, 시스템의 의도 맥락에 따라 다른 이유로 변경되는 것들을 분리하고,

동일한 이유로 변경되는 것들을 묶는다.

사용자 인터페이스가 변경되는 이유는 업무규칙과 관련이 없으므로,

UI 부분과 업무 규칙 부분을 서로 분리한다.

 

또한 입력 유효성 검사와 같은 애플리케이션 관련 업무규칙과

이자계산 같은 업무 도메인관련 업무규칙은 서로 다른 유형의 규칙이므로 

다른속도로 다른이유로 변경될 것이므로, 이들 또한 분리하고 독립적으로 변경 가능하게 만들어야 한다.

유스케이스 결합 분리

유스케이스는 시스템을 분할하는 매우 자연스러운 방법이다.

시스템을 수평적 계층으로 분할하면서 해당계층을 가로지르는 얇은 수직적 유스케이스로 시스템을 분할할 수 있다.

 

 

 

시스템에서 요소들을 결합 분리하면 기존 요소에 지장을 주지 않고 새로운 유스케이스 추가 가능.

유스케이스를 뒷받침하는 UI와 데이터베이스를 서로 묶어 각 유스케이스가 UI와 데이터베이스의 서로 다른 관점을 사용하게 되면,

새로운 유스케이스를 추가해도 기존 유스케이스에 영향을 주는일이 거의 없다.

 

** 관점지향 프로그래밍 Aspect-Oriented Programming

- 횡단 관심사를 분리해 모듈화를 높이는 프로그래밍 패러다임.

기존코드에 추가하는 방식으로 구현. 예외처리, 로깅, 인증, 트랜젝션 등

 

결합 분리 모드

유스케이스를 위해 수행하는 그 결합분리 작업들은 운영에도 도움이 됨.

때때로 컴포넌트를 서비스 수준까지 분리해야 함.

 

개발 독립성

컴포넌트가 완전 분리되면 팀사이 간섭은 줄어듬.

 

배포 독립성

배포 측면에서도 고도의 유연성이 생김.

새로 유스케이스 추가하는일은 나머지 그대로 둔 채 새로운 jar 파일이나 서비스 몇개를 추가하는 정도로 단순함.

 

중복

중복은 일반적으로 나쁨.

진짜 중복 - 한 인스턴스가 변경되면 동일한 변경을 모든 복사본에 적용

우발적 중복 - 중복으로 보이는 두 코드영역이 각자의 경로로 발전한다면 진짜 중복이 아님.

 

데이터베이스 레코드와 동일한 형태의 뷰 모델을 만들어서 각 항목을 복사하는게 아니라,

뷰모델을 별도로 만드는 일은 계층간 결합을 적절히 분리하여 유지하는 태도에 도움이 된다.

 

결합 분리 모드(다시)

  • 소스 수준 분리 모드
    - 소스코드 모듈사이 의존성 제어 가능
    - 모놀리틱 구조
  • 배포 수준 분리 모드
    - 배포 가능한 단위들 사이 의존성 제어.
    - jar,DLL, 공유 라이브러리 같이 독립적 배포 단위로 분할.
  • 서비스 수준 분리 모드
    - 의존수준을 데이터 구조 단위까지 낮출 수 있고, 순전히 네트워크 패킷을 통해서만 통신.
    - 소스와 바이너리 변경에 대해 완전 독립적
    - 서비스, 마이크로 서비스

프로젝트가 성숙해갈수록 최적인 모드가 달라질 수 있음.

서비스 수준의 결합 분리는 개발시간, 시스템 자원 측면 비용도 든다.

 

컴포넌트 결합을 분리하되 서비스가 되기 직전에 멈추는 방식

-> 컴포넌트들을 가능한 동일 주소 공간에 둠.

-> 초기에 컴포넌트가 소스코드 수준에서 분리

-> 서비스수준으로 전환할 배포단위 선택 후 시스템 변경.

 

결론

결합 분리모드를 변경하기 까다롭지만, 변경을 예측하여 반영하도록 만들어져야 한다.

 


17장 경계: 선긋기

선 == 경계

인적자원의 효율을 떨어뜨리는 요인 : 너무 일찍 내려진 결정에 따른 결합

두가지 슬픈 이야기

P회사

데스크톱 애플리케이션을 웹으로 변환하는 프로젝트

모든 도메인 객체가 세가지 인스턴스( GUI, 미들웨어, 데이터베이스) 인스턴스를 가져야한다고 결정을 지음.

새로운 필드를 추가하거나, 변경 기능을 적용하려고 많은 추가적인 일을 하게됨.

개발비용이 가중됨.

 

W사

엔터프라이즈급 서비스 지향 아키텍처를 위해 거대한 도메인 모델 생성.

도메인 객체를 관리하기 위한 서비스 묶음 설계.

새로운 기능을 수정하려면 엄청난 양의 WSDL web service description language 변경해야함.

영향받는 모든것 배포해야함.

 

FitNesse

워드 커닝햄이 인수 테스트 작성을 위해 만든 FIT 도구를 기반으로 하는 간단한 위키페이지. FitNesses

 

초기 내린 결정.

요구에 특화된 웹서비스 직접 작성.

데이터베이스에 대해 고민하지말것. DB에 대한 결정을 미룸.

 

- 데이터를 가져오고 저장하는 일과 관련없는 기능을 구현하는 동안 데이터 접근 메소드를 stub 메소드로 구현함.

- 개발 초기에 업무규칙과 데이터베이스 사이 경계선을 그음.

- 경계선을 긋는 행위는 결정을 늦추고 연기하여 최적의 결정을 할 수 있게 만들어줌.

 

어떻게 선을 그을까? 그리고 언제 그을까?

GUI, 업무규칙, 데이터베이스 사이에는 서로 관계가 없으므로 선이 있어야 함.

업무규칙은 스키마, 쿼리언어, 디비와 관련된 세부사항에 대해 알아서는 안됨.

데이터를 가져오고 저장할 때 사용하는 함수집합을 통해 데이터베이스를 인터페이스 뒤로 숨길 수 있음.

경계선

그리고 경계선은 상속관계를 횡단하며 Database Interface 아래 그어짐.

두 화살표에 주목.

 

업무규칙과 데이터베이스 컴포넌트

엄무규칙이 포한된 컴포넌트와 데이터베이스 접근 클ㄹ스를 포함하는 컴포넌트.

Database 컴포넌트는 BusinessRules가 만들어 낸 호출을 데이터베이스의 쿼리 언어로 변환하는 코드를 담음.

두 컴포넌트 사이 경계선을 그리고 화살표가 BusinessRules를 향하도록 함.

Database 컴포넌트는 다양한 구현체로 교체될 수 있음.

 

입력과 출력은?

입력과 출력은 중요하지 않음.

사용자 경험 인터페이스. (화면, 마우스, 음향 등) 뒤에는 이것을 조작하는 모델(데이터 구조와 함수의 집합) 이 존재.

중요한 것은 업무 규칙.

마찬가지로 GUI 와 BusinessRules 컴포넌트를 경계선으로 분할가능.

 

플러그인 아키텍처

컴포넌트 추가와 관련한 일종의 패턴이 있음..

시스템에서 서드파티 플러그인 사용할 수 잇는 패턴과 동일.

 

업무규칙에 플러그인 형태로 연결

다양하게 구현되는 나머지 컴포넌트로부터 업무규칙은 분리되고 독립.

플러그인 구조로 시작하여, 변경작업을 현실성 있게 만듬.

 

플러그인에 대한 논의

ReShaper와 Visual Studio의 관계.

서로 다른 회사의 다른 개발팀에 의해 만들어짐.

 

ReSharper소스코드는 Visual Studio 소스코드에 의존.

따라서 Visual Studio 팀은 ReSharper 팀을 위험하게 만들수 있음.

 

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

이역시 단일 책임원칙과 같고, 이것이 어디에 경계를 그어야 할지 알려줌.

 

결론

경계선을 그리려면 먼저 시스템을 컴포넌트 단위로 분할.

화살표가 특정방향, 핵심 업무를 향하도록 컴포넌트 소스를 배치.

의존성 역전 원칙과 안정된 추상화 원칙을 응용한 것.

의존성 화살표는 저수준 세부사항에서 고수준의 추상화를 향해야 함.

 


18장 경계 해부학

다양한 형태로 나타나는 경계.

경계 횡단하기

'런타임 경계를 횡단한다.'

비결은 소스 코드 의존성 관리.

경계는 변경이 전파되는 것을 막는 방화벽을 구축. 관리하는 수단.

 

두려운 단일체

소스 수준 분리 모드, 단일체 에서는 배포관점에서 경계가 드러나지 않음.

이 경우 대부분 동적 다형성에 의존하여 내부 의존성을 관리.

 

가장 단순한 형태의 경계횡단은 저수준 클라이언트에서 고수준 서비스로 향하는 함수 호출.

제어흐름은 경계를 횡단할 때 저수준에서 고수준으로 향함.

경계에서 호출되는 쪽에 Data에 대한 정의가 위치한다.

고수준 클라이언트가 저수준 서비스를 호출해야 하면 동적 다형성을 사용해 제어흐름과 반대로 의존성을 역전시킬 수 있음.

제어흐름과 반대로 경계를 횡단

제어흐름은 왼쪽에서 오른쪽으로 경계를 횡단하지만,

고수준 Client는 Service 인터페이스를 통해 저수준인 함수 f() 호출.

경계를 횡단할 때 의존성은 모두 오른쪽에서 왼쪽으로, 고수준 컴포너트를 향함.

데이터 구조의 정의가 호출하는쪽에 위치함.

 

모노리틱 구조라도 이런 방식으로 구조를 분리해 컴포너트를 독립적으로 유지 가능.

고수준 컴포넌트는 저수준 세부사항으로부터 독립적으로 유지.

 

배포형 컴포넌트

경계가 드러나는 단순한 형태는 동적 링크 라이브러리.

공유 라이브러리.

컴포넌트는 바이너리와 같이 배포 가능한 형태로 전달.

배포수준 컴포넌트는 단일체와 동일. 의존성 관리전략도 비슷함.

 

스레드

스레드는 실행계획과 순서를 체계화하는 방법.

 

로컬 프로세스

강한 물리적 형태를 띠는 아키텍처 경계.

주로 명령행이나 유사 시스템 호출을 통해 생성.

여러 프로세서들에서 실행되지만 독립된 주소공간에서 실행.

대체로 socker, mailbox, message queue 처럼 운영체제 제공 통신기능 사용.

 

로컬 프로세스는 컴포넌트 간 의존성을 동적 다형성을 통해 관리하는 저수준 컴포넌트로 구성.

고수준 프로세스의 소스코드가 저수준 프로세스의 이름, 물리주소, 레지스트리 조회 키를 포함해서는 안됨.

저수순이 고수눙 프로세스의 플러그인이 되도록 하는것이 목표.

서비스

물리적 형태의 가장 강력한 경계는 서비스.

프로세스이며, 명령행 또는 호출을 통해 구동.

 

서비스들은 통신이 네트워크를 통해 이뤄짐.

서비스 경계를 지나는 통신이 느리기 때문에 자주 통신하는것을 지양.

latency 문데를 고수준에서 처리할 수 있어야 함.

 

저수준 서비스는 고수준 서비스에 플러그인 되어야 함. 

고소준 소스코드에는 저수준서비스를 특정짓는 물리적 정보(URI 등) 을 포함해서는 안됨.

 

결론

단일체 말고는 대다수가 한가지 이상 경계전략 사용.

개별 서비스, 로컬프로세스는 거의 소스코드 컴포넌트로 구성된 단일체 이거나,

동적으로 링크된 배포형 컴포넌트 집합니다.

한 시스템 안에 여러가지 고여해야할 경계가 혼합되어 있다.