본문 바로가기
iOS/Architecture

클린 아키텍쳐 4부 정리 (12장~14장)

by HaningYa 2022. 4. 8.
728x90

크-린

12장 컴포넌트

SOLID = 벽돌을 벽과 방에 배치하는 방법
컴포넌트 = 빌딩에 방을 배치하는 방법

컴포넌트
  • 배포단위
  • 시스템 구성요소로 배포할 수 있는 가장 작은 단위
  • 여러 컴포넌트를 서로 묶어서 단일 아카이브로 만들 수 있다.

잘설계된 컴포넌트 = 독립적으로 개발, 배포 가능한 능력

우리 프로젝트는 독립적으로 배포가 가능하지 않은데 단일 컴포넌트인가

컴포넌트의 역사
  • 시즌1
    초창기 라이브러리는 메모리의 어느 위치에 로드할지 지정해야함
    한번 지정되면 재배치가 불가능
    소스코드 형태의 라이브러리를 Application 코드에 포함시켜 컴파일

단점) 컴파일 시간이 너무 오래 걸렸다.

  • 시즌2
    라이브러리 코드를 분리하여 개별 컴파일
    바이너리 형태로 심벌 테이블을 통해 Application코드를 컴파일

단점) 앱이 가질 수 있는 주소공간이 점점 커져서 메모리 단편화 발생

  • 시즌3
    재배치 가능한 바이너리
    함수라이브러리를 로드할 위치와 Application을 로드할 위치를 링킹로더를 통해 재배치
    program을 개별적으로 컴파일 하고 로드할 수 있는 단위로 분할

단점) 프로그램이 커져가면서 너무 느려짐

  • 시즌4
    로드 링크중 링크를 프로그래머가 담당(linker application)
    한번 만들어둔 실행 파일을 언제라도 빠르게 로드 가능

단점) 전체 모듈 컴파일 시간은 여전히 느림

  • 시즌5
    막강한 컴퓨팅 파워로 조짐

이번에 빌드시간이 오래 걸리던 것도 M1 pro로 바꾸면서 어느정도 해결된 것 같은데 언제까지 괜찮을까...

결론) runtime에 plugin 형태로 결합할 수 있는 동적 링크 파일 -> 컴포넌트

컴포넌트 플러그인 아키텍쳐 vs 프레임워크 기반 프로그래밍
동적 링크 파일 vs 정적 링크 파일
컴포넌트 vs 모듈
VIBE프로젝트를 각각 작은 프로젝트로 나누어 개발하는게 효과적일까 (Tuist)

프레임워크 기반 프로그래밍


13장 컴포넌트 응집도

3가지 원칙
  • Reuse/Release Equivalence Principle: 재사용/릴리스 등가 원칙
  • Common Closure Principle: 공통 폐쇄 원칙
  • Common Reuse Principle: 공통 재사용 원칙
REP (포함원칙)
  • 재사용 단위는 릴리즈 단위와 같다.
  • 하나의 컴포넌트는 응집성 높은 클래스와 모듈들로 구성되어야 한다.
    -> 하나의 컴포넌트로 묶인 클래스와 모듈은 함께 릴리즈할 수 있어야 한다.

모듈이 컴포넌트의 하위 개념이구나

CCP (포함원칙)
  • SRP(메서드를 다른 클래스로 분리)의 컴포넌트 관점(클래스를 다른 컴포넌트로 분리)
  • 동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어라
    -> 같은 이유로 변경될 가능성이 있는 클래스를 모두 한곳으로 묶어라
    (릴리즈, 재검증, 배포관련 작업량 최소화를 위해)
  • 중요도: 유지보수성 > 재사용성
  • OCP와의 관계
    • 변경에는 닫혀있고 확장에는 열려있다.
      -> 동일한 유형의 변경에 대해 닫혀있는 클래스를 하나의 컴포넌트로 묶는다
동일한 시점에 동일한 이유로 변경되는 것들을 한데 묶어라
서로 다른 시점에 다른 이유로 변경되는 것들은 서로 분리해라
CRP (배제원칙)
  • 컴포넌트 사용자들을 필요하지 않는 것에 의존하게 강요하지 말라
  • 클래스와 모듈을 어느 컴포넌트에 위치 시킬지 결정
  • 강하게 결합되지 않은 클래스들을 동일한 컴포넌트에 위치 시키지 마라!
  • ISP와의 관계
    • ISP의 포괄적인 버전 (사용하지 않는 메서드가 있는 클래스에 의존하지마라)
    • CRP(사용하지 않는 클래스를 가진 컴포넌트에 의존하지마라)
필요하지 않는 것에 의존하지 말라

우리 프로젝트는 무슨 컴포넌트가 있는거지


14장 컴포넌트 결합

  • Acyclic Dependencies Principle: 의존성 비순환 원칙
  • top-down 설계
  • Stable Dependencies Principle: 안정된 의존성 원칙
  • Stable Abstractions Principle: 안정된 추상화 원칙
ADP 의존성 비순환 원칙
컴포넌트 의존성 그래프에 순환이 있어서는 안된다.

숙취 증후군을 해결하기 위해

  1. 주 단위 빌드 (에바)
  2. 의존성 비순환 원칙

컴포넌트가 변경 되더라도 다른 컴포넌트에 영향을 주지 않는다.
-> 점진적으로 통합이 이뤄진다.

구성요소간의 의존성을 파악하고 있으면 시스템을 빌드하는 방법을 알 수 있다.

만약 순환이 발생한다면?

  • 반드시 호환되어야 하는 컴포넌트들 사이에서 릴리스 하기 어려운 컴포넌트가 생김
    (정확하게 동일한 릴리스를 사용해야 하기 때문)

순환을 끊으려면?

  • 의존성 역전 원칙 사용
  • 문제되는 컴포넌트들이 모두 의존하는 새로운 컴포넌트를 생성하고 문제되는 컴포넌트가 모두 의존하는 클래스들을 새로운 컴포넌트로 이동
하양식 설계

컴포넌트 구조는 하향식으로 설계될 수 없다.
컴포넌트 의존성 다이어그램은 애플리케이션의 빌드 가능성과 유지보수성을 보여주는 지도다
(시스템의 기능적 측면을 표현하지 않는다)

-> 변동성 격리!
-> 재사용 가능한 요소 만들기!

아무런 클래스도 설계하지 않은 상태에서 컴포넌트 의존성 구조를 설계한다면 실패..?

결론은 컴포넌트 의존성 구조는 계속 개선해가야함

SDP 안정된 의존성 원칙
더 안정된 쪽에 의존하라

안정성: 쉽게 움직이지 않는/ 수많은 다른 컴포넌트가 해당 컴포넌트에 의존하면 불안정함

세 컴포넌트가 X에 의존하기 때문에 X는 변경하지 말아야할 이유가 세가지나 있어서 X는 안정된 컴포넌트 이다.
X는 어디에도 의존하지 않으므로 X가 변경되도록 만들 수 있는 외적인 영향이 전혀 없다.

변경될 이유가 세가지나 있어서 안정되지 않은거 아닌가??

안정성 지표

  • Fan-in 안으로 들어오는 의존성
  • Fan-out 바깥으로 나가는 의존성
  • I (불안정성) = Fan-out / (fan-in + fan-out)

C++에서 의존성은 ''#include'로 표현된다.
자바의 경우 I지표는 import 구문과 완전한 클래스 이름의 개수를 세어서 계산할 수 있다.

본인이 다른데 의존한다 (불안정) -> 자신에게 의존하는 컴포넌트가 없다 -> 본인을 변경하지 말아야 할 이유가 없다.

본인에게 의존한다 (안정) -> 다른 컴포넌트를 책임진다 -> 본인을 변경하기 어렵다.

본인을 변경하기 쉬우면 안정적이라고 생각했는데 약간 변경하는 사람 입장으로 생각해서 그렇게 이해한것 같다.

SAP 안정된 추상화 원칙
컴포넌트는 안정된 정도만큼만 추상화 되어야한다.

고수준 정책을 어디 위치시켜야 하는가?
고수준 정책: 자주 변경해서는 안되는 로직

우리프로젝트에서 고/저수준 원칙의 예시로는 뭐가 있을까

고수준 정책은 안정된 컴포넌트(I=0)에 위치하고
저수준 정책은 불안정한 컴포넌트(I=1)은 변동성이 큰 곳에 위치

그런데 고수준 정책을 안정된 컴포넌트에 위치시키면 정책을 포함하는 소스코드 수정이 어려움 -> 유연성 상실 -> 변경에 대응할 방법이 없을까? -> OCP -> OCP 준수하는 클래스 -> 추상 클래스

SAP는 안정성과 추상화 정도의 사이 관계를 정의.

불안정한 컴포넌트는 구체 컴포넌트여야한다. (내부 구체 코드를 쉽게 변경하기 위해)
안정적인 컴포넌트라면 인터페이스와 추상클래스로 구성되어있어 쉽게 확장해야한다.

SAP + SDP 결합하면 컴포넌트에 대한 DIP 이다.
-> SDP = 의존성은 안정성의 방향으로 향해야함 + SAP 안정성이 결국 추상화를ㄹ 의미함
결론) 의존성은 추상화 방향으로 향하게됨

차이점) DIP는 클래스에 대한 원칙. 클래스는 추상이거나 아니거나 둘중 하나지만 컴포넌트는 추상적인 부분도 아닌 부분도 있을 수 있다.

추상화 정도 측정
  • Nc: 컴포넌트 클래스 갯수
  • Na: 컴포넌트의 추상 클래스와 인터페이스 갯수
  • A: 추상화 정도 -> A = Na/Nc
  • 0=추상클래스 없음
  • 1= 오로지 추상클래스만 포함

추상클래스는 대체로 다른 추상 클래스로부터 파생되어 만든다.
-> 추상적이면서 의존성을 가진다.

  • 고통의 구역
    • 안정적이면서 구체적
    • 구체적이여서 확장할 수 없고 안정적이라서 변경이 어렵다.
    • 데이터베이스 스키마, 유틸리티 라이브러리를 예로 들 수 있다.
  • 쓸모없는 구역
    • 최고로 추상적이지만 누구도 그 컴포넌트에 의존하지 않음
    • 여기 존재하는 엔티티는 폐기물임
    • 누구도 구현하지 않은 추상 클래스
  • 바람직한 구역 (1,0) ~ (0,1)
    • 주계열의 바로 위 또는 가깝게 위치

결론) 의존성 관리 지표는 설계의 의존성과 추상화 정도가 좋은 패턴이라고 생각하는 수준에 얼마나 잘 부합하는지 측정 그런데 절대적인게 아닌 그냥 표준 측정값임

728x90

댓글