본문 바로가기

회고/세미나

토스 SLASH 21 - 프론트엔드 웹 서비스에서 우아하게 비동기 처리하기 후기

 

 

최근 기술면접 스터디에서 비동기와 동기 처리에 대해 계속 이야기가 나오고 있기도 하고 프로젝트를 하기에 앞서 React를 프론트엔드에서 사용할 생각이라 이런 내용도 알고 있으면 구현하는 데도 도움이 될 것 같아 이번주 세미나는 이 세미나로 결정했다.

React를 사용하면서 비동기 처리를 고려해서 구현한 적이 많이 없었던 것 같고 왜 그렇게 구현해야하는지 주의 깊게 공부하지 못했던 것 같아 이번 세미나가 나에게는 비동기라는 개념에 대해서도 알 수 있고, 어떻게 비동기를 우아하게 처리할 수 있는지 방법까지 공부할 수 있는 세미나였다.

 

  1. 현재 토스의 상황
    1. 토스에서는 React, Next.js, Typescript를 현재 사용하고 있다.
  2. 웹 서비스에서 가장 다루기 어려운 부분은 비동기 프로그래밍
    1. 비동기 프로그래밍이 필요한 이유 : 순서가 보장되지 않는 경우 사용하며, 좋은 사용자 경험을 위해 필수
    2. Callback, Promise, RxJS 등으로 처리
  3. 좋은 코드란?
    1. 코드가 간결하다
    2. 예상할 수 있는 최적의 경우와 문법적 차이가 크지 않다
    3. 함수의 역할을 한눈에 파악할 수 있다
    4. '성공하는 경우'만 다루고, '실패하는 경우'는 catch 절에서 분리해 처리한다
    5. '실패하는 경우'에 대한 처리를 외부에 위임할 수 있다
    6. 성공, 실패의 경우를 분리해 처리할 수 있다
    7. 비즈니스 로직을 파악하기 쉽다
  4. 프론트엔드 웹 서비스에서 지금까지의 비동기 처리
    1. 비동기를 처리하는 부분을 정의한다
    2. 컴포넌트에서 로딩과 에러 처리를 동시에 수행한다
    3. 여러 개의 비동기 처리를 해야할 땐?
      1. 비동기 처리 지옥
  5. React의 비동기 처리는 어렵다
    1. 성공하는 경우에만 집중해 컴포넌트를 구성하기 어렵다
    2. 2개 이상의 비동기 로직이 개입할 때, 비즈니스 로직을 파악하기 점점 어려워진다
  6. React Suspense for Data Fetching (데이터를 가져오기 위한 Suspense)
      1. 컴포넌트는 성공한 상태만 다루고, 로딩 상태와 에러 상태는 외부에 위임함으로써 동기적인 코드와 큰 차이가 없는 코드를 만들겠다는 목표
      2. 에러 상태와 로딩 상태는 어떻게 분리되는가?
          1. 컴포넌트를 '쓰는 쪽'에서 로딩 처리와 에러 처리를 한다
          2. 로딩 상태는 가장 가까운 'Suspense'의 'Fallback'으로 그려진다
          3. 에러 상태는 가장 가까운 'ErrorBoundary'가 componentDidCatch()로 처리한다
      3. 일반적인 Suspense/ErrorBoundary의 용법
        1. Recoil - Async Selector
        2. SWR, React Query - {suspense: true}
        3. 'runPureTask'로 실행시키면, 비동기 함수도 동기적으로 작성할 수 있다
  7. 토스팀에서는 어디에 사용했는가?
    1. TUBA(Toss User Behavior Analyzer) : 토스 대부분의 데이터가 모이고 분석되는 내부 제품
      1. A/B Test 설정
      2. 전환율 분석
      3. 알림, 푸시 전송 - TUBA 메신저
        1. Recoil의 비동기 셀렉터를 이용해서 수많은 비동기 처리를 해결
        2. useRecoilValue를 이용해 Suspense 설정해줌
      4. ...
    2. 데이터가 준비되는 대로 하나씩 자연스럽게 보여주기
  8. 코드 복잡도를 낮춘 방법
    1. React hooks : 상태 관리, 부수 효과 관리, 메모이제이션 관리를 감싸는 컴포넌트가 수행하도록 하게 함
    2. Suspense : 실제 로딩 상태, 에러 상태 처리는 컴포넌트를 감싸는 부모 컴포넌트가 수행
  9. 에러 처리의 복잡도를 낮춘 방법
    1. try-catch : 실제 에러 처리는 컴포넌트를 감싸는 부모 함수가 수행 (실패할 수 있는 함수는 에러를 throw 문으로 발생시킴)
  10. 대수적 효과(Algebraic Effects)
    1. 함수는 필요한 코드 조각을 선언적으로 사용
    2. 실제 관련된 처리는 컴포넌트를 감싸는 부모 함수에 위임
  11. 더 공부하면 좋은 React 요소들
    1. React Concurrent Mode
    2. useTransition
    3. useDeferredValue
    4. -> React에서 컴포넌트의 렌더 트리를 부분적으로만 완성함으로써 사용자 경험을 크게 향상시킬 수 있다
//
<ErrorBoundary fallback={<MyErrorPage />}>
	<Suspense fallback={<Loader />}>
    	<FooBar />
    </Suspense>
</ErrorBoundary>

// React Team의 Sebastian Markbage의 Proof-of-concept
function getUserName(id) {
	var user = JSON.parse(fetchTextSync('/user/' + id));
    return user.name;
}
function getGreeting(name) {
	if(name == "Seb") {
    	return 'Hey';
    }
    return fetchTextSync('/greeting');
}
function getMessage(){
	let name = getUserName(123);
    return getGreeting(name) + ', ' + name + '!';
}
runPureTask(getMessage).then(message => console.log(message));

 

  • Recoil 공부하기
  • React Concurrent Mode, useTransition, useDeferredValue 공부하기

 

반응형