-
Clean Architecture - 설계 원칙Book/Clean Architecture 2022. 9. 26. 08:52
좋지 못한 코드를 작성하면 아키텍처가 큰 의미가 없게 된다.
반대로 코드가 좋아도 아키텍처를 엉망으로 만들면 큰 의미가 없다.
좋은 코드로 좋은 아키텍처를 정의하는 원칙이 필요한데 이를 SOLID 원칙이라고 한다.
SOLID 원칙은 함수와 데이터 구조를 클래스로 배치하고 이 클래스를 서로 결합하는 방법을 제시한다.
여기서 의미하는 클래스는 함수와 데이터를 결합한 집합이다.
SOLID 원칙의 목적은 중간 수준의 소프트웨어 구조를 다음과 같이 만드는 것이다.
- 변경에 유연하다.
- 이해하기 쉽다.
- 많은 시스템에 사용될 수 있는 컴포넌트의 기반이 된다.
SOLID의 간단한 설명
SRP(Single Responsibility Principle): 단일 책임 원칙
각 소프트웨어 모듈은 변경의 이유가 단 하나여야만 한다.
OCP(Open Closed Principle): 개방 폐쇠 원칙
기존의 코드를 수정하기보다 새로운 코드를 추가하는 방식으로 시스템 행위를 변경할 수 있도록 설계해아한다.
LSP(Liskov Substitution Principle): 리스코프 치환 원칙
상호 대체 가능한 구성요소를 이용해서 시스템을 만들려면 구성요소는 반드시 서로 치환가능해야한다.
ISP(Interface Segregation Principle): 인터페이스 분리 원칙
사용하지 않는 것에 의존하지 않아야한다.
DIP(Dependency Inversion Principle): 의존성 역전 원칙
고수준 정책 코드는 저수준 세부사항을 구현하는 코드에 의존해서는 안된다.
세부사항이 정책에 의존해야한다.
SOLID는 워낙 유명하므로 자세한 설명보다는 아키텍처 관점에서 설명한다.
SRP: 단일 책임 원칙
모든 모듈이 단 하나의 일만 해야한다는 의미가 아니다.
함수는 반드시 하나의 일만 해야한다는 원칙과 헷갈리면 안된다.
SRP는 단일 모듈은 변경의 이유가 하나뿐이어야한다. 라는 원칙이다.
변경을 요청하는 한명 이상의 사람, 즉 집단을 액터(Actor)라는 단어를 사용했다.
변경을 요청하는 사람이 한명이 아닐 수 있기때문에 오해를 없애기 위해서 단어를 명확하게 한 거 같다.
하나의 모듈은 하나의 액터에 대해서만 책임을 져야한다.
그럼 모듈이란?
소스파일이라고 생각해도 되고 만약 코드를 소스파일에 저장하지 않는 경우에는 함수와 데이터구조로 구성된 집합으로 보면 된다.
(클래스를 함수와 데이터의 집합이라고 본다면 이 클래스들이 모인것을 모듈이라고 생각하면 될듯하다.)
이후에는 SRP를 위반하는 예시인 Employee 클래스를 이용해 SRP를 이해시키는 부분이 들어가있는데 여기다 옮기지는 않겠다!
67P부터 읽어보면 좋다.
SRP를 지키는 방법으로 여러가지가 있는데 여기서는 Data와 Method를 구분하는 방법을 사용한다.
그리고 이때 생기는 단점인 나눠진 클래스의 인스턴스화와 추적에 대해서는 Facade 패턴을 이용해서 해결한다.
OCP: 개방 폐쇄 원칙
Artifact(개체)는 확장에는 열려 있어야하고 변경에는 닫혀 있어야 한다.
즉 행위는 확장할 수 있어야하지만 이때 개체를 변경하면 안된다는 의미다.
이는 아키텍처를 공부하는 근본적인 이유이기도한데
요구사항을 수정하다가 코드의 엄청 많은 부분을 수정해야하는 경우가 바로 이 경우다.
재무 데이터 출력에 대한 예시로 이해를 돕고 있는데 이 부분은 74P를 참고하면 된다.
OCP의 목표는 시스템을 확장하기 쉽게 만드는 동시에 변경으로 인해서 시스템이 너무 많은 영향을 받지 않도록 하는것이다.
그러기 위해서는 시스템을 컴포넌트 단위로 분리하고 저수준의 컴포넌트에서 발생한 변경으로부터 고수준의 컴포넌트를 보호할 수 있는 의존성 계층 구조를 설계해야한다.
LSP: 리스코프 치환 원칙
Subtype(하위타입)의 정의는
A타입의 객체 a와 B타입의 객체 b가 있다면 B타입을 이용해서 정의한 프로그램에서 b의 자리를 a로 바꿔도 프로그램의 행위가 변하지 않는다면 A는 B의 subtype이다.
LSP를 위반하는 문제로 정사각형/직사각형 문제를 예를 든다.
일반적으로 정사각형을 직사각형의 하위타입이라고 생각할 수 있지만
직사각형은 가로, 세로를 따로따로 지정할 수 있지만 정사각형은 가로 세로 둘 중에 하나만 변경할 수 없기때문에 발생한다.
let rectangle: Rectangle = ... rectangle.setW(5) rectangle.setH(2) rectangle.area() == 10 // true? false?
직사각형일때는 아래가 true겠지만 정사각형이라면 false가된다.
setH(2)를 하면 자동적으로 Width도 2로 변경되기때문!
LSP와 아키텍처
초기에는 상속을 이용하도록 했지만 언어가 발전된 지금은 프로토콜을 이용해서 LSP를 지키도록 노력할 수 있다.
LSP를 지키지않으면 어떤일이 일어날 수 있는지는 taxi dispatch의 예를 들어서 p84에서 설명하고 있으니 읽어보자.
ISP: 인터페이스 분리 원칙
ISP를 설명할때 유명한 다이어그램이다.
User1은 op2를 사용하지 않아도 해당 코드와 관련이 생길수 있다.
그래서 아래와 같이 변경하는게 좋다는 말을 하고 있다.
필요 이상으로 많은 것을 포함하는 모듈에 의존하는것은 위험하다.
코드 의존성뿐만 아니라 불필요한 재컴파일, 재배포를 강제하기 때문이다.
해당 문제는 정적언어와 동적언어에 따라서 재컴파일과 재배포가 필요없을 수도 있다는 말을 하고 있다.
그래서 ISP가 아키텍처가 아니라 언어와 관련된 문제라고 생각할 여지가 있다고 설명한다.
DIP: 의존성 역전 원칙
유연성이 극대화된 시스템이란 의존성이 추상에 의존하고 구체에 의존하지 않는다는것을 말한다.
하지만 이 규칙은 지키기 힘들다고 한다. 어쩔 수 없이 의존할 수 밖에 없지만 그래도 최대한 피하라고 설명하고 있다.
추상 인터페이스가 변경이 생기면 이를 구체화한 구현체도 수정을 해야한다.
하지만 반대로 구현체를 수정한다해도 인터페이스가 변경되는 일은 거의 없다.
- 변동성이 큰 구체 클래스를 참조하지말고 추상 인터페이스를 참조하자.
- 변동성이 큰 쿠체 클래스를 상속하지 말자.
- 구체함수를 override하지 말자.
의존성을 처리할때 추상 팩토리를 사용하는 방법에 대해서 설명을 한다.
DIP 위배를 모두 없앨 수는 없지만 DIP를 위배하는 클래스들을 구체 컴포넌트 내부로 모을 수 있고 이를 다른 부분과 분리 시킬 수 있다.
SOLID 관련 자료
https://www.youtube.com/watch?v=Uhzoseuhkbk
https://mangkyu.tistory.com/194
728x90'Book > Clean Architecture' 카테고리의 다른 글
Clean Architecture - 컴포넌트 원칙 (1) 2022.12.14 Clean Architecture - 프로그래밍 패러다임 (0) 2022.09.18 Clean Architecture - Robert C. Martin (0) 2022.09.17