728x90
반응형
책 정보
https://www.yes24.com/Product/Goods/77283734
컴포넌트 원칙
- SOLID 원칙이 벽과 방에 벽돌을 배치하는 방법을 알려준다면, 컴포넌트 원칙은 빌딩에 방을 배치하는 방법을 설명해줌
- 컴포넌트는 배포 단위로 시스템의 구성 요소로 배포할 수 있는 가장 작은 단위
- 자바의 경우 jar 파일
- 루비에서는 gem 파일
- 닷넷에서는 DLL
- 컴파일형 언어에서는 바이너리 파일의 결합체
- 인터프리터형 언어는 소스 파일의 결합체
12 장 컴포넌트의 간략한 역사
- 컴포넌트
- 초창기에는 메모리에서의 프로그램 위치와 레이아웃을 프로그래머가 직접 제어
- 라이브러리 함수의 소스 코드를 애플리케이션 코드에 직접 포함시켜 단일 프로그램으로 컴파일
- 함수 라이브러리가 크면 클수록 컴파일이 오래 걸림
- 컴파일 시간을 단축시키기 위해 함수 라이브러리의 소스 코드를 애플리케이션 코드로부터 분리
- 하지만 함수를 추가하면 추가 공간을 할당해야 하는 문제
- 초창기에는 메모리에서의 프로그램 위치와 레이아웃을 프로그래머가 직접 제어
- 재배치성
- 재배치가 가능한 바이너리가 해결책
- 메모리에 재배치할 수 있는 형태의 바이너리를 생성하도록 컴파일러를 수정
- 이렇게 링킹 로더가 탄생
- 링커
- 링킹 로더의 등장으로 프로그래머는 프로그램을 개별적으로 컴파일하고 로드할 수 있는 단위로 분할할 수 있게 됨
- 하지만 60년대 말, 70년대 초가 되자 프로그램이 훨씬 커짐 -> 링킹 로더가 느려짐
- 로드와 링크를 두 단계로 분리
- 링커라는 별도의 어플리케이션으로 이 작업을 처리하도록 만듦
- 링커는 링크가 완료된 재배치 코드를 만들어 주었음
- 80년대가 되자 C나, 또 다른 고수준 언어를 사용하기 시작
- 무어의 법칙 -> 디스크는 작아지기 시작하면서 놀랄 만큼 빨라짐
- 90년대 후반이 되자, 프로그램이 커지는 속도보다 링크 시간이 줄어드는 속도가 더 빨라짐
- 이렇게 컴포넌트 플러그인 아키텍처가 탄생
- 결론
- 런타임에 플러그인 형태로 결합할 수 있는 동적 링크 파일 = 소프트웨어 컴포넌트
- 여기까지 오는데 50년
13장 컴포넌트 응집도
- 세 가지 원칙
- REP: 재사용/릴리스 등가 원칙 (Reuse/Release Equivalence Principle)
- CCP: 공통 폐쇄 원칙 (Common Closure Principle)
- CRP: 공통 재사용 원칙 (Common Reuse Principle)
- REP: 재사용/릴리스 등가 원칙
- 재사용 단위는 릴리스 단위와 같다.
- 지난 십 년동안 재사용 가능한 컴포넌트나 컴포넌트 라이브러리가 엄청나게 만들어 짐
- 새로운 버전이 언제 출시되고 무엇이 변했는지 알아야 하기 때문에 릴리스 번호가 필요
- 변경 사항을 살펴보고 기존 버전을 계속 쓸지 여부를 결정
- 아키텍처 관점
- 단일 컴포넌트는 응집성 높은 클래스와 모듈들로 구성되어야 함
- 컴포넌트를 구성하는 모든 모듈은 서로 공유하는 중요한 테마나 목적이 있어야 함
- 하나의 컴포넌트로 묶인 클래스와 모듈은 반드시 함께 릴리스할 수 있어야 함
- 버전 번호가 같아야 하며, 동일한 릴리스로 추적 관리되고 동일한 릴리스 문서에 포함되어야 함
- CCP: 공통 폐쇄 원칙
- 동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어라. 서로 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 분리하라.
- 이 원칙은 SRP를 컴포넌트 관점에서 다시 쓴 것.
- 대다수의 애플리케이션에서 유지보수성은 재사용성보다 훨씬 중요함
- 변경 모두가 단일 컴포넌트에서 발생해야 함 -> 해당 컴포넌트만 재배포하면 되므로
- 같은 이유로 변경될 가능성이 있는 클래스는 모두 한곳으로 묶을 것을 권함
- 따라서 OCP(개방 폐쇄 원칙)과도 밀접하게 관련
- SRP와의 유사성
- CCP는 컴포넌트 수준의 SRP다.
- SRP에서는 서로 다른 이유로 변경되는 메서드를 서로 다른 클래스로 분리하라고 말함
- CCP에서는 서로 다른 이유로 변경되는 클래스를 서로 다른 컴포넌트로 분리하라고 말함
- 동일한 시점에 동일한 이유로 변경되는 것들을 한데 묶어라. 서로 다른 시점에 다른 이유로 변경되는 것들은 서로 분리하라.
- CCP는 컴포넌트 수준의 SRP다.
- CRP: 공통 재사용 원칙
- 컴포넌트 사용자들을 필요하지 않는 것에 의존하게 강요하지 말라.
- CRP도 클래스와 모듈을 어느 컴포넌트에 위치시킬지 결정할 때 도움되는 원칙
- 같이 재사용되는 경향이 있는 클래스와 모듈들은 같은 컴포넌트에 포함해야 함
- 사례
- 컨테이너 클래스와 해당 클래스의 이터레이터 클래스
- 이들 클래스는 강하게 결합되므로 함께 재사용됨
- 따라서 반드시 동일한 컴포넌트에 위치해야 함
- 어떤 컴포넌트가 다른 컴포넌트를 사용하면, 두 컴포넌트 사이에 의존성이 생김
- 의존성때문에 사용되는 컴포넌트가 변경될 때마다 사용하는 컴포넌트도 변경해야 할 가능성이 높음
- 변경하지 않더라도 재컴파일, 재검증, 재배포를 해야 하는 가능성이 남아 있음
- 따라서 의존하는 컴포넌트가 있다면 해당 컴포넌트의 모든 클래스에 대해 의존함을 확실히 인지해야 함
- 한 컴포넌트에 속한 클래스들은 더 작게 그룹지울 수 없음
- 일부 클래스에만 의존하고 다른 클래스와는 독립적일 수 없음
- 따라서 CRP는 어떤 클래스를 한데 묶어도 되는지보다는, 어떤 클래스를 한데 묶어서는 안 되는지에 대해서 훨씬 더 많이 얘기함
- 강하게 결합되지 않은 클래스들을 동일한 컴포넌트에 위치시켜서는 안 된다고 말함
- ISP와의 관계
- CRP는 ISP(인터페이스 분리 원칙)의 포괄적인 버전이다.
- ISP는 사용하지 않은 메서드가 있는 클래스에 의존하지 말라고 조언
- CRP는 사용하지 않는 클래스를 가진 컴포넌트에 의존하지 말라고 조언
- 즉, 필요하지 않은 것에 의존하지 말라.
- CRP는 ISP(인터페이스 분리 원칙)의 포괄적인 버전이다.
- 컴포넌트 응집도에 대한 균형 다이어그램
- 결론
- 컴포넌트 응집도에 관한 세 가지 원칙은 응집도가 가질 수 있는 훨씬 복잡한 다양성을 설명
- 재사용성과 개발 가능성을 반드시 고려해야 함
- 시간이 흐름에 따라 프로젝트의 초점이 개발가능성에서 재사용성으로 바뀌고, 그에 따라 컴포넌트를 구성하는 방식도 조금씩 흐트러지고 또 진화한다.
14장 컴포넌트 결합
- ADP: 의존성 비순환 원칙
- 컴포넌트 의존성 그래프에 순환(cycle)이 있어서는 안 된다.
- 숙취 증후군(the morning after syndrome) : 하루 종일 작동하고 퇴근했는데, 이튿날 전혀 돌아가지 않는 현상
- 누군가 뒤늦게 의존하고 있던 무언가를 수정했기 때문
- 해결책 2가지
- 주 단위 빌드
- 의존성 비순환 원칙
- 주 단위 빌드(Weekly Build)
- 일주일의 첫 4일 동안은 서로를 신경 쓰지 않음.
- 금요일이 되면 변경된 코드를 모두 통합하여 시스템을 빌드
- 하지만, 프로젝트가 커지면 금요일 하루 만에 통합이 불가능
- 순환 의존성 제거하기
- 해결책은 개발 환경을 릴리스 가능한 컴포넌트 단위로 분리하는 것
- 이를 통해 컴포넌트는 개별 개발자 또는 단일 개발팀이 책임질 수 있느 작업 단위가 됨
- 특정 컴포넌트가 변경되더라도 다른 팀에 즉각 영향을 주지는 않음
- 성공적으로 동작하기 위해서는 컴포넌트 사이읭 의존성 구조를 반드시 관리해야 함
- 순환이 있어서는 안 된다.
- 시스템 전체를 릴리스해야 할 때가 오면 릴리스 절차는 상향식으로 진행됨 (구성요소 간 의존성을 파악하고 있으면 시스템을 빌드하는 방법을 알 수 있음)
- 순환이 컴포넌트 의존성 그래프에 미치는 영향
- 순환이 생기면 컴포넌트를 분리하기가 상당히 어려워짐
- 단위 테스트 및 릴리스도 굉장히 어려워 짐
- 순환 끊기 2가지 해결책
- 의존성 역전 원칙(DIP) 적용
- 모두 의존하는 새로운 컴포넌트를 생성
- 흐트러짐 (Jitters)
- 2번째 해결책에서 시사하는 바 : 요구사항이 변경되면 컴포넌트 구조도 변경될 수 있음
- 애플리케이션이 성장함에 따라 컴포넌트 의존성 구조는 서서히 흐트러지며 또 성장함
- 따라서 의존성 구조에 순환이 발생하는지를 항상 관찰해야 하며 순환이 발생하면 어떤 식으로든 끊어야 함
- 하향식(top-down) 설계
- 컴포넌트 구조는 하향식으로 설계될 수 없음
- 의존성 구조와 관련된 최우선 관심사는 변동성을 격리하는 일
- 예 ) GUI에서 표현 형식이 변경되더라도 업무 규칙에까지 영향을 주는 일은 바라 지 않음
- 애플리케이션이 성장함에 따라 재사용 가능한 요소를 만드는 일에 관심을 기울이기 시작
- 공통 재사용 원칙(CRP)가 영향을 미침
- 순환이 발생하면(ADP)가 적용
- 아무런 클래스도 설계되지 않은 상태에서 컴포넌트 의존성 구조를 설계하려고 시도한다면 큰 실패를 맛볼 것
- SDP: 안정된 의존성 원칙
- 안정성의 방향으로(더 안정된 쪽에) 의존하라.
- 변경이 쉽지 않은 컴포넌트가 변동이 예상되는 컴포넌트에 의존하게 만들어서는 절대로 안됨
- 안정성 : "쉽게 움직이지 않는'
- 변경을 만들기 위해 필요한 작업량과 관련.
- 옆면으로 선 동전이 안정적이지 않은 이유는 그다지 힘을 쓰지 않고도 넘어뜨릴 수 있음
- 탁자의 경우에는 탁자를 뒤집기 위해서 힘을 많이 써야 함 -> 안정적
- 컴포넌트를 변경하기 어렵게 만드는 방법 -> 수많은 컴포넌트에 의존하게 만드는 것
- 안정성 지표
- Fan-in : 안으로 들어오는 의존성. 컴포넌트 내부의 클래스에 의존하는 컴포넌트 외부의 클래스 개수
- Fan-out: 바깥으로 나가는 의존성. 컴포넌트 외부의 클레스에 의존하는 컴포넌트 내부의 클래스 개수
- I (불안정성): I = Fan-out % (Fan-in + Fan-out)
- I = 0 : 안정
- I = 1 : 불안정
- SDP에서 컴포넌트의 I 지표는 그 컴포넌트가 의존하는 다른 컴포넌트들의 I보다 커야 한다고 말함
- 즉, 의존성 방향으로 갈수록 I 지표 값이 감소해야 함
- 모든 컴포넌트가 안정적이어야 하는 것은 아니다
- 모든 컴포넌트가 안정적인 시스템이라면 변경이 불가능
- 추상 컴포넌트
- 인터페이스만을 포함하는 컴포넌트를 생성하는 방식이 이상하게 보일 수도 있음
- 하지만 자바나 C# 같은 정적 타입 언어를 사용할 때 흔하며 꼭 필요한 전략
- 루비나 파이썬 같은 동적 타입 언어를 사용할 때는 이러한 추상 컴포넌트가 전혀 존재하지 않을 분만 아니라, 추상 컴포넌트로 향하는 의존성 같은 것도 전혀 없음
- 의존성을 역전시킬 때 인터페이스를 선언하거나 상속받는 일이 전혀 필요하지 않음
- SAP: 안정된 추상화 원칙
- 컴포넌트는 안정된 정도만큼만 추상화되어야 한다.
- 고수준 정책을 어디에 위치시켜야 하는가?
- 자주 변경해서는 안되는 소프트웨어가 있음 (고수준 아키텍처나 정책 결정과 관련된 소프트웨어)
- 따라서 반드시 안정된 컴포넌트에 위치
- 하지만 고수준 정책을 안정된 컴포넌트에 위치시키면, 그 정책을 포함하는 소스 코드는 수정하기가 어려워짐
- 전체 아키텍처가 유연성을 잃음
- 컴포넌트가 최고로 안정된 상태이면서도 동시에 변경에 충분히 대응 할 수 있도록 만드려면? -> 개방 폐쇄 원칙(OCP)
- 추상 클래스를 통해 클래스를 수정하지 않고도 확장 가능할 정도로 만든다.
- 안정된 추상화 원칙
- SAP는 안정성과 추상화 정도 사이의 관계를 정의함
- 안정된 컴포넌트는 추상 컴포넌트여야 함
- 안정성이 컴포넌트를 확장하는 일을 방해해서는 안됨
- 안정적인 컴포넌트라면 반드시 인터페이스와 추상 클래스로 구성되어 쉽게 확장할 수 있어야 함
- SAP와 SDP를 결합하면 컴포넌트에 대한 DIP가 됨
- SDP에서는 의존성이 반드시 안정성의 방향으로 향해야 함
- SAP에서는 안정성이 결국 추상화를 의미 함
- 따라서 의존성으 ㄴ 추상화의 방향으로 향하게 된다.
- 하지만 DIP는 클래스에 대한 원칙
- 클래스의 경우 중간은 존재하지 X -> 추상적이거나 아니거나
- SDP와 SAP의 조합은 컴포넌트에 대한 원칙 -> 어떤 부분은 추상적이면서 다른 부분은 안정적일 수 있음
- 추상화 정도 측정하기
- A 지표는 컴포넌트의 추상화 정도를 측정한 값
- Nc: 컴포넌트의 클래스 개수
- Na: 컴포넌트의 추상 클래스와 인터페이스의 개수
- A: 추상화 정도. A = Na % Nc
- A가 0이면 컴포넌트에는 추상 클래스가 하나도 없다는 뜻
- A가 1이면 컴포넌트는 오로지 추상 클래스만을 포함한다는 뜻
- A 지표는 컴포넌트의 추상화 정도를 측정한 값
- 주계열
- 고통의 구역
- (0, 0) 주변 구역에 위치한 컴포넌트 : 매우 안정적이며 구체적
- 추상적이지 않으므로 확장할 수 없고, 안정적이므로 변경하기 어려움
- 쓸모없는 구역
- (1, 1) 주변의 컴포넌트 : 추상적이지만 누구도 의존하지 않음
- 쓸모가 없음
- 배제 구역 벗어나기
- 따라서 변동성이 큰 컴포넌트 대부분은 두 배제 구역으로부터 가능한 멀리 떨어뜨려야 함
- 주계열과의 거리
- D4 : D = |A + I -1|
- 결론
- 의존성 관리 지표는 설계의 의존성과 추상화 정도가 얼마나 훌륭한지 측정
- 지표는 불완전하지만, 지표로부터 유용한 것을 찾을 수 있음
- 고통의 구역
728x90
반응형
'도서 리뷰 > IT 도서 리뷰' 카테고리의 다른 글
[IT 도서 리뷰] 클린 아키텍처 (6부 세부사항) (0) | 2023.08.28 |
---|---|
[IT 도서 리뷰] 클린 아키텍처 (5부 아키텍처) (0) | 2023.08.15 |
[IT 도서 리뷰] 클린 아키텍처 (3부 설계 원칙) (1) | 2023.07.03 |
[IT 도서 리뷰] 클린 아키텍처 (2부 벽돌부터 시작하기: 프로그래밍 패러다임) (0) | 2023.07.02 |
[IT 도서 리뷰] 클린 아키텍처 (1부 소개) (0) | 2023.06.25 |