Skip to content

Commit 9deb943

Browse files
committed
feat: Add chapter07~14
1 parent e1bab10 commit 9deb943

File tree

16 files changed

+376
-0
lines changed

16 files changed

+376
-0
lines changed

chapter07/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 7장. SRP: 단일 책임 원칙
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter07/yumin/README.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# 7장. SRP : 단일 책임 원칙
2+
3+
SRP는 모든 모듈이 단 하나의 일만 해야 한다는 의미로 받아들이기 쉽다.
4+
5+
함수는 반드시 하나의, 단 하나의 일만 해야 한다는 원칙이다.
6+
7+
이 원칙은 커다란 함수를 작은 함수들로 리팩터링하는 더 저수준에서 사용된다.
8+
9+
이 원칙은 SOLID도, SRP도 아니다.
10+
11+
SRP는 역사적으로 아래와 같이 기술되어 왔다.
12+
13+
단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다.
14+
15+
하나의 모듈은 하나의, 오직 하나의 사용자 또는 이해관계자에 대해서만 책임져야 한다.
16+
17+
→ 하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.
18+
19+
모듈은 또 무슨 뜻인가?
20+
21+
- 가장 단순한 정의는 바로 소스 파일이다.
22+
23+
‘응집된’ 이라는 단어는 SRP를 암시한다.
24+
25+
위 원칙을 이해하는 데에는 위반하는 징후들을 살펴보는 게 좋다.
26+
27+
1. 우발적 중복
28+
1. 우발적 중복 같은 상황을 목격한 경험이 있을 것이다. 이러한 문제는 서로 다른 액터가 의존하는 코드를 너무 가까이 배치했기 때문이다. SRP는 서로 다른 액터가 의존하는 코드를 서로 분리하라고 말한다.
29+
2. 병합
30+
1. 각각 다른 사람이 같은 코드를 수정할 경우 변경사항은 서로 충돌하고, 결과적으로 병합이 발생한다.
31+
2. 이 문제를 벗어나는 방법은 서로 다른 액터를 뒷받침하는 코드를 서로 분리하는 것이다.
32+
33+
### 결론
34+
35+
단일 책임 원칙은 메서드와 클래스 수준의 우너칙이다.
36+
37+
컴포넌트 수준에서는 공통 폐쇄 원칙(Common Closure Principle)이 된다. 아키텍처 수준에서는 아키텍처 경계의 생성을 책임지는 변경의 축이 된다.

chapter08/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 8장. OCP: 개방-폐쇄 원칙
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter08/yumin/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# 8장. OCP: 개방-폐쇄 원칙
2+
3+
소프트웨어 개체는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.
4+
5+
개체의 행위는 확장할 수 있어야 하지만, 이때 개체를 변경해서는 안 된다.
6+
7+
OCP는 보통 클래스와 모듈을 설계할 때 도움이 되는 원칙이라고 알고 있지만, 아키텍처 컴포넌트 수준에서 OCP를 고려할 때 훨씬 중요한 의미를 가진다.
8+
9+
사고 실험을 해 보면 이 점이 분명해진다.
10+
11+
아키텍트는 기능이 어떻게, 왜, 언제 발생하는지에 따라서 기능을 분리하고, 분리한 기능을 컴포넌트의 계층구조로 조직화한다.
12+
13+
추이 종속성
14+
15+
- 추이 종속성을 가지게 되면, 소프트웨어 엔티티는 자신이 직접 사용하지 않는 요소에는 절대로 의존해서는 안 된다는 소프트웨어 원칙을 위반하게 된다.
16+
- Controller에서 변경이 발생할 경우 Interceptor를 보호하는 게 우선순위가 높다면, 반대로 Interceptor에서 발생한 변경도 Controller가 보호되기를 바란다. 이를 위해서 내부를 은닉하는 것 이다.
17+
18+
### 결론
19+
20+
OCP는 시스템의 아키텍처를 떠받치는 원동력 중 하나다. OCP의 목표는 시스템을 확장하기 쉬운 동시에 변경으로 인해 시스템이 너무 많은 영향을 받지 않도록 하는 데 있다.
21+
22+
시스템을 컴포넌트 단위로 분리하고, 저수준 컴포넌트에서 발생한 변경으로부터 고수준 컴포넌트를 보호할 수 있는 형태의 의존성 계층구조가 만들어지도록 해야 한다.

chapter09/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 9장. LSP: 리스코프 치환 원칙
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter09/yumin/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# 9장. LSP : 리스코프 치환 원칙
2+
3+
바바라 리스코프는 하위 타입을 아래와 같이 정의했다.
4+
5+
- 여기에서 필요한 것은 다음과 같은 치환원칙이다. S타입의 객체 o1 각각에 대응하는 T 타입 객체 o2가 있고, T타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위가 변하지 않는다면, S는 T의 하위 타입이다.
6+
7+
리스코프 치환 원칙으로 알려진 이 개념을 이해하기 위해 몇 가지 예제를 살펴본다.
8+
9+
- 상속을 사용하도록 가이드하기
10+
- LSP와 아키텍처
11+
- 객체 지향이 혁명처럼 등장한 초기에는 LSP는 상속을 사용하도록 가이드하는 방법 정도로 간주되었다.
12+
- 시간이 지나면서 LSP는 인터페이스와 구현체에도 적용되는 더 광범위한 소프트웨어 설계 원칙으로 변모해 왔다.
13+
- 자바스러운 언어라면 인터페이스 하나와 이를 구현하는 여러 개의 클래스로 구성된다.
14+
- LSP 위배 사례
15+
- 택시 파견 서비스 애플리케이션
16+
- 고객은 어느 택시업체인지는 신경쓰지 않고 자신의 상황에 가장 적합한 택시를 찾는다.
17+
- 이럴 경우 파견 서비스를 만들 때 다양한 택시업체에서 동일한 REST인터페이스를 반드시 준수하도록 만들어야 한다.
18+
- 서로 다른 택시업체가 필드들에 대하여 모두 동일한 방식으로 처리해야 한다.
19+
- 이를 위배 할 경우 꼬이게 되는 것…
20+
21+
### 결론
22+
23+
LSP는 아키텍처 수준까지 확장할 수 있고, 반드시 확장해야만 한다. 치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 상당량의 별도 메커니즘을 추가해야 할 수 있기 때문이다.

chapter10/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 10장. ISP: 인터페이스 분리 원칙
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter10/yumin/README.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# 10장. ISP : 인터페이스 분리 원칙
2+
3+
`OPS 클래스`
4+
5+
`User1 : op1만을 사용`
6+
7+
`User2 : op2만을 사용`
8+
9+
`User3 : op3만을 사용`
10+
11+
위 경우 OPS가 정적 타입 언어로 작성된 클래스라고 해보자. 이 경우 User1에서는 op2와 op3을 전혀 사용하지 않음에도 User1의 소스 코드는 이 두 메서드에 의존하게 된다.
12+
13+
OPS 클래스에서 op2의 소스 코드가 변경되면 User1도 다시 컴파일한 후 새로 배포해야 한다.
14+
15+
### ISP와 아키텍처
16+
17+
ISP를 사용하는 근본적인 동기
18+
19+
- 잠재되어 있는 더 깊은 우려사항을 볼 수 있다
20+
- 일반적으로 필요 이상으로 많은 걸 포함하는 모듈에 의존하는 것은 해로운 일이다.
21+
22+
### 결론
23+
24+
불필요한 짐을 실은 무언가에 의존하면 예상치도 못한 문제에 빠진다.

chapter11/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 11장. DIP: 의존성 역전 원칙
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter11/yumin/README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# 11장. DIP : 의존성 역전 원칙
2+
3+
의존성 역전 원칙에서 말하는 ‘유연성이 극대화된 시스템’ 이란 소스 코드 의존성이 추상에 의존하며 구체에는 의존하지 않는 시스템이다.
4+
5+
자바와 같은 정적 타입 언어에서 이 말은 use, import, include 구문은 오직 인터페이스나 추상 클래스 같은 추상적인 선언만을 참조해야 한다는 뜻이다. 구체적인 대상에는 절대로 의존해서는 안 된다.
6+
7+
DIP를 논할 때 운영체제나 플랫폼 같이 안정성이 보장된 환경에 대해서는 무시하는 편이다.
8+
9+
우리가 의존하지 않도록 피하고자 하는 것은 변동성이 큰 구체적인 요소다.
10+
11+
이 구체적인 요소는 우리가 열심히 개발하는 모듈들이 될 수 있다.
12+
13+
### 안정된 추상화
14+
15+
추상 인터페이스에 변경이 생기면 이를 구체화한 구현체들도 따라서 수정해야 한다.
16+
17+
반대로 구체적인 구현체에 변경이 생기더라도 그 구현체가 구현하는 인터페이스는 항상 좀 더 정확히 말하면 대다수의 경우 변경될 필요가 없다. 따라서 인터페이스는 구현체보다 변동성이 낮다.
18+
19+
뛰어난 소프트웨어 설계자와 아키텍트라면 인터페이스의 변동성을 낮추기 위해 애쓴다.
20+
21+
안정된 소프트웨어 아키텍처란 변동성이 큰 구현체에 의존하는 일은 지양하고, 안정된 추상 인터페이스를 선호하는 아키텍처라는 뜻이다.
22+
23+
- 변동성이 큰 구체 클래스를 참조하지 말라. 대신 추상 인터페이스를 참조하라.
24+
- 변동성이 큰 구체 클래스로부터 파생하지 말라.
25+
- 구체 함수를 오버라이드 하지 말라.
26+
27+
### 팩토리
28+
29+
추상 컴포넌트와 구체 컴포넌트
30+
31+
- 추상 컴포넌트는 애플리케이션의 모든 고수준 업무 규칙을 포함한다.
32+
- 구체 컴포넌트는 업무 규칙을 다루기 위해 필요한 모든 세부사항을 포함한다.
33+
34+
소스 코드 의존성은 제어흐름과는 반대 방향으로 역전된다. 이러한 이유로 이 원칙을 의존성 역전이라고 부른다.
35+
36+
### 결론
37+
38+
앞으로 고수준의 아키텍처 원칙을 다루게 되면서 DIP는 몇 번이고 계속 등장할 것이다.
39+
40+
의존성은 앞의 곡선을 경계로(구체 / 추상 컴포넌트) 더 추상적인 엔티티가 있는 쪽으로만 향한다.
41+
42+
추후 이 규칙은 의존성 규칙(Dependency rule)이라 부를 것 이다.

chapter12/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 12장. 컴포넌트
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter12/yumin/README.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# 12장. 컴포넌트
2+
3+
컴포넌트는 배포 단위다.
4+
5+
컴포넌트는 시스템의 구성 요소로 배포할 수 있는 가장 작은 단위다.
6+
7+
자바의 경우 jar파일이 컴포넌트다.
8+
9+
모든 언어에서 컴포넌트는 배포할 수 있는 단위 입자다.
10+
11+
여러 컴포넌트를 서로 링크하여 실행 가능한 단일 파일로 생성할 수 있다.
12+
13+
.war파일과 같은 단일 아카이브로 만들수도 있다.
14+
15+
### 컴포넌트의 간략한 역사
16+
17+
프로그래밍 초창기에는 프로그램을 로드할 메모리의 위치를 정하는 일이 프로그래머가 가장 먼저 결정해야 하는 사항 중 하나였다.
18+
19+
이걸 배치하고 나면 재배치가 불가능하였다.
20+
21+
이러한 구시대에는 라이브러리 함수에 어떻게 접근했나?
22+
23+
- 프로그래머가 라이브러리 함수의 소스 코드를 애플리케이션 코드에 직접 포함시켜 단일 프로그램으로 컴파일했다.
24+
25+
메모리는 비싸고, 한정적인 자원이었기 때문이다.
26+
27+
컴파일러는 소스 코드 전체를 여러 번에 걸쳐서 읽어야 했지만, 메모리가 너무 작아서 소스 코드 전체를 메모리에 상주시킬수가 없었다.
28+
29+
### 재배치성
30+
31+
해결책은 재배치가 가능한 바이너리였다.
32+
33+
지능적인 로더를 사용해서 메모리에 재배치할 수 있는 형태의 바이너리를 생성하도록 컴파일러를 수정하자는 것이었다.
34+
35+
프로그래머는 오직 필요한 함수만을 로드할 수 있게 되었다.
36+
37+
재배치 가능한 바이너리 안의 함수 이름을 메타데이터 형태로 생성하도록 수정되었다.
38+
39+
라이브러리 함수를 정의하는 프로그램이라면 컴파일러는 해당 이름을 외부 정의로 생성했다.
40+
41+
이렇게 함으로써 외부 정의를 로드할 위치가 정해지기만 하면 로더가 외부 참조를 외부 정의에 링크시킬 수 있게 된다.
42+
43+
- 이렇게 링킹 로더가 탄생하였다.
44+
45+
### 결론
46+
47+
런타임에 플러그인 형태로 결합할 수 있는 동적 링크 파일이 이 책에서 말하는 소프트웨어 컴포넌트에 해당한다.
48+
49+
여기까지 오는 데 50년이 걸렸다.
50+
51+
과거에는 초인적인 노력을 들여야만 컴포넌트 플러그인 아키텍처를 적용할 수 있었다. (지금과 다름)

chapter13/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 13장. 컴포넌트 응집도
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

chapter13/yumin/README.md

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# 13장. 컴포넌트 응집도
2+
3+
### 컴포넌트 응집도와 관련된 세 가지 원칙
4+
5+
1. REP : 재사용 / 릴리스 등가 원칙
6+
2. CCP : 공통 폐쇄 원칙
7+
3. CRP : 공통 재사용 원칙
8+
9+
## REP : 재사용 / 릴리스 등가 원칙
10+
11+
---
12+
13+
재사용 단위는 릴리즈 단위와 같다.
14+
15+
재사용 / 릴리즈 등가 원칙은 너무 당연해 보인다. 소프트웨어 컴포넌트가 릴리즈 절차를 통해 추적 관리되지 않거나 릴리즈 번호가 부여되지 않는다면 해당 컴포넌트를 재사용하고 싶어도 할 수도 없고, 하지도 않을 것이다.
16+
17+
만약 컴포넌트가 REP를 위배한다면 컴포넌트 사용자가 알게 되고, 당신의 아키텍트로서의 능력을 높게 평하지 않을 것이다.
18+
19+
이 원칙의 약점은 다음에 다를 두 원칙이 지닌 강점을 통해 충분히 보완할 수 있다.
20+
21+
CCP와 CRP는 REP를 엄격하게, 하지만 제약을 가하는 측면에서 정의한다.
22+
23+
### CCP: 공통 폐쇄 원칙
24+
25+
---
26+
27+
동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어라.
28+
29+
서로 다른 시점에 다른 이유로 변경되는 클래스는 다른 컴포넌트로 분리하라.
30+
31+
이 원칙은 단일 책임 원칙을 컴포넌트 관점에서 다시 쓴 것이다.
32+
33+
변경될 가능성이 있는 클래스는 모두 한곳으로 묶을것을 권한다.
34+
35+
CCP에서는 동일한 유형의 변경에 대해 닫혀 있는 클래스들을 하나의 컴포넌트로 묶음으로써 OCP에서 얻은 교훈을 확대 적용한다.
36+
37+
SRP의 컴포넌트 수준 : CCP
38+
39+
### CRP : 공통 재사용 원칙
40+
41+
---
42+
43+
컴포넌트 사용자들을 필요하지 않는것에 의존하게 강요하지 말라.
44+
45+
개별 클래스가 단독으로 재사용되는 경우는 거의 없다.
46+
47+
대체로 재사용 가능한 클래스는 재사용 모듈의 일부로써 해당 모듈의 다른 클래스와 상호작용 하는 경우가 많다.
48+
49+
ISP와의 관계
50+
51+
- CRP는 인터페이스 분리 원칙의 포괄적인 버전이다. CRP는 사용하지 않는 클래스를 가진 컴포넌트에 의존하지 말라고 한다.
52+
53+
- 필요하지 않은 것에 의존하지 말라.
54+
55+
### 컴포넌트 응집도에 대한 균형 다이어그램
56+
57+
---
58+
59+
REP - CCP : 포함 원칙, 두 원칙은 컴포넌트를 더욱 크게 만든다.
60+
61+
CRP : 배제 원칙
62+
63+
### 결론
64+
65+
과거에는 결합도에 대한 우리의 인식 수준이 REP, CCP, CRP가 의미하는 것 보다는 훨씬 단순했다.
66+
67+
응집도를 모듈은 단 하나의 기능만 수행해야 한다는 속성 정도로 단순하게 이해한 적도 있었다.
68+
69+
하지만 컴포넌트 응집도에 관한 세 가지 원칙은 응집도가 가질 수 있는 훨씬 복잡한 다양성을 설명해 준다.

chapter14/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# 14장. 컴포넌트 결합
22

33
- [zhoon](./zhoon/)
4+
- [yumin](./yumin/)

0 commit comments

Comments
 (0)