[Clean Architecture] 8장. OCP: 개방-폐쇄 원칙
|Introduction
소프트웨어 개체 (
artifact
) 는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.
- 소프트웨어 개체의 행위는 확장할 수 있어야 하지만, 이때 개체를 변경해서는 안된다.
- 소프트웨어 아키텍처를 공부하는 가장 근본적인 이유
- 대다수는
OCP
를 클래스와 모듈을 설계할 때 도움되는 원칙이라고 알고 있음 - 아키텍처 수준에서
OCP
를 고려할 때 훨씬 중요한 의미가 됨
사고 실험
- 재무제표를 웹 페이지로 보여주는 시스템
- 데이터는 스크롤 가능
- 음수는 빨간색으로 출력
- 이때 이해관계자가 동일한 정보를 보고서 형태로 변환해서 흑백 프린터로 출력해달라고 요청함
- 보고서에는 페이지 번호가 있어야 하고,
- 페이지마다 적절한 머릿글과 바닥글이 있어야 하며,
- 표의 각 열에는 레이블이 있어야 하고,
- 음수는 괄호로 감싸야 한다.
- 원래 코드는 얼마나 많이 수정해야 할까?
- 소프트웨어 아키텍처가 훌륭하다면 변경되는 코드의 양은 가능한 한 최소화될 것
- 이상적인 변경량은 0
- 어떻게?
- 서로 다른 목적으로 변경되는 요소를 적절하게 분리하고 (
SRP
), - 이들 요소 사이의 의존성을 체계화함으로써 (
DIP
) 변경량을 최소화할 수 있다.
- 서로 다른 목적으로 변경되는 요소를 적절하게 분리하고 (
- SRP 를 적용하면
- 보고서 생성이 두 개의 책임으로 분리됨
- 모든 컴포넌트 관계는 단방향으로 이뤄짐
Interactor
는OCP
를 가장 잘 준수할 수 있는 곳에 위치Database
,Controller
,Presenter
,View
에서 발생한 어떤 변경도Interactor
에 영향을 주지 않음
- 왜
Interactor
가 이처럼 특별한 위치를 차지해야만 하는가?- 그 이유는
Interactor
가 업무 규칙을 포함하기 때문에 Interactor
는 애플리케이션에서 가장 높은 수준의 정책을 포함Interactor
이외의 컴포넌트는 모두 주변적인 문제를 처리Interactor
는 가장 중요한 문제를 담당
- 그 이유는
- 보호의 계층구조가 ‘수준(
level
)’ 이라는 개념으로 어떻게 생성되는지 주목 - 이게 바로 아키텍처 수준에서
OCP
가 동작하는 방식 - 아키텍트는 기능이 어떻게, 왜, 언제 발생하는지에 따라서 기능을 분리하고, 분리한 기능을 컴포넌트의 계층구조로 조직화함
- 컴포넌트 계층구조를 이와 같이 조직화하면 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있음
방향성 제어
- 컴포넌트 간 의존성이 제대로 된 방향으로 향하고 있음을 확실히 보여주고 있음
정보 은닉
FinancialReportRequester
인터페이스- 방향성 제어와는 다른 목적을 가짐
FinancialReportController
가Interactor
내부에 대해 너무 많이 알지 못하도록 막기 위해서 존재- 만약 이 인터페이스가 없었다면,
Controller
는FinancialEntities
에 대해 추이 종속성을 가지게 됨- transitive dependency
- 추이 종속성을 가지게 되면
- 소프트웨어 엔티티는 ‘자신이 직접 사용하지 않는 요소에는 절대로 의존해서는 안된다’ 는 소프트웨어 원칙을 위반하게 됨
- 이 원칙은 인터페이스 분리 원칙(
ISP
)과 공통 재사용 원칙(CRP
)을 설명할 때 다시 나옴
- 이 원칙은 인터페이스 분리 원칙(
- 소프트웨어 엔티티는 ‘자신이 직접 사용하지 않는 요소에는 절대로 의존해서는 안된다’ 는 소프트웨어 원칙을 위반하게 됨
결론
OCP
는 시스템의 아키텍처를 떠받치는 원동력 중 하나OCP
의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하는데 있음- 이러한 목표를 달성하려면 시스템을 컴포넌트 단위로 분리하고, 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있는 형태의 의존성 계층구조가 만들어지도록 해야 한다.