[클린 아키텍처] 8. OCP: 개방-폐쇄 원칙

햄도·2021년 8월 24일
0

Clean Architecture

목록 보기
8/11

출처

클린 아키텍처를 읽으며 정리한 내용입니다.

8. OCP: 개방-폐쇄 원칙

소프트웨어 개체의 행위는 확장할 수 있어야 하지만, 이때 산출물을 변경해서는 안된다. 2장을 읽었다면 알겠지만, 이것이 소프트웨어 아키텍처를 공부하는 가장 근본적인 이유라고 할 수 있다.

OCP는 클래스와 모듈을 설계할 때에도 도움이 되지만, 아키텍처 컴포넌트 수준에서 고려할 때 훨씬 중요한 의미를 가진다.

사고 실험

웹 페이지로 보여주던 재무제표를 동일한 형태로 출력해야 할 때, 원래 코드를 얼마나 많이 수정해야 할까?
소프트웨어 아키텍처가 훌륭하다면, 변경량은 최소가 되어야 하며 이상적인 변경량은 0이다. 서로 다른 목적으로 변경되는 요소를 적절하게 분리하고, 이 요소 사이의 의존성을 체계화하면 수정해야 하는 범위를 최소화할 수 있다.

재무 분석기를 통해 가공한 재무 데이터를 상황에 따라 웹에 표시하거나 프린터로 출력하는 두 가지 용도로 사용한다고 했을 때, 단일 책임 원칙을 적용하면 재무 데이터를 가공한 후 보고서용 데이터를 생성, 적절히 포매팅하는 데이터 흐름을 만들 수 있다.

여기서의 핵심은 보고서 생성이 두 개의 책임(웹과 출력)으로 분리된다는 사실이다. 이렇게 책임을 분리했다면, 두 책임 중 하나에서 변경이 발생하더라도 다른 하나는 변경되지 않도록 소스 코드 의존성도 확실히 조직화해야 한다.

이러한 목적을 달성하려면 이 클래스를 컴포넌트 단위로 구분해야 한다.
이 때 주의할 점은 모든 컴포넌트 관계는 단방향으로만 이루어지며, 이 화살표는 변경으로부터 보호하려는 컴포넌트를 향하도록 그려진다는 것이다.

즉 A 컴포넌트에서 발생한 변경으로부터 B 컴포넌트를 보호하려면, 반드시 A 컴포넌트가 B 컴포넌트에 의존해야 한다.

또한 업무 규칙을 포함하는 컴포넌트는 가장 중요한 문제를 담당하기 때문에, OCP를 가장 잘 준수할 수 있는 곳에 위치해야 한다. 따라서 업무 규칙을 포함하는 클래스는 어떤 변경도 영향을 줄 수 없는 곳에 위치한다.

이처럼 의존하는 관계는 담당하는 문제의 중요도와도 관련이 있다. 덜 중요한 쪽이 더 중요한 쪽에 의존한다.

이것이 아키텍처 수준에서 OCP가 동작하는 방식이다. 아키텍트는 기능이 어떻게, 왜, 언제 발생하는지에 따라서 기능을 분리하고, 컴포넌트의 계층구조로 조직화한다.

이렇게 조직화하면 저수준 컴포넌트에서 발생한 변경으로부터 고수준의 컴포넌트를 보호할 수 있다.

방향성 제어

본문의 다이어그램에서 의존의 방향을 제어하기 위해 인터페이스를 이용해 의존성을 역전시킨 것도 눈여겨볼만 하다.

FinancialDataGateway 인터페이스는 FinancialReportGeneratorFinancialDataMapper 사이에 위치하는데, 이 인터페이스가 없었다면 의존성이 더 중요한 Interactor 컴포넌트에서 덜 중요한 Database 컴포넌트로 향하게 된다.

FinancialReportPresenter 인터페이스와 2개의 View 인터페이스도 같은 목적을 가진다.

정보 은닉

FinancialReportRequester 인터페이스는 앞서 말한 인터페이스들과는 달리, FinancialReportController가 Interactor 내부에 대해 너무 많이 알지 못하도록 막기 위해 존재한다.

이 인터페이스가 없었다면 Controller는 FinancialEntities에 대해 추이 종속성을 가지게 된다. 추이 종속성을 가지게 되면, 소프트웨어 엔티티는 '자신이 직접 사용하지 않는 요소에는 절대 의존해서는 안된다'는 소프트웨어 원칙을 위반하게 된다.

Controller에서 발생한 변경으로부터 Interactor를 보호하는 동시에, Interactor에서 발생한 변경으로부터 Controller도 보호되도록 하기 위해 Interactor 내부를 은닉한다.

결론

OCP의 목표는 시스템을 확장하기 쉬우면서도 변경으로 인해 시스템이 영향을 받지 않도록 하는 데에 있다.

이 목표를 달성하려면 시스템을 컴포넌트 단위로 분리하고, 저수준 컴포넌트의 변경으로부터 고수준 컴포넌트를 보호할 수 있는 의존성 계층구조가 만들어지도록 해야 한다.

profile
developer hamdoe

0개의 댓글