아키텍처
SOLID 설계 원칙
(클린 아키텍처를 기반으로 작성하였습니다. 개발자라면 클린 아키텍처 책을 꼭 읽어보시길 추천드립니다)
SOLID 원칙의 목적은 다음과 같다
- 변경에 유연하다
- 이해하기 쉽다
- 많은 소프트웨어 시스템에서 사용될 수 있는 컴포넌트의 기반이 된다 (재사용하기 좋다)
SRP: 단일 책임 원칙
헷갈리지 말라 단일 모듈이 단 하나의 일만 해야 한다는 의미 아니다. 단일 모듈의 변경 이유가 오직 하나 뿐이어야 한다. 좀 더 명확히 하면 단일 모듈은 오직 하나의 사용자(또는 이해관계자)에 대해서만 책임져야 한다.
아래와 같이 하나의 클래스가 서로 다른 세 명의 액터를 책임지므로 SRP 위반이며 3개의 클래스로 분리해야 한다.
예를 들면 이렇게
그러나 각각을 추적 관리하기 어려우므로 퍼사드(Facade) 패턴을 사용하면 좋다
OCP: 개방-폐쇄 원칙
소프트웨어 개체는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다. 즉 요구사항을 살짝 확장하는데 엄청난 수정이 필요하면 망한 아키텍처일 것이다.
이를 달성하려면 시스템을 컴포넌트 단위로 분리하고 저수준 컴포넌트의 변경으로 부터 고수준 컴포넌트를 보호할 수 있도록 의존 관계를 구성해야 한다. 이때 인터페이스를 사용하여 정보를 은닉하거나 필요한 경우 의존성을 역전(DIP)시킨다.
참고로 수준(level)은 입력 또는 출력까지의 거리라고 정의하는데 업무 규칙(비지니스 로직)이 고수준이고 UI나 웹, 외부 API, DB가 저수준이라고 보면 된다.
LSP: 리스코프 치환 원칙
S타입의 객체 o1 각각에 대응하는 T타입 객체 o2가 있고, T타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위가 변하지 않는다면, S는 T의 하위 타입니다.
내용이 다소 난해하지만 자세히 읽어보면 당연한 내용이다. 상속이나 인터페이스와 구현체에 적용되는 설계 원칙이다.
ISP: 인터페이스 분리 원칙
사용하지 않는 모듈에 대한 의존도를 제거하는 가장 효과적인 방법이다. 사용자 관점에서 생각해보아도 필요한 버튼(기능)만 보이는 것이 가장 쉽고 문제의 소지가 적다.
DIP: 의존성 역전 원칙
DIP는 클린 아키텍처나 헥사고날 아키텍처를 구현하기 위한 가장 핵심적인 원칙이다.
DB나 외부 API와 같은 경우 사용 관점에서 보면 고수준에서 저수준으로 의존성을 가지게 된다. 하지만 이때 추상 인터페이스를 잘 사용하면 의존성을 역전시킬 수 있다. 여기서 중요한 것은 추상 인터페이스가 고수준 패키지로 포함되도록 하는 것이다. 고수준의 업무 규칙의 관점에서 추상 인터페이스를 정의하고 저수준에서 구현하도록 하여 의존성을 역전시킨다.