Search

17. 타임라인 조율하기

이전 내용 요약 (저번주 찬원님 부분)

문제: 장바구니 금액 계산 코드 최적화 이후 타이밍 버그 발생

 해결책: 다이어그램 그리기 → 실행 가능한 순서 분석을 통한 문제 파악

  최적화 적용 전
 최적화 적용 후

실행 가능한 순서 분석하기 & 왜 지금 타임라인이 더 빠를까요? (p483~4)

  최적화 적용 전 코드
// (...) function calc_cart_total(cart, callback) { var total = 0; 1. cost_ajax: 장바구니에 제품 가격을 합산 cost_ajax(cart, function(cost) { total += cost; 2. shipping_ajax: 장바구니에 배송비를 합산 shipping_ajax(cart, function(shipping) { total += shipping; callback(total); }); }); } // (...)
JavaScript
복사
  최적화 적용 전 타임라인
 최적화 적용 후 코드
// (...) function calc_cart_total(cart, callback) { var total = 0; 1. cost_ajax: 장바구니에 제품 가격을 합산 cost_ajax(cart, function(cost) { total += cost; }); 2. shipping_ajax: 장바구니에 배송비를 합산 shipping_ajax(cart, function(shipping) { total += shipping; callback(total); }); } // (...)
JavaScript
복사
 최적화 적용 후 타임라인
  최적화 적용 전 소요시간
 최적화 적용 후 소요시간

쉬는 시간 (p485)

먼저 요청한 cost_ajax 요청의 응답이 shipping_ajax 요청의 응답보다 가끔 늦어 지는 이유
문제를 찾기 위해 많은 단계가 필요한데, 모든 단계의 타임라인을 그려야 하나요?

모든 병렬 콜백 기다리기 (p486)

  현재 다이어그램
 원하는 결과

타임라인을 나누기 위한 동시성 기본형 (p487)

  경쟁조건 : 어떤 동작이 먼저 끝나는 타임라인에 의존할 때 발생

Cut() (≒ Promise.all())

Cut()의 코드
function Cut(num, callback) { var num_finished = 0; return function() { num_finished += 1; if(num_finished === num) callback(); }; }
JavaScript
복사
Cut() 세부 분석
1. 기다릴 타임라인의 수 2. 최종적으로 실행할 콜백 function Cut(num, callback) { 3. 카운터를 0으로 초기화 var num_finished = 0; return function() { 4. 함수를 호출할 때마다 카운터 증가 num_finished += 1; 5. 마지막 타임라인이 끝났을 때 콜백을 호출 if(num_finished === num) callback(); }; }
JavaScript
복사

코드에 Cut() 적용하기 (p489)

Cut()을 보관할 범위

→ 실행 순서 문제가 발생하는 두 함수를 포함하는 calc_cart_total() 함수

Cut()에 어떤 콜백을 넣을 지

→ 기존에 total 값 계산이 끝났을 때 최종적으로 호출 되는 함수 (callback: update_total_dom())

  Cut() 적용 전 코드
function calc_cart_total(cart, callback) { var total = 0; cost_ajax(cart, function(cost) { total += cost; }); shipping_ajax(cart, function(shipping) { total += shipping; callback(total); }); }
JavaScript
복사
  Cut() 적용 전 타임라인
 Cut()적용 후 코드
function calc_cart_total(cart, callback) { var total = 0; var done = Cut(2, function() { callback(total); }); cost_ajax(cart, function(cost) { total += cost; done(); }); shipping_ajax(cart, function(shipping) { total += shipping; done(); }); }
JavaScript
복사
 Cut()적용 후 타임라인

쉬는 시간 (p490)

Cut()은 정말 잘 작동하나요?
Cut()은 정말 작은 코드입니다. 이렇게 간단한 코드가 유용할 수 있나요?
Promise처럼 다른 것을 사용하는 것이 더 좋지 않나요?

불확실한 순서 분석하기 (p491)

→ Cut() 적용 후 모든 경우에 대해 정상적인 결과 반환!!

Cut() 적용 후 타임라인
Cut() 적용 후 경우의 수

병렬 실행 분석 (p492)

→ 속도 개선과 동시에 타이밍 버그도 해결

  Cut() 적용 전 소요시간 (최대 4초)
 Cut()적용 후 소요 시간 (최대 4초)

여러 번 클릭하는 경우 분석 (p493)

→ 정상적으로 동작하나 타임라인은 복잡해짐…

이러한 복잡성이 왜 생기는 것인지?

1. 비동기 웹 요청(ajax) → ajax 사용안할 시 새로고침 다수 발생

2. 결과를 합쳐야 하는 API 응답 → 한 개의 API로 요청 시 서버로 복잡성을 단순히 옮기는 꼴

3. 예측 불가능한 사용자의 액션 → 사용자에게 순차적인 flow 강요 시 나쁜 유저경험 하게 됨

“결국 복잡성을 다루는 좋은 프로그래밍 기술이 필요”

딱 한 번만 호출하는 기본형 (p500)

문제: 제품을 처음 장바구니에 추가 시에만 메세지 보내는 기능 개발 필요

 해결책: 여러 번 호출해도 한 번만 실행되는 동시성 기본형 도입

JustOnce() (≒ debouncing)

JustOnce()의 코드
function JustOnce(action) { var alreadyCalled = false; return function(a, b, c) { if(alreadyCalled) return; alreadyCalled = true; return action(a, b, c); }; }
JavaScript
복사
JustOnce() 세부 분석
1. 액션을 전달 function JustOnce(action) { 2. 함수가 실행됐는지 기억 var alreadyCalled = false; return function(a, b, c) { 3. 실행한 적이 있다면 바로 종료 if(alreadyCalled) return; 4. 함수가 실행 됬다고 생각하고 실행 사실 기록 alreadyCalled = true; 5. 액션 호출 return action(a, b, c); }; }
JavaScript
복사
 되새겨보기
자바스크립트는 단일스레드 언어 → 타임라인은 다른 타임라인 시작 전 완료
다른 언어에서는 타임라인 조율을 위해 락(lock)이나 다른 기능 필요
 멱등원
최초 한 번만 효과가 발생하는 액션
JustOnce는 어떤 액션이든 멱등원으로 만들어 줌

암묵적 시간 모델 vs 명시적 시간 모델 (p502)

암묵적 시간 모델

모든언어가 기본적으로 제공
원하는대로 실행 방식 커스텀은 불가 (간단한 프로그램에서는 유용)

명시적 시간 모델

함수형 개발자가 필요에 따라 만듬
필요한 실행 방식에 동작 하도록 할 수 있음
1. Queue() : 비동기 콜백 사용 시 새로운 타임라인을 만들지 않도록 함 2. JustOnce() : 여러 번 호출해도 한 번만 실행
JavaScript
복사

쉬는 시간 (p504)

앞에서 만든 동시성 기본형이 모두 고차 함수인데 모든 동시성 기본형은 고차함수로 만들어야 하나요?
다섯 번째 원칙에서 ‘시간을 다룬다’라는 말이 있습니다. 조금 과장된 표현이 아닌가요?

요약: 타임라인 사용하기 (p507)

1. 타임라인 수 줄이기: 서버 요청 줄이기 → 시스템 단순화

2. 타임라인 길이 줄이기: 액션을 계산(타임라인에 미표시)으로 바꾸기 → 타임라인 단순화

3. 공유 자원을 없애기: 자원을 공유하지 않는 타임라인은 순서문제 X

4. 동시성 기본형으로 자원 공유: 큐나 락을 이용해 자원을 안전하게 공유

5. 동시성 기본형으로 조율: Promise나 Cut을 이용 액션의 순서나 반복을 제한

Chap. 18 - 반응형 아키텍처와 어니언 아키텍처

두 아키텍처 패턴은 독립적입니다

반응형 아키텍처 (≒ Redux의 store)

순차적 액션 단계에 활용
효과와 원인을 분리 → 코드의 복잡하게 꼬인 부분을 풀어줌

어니언 아키텍처

서비스의 모든 단계에 사용
현실 세계와 상호작용하는 서비스 구조를 만듬

“두 패턴은 함께 사용할 수도 따로 사용할 수도 있음”

변경에 대한 원인과 효과가 강력하게 결합

문제: 장바구니 UI 수정 시 수정할 곳이 계속해서 늘어남 (n x m 문제)

 해결책: 반응형 아키텍처를 사용하여 결합 된 액션을 분리

To Be continued…