본문 바로가기
Programming/Clean Architecture

8장. OCP: 개방 - 폐쇄 원칙

by JKROH 2023. 11. 21.
반응형

개방 - 폐쇄 원칙

  • 소프트웨어 개체는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.
  • 즉, 소프트웨어 개체의 행위는 확장할 수 있어야 하지만, 이때 개체를 변경해서는 안된다.

사고 실험

  • 보고서를 웹 페이지로 표시하는 프로그램에, 보고서를 프린트하는 기능을 추가한다고 해보자.
  • 소프트웨어 아키텍처가 훌륭하다면 기존 코드의 수정량은 거의 없을 것이다.
  • 서로 다른 목적으로 변경되는 요소를 적절히 분리(SRP)하고, 이들 요소 사이의 의존성을 체계화(DIP)하면 변경량의 최소화가 가능하다.
  • 단일 책임 원칙에 따라 위의 과정을 책임으로 나눠보자.
    • 주어진 데이터를 분석하고 계산한다.
    • 계산된 데이터로 웹 페이지용 보고서를 만들거나, 프린트용 보고서를 만든다.
  • 우리는 보고서 생성이라는 하나의 과정이 두 개의 책임으로 분리될 수 있음을 알 수 있다.
    • 데이터의 분석
    • 출력
  • 이렇게 책임을 분리했다면, 두 책임 중 하나에서 변경이 발생해도 다른 하나는 변경되지 않도록 소스코드 의존성도 확실히 조직화해야 한다.
  • 동시에, 새로 조직화한 구조에서는 행위가 확장될 때 변경이 발생하지 않음을 보장해야 한다.
  • 이러한 목적을 달성하기 위해 처리 과정을 클래스 단위로 분할하고, 분할한 클래스를 컴포넌트 단위로 구분한다.

<I> : Interface / <DS>: Data Structure / 열린 화살표 : 사용 / 닫힌 화살표 : 구현 또는 상속

  • A 컴포넌트에서 발생한 변경으로부터 B 컴포넌트를 변경하려면 반드시 A 컴포넌트가 B 컴포넌트에 의존해야한다.
    • A가 B에 의존하면 B의 변경에 따른 전파만 A에 가해질 뿐, A의 변경에 의한 B로의 전파는 이뤄지지 않는다.
  • 위의 그림에서 모든 컴포넌트 간 관계는 단방향으로 이루어져있다. 즉, 양방향 의존으로 인한 변경 전파 등의 문제가 발생하지 않는다. 
  • 그렇다면 가장 보호받는 컴포넌트는 무엇일까? 바로 Interactor다. 가장 보호받는다는 말은 OCP를 가장 잘 준수한다는 말과 같다.
  • 왜 Interactor가 가장 보호받을까? Interactor는 비즈니스 규칙을 포함하기 때문이다. 가장 중요한 문제는 Interactor가 처리하고, 나머지 컴포넌트는 부수적인 문제를 처리한다.
  • 보호의 순위를 따져보면 Interactor - Controller - Presenter - View로 순위를 매길 수 있다.
  • 보호의 순위는 다시 말하면 수준의 순위다. 보호 순위가 높을 수록 고수준의 개념을 담당한다.
  • 컴포넌트 계층구조를 이렇게 조직화하면 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있다.

방향성 제어

  • 위 예시에서 Financial Report Generator 는 Financial Data Gateway 인터페이스를 사용하고 있으며, Financial Data Mapper 는 Financial Data Gateway를 구현한다.
  • 이러한 설계를 통해 의존 관계를 역전시킬 수 있다.
  • 만일 Financital Data Gateway가 없었다면, Financial Report Generator는 Financial Data Mapper에 직접 의존했을 것이다. 즉, Interactor -> Database의 의존이 생겼을 것이다.
  • 그러나 의존 관계를 역전시킴으로써 Interactor <- Database로 의존 방향이 변경되었고, 이를 통해 중요한 컴포넌트인 Interactor를 보호할 수 있게 됐다.

정보 은닉

  • 그렇다면 Financial Report Requester 인터페이스의 존재 이유는 무엇일까? 이 인터페이스는 Financial Report Controller가 Interactor 내부를 지나치게 많이 아는 것을 방지하기 위해 존재한다.
  • 만일 해당 인터페이스가 존재하지 않았다면, Financial Report Controller는 Financial Report Generator에 직접 의존했을 것이다. 그런데, Financial Report Generator는 Financial Entities에 의존한다.
  • 즉, Financial Report Controller는 Financial Entities에 추이 종속성을 가지게 된다.
    • A -> B / B -> C의 의존관계가 있을 때, A -> C의 의존 관계가 생긴다. 이를 추이 종속성이라 부른다.
  • 추이 종속성을 가지면, 소프트웨어 엔티티는 자신이 직접 사용하지 않는 요소에는 절대 의존하면 안된다는 소프트웨어 원칙을 위반하게 된다.
  • 즉, Controller의 변경으로부터 Interactor를 보호하는 일의 우선순위가 높지만, Interactor로부터 발생한 변경으로부터도 Controller를 보호하기 위해서 Interactor 내부를 은닉하는 것이다.

결론

  • OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인한 영향을 줄이는 것이다.
  • 이러한 목표를 달성하기 위해서는 시스템을 컴포넌트 단위로 분리하고, 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있는 형태의 의존성 계층구조가 만들어지도록 해야한다.
반응형

댓글