Published on

리액트의 13가지 디자인 원칙

Authors
  • avatar
    Name
    김희열
    Twitter

*리액트 공식문서 Design Principles를 보고 정리한 글입니다.

리액트에는 몇 가지 디자인 원칙들이 있습니다. 이를 통해 React가 무엇을 하는지, 혹은 무엇을 하지 않는지 결정하는 방식과 개발 철학을 이해할 수 있습니다.

Composition

  1. React의 핵심 기능은 컴포넌트의 합성입니다.
  2. UI 컴포넌트든, UI가 아닌 기능이든 여러 컴포넌트에서 재사용하기를 원한다면, 별도의 JavaScript 모듈로 분리할 수 있습니다.
  3. 컴포넌트에서 해당 컴포넌트, 함수, 객체, 클래스 등을 import해서 사용할 수 있습니다.
  4. 함수 컴포넌트에서 컴포넌트는 단순 ‘함수’로 묘사되지만, 그 이상의 것을 필요로 합니다.
  5. React에서 컴포넌트는 구성 가능한 모든 동작을 기술합니다. 렌더링, state, props 등이 대표적인 예라고 할 수 있습니다.

Common Abstraction

  1. 일반적으로 React팀은 사용자가 구현할 수 있는 기능을 추가하지 않습니다.
  2. 언제나 예외는 있습니다. 로컬 state, 생명주기 메서드의 경우 사용자가 각자 추상화를 만들게 된다면 여러 개의 추상화가 충돌할 가능성이 생깁니다. 이러한 것들은 최소 공통 분모로 존재해야 합니다. 이런 이유로 React에서 기능을 추가하기도 합니다.
  3. 하지만 대부분은 새로운 기능을 추가하지 않습니다. 추상화 레벨을 올리는 것이 전체 생태계에 이익이 된다는 확신이 있기 때문입니다.
  4. state, 생명주기 메서드, 크로스 브라우저의 이벤트 정규화가 높은 레벨의 공통 추상화 예시입니다.

Escape Hatches

  1. React는 Facebook에서 작성된 제품의 필요에 의해 탄생한 라이브러리입니다. 그렇기에 실용적입니다.
  2. 다양한 기술과 경험을 가진 광범위한 개발자에게 접근 가능하도록 유지하는 것이 React 프로젝트의 목표입니다.
  3. React팀에서 원하지 않는 방식을 더 이상 사용하지 않으려면, 해당 패턴에 대한 모든 기존 사용 사례를 고려하고 그 대안에 대해 교육하는 것은 React팀의 책임입니다.

Stability

  1. React팀은 API 안정성에 가치를 둡니다.
  2. Facebook은 React를 사용한 5만 개 이상의 컴포넌트를 사용합니다. Twitter, Airbnb를 포함한 다양한 React의 헤비 유저도 존재합니다. 그렇기 때문에 React팀은 공용 API, behavior의 변경을 꺼립니다.
  3. 프로덕션 환경에서 자주 사용되는 무언가가 변경되었을 때는 명확하고 자동화된 마이그레이션 방법을 제공합니다.
  4. 특정 패턴을 사용하지 않고 싶은 경우, Facebook 내부에서 해당 사용법을 조사하고 경고를 추가합니다. 그렇게 변화의 영향을 미리 추적할 수 있습니다.
  5. 변경이 시기상조거나, 변경에 대한 준비가 충분하지 않은 경우 React팀은 경고를 되돌릴 수도 있습니다.
  6. 변경의 파장이 크지 않다거나, 모든 유스케이스에서 마이그레이션 전략이 실행 가능하다고 확신하는 경우 오픈소스 커뮤니티에 경고를 공개합니다.

Interoperability

  1. 상호 운용이란 기존 시스템에서 React를 점진적으로 도입하거나, 기존 시스템과 React 코드를 혼합해서 같이 사용해야 하는 경우에 각 시스템이 충돌하지 않고 ‘잘’ 운영되는 것을 의미합니다.
  2. Facebook은 거대한 non-React 코드베이스를 가지고 있습니다. XHP라는 서버 사이드 컴포넌트 시스템, 내부 UI 라이브러리, React를 조합해서 사용하고 있습니다.
  3. 이것이 React가 변경 가능한 모델을 다루기 위한 해결책을 제시하고, 다른 UI 라이브러리들과 잘 동작하도록 노력하는 이유입니다.

Scheduling ⭐️

  1. 컴포넌트가 단순 함수이지만 React를 사용할 땐 컴포넌트를 직접 호출하지 않는 게 좋습니다. 사용자가 아니라 React가 컴포넌트 함수를 호출할 때, 필요한 경우 특정 컴포넌트의 호출을 지연할 수 있는 권한이 React에 있다는 것을 의미하기 때문입니다.
  2. 현재 구현 단계에서 React는 트리를 재귀적으로 조사하고 단일 Tick 동안 전체 갱신된 트리의 렌더링 함수를 호출합니다.
  3. 어떤 라이브러리는 “push” 접근법을 사용합니다. 이 접근법은 새로운 데이터가 “사용 가능할 때 계산됩니다”. 하지만 React는 “pull” 접근법을 사용합니다. 필요할 때까지 계산을 지연할 수 있습니다.
  4. 이것은 React가 어떤 계산이 필요하고 어떤 계산이 필요하지 않은지 알 수 있는 특별한 위치를 점유했다는 뜻입니다. React는 데이터 처리 라이브러리가 아니라 UI를 만들기 위한 라이브러리라는 점에서 이 장점은 더욱 부각될 수 있습니다. (Concurrent Mode)
  5. 화면 밖에 있는 로직은 지연시킬 수 있습니다. 데이터가 프레임 속도보다 좀 더 빠르게 도착하는 경우 통합 및 일괄 업데이트를 할 수 있습니다. 중요도가 낮은 백그라운드 작업보다 사용자 인터렉션을 우선할 수도 있습니다.
  6. 명확하게는 React팀에서 이것을 사용하고 있지는 않습니다. 하지만 이런 일을 할 수 있는 자유는, 왜 React팀이 스케줄링에 대한 통제권을 선호하는지, 왜 setState()는 비동기적인지에 대한 이유입니다. React는 완전히 반응적(Reactive)이고 싶지 않습니다.

Developer Experience

  1. 좋은 개발자 경험을 제공하는 것은 중요합니다.
  2. React DevTools를 유지합니다. 이것은 Facebook 엔지니어와 커뮤니티 모두에게 큰 생산성 향상을 가져왔습니다.
  3. 도움이 될 만한 개발자 경고를 제공하기 위해 노력하고 있습니다. 이는 React 개발자 버전이 프로덕션 버전보다 조금 더 느린 주요한 이유입니다.

Debugging

  1. 문제가 발생했을 때 코드베이스로 실수의 원인을 추적할 수 있는 표식을 만드는 것이 중요합니다. React에서 props, state가 이러한 표식입니다.
  2. React DevTools를 열고 렌더링을 담당한 컴포넌트를 찾은 후 props와 state가 올바른지 확인할 수 있습니다.
  3. state가 바르지 않다면 이 파일 내의 setState() 호출 중 하나의 문제입니다. props가 바르지 않다면 인스펙터로 거슬러 올라가며 트리를 탐색해 문제가 있는 props를 전달함으로써 문제가 있는 컴포넌트를 찾을 수 있습니다.
  4. state가 Closure와 연결자에 갇히지 않고, React에 직접적으로 이용할 수 있는 것은 명확한 React 설계 목표입니다.

Configuration

  1. 전역 런타임 설정 옵션에 문제가 있음을 확인했습니다. 이에 대해 React.configure(options), React.register(component)와 같은 기능을 구현해 달라는 요청을 받습니다. 하지만 전역 설정이 합성에서 제대로 동작하지 않을 것이라고 생각합니다. 그래서 우리는 코드에서 전역 설정을 제공하지 않습니다.
  2. 하지만 빌드 레벨에서 몇 가지 전역 설정을 제공합니다. 예를 들어, 분리된 개발 빌드와 프로덕션 빌드를 제공합니다. 추후에는 프로파일링 빌드를 추가할 가능성도 있습니다.

Beyond the DOM

  1. 렌더러에 구속받지 않는 것은 React의 중요 설계상 제약입니다.
  2. React팀은 더 적은 버그의 컴포넌트를 작성하여 구성할 수 있는 방식에 가치를 두고 있습니다. DOM은 React에서 중요한 렌더링 대상이지만 React Native 또한 중요합니다.
  3. 단일 프로그래밍 모델을 가짐으로써 내부 표현에 약간의 오버헤드를 가지게 되지만, React팀은 플랫폼 대신 프로덕트 중심의 엔지니어링 팀을 구성할 수 있습니다. 그러므로 트레이드 오프는 그만한 가치가 있습니다.

Implementation

  1. 새로운 코드를 평가할 때 올바르고 성능이 좋고 뛰어난 개발자 경험을 제공하는 구현을 기대합니다. 세련되고 우아한 것을 그 다음 문제입니다.
  2. 실세계는 완벽한 것과 거리가 있기 때문입니다. 사용자가 못생긴 코드를 작성하지 않아도 된다면, 합리적인 범위에서 React팀은 라이브러리에 그 못생긴 코드를 삽입하는 것을 선호합니다.
  3. 현명한 코드보다 지루한 코드를 선호합니다. 코드는 일회성이며 자주 변경되기 때문에 절대적으로 필요한 것이 아니라면 새로운 내부 추상화를 도입하지 않습니다.

Optimized for Tooling

  1. didMount()나 onMount() 대신 componentDidMount()를 사용하는 것은 의도적입니다. 라이브러리와의 인터렉션 포인트를 눈에 띄게 하기 때문입니다.
  2. 특히 dangerouslySetInnerHTML처럼 조심스럽게 사용해야만 하는 기능을 눈에 띄고, 검색하기 쉽게 만드는 것은 이 코드를 코드 리뷰 단계에서 간과하기 힘들게 합니다.
  3. 그 밖에 React 사용에 대한 Lint 규칙을 만들 수도, 미적, 실용적 이유로 JSX를 사용할수도 있습니다.

Dogfooding

  1. Dog fooding이란 자사 제품이나 서비스를 직원들이 일상적으로 사용하고 제품의 문제점을 확인하는 것을 말합니다.
  2. React팀은 커뮤니티에서 제기한 문제를 해결하려고 최선을 다합니다. 하지만 Facebook 내부적으로 겪고 있는 이슈를 우선시할 수도 있습니다.
  3. 내부적으로 많이 사용하기 때문에 React가 내일 사라지지는 않을 것입니다. 또한 React는 Facebook에서의 문제를 해결하기 위해 만들어졌습니다.
  4. React는 기업에 확실한 비즈니스 가치를 가져다 주며 많은 프로덕트에 사용됩니다. Dog fooding은 우리의 미래를 날카롭게 유지하며 앞으로 나아가는 방향으로 초점을 맞추고 있다는 것을 의미합니다.
  5. 하지만 React팀이 커뮤니티에서 제기하는 이슈를 무시한다는 의미는 아닙니다. 예를 들어 Facebook에서는 어느 하나 의존하지 않지만, 웹 컴포넌트와 SVG에 대한 지원을 React에 추가했습니다.