0620 - 0626

0621

컴포넌트 설계 윈칙

React 컴포넌트의 의존성이란 리액트 컴포넌트를 만들 때 필요한 것
예를 들어 props로 받거나, 커스텀 훅, import 의존성 등이 있다.

ex) 스타일, 특정한 커스텀 로직, 전역 상태, 리모트 데이터 스키마

비슷한 관심사라면 가까운 곳

  • 예를 들어 스타일과 로직의 경우 같은 파일 내에 위치시킬 수 있다.
  • 컴포넌트가 커지는 것이 걱정이라면 같은 폴더 내에 다른 폴더로 분리할 것
  • 상위 컴포넌트에서는 ID만 받고, 데이터 저장소에서 ID를 통해 해당 데이터를 받아올 수 있게 해서 의존성을 끊어낼 수 있다.

개선 전

37AC883B-D781-4DDF-8D0E-A4E88D2FFC3A

개선 후

DBFB3EDA-49D8-4F32-9356-1F4A51936D7F

데이터를 ID 기반으로 정리하기

개선 전

6474F950-2D90-4E0A-899B-E61D737641C0

개선 후

2057C0AB-B813-48D7-A018-04912D0A282E

모델명과 ID만 가지고 특정 데이터를 뽑아낼 수 있게 된다.
이를 데이터 정규화라고 한다.

데이터 정규화를 도와주는 라이브러리
yarn add normalizr

여기에는 또 다른 숨은 의존성이 생기는데 바로 모델을 상위에서 정확하게 알고 있어야 한다는 점이다.

Global ID

  • 전역 아이디는 특정정 객체를 식별하기 위해 모델명을 따로 넘길 필요 없이 ID 값만 가지고 특정 데이터를 유일하게 식별할 수 있도록 하는 체계
  • 보통 모델명과 ID 값을 string concat 해서 생성
  • 경우에 따라 base64 인코드, 디코드

개선 전

1B8F3620-8CBE-45F6-B891-06CAE6E06008

useArticle 훅 이름을 보면 해당 컴포넌트가 Article이라는 정보가 필요하다는 것 역시 컴포넌트 바깥에서 주입받고 있는 걸 확인할 수 있다.

개선 후

AA5CC8E3-FEA0-4A83-9651-BC3D98397DE5

전역 ID를 통해 데이터를 가져오는 useNode hooks로 바꾸면 사용할 모델 정보마저 컴포넌트 내부에 함께 둘 수 있게 된다.

GOI (Global Object Identification)
어떠한 코드 위치, 맥락에 있든 Global ID 기반으로 특정 객체를 가져올 수 있는 API

  • 데이터 저장소에 특정 필드가 없을 때 추가적으로 데이터를 가져올 수 있도록 자동화 할 수 있다.
  • 해당 컴포넌트가 어떤 필드를 사용하고 있는지 표현해야 하는데, 다음과 같은 형태 코드로 어떤 필드를 사용할지 표현할 수 있다.

DE83FB55-C315-49ED-9DFD-6859836614AB

0E2314F8-2025-41B3-BDF4-79C3AA1FE413

  • 루트 컴포넌트에서 가져온 데이터를 정규화해 데이터 저장소에 정리해서 넣어 놓는다.
  • 작성한 컴포넌트는 상위 컴포넌트로부터 Global ID를 받게 되고, 데이터 저장소에 특정 데이터를 요청한다.
  • 원하는 필드가 없다고 가정했을 때, 데이터 저장소는 자동으로 api 서버에 GOI를 활용해 데이터를 요청한다.
  • 해당 요청이 성공하고 컴포넌트는 완전한 데이터를 언제나 보장받는다.

새로 고침을 할 수 있는 버튼을 노출하거나, 수정이 일어났을 때 refetch를 호출하는 경우가 많다. useNode에 refetch를 노출하게 되면 루트 컴포넌트나 상위 컴포넌트에 관계없이 refetch 로직을 쉽게 호출할 수 있다.

의존한다면 그대로 드러내기

9C37E52A-7AA1-4F2C-8601-2C81641BF1A2

  • 유저와 이미지 모델을 의존하는 경우, User와 Image 모델을 사용하는 것을 그대로 드러내자
  • User와 Image 모델 사이의 관계 정보까지 표현하면 다음과 같은 모습으로 Props가 만들어진다.

957CCB15-005A-446B-997C-06B9ACF5AB8B

  • 전역 ID를 통해 필요한 객체의 래퍼런스만 받아 오게 되면, 의존성이 느슨해지면서 재사용성이 높아진 컴포넌트를 만들 수 있다.

모델 기준으로 컴포넌트 분리하기

컴포넌트는 끊임없이 변화하면서도 유저에게 일관된 경험을 제공해주어야 한다.
유저들이 생각하는 일관적인 경험은 대부분 모델을 기반으로 한다.

컴포넌트를 분리해야 할지 재사용할지 고민이된다면
같은 모델을 의존하는 컴포넌트: 재사용
다른 모델을 의존하는 컴포넌트: 분리

대부분의 변화는 리모드 데이터 스키마가 변화하는 방향을 따라서 움직인다.

EC727BEA-D6AC-4481-969D-2454F70E9C35

왼쪽: 일반 게시글, 오른쪽: 비즈 게시글

6FBE1B4D-6CAF-4731-8015-630BD9A85C78

map 함수 내부에서 switch 문을 작성하면 api에서 타입 이름을 함께 내려주도록 하게 되면 해당 타입 이름을 통해 어떤 컴포넌트를 사용할 지 패턴을 만들어주면 된다.
제품 여기저기서 Article 모델에 접근할 수 있는 전역 아이디만 있다면 거래 카드 컴포넌트를 안심하고 재사용할 수 있게 된다.
-> 일관성 있게 변화 가능

기술 도입이 성공하기 위해서는 유저 경험에 이르기까지 영향을 미칠 수 있어야 한다.

reference
[A3] 컴포넌트, 다시 생각하기




0623

Effective Component

변경에 유연하게 대응할 수 있는 컴포넌트 만들기

Headless UI 기반의 추상화하기

데이터 추상화
83E2E221-5E51-4ED1-914B-2E04006445BD

달력에 대한 데이터를 추상화하여 useCalendar라는 hooks에서 반환된 값을 어떻게 보여줄지만 정의하면 된다.

또 다른 달력 컴포넌트를 만들어야 할 때, 디자인이 다르더라도 useCalendar 훅을 사용할 수 있다. UI를 관심사에서 제거함으로써, 데이터에만 집중해서 모듈화 할 수 있다.


동작 추상화
4B1C2BCE-F0F1-42D0-B33D-528DECE2A0B2

이와 같이 동작도 추상화 할 수 있는데, 컴포넌트에서는 hooks로부터 반환되는 값을 UI에 적용하기만 하고, 어떻게 보일지만 집중할 수 있게 된다.
또한 다른 컴포넌트에서도 longPress 동작을 정의할 때 가져다가 사용할 수 있다.

변경에 유연해지려면 각 모듈이 한 가지 일만 하는 것이 중요

한 가지 역할만 하기

DD245EB9-F6D5-4AE5-8782-C61240B99AA8

위와 같이 복잡한 컴포넌트의 경우, 재사용하기가 더욱 쉽지 않다.
예를 들어, label만 바뀌어도 재사용이 힘들기 때문에 props로 label을 받아야 한다. 또한 InputButton 대신에 다른 컴포넌트를 사용하고 싶을 때도 변경에 유연하지 못하다.

A46A14EE-4606-4356-A6D3-6CB60838B837

다루고 있는 데이터를 기준으로, 담당하고 있는 역할을 기준으로 분리

0E646D31-B06B-4580-AD2A-4CF050D88ECB

F5E3BDFA-FFDD-4253-901A-C5F6AEDB48EC

Select 컴포넌트와 trigger로 전달한 InputButton 컴포넌트는 서로의 존재에 대해 알지 못한다.
서로의 변경이 서로에게 영향을 끼치지 않게 됨으로써, 각각의 컴포넌트가 변경에 유연하도록 만든다.
이렇게 합성 가능하도록 컴포넌트를 설계하면 재사용하기 좋고, 확장하기도 좋다.

도메인 분리하기

위에서 설명한 FrameworkSelect 컴포넌트에서 도메인을 분리하면 좀 더 다양한 도메인에서도 컴포넌트를 재사용 할 수 있다.
우선 Props 네이밍에서 도메인 맥락을 제거하고 일반적인 이름으로 바꾸어야 한다.

C33D784A-B71F-4148-996C-C8187FF623CF

컴포넌트 인터페이스는 일반적일수록 이해하기 쉽다.
-> 배경지식으로 무언가를 해석하기에 최대한 많은 사람들이 알만한 단어로 표현해야 의도를 드러내기 쉽다.

내 생각

컴포넌트를 설계할 원칙들에 대해 알아보기 위해 토스와 당근 마켓에서 발표한 웨비나를 시청했다.
토스의 영상은 재사용을 중점으로 컴포넌트를 설계하는 방법에 대해 배울 수 있었고, 당근 마켓은 재사용하면서도 요구 사항이 변경되었을 때 발생하는 문제까지 고려해서 모델 기준으로 컴포넌트를 분리하는 것이 기억에 남는다.
이러한 원칙들을 머릿속에 넣어두고, 물론 내가 직접 부딪히며 설계해봐야겠지만 나보다 더 경험 많은 개발자들의 생각을 들을 수 있어서 의미있는 시간이었다.
앞으로도 이러한 웨비나 영상들을 자주 찾아보고, 영감을 얻을 수 있는 활동들을 꾸준히 해야겠다.



reference
토스ㅣSLASH 22 - Effective Component 지속 가능한 성장과 컴포넌트

태그:

카테고리:

업데이트: