OCP

- 모든 컴포넌트간의 관계는 단방향으로 이루어지고, 이들 화살표는 변경으로부터 보호하려는 컴포넌트를 향하도록 그려진다.
- 즉, A 컴포넌트에서 발생한 변경으로부터 B 컴포넌트를 보호하려면 A 컴포넌트가 B 컴포넌트에 의존해야 한다.
- 위 예제에서 Presenter에서 발생한 변경으로부터 Controller를 보호하고자 하고, View에서 발생한 변경으로부터 Presenter를 보호하고자 한다.
- Interactor는 OCP(라 말하고 캡슐화의 의미가 조금 더 짙어보인다)를 가장 잘 준수할 수 있는 곳에 위치한다. (= 즉, 모든 다른 컴포넌트의 변경으로부터 영향을 받지 않는다 )
- Interactor가 이처럼 특별한 위치를 차지하는 이유는 Interactor가 애플리케이션에서 가장 높은 수준의 정책인 업무 규칙을 포함하기 때문임.
이러한 방식이 아키텍처 수준에서 OCP가 동작하는 방식임. 아키텍처는 기능이 어떻게, 왜, 언제 발생하는지에 따라 기능을 분리하고, 분리한 기능을 컴포넌트의 계층구조로 조직화 한다. 컴포넌트 계층구조를 이와 같이 조직화하면 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있다.
OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하는 데 있다. 이러한 목표를 달성하려면 시스템을 컴포넌트 단위로 분리하고, 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있는 형태의 의존성 계층구조가 만들어지도록 해야 한다.
LSP
- LSP는 아키텍처 관점에서도 지켜져야 할 원칙이다.
행동호환성
REST API를 예로 들어 설명하면, 여러 회사가 지켜야할 표준의 API 명세가 있는데 해당 API 명세를 지키지 않고 개발한 회사가 있다고 가정하자. 이러한 상황에서 해당 회사의 API를 이용하려면 if 문을 잔뜩 붙여야 하게 될 것이다.. (이러한 상황에서 실력 있는 아키텍트라면 절대 if 문을 붙이는 것이 아닌 설정용 데이터베이스와 같은 방식을 사용할 것임)
- 즉, 아키텍처 관점에서도 치환 가능성을 위배하게 되면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 하게 된다.
ISP
- 필요 이상으로 많은 걸 포함하는 모듈에 의존하는 것은 해로운 일이다.
- 소스 코드 의존성의 경우 이는 분명한 사실인데, 불필요한 재컴파일과 재배포를 강제하기 때문
- 하지만 더 고수준인 아키텍처 수준에서도 마찬가지 상황이 발생한다.
DIP
- 뛰어난 소프트웨어 설계자와 아키텍트라면 인터페이스의 변동성을 낮추기 위해 애쓴다. 인터페이스를 변경하지 않고도 구현체에 기능을 추가할 수 있는 방법을 찾기위해 노력한다. 이는 소프트웨어 설계의 기본이다.
- 안정된 소프트웨어 아키텍쳐란 변동성이 큰 구현체에 의존하는 일은 지양하고, 안정된 추상 인터페이스를 선호하는 아키텍처라는 뜻임
- 코딩 실천법
- 변동성이 큰 구체클래스를 참조하지 말라
- 변동성이 큰 구체클래스로부터 파생하지말라 (상속)
- 구체 함수를 오버라이드 하지 말라(추상 함수를 오버라이드 하기)

- 곡선은 시스템을 두 가지 컴포넌트로 분리함. 하나는 추상 컴포넌트이며 다른 하나는 구체 컴포넌트
- 추상 컴포넌트는 애플리케이션의 모든 고수준 업무 규칙을 포함
- 구체 컴포넌트는 업무 규칙을 다루기 위해 필요한 모든 세부사항을 포함함
- 해당 곡선이 아키텍처 경계가 됨. 그리고 의존성은 이 경계를 기준으로 더 추상적인 엔티티가 있는 쪽으로만 향한다. ⇒ 의존성 규칙(
Dependency Rule
)