SOLID
- 함수와 데이터 구조를 클래스로 배치하고 결합하는 방법
종류
SRP: 단일 책임 원칙
- 소프트웨어 모듈은 변경 이유가 하나여야 함
OCP: 개방-폐쇄 원칙
- 기존 코드를 수정하기 보다 새로운 코드를 추가하는 방법으로 행위를 변경해야 함
LSP: 리스코프 치환 원칙
- 상호 대체 가능한 구성요소를 이용해 소프트웨어 시스템을 만들 수 있으려면, 구성요소는 반드시 서로 치환 가능해야 함
ISP: 인터페이스 분리 원칙
- 소프트웨어 설계자는 사용하지 않은 것에 의존하지 않아야 함
DIP: 의존성 역전 원칙
- 고수준 정책을 구현하는 코드는 저수준 세부사항을 구현하는 코드에 의존해서는 안됨
> 세부사항이 정책에 의존
장점
- 변경에 유연
- 이해하기 쉬움
- 컴포넌트 기반
7장, SRP: 단일 책임 원칙
단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다.
-> 하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.
-> 응집성
SRP: 메서드와 클래스 수준의 원칙
- 아키텍처 수준에서 아키텍처 경계의 생성을 책임지는 변경의 축이 됨
우발적 중복
- 각자 다른 팀에서 Employee 기능을 정의함 -> 변경 시 문제 발생
- 서로 다른 액터가 의존하지 않아야 함
병합
- 병합은 항상 위험이 나타남
해결
메서드를 각기 다른 클래스로 이동하면 해결 가능
- 퍼사드 패턴
8장, OCP: 개방-폐쇄 원칙
소프트웨어 개체는 확장에 열려있어야 하고, 변경에는 닫혀있어야 한다.
- 요구사항을 확장하는 데, 많은 수정이 있으면 아키텍처는 실패한 것이다.
처리 과정
1. 클래스 단위로 분할
2. 컴포넌트 단위로 구분
3. 인터페이스를 이용하여 의존성 표시
4. 모든 컴포넌트는 단방향
5. Interactor: OCP를 가장 잘 준수하는 곳에 위치
-> 업무 규칙을 포함하기 때문에 가장 높은 수준의 정책을 포함함
-> 변경 시, Controller 등을 보호하기 위해 Interactor 내부를 은닉
6. 보호 계층 구조가 LEVEL 개념을 바탕으로 생성 되는 것에 주목
결론
OCP는 HOW, WHY, WHEN에 따라 기능을 분리하고, 컴포너늩의 계층 구조로 조직화
9장, LSP: 리스코프 치환 원칙
S타입의 객체 o1 각각에 대응하는 T타입 객체 o2가 있고, T타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위는 변하지 않는다면, S는 T의 하위 타입이다.
상속
1. 충족
- License가 하위 타입 중 무엇을 사용하는 지 의존하지 않아, 하위 타입은 모두 Licnese 타입을 치환 할 수 있음
2. 위반
- Rectangle의 높이와 너비가 서로 독립적으로 변경 되지만, Square는 항상 같이 변경됨
-> if문 등을 이용해 Rectangle이 Square인지 검사를 해야 함 (User의 행위가 타입에 의존) -> 치환 불가
결론
LSP를 아키텍처 수준까지 확장해서 치환 가능성을 남겨야 함
ex) REST에서, 인터페이스를 준수하지 않았을 때, 버그로부터 시스템을 격리할 수 있어야 함
10장, ISP: 인터페이스 분리 원칙
- User1과 User2는 관계가 없지만, User1이 op1을 변경하면 op2도 영향을 받아서 다시 컴파일을 해야 함
- 오른쪽 사진과 같이 인터페이스 분리
- 인터페이스가 분리되지 않는 이유: import, use, include 등의 문제
-> 루비나 파이썬 같은 동적 타입 언어는 발생하지 않음 (결합도 낮음)
11장, DIP: 의존성 역전 원칙
유연성이 극대화된 시스템, 소스코드 의존성이 추상에 의존하여 구체에는 의존하지 않은 시스템
안정화된 추상화
- 추상 인터페이스에 변경이 생기면 구체화한 구현체들도 따라서 수정해야 함
- 구체적인 구현체에 변경이 생기더라도 인터페이스는 거의 변경 될 필요가 없음
> 인터페이스는 구현체보다 변동성이 낮음
방법
1. 변동성이 큰 구체 클래스를 참조하지 않음 -> 추상 인터페이스, 추상 팩토리 사용을 강제
2. 변동성이 큰 구체 클래스로부터 파생X
3. 구체 함수를 오버라이드X
-> 의존성을 상속하게 됨
4. 구체적이며 변동성이 크면 이름을 언급하지 말아라
팩토리
의존성을 처리할 때, 추상 팩토리를 사용함
1. Application은 Service 인터페이스를 통해 ConcreteImpl 인스턴스를 생성
-> ConcreteImple에 대해 소스 코드 의존성X
2. SeviceFactory 인터페이스의 makeSvc 호출 -> ServiceFactory로부터 파생된 ServiceFactoryImpl에서 구현
3. ServiceFactoryImpl 구현체가 ConcreteImpl의 인스턴스를 생성 후 Service로 반환
> 제어흐름은 소스 코드 의존성과는 정반대 방향으로 곡선을 가로지름 (곡선: 아키텍처 경계)
+) 구체 컴포넌트는 최소한 하나는 포함됨 = main
'IT > 책' 카테고리의 다른 글
[Clean Architecture] 5부, 아키텍처(1) (0) | 2021.12.12 |
---|---|
[Clean Architecture] 4부, 컴포넌트 원칙 (0) | 2021.12.04 |
[Clean Architecture] 2부, 프로그래밍 패러다임 (0) | 2021.11.27 |
[Clean Architecture] 1부, 소개 (0) | 2021.11.27 |
[Clean Code] 1달1권, 첫번째 책 후기 (0) | 2021.11.22 |