본문 바로가기

클린아키텍쳐

[클린아키텍쳐] 주요 원칙 정리

 

안녕하세요 주니오스입니다! ✋

 

최근 읽고있는 책인 '클린아키텍쳐(로버트 C. 마틴)'의 중간 점검으로 주요 개념들을 정리해 보려고 합니다.

 

단일 책임원칙

공통 패쇄원칙

의존성 역전 원칙

안정된 의존성 원칙

안정된 추상화 원칙

 

SRP: 단일 책임원칙

단일책인 원칙은 클래스와 함수 레벨에서 사용되는 개념입니다.

 

함수의 경우 하나의 작업만을 수행해야 합니다. 그리고 클래스의 경우 하나의 엑터에 대한 동작만을 수행해야 합니다.

 

예르들어 다수의 엑터가 하나의 클래스를 사용하는 경우를 가정하겠습니다.

 

상점이라는 클래스가 있습니다. 해당 클래스는 '상품 적재' 엑터, '상품 판매' 엑터가 모두 해당 클래스를 사용합니다.

 

이 경우 적재 정책(비즈니스 로직)이 변경되어 상점 클래스를 수정해야하는 일이 발생할 수 있습니다.

 

'상품 적재' 엑터의 마음대로 매서드를 변경하는 경우 '상품 판매' 엑터와 공유하는 매서드를 변경한다면,

 

후자 엑터는 예기치 못한 상황을 맞이할 수 있습니다.

 

따라서 하나의 클래스는 반드시 하나의 엑터만을 위해 존재해야 합니다.

 

하지만, 모든 엑터에 대한 클래스를 추적하는 것은 다소 힘들 수 있습니다. 따라서 이때는 Facade패턴을 사용할 수 있습니다.

 

Facade패턴은 하나의 클래스가 다른 클래스들을 모두 포함하는 패턴입니다.

 

하나의 클래스에서 다른 클래스들을 추적할 수 있음으로 앞선 문제를 해결할 수 있습니다.

 

클래스 함수 수준의 단일 책임원칙은 좀더 고수준인 컴포넌트 단위로 확장될 수 있으며 해당 수준부터는 '개방-패쇄 원칙'으로 불립니다.

 

 

OCP: 개방-패쇄 원칙

앞선 '단일책임 원칙'의 경우 충돌을 방지하는 부분을 주목했다고 볼 수 있습니다.

 

개발-패쇄 원칙의 경우 해당 단계를 넘어서 변형에 대한 격리를 의미합니다.

 

클래스를 변동성측면에 분류하는 개념입니다.

 

예를들어 주식계좌 어플리케이션을 생각해보겠습니다.

 

주식을 사고/파는 비즈니스 로직과 UI중 어떤 것이 변동성이 높을 까요? 상대적으로 후자일 것입니다.

 

이 경우 UI의 변동이 비즈니스 로직에 영향을 미치지 않도록 하는 것이 해당 원칙의 주요 관점입니다.

 

따라서 개발자는 변동성의 측면에서 클래스들을 그룹화해야 합니다. 그룹화된 클래스들을 컴포넌트라고 표현합니다.

 

컴포넌트는 변동성 측면에서 고수준과 저수준으로 분류됩니다.

 

가장 고수준의 컴포넌트일 수록 변동성이 적어야 합니다.

 

최고수준의 컴포넌트 비즈니스로직 또는 어플리케이션의 주요 정책이 위치할 수 있겠군요. 🤔

 

한가지 예시를 들어보겠습니다.

 

고수준 저수준 컴포넌트

 

위 그림을 보시면 주식 구입 로직은 주식 구입 UI의 존재를 알지 못합니다.

 

즉, 주식 구입 UI는 언제는 변경이 가능합니다.

 

하지만 주식 구입 로직은 변하지 않지요. 변동성의 차이가발생하는 부분입니다.

 

마치 고수준의 컴포넌트의 인터페이스는 콘센트로 볼 수 있고 저수준의 경우 플러그라고 할 수 있습니다.

플로그 인

 

콘센트에 꼿히는 기계는 변할 수 있어도 콘센트 자체는 변하지 않지요. 👆

 

이 처럼 저수준 컴포넌트의 변형이 고수준 컴포넌트에 영향을 미치지 않도록 하는 것이 개방-패쇄 원칙의 가장 중요한 포인트입니다.

 

 

DIP: 의존성 역전의 원칙

개팡-패쇄 원칙에서 다룬 주식 구매 다이어 그램에서 이미 의존성 역전이 사용되 었다.

 

그림을 다시한 번보자

의존성 역전

 

위 그림은 컴포넌트간 수준을 나타내기 위한 표현이지만 다음과 같이 표시할 수 있다.

 

인터페이스가 있는 경우 의존성

 

이 경우 인터페이스를 없애보자

 

인터페이스가 있는/없는 경우 의존성 그래프

 

인터페이스가 사라져 '주식 구입UI'는 '주식구입 로직'을 직접적으로 의존해야 한다.

 

하지만 인터페이스에 의해 주식구입이 오히려 인터페이스를 의존하는 방향이 형성된다.

 

의존성 그래프의 방향이 반대가 되어서 의존성 역전이라고 한다. 🙌

 

의존성 역전의 장점은 다음과 같다.

 

위 예제의 경우 앞서 주식구입로직이 고수준 컴포넌트로 변동성이 낮다고 기술하였다.

 

이러한 변동성의 저하가 바로 인터페이스에 의해서 강제되는 것이다.

 

인터페이스가 없는 경우 앞서언급한대로 UI는 '주식구입 로직' 구체타입에 의존해야 하는데

 

주식구입 로직은 아무런 제약사항이 없음으로 변형에 자유롭다. 즉, 주식 구입UI는 해당 변환에 늘 의존적인 변화를 가져야 한다.

 

이러한 구조는 개발 효율성이 크게 저하되는 요소이다.

 

따라서 의존성 역전이 필요하다!

 

 

여기까지 글에서 깨달은 부분이 있다.

 

"비즈니스 로직및 정책은 변경이 자주 발생하면안된다" 가 먼저가 아니라

 

"비즈니스 로직및 정책은 변경이 자주발생하지 않는 환경에 존재해야한다"가 맞다는 결론을 내리게 되었다. 🤔

 

 

안전된 추상화

 

안정된 소프트웨어 아키텍처란 변동성이 큰 구현체에 의존하는 일은 지양하고, 안정된 추상화 인터페이스를 의존해야한다.

 

앞선 의존성 역전과 이어지는 내용이다.

 

구체타입이 아닌 인터페이스를 의존해한다는 것이다.

 

안정된 추상화 원칙은 다음과 같다.

 

💡변동성이 큰 구체 클래스는 참조하지 말아라

 

import를 통한 참조는 인터페이스 타겟으로 한정하라는 의미이다.

 

객체를 내부적으로 생성해야 하는 경우 팩토리 패턴을 사용해야 한다.

 

팩토리 패턴을 사용한 객체 생성

 

 

💡변동성이 큰 구체 클래스로 부터 파생하지 말라

 

상속은 신중하게 사용하라는 말이다.

 

💡구체 함수를 오버라이드 하지 말아라

 

사실상 이경우 첫번째로 언급한 원칙인 구체 클래스에 대한 참조로 이어진다.

 

 

지금까지 클린아키텍처 책을 중간정도 읽고 내용을 간략하게 정리해보았습니다.

 

앞으로 Tuist와 함께 해당 원칙들을 준수하며 코드를 짜보려하고 합니다. 

 

관련된 추가적인 내용을 앞으로 업로드할 예정이니 다음 포스팅도 기대해주세요~! 🤗