-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
157 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
# 18장 반응형 아키텍처와 어니언 아키텍처 | ||
|
||
### 두 아키텍처 패턴은 독립적이다. | ||
|
||
반응형 아키텍처는 순차적 액션 단계에서 사용하고, 어니언 아키텍처는 서비스의 모든 단계에 사용한다. | ||
|
||
두 패턴은 함께 사용할 수 있지만 따로 사용할 수도 있다. | ||
|
||
### 변경에 대한 원인과 효과가 강력하게 결합한다. | ||
|
||
장바구니에 관한 UI(n 이라 가정)를 바꿀 때 마다 고쳐야하는 곳이 m 만큼 커진다. (n x m 문제) | ||
⇒ n 액션과 m 액션이 결합되어서 | ||
|
||
### 반응형 아키텍처 | ||
|
||
코드의 순차적 액션의 순서를 뒤집으면 됨. | ||
⇒ X를 하고 Y를 하는 대신, X가 일어나면 언제나 Y를 함. 이러면 대체적으로 코드 읽기 쉽고 유지보수 용이해짐, 하지만 만능은 아니고 무조건 맞는것도 아니니 목적에 맞게 잘 사용하기 | ||
|
||
⇒ 장점으로 타임라인이 유연해짐 | ||
|
||
### valueCell을 반응형으로 만들기 | ||
|
||
셀은 일급 상태임. 셀이 뭐임? | ||
⇒ 구글 스프레드시트에서 셀값을 바꾸면 그에 대한 반응으로 스프레드시트 함수가 다시 계산되는 반응형 아키텍처로 만든 스프레드시트의 영향을 받아서 ValueCell이라는 이름을 지었다고 함 | ||
|
||
ValueCell 에 observer 추가해서 값이 바뀔 때마다(이전값과 현재 값이 다르다면) 모든 옵저버 실행하는 코드 실행 | ||
|
||
⇒ 리액트로 치면 redux store, recoil atom 이라고 생각하면 됨. react-query의 queryObserver 같은… | ||
|
||
### (여담) react-querty queryObserver 동작 방식 일부 | ||
|
||
useBaseQuery => observer 인스턴스를 생성 => queryObserver constructor에 this.setOptions => #updateQuery => observer.subscribe(notifyManager.batchCalls(onStoreChange)) 가 변화를 감지 => shouldAssignObserverCurrentProperties shallowEqualObjects(current, prev) 해서 바뀌었으면 true, 안바뀌었으면 false | ||
|
||
``` | ||
// queryObserver.ts | ||
#notify(notifyOptions: NotifyOptions): void { | ||
notifyManager.batch(() => { | ||
// First, trigger the listeners | ||
if (notifyOptions.listeners) { | ||
this.listeners.forEach((listener) => { | ||
listener(this.#currentResult) | ||
}) | ||
} | ||
// Then the cache listeners | ||
this.#client.getQueryCache().notify({ | ||
query: this.#currentQuery, | ||
type: 'observerResultsUpdated', | ||
}) | ||
}) | ||
} | ||
``` | ||
|
||
ValueCell은 다른 타임라인에서 읽거나 쓰는 순서를 보장하지 않음. | ||
하지만 어떤 값이 저장되어도 그 값이 항상 올바른 값이라는 것은 보장함. | ||
|
||
### 그래서 반응형 아키텍처가 시스템을 어떻게 바꾸었나? | ||
|
||
어떤 것이 바뀔 때 실행되는 핸들러로 만들었다. | ||
|
||
![image](https://github.com/muhandojeon/Grokking-Simplicity/assets/43921054/d923af61-939c-4ed1-bb66-4b9e52acc510) | ||
|
||
|
||
반응형 아키텍처는 코드에 3가지 중요한 영향을 준다. | ||
|
||
1. 원인과 효과가 결합된 것을 분리한다. | ||
|
||
⇒ 처음에 언급한 바꾸는 방법(원인) 5가지와 할 일(효과) 4가지를 곱한 값 20개를 관리해야함 | ||
⇒ 원인과 효과를 분리하면 5개의 원인, 4개의 결과가 5x4 대신 5+4로 만들 수 있음 | ||
|
||
2. 여러 단계를 파이프라인으로 처리 | ||
|
||
⇒ Promise로 액션과 계산을 조합해 파이프라인을 구성 가능하다. then 메서드를 통해 단일 값을 전달하고 파이프라인 단계간 데이터 전달 가능하게 됨. | ||
⇒ 여기서 단일 이벤트 대신 이벤트 스트림이 필요하다면 ReactiveX 라이브러리를 사용해봐라! RxJS로 구현되어있다! (?????) | ||
|
||
⇒ kafka나 RabbitMQ같은 외부 스트림 서비스로 파이프라인을 구현할 수 있다! (?????) | ||
|
||
3. 타임라인이 유연해짐 | ||
|
||
⇒ 장바구니는 ValueCell에서 감시자 호출, 장바구니 합계 계층은 FormulaCell이 감시자로 담당. | ||
⇒ 이렇게 되면 장바구니 값을 전역변수로 사용하지 않아도 되고 타임라인은 서로 다른 자원을 사용하기 때문에 안전하게 사용할 수 있다. | ||
|
||
|
||
### 어니언 아키텍처 패턴 | ||
|
||
![image](https://github.com/muhandojeon/Grokking-Simplicity/assets/43921054/23b9df8b-ea83-487e-89e2-b221019af2e3) | ||
|
||
|
||
함수형 시스템이 잘 동작할 수 있는 규칙 | ||
|
||
1. 현실 세계와 상호작용은 인터랙션 계층 | ||
2. 계층에서 호출하는 방향은 중심 방향 | ||
3. 계층은 외부에 어떤 계층이 있는지 모름 | ||
|
||
### **전통적 아키텍처 VS 함수형 아키텍처** | ||
|
||
![image](https://github.com/muhandojeon/Grokking-Simplicity/assets/43921054/1129b6ad-aaac-4fab-ad76-12e691941035) | ||
|
||
|
||
- 데이터베이스 계층과 도메인 계층의 관계의 차이가 크다. | ||
- 함수형 아키텍처는 도메인 계층이 데이터베이스 계층에 의존하지 않음 | ||
- 데이터 베이스 동작은 값을 바꾸거나 데이터베이스에 접근하기 때문에 액션 | ||
- 데이터베이스는 변경 가능하고 접근하는 모든 것을 액션으로 만든다는 것이 핵심 | ||
- 도메인을 포함해 그래프에 가장 위에 있는 것까지 모두 액션 | ||
- 액션과 계산을 명확하게 구분하려고 하고 도메인 로직은 모두 계산으로 만들어야 한다고 생각함 | ||
- 데이터베이스를 도메인과 분리하는 것이 중요 | ||
|
||
--- | ||
|
||
## **변경과 재사용이 쉬워야 한다.** | ||
|
||
- 어떤 의미에서 소프트웨어 아키텍처는 변화를 다루는 일 | ||
- 어니언 아키텍처는 인터렉션 계층을 바꾸기 쉽다. | ||
|
||
![image](https://github.com/muhandojeon/Grokking-Simplicity/assets/43921054/4ab4ccd0-6b35-4dc0-acf5-a81f16075e2b) | ||
|
||
|
||
정리해보면 | ||
|
||
- 어니언 아키텍처는 데이터베이스나 API 호출과 같은 외부 서비스를 바꾸기 쉽다. | ||
- 가장 높은 계층에서 사용하기 때문 | ||
- 도메인 계층은 외부 서비스에 의존하지 않아서 테스트하기 좋다. | ||
- 어니언 아키텍처는 좋은 인프라보다 좋은 도메인을 강조 | ||
⇒ 이게 와닿지는 않음 | ||
|
||
![image](https://github.com/muhandojeon/Grokking-Simplicity/assets/43921054/b5cd84cc-d7b3-45fb-b6b6-108266c2ac4a) | ||
|
||
|
||
전형적인 아키텍처에서 도메인 규칙은 데이터베이스를 부른다. 하지만 어니언 아키텍처에서는 안 된다. | ||
|
||
전형적인 아키텍처 | ||
|
||
- 계층이 순서대로 | ||
- 웹 요청은 핸들러가 처리 | ||
- 핸들러는 데이터베이스에 접속하고 클라이언트에게 응답하기 위해 가장 높은 웹 계층으로 결과를 리턴 | ||
|
||
어니언 아키텍처 | ||
|
||
- 경계선이 경사짐 | ||
- 웹서버와 핸들러, 데이터베이스는 인터랙션 계층에 속함. | ||
|
||
--- | ||
|
||
## **도메인 규칙은 도메인 용어를 사용** | ||
|
||
프로그램의 핵심 로직을 **`도메인 규칙`** 또는 **`비즈니스 규칙`**이라고 한다. | ||
|
||
도메인 규칙에는 제품, 이미지, 가격, 할인 등과 같은 용어를 사용 | ||
|
||
데이터 베이스는 도메인을 나타내는 용어가 아니다. | ||
|
||
> 도메인 규칙은 도메인 용어를 사용한다. | ||
> | ||
> | ||
> **도메인 규칙에 솏하는지 인터랙션 계층에 속하는지 판단하려면 코드에서 사용하는 용어를 보자** | ||
> |