ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Clean Architecture - 컴포넌트 원칙
    Book/Clean Architecture 2022. 12. 14. 09:17

    이번 챕터에서는 3가지에 대해서 알아본다.

     

    1. 소프트웨어 컴포넌트란?
    2. 컴포넌트의 구성요소
    3. 컴포넌트를 결합하여 시스템을 구성하는 방법

     

     

    컴포넌트란?

    컴포넌트는 시스템의 구성요소로 배포할 수 있는 가장 작은 단위이다.

     

    루비에서는 gem

    닷넷에서 DLL

    스위프트는 컴파일 언어이기 때문에 바이너리 파일의 결합체가 하나의 컴포넌트이다.

     

    잘 설계된 컴포넌트라면 독립적으로 배포 가능해야 한다.

    100p에서부터는 컴포넌트의 역사에 대해서 설명한다.

     


    컴포넌트 응집도

     

    클래스들을 어떤 컴포넌트에 넣을것인지?에 관한 세 가지 원칙이 있다.

     

    1. REP: Reuse/Release Equivalence Principle
    2. CCP: Common Closure Principle
    3. CRP: Common Reuse Principle

     

     

    REP: 재사용 릴리스 등가 원칙

    재사용단위는 릴리스 단위와 같다.

     

    아키텍처 관점에서 보면 단일 컴포넌트는 응집성 높은 클래스와 모듈들로 구성되어야 한다.

    서로 공유하는 중요한 목적이 있어야 한다,

     

     

    CCP: 공통 폐쇄 원칙

    같은 이유로 동일한 시점에 변경되는 클래스들을 하나의 컴포넌트로 묶어라.

    SRP를 컴포넌트 관점에서 다시 말한 원칙이다.

     

     

    CRP: 공통 재사용 원칙

    컴포넌트 사용자들을 필요하지 않은 것에 의존하게 강요하지 말아라.

    즉 같이 재사용되는 경향이 있는 클래스와 모듈을 같은 컴포넌트에 포함해야 한다.

     

     

    개발 가능성과 재사용성 사이에서 균형을 잘 이루어야 한다.

    이는 프로젝트가 진행되면서 변할 수 있다.

    초창기에는 재사용성보다 개발가능성에 초점이 맞춰지고 이후에 점점 재사용성에 초점이 맞춰지게 된다.

     

     


     

    컴포넌트 결합

     

    각 컴포넌트 사이의 관계를 설명하는 세 가지 원칙

     

    1. ADP
    2. SDP
    3. SAP

     

    ADP: 의존성 비순환 원칙

    컴포넌트 의존성 그래프에 순환이 있으면 안 된다.

     

    순환 의존성을 제거하기 위해서 개발환경을 릴리즈 가능한 컴포넌트 단위로 분리한다.

    각 컴포넌트를 단일 개발팀이 맞게 된다.

    컴포넌트를 릴리즈해서 다른 개발자들이 사용할 수 있도록 하고 릴리즈번호를 부여해서 다른 개발자들이 사용하는 디렉토리로 이동시킨 후 컴포넌트를 지속적으로 수정한다. 

    다른 개발자들은 릴리즈 된 버전을 이용하고 버전이 업데이트되면 새 릴리즈버전을 적용할지 고민하면 된다.

    이렇게 하면 컴포넌트가 변경되더라도 다른 팀에게 영향을 바로 주지 않는다.

     

    하지만 이렇게 동작하기 위해서는 반드시 컴포넌트 의존성을 관리해야 한다.

    의존성에 순환이 생기면 서로 영향을 끼치기 때문이다.

     

    117p에서부터 의존성 순환이 미치는 영향에 대해서 설명하고 있다.

     

     

    순환 끊기

    컴포넌트 사이의 순환을 끊고 의존성을 돌리기 위해서 주요한 메커니즘 2가지

     

    1. DIP(의존성 역전 원칙) 인터페이스를 하나 만들어서 의존성을 역전시킨다.
    2. 둘 다 모두 의존하는 새로운 컴포넌트 생성하고 둘 다 의존하는 클래스들을 새로운 컴포넌트로 옮기기.

     

    컴포넌트 의존성 구조는 프로그램이 성장하면서 변하게 된다. 이때 중요한 것은 의존성 순환이 발생하는지를 잘 보고 어떤 식으로든 이것을 끊어야 한다.

     

     

    ADP 결론

    컴포넌트구조는 하향식 설계를 할 수 없다.

    컴포넌트를 가장 먼저 설계하고 개발을 하는 게 아니다. 컴포넌트는 프로그램과 같이 변경되기 때문이다!

    아직 아무런 클래스도 만들지 않았는데 컴포넌트 의존성 구조를 설계하려고 하면 큰 실패를 겪게 된다.

     

    우리가 원하는 것은 자주 변경되는 컴포넌트들로 인해 잘 변경되지 않는 컴포넌트가 영향을 받지 않는 것이다.

     

     

    SDP: 안정된 의존성 원칙

    더 안정된 쪽으로 의존해라.

     

    즉 변경이 쉽지 않은 컴포넌트를 변경이 잦을 것으로 예상되는 컴포넌트에 의존하도록 하면 절대!!! 안된다.

    이렇게 되면 변동성이 큰 컴포넌트도 변경하기 어려워진다.

     

    내가 변경하기 쉬운 모듈을 만들었어도 누군가 여기에 의존성을 걸면 내 모듈도 변경하기 힘들어진다.

    변경하면 다른 모듈도 변경이 필요 해질 테니까!

     

     

    안정성이란?

    컴포넌트를 변경하기 어렵게 만드는 것 중에 하나는 수많은 다른 컴포넌트가 이 컴포넌트를 의존하는 것이다.

    변경하기 어렵다는 것은? -> 안정적이라는 의미이다.

    나를 의존하는 게 많을수록 안정적이라는 뜻

     

    안정성 지표를 파악하려면 들어오고 나가는 의존성을 체크해보면 된다.

    • Fan-in: 안으로 들어오는 의존성
    • Fan-out: 밖으로 나가는 의존성
    • I(불안정성 지표) = Fan-out % (Fan-in + Fan-out)

    I는 0~1의 값을 가지고 1이면 불안정하고 0이면 안정하다는 의미이다.

     

    I == 1이면 최고로 불안정하다는 의미이고 이는 자신을 의존하는 컴포넌트(Fan-in)는 하나도 없지만 내가 의존하는 컴포넌트(Fan-out)는 있다는 말이다.

    그럼 이 컴포넌트는 변경하지 말아야 할 이유가 없다. 즉 언젠가 변경할 일이 있다.

    불안정한 컴포넌트

     

     

    I == 0이면 안정한 상태이고 자신을 의존하는 컴포넌트(Fan-in)만 존재하고 내가 의존하는 컴포넌트(Fan-out)는 없다는 의미이다.

    이 상태는 다른 컴포넌트를 책임지며 독립적인 상태이다.

    독립적이기 때문에 변경을 강제하는 의존성은 없다. 하지만 변경을 해야 한다면 의존하고 있는 컴포넌트들이 있기 때문에 변경이 쉽지 않다.

    안정한 컴포넌트

     

    SDP는 I가 의존하는 방향으로 갈수록 감소해야 한다는 말을 하는 것과 같다.

    내가 의존하는 컴포넌트가 나보다 I가 크면 안 된다.

     

    모든 컴포넌트가 안정한 상태이면 프로그램은 변경이 불가능하다.

    모든 게 안정한 게 좋은 상황이 아니라 안정한 컴포넌트와 불안정한 컴포넌트가 섞여있어야 한다.

     

    다이어그램을 그릴 때는 관례적으로 불안정한 컴포넌트를 위쪽에 둔다.

    그래서 다이어그램에서 위로 향하는 화살표가 있다면 SDP를 위배하는 다이어그램이다.

     

     

    SDP 문제 해결 방법

    이렇게 SDP를 위배하게 된다면 어떤 식으로든 의존성을 끊어내야 한다.

     

     

    DIP를 이용해서 US 프로토콜을 만들고 UServer 컴포넌트에 위치시킨다.

    그러고 나서 C에서 프로토콜을 채택하고 구현하면 문제를 해결할 수 있다.

     

    프로토콜만 포함한 컴포넌트(UServer)가 이상하게 보일 수 있지만 이 방식은 꼭 필요한 방식이다.

    이를 추상 컴포넌트라고 하며 추상 컴포넌트는 실제 구현 코드가 없기 때문에 상당히 안정적이어서  상대적으로 I가 높은 컴포넌트가 의존하기 좋은 대상이다.

    (이는 정적 타입 언어에서만 사용하고 동적 타입 언어에서는 사용할 필요가 없다.)

     


    SAP: 안정화된 추상화 원칙

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

     

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

     

    고수준 정책을 캡슐화하는 소프트웨어는 반드시 안정된 컴포넌트(I=0)에 위치해야 한다.

    하지만 이렇게 하면 해당 정책을 포함하는 코드는 수정하기 힘들어진다.

    I=0을 유지하면서 이를 해결하기 위해서는 OCP의 개념을 생각해보면 된다.

     

    안정된 컴포넌트는 추상 컴포넌트로 하고 안정성이 확장을 방해해서는 안된다.

    불안정한 컴포넌트는 반드시 구체 컴포넌트여야 한다.

    즉, 안정적인 컴포넌트라면 프로토콜과 추상 클래스로 구성되어 쉽게 확장할 수 있어야 한다.

     

    SAP와 SDP를 같이 생각해보면 의존성은 반드시 안정한 쪽으로 향해야 하고 안정할수록 추상화가 높다.

    이를 컴포넌트를 클래스로 바꿔 생각해보면 DIP나 마찬가지 의미이다.

    추상적인 것이 구체적인 것을 의존하면 안 된다.

     

     

    추상화 정도

    안정성 지표(I)처럼 추상화정도(A)도 있다

     

    • Nc: 컴포넌트의 클래스 개수
    • Na: 컴포넌트의 추상 클래스와 인터페이스의 개수
    • A: 추상화정도 = Na / Nc

    A는 0~1의 값을 가지며 0이면 추상 클래스가 없다는 의미이고 1이라면 추상 클래스로만 구성돼어있다는 의미이다.

    즉 1일 수록 추상화 정도가 높다.

     

     

    A/I 그래프

    추상화정도와 안정성으로 그래프를 그려볼 수 있다.

    이 그래프에서 설명하고자 하는 바는 컴포넌트가 위치해서는 안 되는 구역을 시각화해준다.

     

     

    고통의 구역

    원점에 가깝다면, 즉 고통의 구역이라면 컴포넌트는 안정적이며 구체적이다.

    즉 추상적이지 않아서 확장하기도 힘들고 안정적이므로 변경하기도 힘들다.

    일부 소프트웨어 엔티티는 여기에 위치하곤 한다.

    DB Schme가 대표적인 예시이다.

    변동성이 높지만 매우 구체적이고 많은 컴포넌트가 의존하기 때문이다.

     

     

    쓸모없는 구역

    (1.1)에 가깝다면 매우 추상적이지만 어떠한 컴포넌트도 여기에 의존하지 않는다.

    이런 것은 사실상 쓸모없다.

     

     

    주계열

    두 구역에서 최대한 멀리 존재하는 구역이 바로 주계열이다.

    여기에 존재하는 컴포넌트가 가장 이상적이다.

     

    이후에 주계열에서 컴포넌트가 얼마나 떨어져 있는지의 정도인 D에 대해서 설명하는데 이 부분은 P137에서 설명하고 있다.

     

     

     

    728x90
Designed by Tistory.