1부/ chap03. RxJs가 해결하려고 했던 문제(3)_로직 오류

1부/ chap03. RxJs가 해결하려고 했던 문제(3)_로직 오류

[📕 퀵스타트 Rxjs]를 보고 메모한 부분을 정리했습니다.

목차

  1. 웹 어플리케이션의 로직
  2. 로직의 복잡성 그리고 오류
  3. 자바스크립트의 솔루션



1. 웹 어플리케이션의 로직

데이터를 추출하고 변환하는 작업을 빈번하게 하고 있다.

  • 반복문 사용, 분기문 사용, 변수 사용

2. 로직의 복잡성 그리고 오류

반복문, 분기문, 변수는 우리 코드를 복잡하게 만든다.
반복문 : 가독성을 떨어뜨림
분기문 : 확인해야 할 프로그램의 흐름을 여러 개로 만듦
변수 : 누군가에 의해 변경 될 수 있다.
=> 오류 발생 빈도를 높인다.

2.1 반복문과 분기문

로직의 복잡성을 줄이는 방법 : 기능을 쪼개기 (관심사 분리)
기능을 추상화

2.3 변수는 오류의 시작

변수의 사용은 오류를 발생시킬 수 잇는 확률을 높인다는 것.


3. 자바스크립트의 솔루션

함수형 프로그래밍의 특성을 가진 자바스크립트 함수를 이용하면
실제 로직과 상관없는 반복분, 분기문을 분리할 수 있다.

자바스크립트는 일급객체!

  • 함수를 변수 혹은 데이터 구조에 저장할 수 있다.
  • 파라미터로 함수를 전달 할 수 있다.
  • 반환값으로 사용할 수 있다.

3.1 로직의 분리

고차함수 Higher-order function

  • 다른 함수를 인자로 받거나 그 결과로 함수를 반환하는 함수
  • 고차 함수는 변경되는 주요 부분을 함수로 제공함으로써 동일한 패턴 내에 존재하는 문제를 손수비게 해결할 수 있는 고급 프로그래밍 기법이다.
  • 고차 함수를 이용하면 함수의 합성, 변형과 같은 작업을 손쉽게 할 수 있다.
    더불어 커링, 메모이제이션과 같은 기법도 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
function process(people){
const html = [];
for (const user of people.results) {
if(/male|female/.test(user.gender)) {
const result = logic(user.height, user.mass, user.gender);
Object.assign(user,result);
html.push(makeHtml(user));
}
}
return html.join('');
}
1
2
3
4
5
6
7
8
9
10
// 고차 함수를 이용하여 개선
function process(people){
return people.results
.filter(user => /male|femail/.test(user.gender))
.map(user => Object.assign(user, logic(user.height, user.mass, user.gender)))
.reduce((acc,user)=> {
acc.push(makeHtml(user))
return acc;
}, []).join('')
}

개선된 process에서는 반복문, 분기문, 변수가 존재하지 않는다.
핵심로직은 분리되었고
코드의 흐름은 단일화 되었다.
변수를 사용하지 않음으로써 오류 발생 빈도도 크게 줄었다.


4. rxjs는 어떻게 개선하였나?

4.1 rxjs가 제공하는 오퍼레이터

http://reactivex.io/rxjs/manual/index.html
rxjs에서 제공하는 오퍼레이터를 이용하면 observable을 생성할 수도 있고,
전달된 데이터를 변환하거나 필요한 데이터만을 추출할 수도 있다.

참고

4.2 불변 객체 observable

ES5 Array의 고차함수들이 반환값으로 새로운 Array 객체를 반환하여 각각에 영향을 미치지 않도록 하는 것과 같이,
rxjs의 오퍼레이터는 항상 새로운 observable을 반환함으로써 array의 고차 함수와 같이 불변 객체(immutable object)를 반환한다.

차이점 : Array의 리턴 객체는 새로운 레퍼런스 객체지만,observable과 달리 객체 자체가 불변객체는 아니다.

1
2
3
4
var arr = [1,2,3];
var mappedArr = arr.map(v => v);

console.log(arr === mappedArr); // false
  • Array의 경우 새로운 Array 객체 생성 작업만 함
  • Observable은 *새로운 Observable을 만들고, *
    그 Observable이 오퍼레이터를 호출한 원래의 Observable을 내부적으로 구독한다!!
    • 링크드 리스트 형태로 기존 Observable 객체와 새롭게 만든 Observable 객체를 오퍼레이터로 연결한다.
1
2
3
4
5
6
7
8
9
10
11
map = function(transformationFn){
const source = this;
const result = new rxjs.Observable(observer => {
source.subscribe(
function(x) { observer.next(transformationFn(x))}
function(err) { observer.error(err)}
function() { observer.complete()}
)
})
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
ajax$.pipe(
switchMap(data => of(...data.results)),
filter(user => /male|female/.test(user.gender)),
map(user => Object.assign(user, logic(user.height, user.mass, user.gender))),
reduce((acc,user)=> {
acc.push(makeHtml(user));
return acc;
}, []),
map(htmlArr => htmlArr.join(""))
).subscribe(v => {
document.getElementById("users").innerHtml = v;
})

∴ rxjs의 오퍼레이터로 생성된 Observable은 항상 불변 객체를 반환한다. 오퍼레이터의 인자로 순수함수를 받음으로써, 함수형 프로그래밍에서 추구하는 부원인과 부작용을 제거한다.


참고링크
http://reactivex.io/rxjs/manual/index.html