본 게시물은 안희종 님이 발표하신 FE CONF 2021의 '왜 나는 React를 사랑하는가'를 듣고 정리한 내용입니다.
이미지 출처 : FEConf 페이스북
클리어한 멘탈 모델, 작고 단단한 코어
리액트는 프로그래밍 언어와 닮은 점이 많다.
Reconciler는 리액트 코드를 해석하고 실행하는 역할, 즉 엔진(컴파일러)의 역할을 한다.
프로그래밍 언어가 컴파일러를 통해 기계가 이해할 수 있는 어셈블리어로 컴파일되는데, 리액트가 프로그래밍을 프로그래밍 언어에 비유했을 때 어셈블리어는 호스트 환경에 따라 달라지게 된다.
Learn Once, Write Anywhere
- HTML : react-dom
- iOS, Android : react-native
- 터미널 : ink
- Three.js : react-three-fiber
- JSON : react-test-renderer
다른 호스트 환경에서 동일한 React API(문법)을 사용할 수 있다.
React API? props, hooks, ...
명확한 문제 및 목표 정의
만약 React가 웹만을 위한 UI 라이브러리였다면?
위 커스텀 렌더러가 존재하지 않을 수도 있고 한 번 배워서 모든 곳에 쓸 수 있는 장점 또한 존재하지 않을 수 있다.
Virtual DOM은 너무 느려
리액트의 여러 경쟁 라이브러리들이 언급하는 리액트의 단점이다.
리액트가 웹만을 위한 라이브러리라면 단점으로 취급될 수 있지만, 코어 로직이 웹 환경과 직접적으로 연관되어 있지 않는 것이 리액트의 의도적인 결정이기 때문에 리액트의 목표와는 핀트가 벗어난 비판이다.
Virtual DOM과 관련하여 내가 쓴 글과는 다른 관점으로 해당 단점을 상쇄하고 있는데, 리액트가 정의한 해결방법에 더욱 근접히 다가가 도출해낼 수 있던 관점이라고 생각됩니다. 제 게시물은 다음 링크에서 확인하실 수 있습니다.
꾸준히 성장하는 거대한 커뮤니티
낯섦 예산의 현명한 소비
The language strangeness budget
프로그래밍 언어를 만드는 건 쉽지만 사람들이 그 언어를 쓰게 만드는 건 훨씬, 훨씬 어렵다. 당신의 언어에 새롭고, 재미있고, 흥분되는 기능이 얼마나 많이 포함되어 있는지 인지하고, 그 수를 세심하게 고려해야 합니다. - Rust 코어팀의 Steve Klabnik
어떤 기술을 선택하는 것도 예산을 지불하는 것일텐데, 가치가 비용보다 크며 전체 예산이 소모되는 전체 비용보다 큰 경우에만 예산을 지불, 즉 기술을 선택하게 된다.
리액트와 비슷한 문제를 해결하기 위해 새로운 언어를 개발한 사례가 Elm, ReScript 등이 있었다.
하지만 React와 비교하였을 때 큰 성공은 거두지 못했는데 이는 React가 프로그래밍 언어가 아닌, 라이브러리의 형태를 띄고 있는 부분이 크게 작용했다고 생각한다.
만약 React가 언어였을 시
- 부족한 리소스, 텅 빈 Stack Overflow
- 새로운 패키지 매니저
- 적은 유저 풀
- JSX
- 컴포넌트 기반 개발
- 선언적 렌더링
등의 난관이 있었을 텐데 라이브러리의 형태를 통해
- JSX
- 컴포넌트 기반 개발
- 선언적 렌더링
생태계 측면의 난관을 없앤 위 세가지 문법적 요소와 동작에서의 새로운 멘탈 모델에 집중 할 수 있었다.
도전적인 과제, 우아한 해결책
답안지 훔쳐보기
환원을 통해 문제를 해결할 수 있다.
환원이란? 새로운 문제 A가 생겼을 때, 이러이러한 면에서 답안지가 존재하는 문제 B를 참고하여 해결하는 것
리액트에서의 환원
Context
필요 : 컴포넌트가 트리 저 위쪽에 정의된 무언가로부터 값을 꺼내올 수단
환원 : 참조 시점에 둘러싼 환경을 기준으로 평가되는 변수
답안지 : 프로그래밍 언어의 동적 스코핑
Dan Abramov의 블로그에는 해당 내용이 기재되어 있음
Fiber
필요 : JS의 싱글 스레드 호나경에서 느린 컴포넌트가 우선순위 높은 업데이트를 막아 생기는 반응성 저해를 방지할 수단
환원 : 하나의 실행 주체로 우선순위가 다른 여러 작업이 동시에 잘 실행되게 만드는 일
답안지 : 운영체제의 스케쥴링
Hooks
필요 : 함수 컴포넌트의 제약을 제거하고 상태 로직의 응집성, 재사용성을 개선
환원 : 특정 효과(상태, 라이프사이클 이펙트)의 처리를 React에게 위임할 수단을 찾아야 함
답안지 : 대수적 효과
대수적 효과는 Dan Abramov의 블로그에 자세히 기술되어 있습니다. 제가 이해한 대수적 효과를 짧게 적어보자면 '무엇'을 하는지에만 집중하는 코드를 작성할 수 있으며, '어떻게'는 나중에 명시하면 되는 방법입니다.
Suspense
필요 : 비동기로 불러와야 하는 리소스를 선언적으로 정의
환원 : 특정 효과의 처리를 React에게 위임할 수단을 찾아야 함
답안지 : 대수적 효과
적용 사례
Flex 팀에서는 리모트 레이어를 개선하고 싶었다.
문제
-
호출 함수에서 다양한 작성 방법이 모두 달랐다.
ex) query parameter를 문자열 보관 vs axios request config를 통해 전달
-
SWR의 Key를 유니크하게 관리하는 것이 온전히 개발자에게 맡겨진 일이라 적용하는 방식이 모두 달랐다.
해당 문제를 리모트 리소스 정의, SWR 키 생성 방식이 사용처 별로 제각각이다로 정의하였으면 컨벤션을 마련하는 방법으로 해결할 수 있었겠지만,
리모트 리소스 정의, SWR 키 생성 방식을 개발자가 수동으로 반복하고 있다로 정의하여 이를 자동화하는 방법으로 해결하기 위해 접근할 수 있었다.
낯섦 예산의 현명한 소비
개발하는 방식을 한번에 바꾸려 했다면, 각자의 우선순위에 의해 부담스러워 오히려 도입이 늦어질 수 있다고 판단하여 작은 부분부터 나눠 도입하였다.
- 리모트 리소스 정의 방식 일원화
- 리모트 리소스를 사용할 수 있는 리모트 훅 생성
- 1단계의 수동으로 생성했던 리소스를 스펙으로부터 자동 생성하는 방법
답안지 훔쳐보기
- 리모트 식별자로부터 자동 생성된 키를 사용하는 것은 SWR의 useRequest에서 힌트를 얻을 수 있었다.
- 리모트 레이어 전체를 Hook에서 생성할 수 있다는 것을 GraphQL code generator를 통해 알 수 있었다.
- openapi-generator 프로젝트를 통해 실험적 도입 경험과 FEConf 도입 사례를 통해 자신감을 얻었다.
정리
리액트를 사랑하는 이유
- 많은 이유가 있지만 프로그래밍 언어를 닮았다는 지점으로 모아진다.
- 클리어한 멘탈 모델과 한 번 배워 모든 곳에 쓸 수 있는 점을 통해 명확한 문제 정의 및 목표 정의를 배울 수 있었다.
- 꾸준히 성장하는 거대한 커뮤니티를 통해 낯섦 예산의 현명한 소비를 배울 수 있었다.
- 도전적인 과제와 우아한 해결책을 통해 답안지 훔쳐보기를 배울 수 있었다.
내 정리
해당 발표를 통해 대수적 효과를 얕게나마 이해할 수 있는 계기가 되었습니다.
지금까지 이해한 바로는 Toss SLASH 21 클린 코드 세션에서 다루었던 추상화와 선언적 프로그래밍과 같은 곳을 짚고 있는 것 같습니다.
위에서도 기술하였지만 Virtual DOM에 대한 시각이 리액트가 정의한 해결 방법에 더욱 깊게 다가갔을 때 다른 시각에서 상쇄될 수 있다는 것이 더욱 제 시야를 넓혀줄 수 있었습니다.
처음 해당 발표를 들으면서 예상했던 내용은 React를 사용한 개발 방법에 대한 내용이였으나, 소프트웨어 개발의 전반적으로 적용되는 개념들을 React의 사례로 들으면서 이해할 수 있음과 동시에 현업에서 적용 사례를 들을 수 있어서 알찬 발표였다고 생각됩니다.