Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[노예찬] 챕터 13: 함수형 도구 체이닝 , 챕터 14: 중첩된 데이터에 함수형 도구 사용하기 #67

Merged
merged 2 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions 챕터_13/노예찬.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
이번 장에서 배워야 할 것은 "체이닝"이다. 그러니까, 여러 함수들을 조합하는 방식에 대해서 설명할 것으로 보인다. 어떻게 조합할 것인지? 조합하면 무엇이 좋은지? 에 포커스를 맞춰서 이해하면 좋을 것 같다.

## 1. 체이닝이란?

> 여러 단계를 하나로 조합하는 것을 체이닝이라고 한다. P.318

함수형 체이닝을 활용하면, 코드를 더 간결하고 명확하게 만들 수 있다. 완성된 코드는 글로도 그대로 바꿔 쓸 수 있을 정도로 명확하다.
또한, 재사용성을 높일 수 있다는 장점이 있다.

## 2. 복합해져 있던 코드를 체이닝으로 개선하기

1. 우선 필요한 코드를 map과 filter를 활용해 작성한다.
2. 만들어진 함수를 콜백으로 분리시킨다.
3. 콜백에 중첩이 있는 경우에 복잡도가 높아진다. 이를 해결하기 위해 2가지 방법을 사용할 수 있다.
3-1. 각 함수의 단계에 이름을 붙인다.
3-2. 함수 대신 콜백에 이름을 붙인다.

이렇게 3단계로 코드를 개선할 수 있다. 그런데 3-1과 3-2를 비교해보면, 3-2가 훨씬 더 명확하다는 것을 이해할 수 있다. 그리고 재사용하기에도 좋다.
하지만, 상황에 따라서 함수에 이름을 붙이던지, 콜백에 이름을 붙이던지, 방법을 선택하는 것이 좋다.

## 3. 체이닝을 위한 팁

1. 데이터 만들기 : 함수형 도구는 배열 전체를 다룰 때 잘 동작한다. 그러니까, 배열을 만들어서 함수형 도구를 사용하는 것이 좋다.
2. 배열 전체를 다루기
3. 작은 단계로 나누기 : 작은 단계로 나누면, 코드를 이해하기 쉽고, 재사용하기 쉽다.
4. 보너스 - 조건문을 filter로 바꾸기
5. 보너스 - 유용한 함수로 추출하기 : 함수형 도구는 스스로 만들고 찾을 수 있다.

> \*스트림 결합 :
> map, filter와 같은 함수형 도구는 배열을 새로 생성하기 때문에 메모리 관리 측면에서 비효율적일 수 있다.
> 이런 경우에는 스트림 결합을 사용할 수 있다. 스트림 결합은 여러 함수를 하나로 합치는 것이다.
> 예를 들어 var a = map(customers, getFullnames); var b = map(names, stringLength);와 같은 함수가 있다면,
> var c = map(customers, stringLength(getFullnames))와 같이 하나로 합칠 수 있다.
Comment on lines +29 to +33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍 👍


외에도, 함수형 체이닝으로 리팩토링하기, 다양한 함수형 도구, reduce의 활용 등에 대한 내용이 있다.
이번 장은 조금 아쉬운 것이, 특정 주제에 대한 응집도가 낮다고 느껴졌다. chain이라는 주제로 시작해서, 아예 연관이 없지는 않지만 다양한 주제로 넘어가는 것이 조금 아쉽다.

---

## \* 이벤트 소싱이란? :

이벤트 소싱(Event Sourcing)은 소프트웨어 설계 패턴 중 하나로, 시스템의 상태를 이벤트(event)의 시퀀스로 저장하고 관리하는 방식입니다. 각 이벤트는 상태 변화의 기록을 나타내며, 이러한 이벤트의 연속을 통해 시스템의 현재 상태를 재구성할 수 있습니다.

이벤트 소싱의 주요 개념

1. 이벤트(Event): 시스템 내에서 발생한 중요한 상태 변화를 기록한 것. 예를 들어, “사용자가 상품을 구매했다”는 이벤트가 될 수 있습니다.
2. 이벤트 스토어(Event Store): 이벤트를 저장하는 저장소. 일반적인 데이터베이스와는 달리 이벤트 로그의 형태로 저장됩니다.
3. 상태 재구성(State Reconstruction): 이벤트 로그를 순차적으로 재생하여 현재 시스템의 상태를 재구성하는 과정.

함수형 프로그래밍과의 관계

함수형 프로그래밍은 불변성과 순수 함수를 중시하는 프로그래밍 패러다임입니다. 이벤트 소싱은 이러한 함수형 프로그래밍의 철학과 잘 맞아떨어집니다. 다음은 그 이유입니다:

1. 불변성: 이벤트는 발생한 이후에는 변경되지 않는 불변 데이터입니다. 이는 함수형 프로그래밍에서 강조하는 불변성과 일치합니다.
2. 순수 함수: 이벤트를 처리하는 함수는 주어진 이벤트와 이전 상태를 입력으로 받아 새로운 상태를 반환하는 순수 함수가 될 수 있습니다. 이는 함수형 프로그래밍의 핵심 개념 중 하나입니다.
3. 투명성: 이벤트 소싱은 시스템의 상태 변화를 명확하게 기록하므로, 함수형 프로그래밍의 투명성(transparency)을 유지하는 데 도움을 줍니다.

이벤트 소싱의 장점

• 추적 가능성: 모든 상태 변화가 이벤트로 기록되므로, 시스템의 상태를 언제든지 재구성하고 검토할 수 있습니다.
• 이벤트 재생: 과거 이벤트를 재생하여 시스템의 특정 시점의 상태를 쉽게 재구성할 수 있습니다.
• 확장성: 이벤트 기반 아키텍처는 시스템을 더 유연하고 확장 가능하게 만듭니다.

이벤트 소싱의 단점

• 복잡성: 이벤트를 관리하고 저장하는 데 추가적인 복잡성이 수반됩니다.
• 성능: 모든 이벤트를 재생하여 상태를 재구성하는 것은 성능에 부담이 될 수 있습니다.

이벤트 소싱은 특히 복잡한 비즈니스 로직을 다루는 시스템에서 유용하게 사용할 수 있으며, 함수형 프로그래밍의 철학과 결합할 때 매우 강력한 도구가 될 수 있습니다.
Comment on lines +40 to +69
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

깔꼼하네요 .. 역시 👍 👍 👍 👍


---

## 내가 사용했던 체이닝

```js
export const makeCanceledLineOptions = (refundOrderTable: RefundOrderView[]) =>
pipe(
filterByProp({ key: "checked", value: true }),
removeProperty("checked"),
mapRefundOrderTable
)(refundOrderTable);

// filterByProp
import { propEq, filter } from "../fpUtils";
export const filterByProp =
({ key, value }) =>
array => {
const predicate = propEq(key, value);
return filter(predicate, array);
};
const propEq = (key, value) => obj => obj[key] === value;

// removeProperty
import { map, omit } from "ramda";
export const removeProperty = prop => items => {
const removeKey = omit([prop]);
return map(removeKey)(items);
};

const mapRefundOrderTable = (refundOrderTable: RefundOrderTableRequest[]) =>
refundOrderTable.map(refundOrder => ({
productOptionId: refundOrder.optionId,
quantity: refundOrder.refundQuantity,
}));
```

```js
export const pipe =
(...fns: Function[]) =>
(arg: any) =>
fns.reduce((prev, fn) => fn(prev), arg);

/*
1. fns로 순회함
2. arg로 받은 값을 첫번째 fn에 넘겨주어 호출함
3. 이전에 arg와 함께 호출된 fn의 값을 다음 fn에 넘겨줌.


pipe는 왼쪽에서 오른쪽(->)방향 : pipe(filterByProp, removeProperty)(refundOrderTable);
compose는 오른쪽에서 왼쪽(<-)방향 : compose(removeProperty,filterByProp)(refundOrderTable)
*/
```
32 changes: 32 additions & 0 deletions 챕터_14/노예찬.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
13장에서는 함수형에서 배열을 다루는 방법에 대해서 살펴보았다. 이번 장에서는 함수형에서 객체를 다루는 방법에 대해서 살펴본다. 특히 중첩된 객체 데이터를 어떻게 다룰 것인지, 그러한 함수형 도구에는 무엇이 있는지를 살펴보려 한다.

---

## 14장의 흐름

14장의 흐름을 정리해보겠다.

1. 객체의 특정 내용을 변경하는 함수가 여럿있다.
2. 객체의 내용을 설정하는 이런 함수들을 추상화하면 update라는 함수를 만들 수 있다.
3. 여기까지는 좋았는데, 중첩된 객체가 나오기 시작했다. 중첩된 객체의 내용을 변경하기 위해 update를 중첩해서 호출하는 방법을 보여준다. update2, update3, ... updateN 과 같은 방식으로..
4. 그런데 update를 중첩해서 호출하는 방법에도 문제가 있었으니, 바로 함수 이름에 있는 암묵적 인자라는 냄새가 난다는 것이다.
5. 이것을 해결하는 방법으로 nestedUpdate라는 함수를 사용할 수 있다.
6. nestedUpdate라는 함수를 구현하기 위해서는 재귀함수가 필요하기에, 재귀함수에 대해서 설명한다.
7. nestedUpdate를 통해서 중첩된 객체의 데이터를 깔끔하게 설정할 수 있게 되었다. 하지만, 여기에도 문제는 있다. 객체의 깊이가 깊을수록 개발자가 기억해야 할 객체의 구조가 많다는 것이다.
8. 이런 경우에는 nestedUpdate를 이용하기 보다는 직접 구현 패턴을 이용해, 추상화 벽을 세우는 것이 더욱 간결하고 명확한 코드를 만들 수 있게 된다.

결국 14장의 흐름을 다시 정리하면,

- 문제1 (객체 변경 함수 중복) -> 해결방안1 (update 함수)
- 문제2 (중첩된 객체) -> 해결 방안2 (update함수 중첩호출)
- 문제3 (중첩 update함수의 냄새) -> 해결 방안3 (nestedUpdate) -> 부연설명(재귀호출)
- 문제4 (nestedUpdate의 인지적 과부화) -> 해결방안4 (추상화벽)

4번의 문제와 4번의 해결방안을 소개하는 것으로 이루어져 있다.

## 14장에서 얻을 수 있는 것

- 객체를 다룰 때 사용할 수 있는 함수형 도구 => update
- 중첩된 객체를 다룰 때 사용할 수 있는 함수형 도구 => nestedUpdate
- nestedUpdate로 인지적 과부화가 올 때 적용할 수 있는 패턴 => 추상화 벽
- update, nestedUpdate가 만들어지는 과정.
Loading