2022.01.07 - [Study/컴퓨터 공학] - 클린 아키텍처
2022.01.11 - [Study/컴퓨터 공학] - 클린 아키텍처 #2
2022.02.15 - [Study/컴퓨터 공학] - 클린 아키텍처 #4
2022.03.02 - [Study/컴퓨터 공학] - 클린 아키텍처 #5
2022.05.16 - [Study/컴퓨터 공학] - 클린 아키텍처 #6
클린 아키텍처 : 3부 11장까지
저자 : 로버트 C. 마틴
출판 : 인사이트
출간 : 2019.08.20.
학습 방법 : 책을 읽고 소제목 단위로 핵심 내용을 1~3문장 정도로 요약
3부. 설계 원칙
⦿ SOLID 원칙
✓ 함수와 데이터를 결합한 집합(클래스와 같은)에 적용되는 원칙
✓ 목적
- 변경에 유연하다.
- 이해하기 쉽다.
- 재사용 가능한 컴포넌트의 기반이 된다.
✓ 모듈과 컴포넌트 내부에서 사용되는 소프트웨어 구조를 정의
SRP(Single Responsibility Principle) : 단일 책임의 원칙
OCP(Open-Closed Principle) : 개방-폐쇄의 원칙
LSP(Liskov Substitution Principle) : 리스코프 치환 원칙
ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
DIP(Dependency Inversion Principle) : 의존성 역전의 원칙
7장. SRP: 단일 책임의 원칙
✓ SRP(Single Responsibility Principle) : 단일 책임의 원칙에 대한 오해
- 모든 모듈이 단 하나의 일만 해야 한다.
✓ 제대로 된 의미
- 단일 모듈은 변경의 이유가 오직 하나뿐이어야 한다.
- 하나의 모듈은 오직 하나의 사용자 또는 이해관계자에 대해서만 책임져야 한다.
- 최종버전 : 하나의 모듈은 오직 하나의 액터에 대해서만 책임져야 한다.
⦿ (SRP 위반)징후1 : 우발적 중복
✓ 서로 다른 액터가 같은 기능을 공유하지만 공유된 기능에서 한 액터에게만 필요한 변경이 발생하는 경우
⦿ (SRP 위반)징후2 : 병합
✓ 서로 다른 액터를 담당하는 두 개발자가 동시에 각자가 담당하는 액터를 위한 수정을 진행할 때 버전 관리 시스템에서는 위험한 병합이 발생할 수 있다.
⦿ 해결책
✓ 액터별로 완전히 독립된 클래스를 만들고 데이터를 공유한다.
✓ 다수의 클래스를 관리해야 하는 어려움을 피하기 위해 Facade 패턴을 이용한다. Facade 클래스는 독립된 각각의 클래스 객체를 생성하고 요청된 메서드를 가진 객체에 위임하는 역할을 한다.
✓ 가장 중요한 메서드를 가진 클래스를 Facade로 만들어 데이터까지 관리하고 덜 중요한 메서드를 가진 클래스를 분리한다.
⦿ 결론
✓ 단일 책임의 원칙은 메서드와 클래스 수준의 원칙이다.
✓ 보다 상위에서는 다음 두 원칙으로 확장된다.
- 컴포넌트 수준 : 공통 폐쇄의 원칙
- 아키텍처 경계의 생성 : 변경의 축
8장. OCP: 개방-폐쇄 원칙
✓ 버트란트 마이어, 1988
“ 소프트웨어 개체(artifact)는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다. “
✓ 소프트웨어 개체의 행위는 확장할 수 있어야 하지만, 이 때 개체를 변경해서는 안된다.
✓ 아키텍처 컴포넌트 수준에서 고려할 때 훨씬 중요.
⦿ 사고 실험
✓ 서로 다른 책임이 있다면(액터가 다르다면) 각각의 책임을 (중요도의 계층 구조에 따라)분리한다(소스 코드도 분리).
✓ 변경할 컴포넌트는 변경으로부터 보호되어야 할 컴포넌트에 의존해야 한다.
✓ 가장 엄격하게 보호 받아야 하는 컴포넌트는 가장 높은 수준의 정책을 포함한(업무 규칙을 포함한) 컴포넌트이다.
UML에서 화살표가 출발한 클래스는 화살표가 가리키는 클래스를 알고 있으나 그 반대로는 전혀 알지 못한다. 즉, 인터페이스 구현체는 인터페이스를 implements 하면서 그 존재를 알게 되지만 인터페이스는 어떤 자식 클래스들이 있는지 알지 못하는 것과 같다.
⦿ 방향성 제어
✓ 인터페이스는 의존성을 역전시키기 위해 존재한다.
✓ 보호받아야 할 컴포넌트가 변경될 컴포넌트에 의존하는 상황을 인터페이스를 통해 역전시킨다.
⦿ 정보 은닉
✓ 추이 종속성으로 인해 “자신이 직접 사용하지 않는 요소에는 절대로 의존해서는 안된다”는 원칙을 위반하는 경우를 방지
✓ 인터페이스를 통해 불필요한 정보의 노출을 막는다.
⦿ 결론
✓ OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하는 데 있다.
✓ 이를 위해 시스템은 컴포넌트 단위로 분리하고 저수준 컴포넌트의 변경으로부터 고수준 컴포넌트가 보호받을 수 있도록 의존성 계층 구조를 만들어야 한다.
9장. LSP: 리스코프 치환 원칙
⦿ 바바라 리스코프의 하위 타입
“여기에서 필요한 것은 다음과 같은 치환(substitution) 원칙이다. S 타입의 객체 01 각각에 대응하는 T 타입 객체 02가 있고, T 타입을 이용해서 정의한 모든 프로그램 P에서 02 자리에 01을 치환하더라도 P의 행위가 변하지 않는다면 S는 T의 하위 타입이다. “
⦿ 상속을 사용하도록 가이드하기
✓ 주 프로그램이 인터페이스를 사용하게 되면 주 프로그램은 인터페이스의 하위 타입(인터페이스의 구현체)의 행위에 상관없이 기능할 수 있다.
⦿ 정사각형/직사각형 문제
✓ 수학적으로는 정각형은 직사각형의 부분집합(하위 타입)이지만 프로그램상으로는 그렇지 않다(정사각형은 가로와 세로가 동일한 값을 갖도록 강제됨).
✓ 이로 인해 직사각형의 인터페이스를 만들고 이를 구현한 정사각형 클래스를 만들게 되면 정사각형 클래스는 직사각형 인터페이스를 대체할 수 없아 리스코프 치환 법칙에 위배된다.
⦿ LSP와 아키텍처
✓ 클래스의 상속, 인터페이스의 구현 등 LSP는 광범위한 소프트웨어 설계 원칙으로 변모해왔다.
✓ 루비의 덕타이핑, 동일한 REST 인터페이스에 응답하는 서비스 집단 등에도 적용할 수 있다.
⦿ LSP 위배 사례
✓ LSP 원칙을 위해하는 순간 이에 대응하기 위한 수많은 분기와 설정이 추가되어야 한다(복잡도의 증가).
⦿ 결론
✓ 시스템의 복잡도가 올라가는 것을 막기 위해 LSP는 아키텍처 수준까지 확장해야만 한다.
10장. ISP: 인터페이스 분리 원칙
✓ 정적 타입 언어의 경우 서로 다른 클래스에서 각각 전용으로 사용하는 함수들을 모두 포함하는 하나의 클래스가 존재할 경우 하나의 클래스와 관련된 함수가 변경되면 모든 클래스들을 다시 컴파일해서 배포해야 한다.
✓ 이에 대한 해결책은 각각의 클래스에 대응하는 인터페이스를 만들어 연결하는 것이다.
- 정적 타입 언어 : 컴파일 시에 자료형을 결정해야 하는 언어 (C, C++, JAVA, C# 등)
⦿ ISP와 언어
✓ 앞의 사례는 정적 타입 언어에서만 발생하는 문제(모듈 포함을 위한 선언문으로 야기된)로 아키텍처가 아닌 언어와 관련된 문제로 결론 내릴 여지가 있다.
- 89쪽 주석1 참조 필요
⦿ ISP와 아키텍처
✓ 필요 이상으로 많은 것을 포함하는 모듈에 의존하는 것은 위험하다.
✓ 필요로 하는 기능이 아닌 부분에서 문제가 발생할 경우 영향을 받는 상황이 발생할 수 있다.
⦿ 결론
✓불필요한 기능을 포함한 모듈에 의존하는 것은 위험하다.
11장. DIP: 의존성 역전 원칙
✓ 유연성이 극대화된 시스템 : 소스 코드 의존성이 추상에 의존하며 구체에는 의존하지 않는 시스템
✓ 안정성이 보장된 환경에서는 대체로 무시하는 원칙
✓ 변동성이 큰 구체적인 요소에 대해서 지켜야 하는 원칙
⦿ 안정된 추상화
✓ 인터페이스는 구현체보다 변동성이 낮다.
✓ 안정된 소프트웨어 아키텍처 : 변동성이 큰 구현체에 의존하는 일은 지양하고 추상 인터페이스를 선호하는 아키텍처
- 변동성이 큰 구체 클래스를 참조하지 말라.
- 변동성이 큰 구체 클래스로부터 파생하지 말라.
- 구체 함수를 오버라이드 하지 말라.
- 구체적이며 변동성이 크다면 절대로 그 이름을 언급하지 말라.
⦿ 팩토리
✓ 변동성이 큰 구체적인 객체 참조를 막기 위해 추상 팩토리를 사용한다.
✓ 추상 팩토리를 이용하면 소스 코드의 의존성은 제어흐름과는 반대 방향으로 향한다.
팩토리 패턴의 이점 : 개별 클래스에서 객체를 생성하지 않아 객체 생성 방법이 변경된 경우 수정이 용이하다.
⦿ 구체 컴포넌트
✓ DIP 위배를 모두 없앨 수는 없으며 다만 DIP를 위반하는 클래스들을 적은 수의 구체 컴포넌트 내부로 모을 수 있다.
✓ 대표적인 구체 컴포넌트로 main 함수가 있다.
⦿ 결론
✓ 아키텍처 다이어그램에서 가장 눈에 드러나는 원칙
✓ 의존성은 더 추상적인 엔티티가 있는 쪽으로만 향한다.
'Study > 컴퓨터 공학' 카테고리의 다른 글
클린 아키텍처 #6 (0) | 2022.05.16 |
---|---|
클린 아키텍처 #5 (0) | 2022.03.02 |
클린 아키텍처 #4 (0) | 2022.02.15 |
클린 아키텍처 #2 (0) | 2022.01.11 |
클린 아키텍처 (0) | 2022.01.07 |