Development/Code

[클린 아키텍처] 컴포넌트 원칙과 Spring Boot 어플리케이션

Danny Seo 2024. 1. 27. 20:52

S.O.L.I.D. 원칙에 대한 논의 후, 이제 소프트웨어 컴포넌트 원칙을 살펴볼 시간입니다.
첫 번째 원칙 세트에서는 클래스, 인터페이스, 메소드와 같은 더 저수준에서 소프트웨어 시스템을 구조화하는 방법에 대해 이야기했습니다. 여기에서는 마이크로서비스, 컴포넌트, 플러그인, 패키지를 구축하는 방법에 대한 패턴을 고려하는 더 고수준의 원칙들에 대해 논의합니다. 컴포넌트 원칙에는 두 가지 주요 방향이 있습니다: 응집도 원칙결합도 원칙. 오늘 우리는 응집도 원칙과 그것이 스프링 부트 애플리케이션에 구현되는 방법을 다룰 것입니다.

응집도 원칙

응집도 원칙에서 주된 관심사는 그들의 응집도에 기반한 소프트웨어 컴포넌트의 구조화입니다. 클래스들이 서로 속해 있다면, 함께 구축되어야 합니다. 여기서 세 가지 주요 원칙은 다음과 같습니다:

  • REP: 재사용/릴리스 등가 원칙
  • CCP: 공통 폐쇄 원칙
  • CRP: 공통 재사용 원칙

재사용/릴리스 등가 원칙 (REP)컴포넌트를 형성하는 클래스와 모듈들이 응집된 그룹에 속해야 함을 의미합니다. 컴포넌트는 단순히 무작위의 클래스와 모듈들의 혼합체로 구성될 수 없으며, 대신 이 모듈들이 공유하는 어떤 종합적인 주제나 목적이 있어야 합니다.

 

이 원칙에서 주된 관심사는 클래스, 패키지, 플러그인의 응집도와 그것의 배포 가능성에 관한 것입니다. 특정 컴포넌트의 공개는 무작위 클래스에서의 무작위 변경에 의해 촉발되어서는 안 됩니다. 반대로 함께 배포할 수 있는 컴포넌트들만 묶여야 합니다. 따라서 릴리스의 버전, 태그 또는 문서는 오직 응집된 컴포넌트들만 모아야 합니다.

 

공통 폐쇄 원칙 (CCP)같은 이유와 같은 시점에 변경되는 클래스들을 컴포넌트로 모으는 것을 의미합니다. 다른 시점에 다른 이유로 변경되는 클래스들은 다른 컴포넌트로 분리합니다.

 

이 원칙은 고수준 컴포넌트에 재정의된 단일 책임 원칙과 개방-폐쇄 원칙을 기반으로 합니다. (이 원칙들에 대해서는 제 다른 블로그 시리즈를 참조하세요: SRP, OCP). 이 원칙은 소프트웨어에 안정성을 가져다주며, 컴포넌트의 변경이 다른 컴포넌트에 최소한의 영향을 미쳐야 함을 의미합니다. 반면에, 새로운 기능은 최소한의 컴포넌트를 확장할 것입니다 (OCP를 참조).

 

공통 재사용 원칙 (CRP) "컴포넌트의 사용자들에게 필요하지 않은 것에 의존하도록 강요하지 마라"고 말합니다.

 

이 원칙은 컴포넌트들을 격리시키는 것이 최선의 관행임을 명시합니다. 컴포넌트 간의 의존성 흐름을 최소화해야 합니다. 따라서 사용하는 컴포넌트가 사용된 컴포넌트에 의존성이 있다면, 사용된 컴포넌트가 변경될 때마다 사용하는 컴포넌트도 변경해야 합니다. 이를 방지하기 위해 의존하는 아티팩트들을 같은 컴포넌트 안에 유지해야 합니다.

 

따라서, 이 세 가지 원칙을 모두 논의한 후에, REP와 CCP는 포함 원칙이고 CRP는 배제 원칙임을 알 수 있습니다.
(이들 세 원칙은 상충하는 관계입니다, 아래 다이어그램을 보시죠.)

경험 많은 아키텍트는 불필요한 릴리스가 너무 많거나, 자주 변경되는 컴포넌트, 사용하기 어려운 컴포넌트를 피하기 위해 이러한 원칙들 사이에서 타협점을 찾아야 합니다. 따라서 중간 지점이 어딘가에 있어야 합니다.

 

그렇다면 이 원칙들을 스프링 부트 애플리케이션 리팩토링을 통해 구현하는 실제 예제를 살펴봅시다.


 

위에서 주어진 원칙들을 적용하기 위해, 수입(Income)과 지출(Expense) 두 가지 사용 사례가 있는 현금 흐름(Cashflow) 시스템의 스프링 부트 애플리케이션을 만들어봅시다. 처음에는 다음 클래스 다이어그램에서 볼 수 있듯이, 두 사용 사례 모두 동일한 현금 흐름 컴포넌트 아래에 모아져 있습니다. 하지만, 이것은 좋지 못한 설계입니다. Income API에 변경이 필요한 상황을 상상해 보세요. 이 경우에는 두 사용 사례 모두 동일한 컴포넌트(Cashflow) 에 있기 때문에 다시 컴파일하고 배포하고 릴리스해야 합니다. 따라서 한 사용 사례가 변경될 때마다 다른 하나도 영향을 받게 됩니다.

 

 

자 이제, 현금 흐름 애플리케이션에 컴포넌트 응집 원칙을 적용해 봅시다. 기본적으로 해야 할 일은 사용 사례를 다른 컴포넌트로, 우리 상황에서는 다른 플러그인으로 분리하는 것입니다. 따라서 현금 흐름 플러그인 아래에 모든 것을 두는 대신, 현금 흐름을 수입과 지출이라는 두 개의 독립된 플러그인으로 분리하여 소프트웨어를 재구조화합니다. 아래 주어진 리팩토링된 클래스 다이어그램에서 볼 수 있듯이, 수입 플러그인에서의 변경이 지출 플러그인에 영향을 미치지 않습니다. 따라서 지출 플러그인을 다시 컴파일, 재배포 및 릴리스할 필요가 없습니다.