💻 Frontend

Effective Component 지속 가능한 성장과 컴포넌트

category
💻 Frontend

Effective Component

토스 slash 컨퍼런스 영상을 보고 알게된 내용이나 느낀점을 정리해보겠다!
 

변경?!

우리는 개발을 하는 순간마다 변경이라는 상황을 맞이하게 된다.
이번 스프린트에서 변경된 내용은 ~~~
oo 컴포넌트에서 해당 사항을 변경해야 할 것 같아요.
왜 이렇게 변경을 마주하는 상황이 오는 걸까? 반대로 생각해보자.

제품이 변경되지 않아야 하는 이유가 뭘까? 바로 사용자가 잘 사용하기 위해서이다.
사실상 모든 사용자가 잘 사용할 수 있는 제품을 만들기 힘들다. 그래서 우리가 이렇게 많은 변화를 겪는것이다.
변경을 했다는 것은 놓쳤던 고객 니즈를 발견했던게 아닐까?
사실 이번 Hello, GSM v2를 하면서 많은 변경에 힘듦을 겪었다. “기존 v1도 문제없이 잘 운영되었는데..” 하지만 우리 프로젝트는 많은 변경으로 인해 사용자에게 더욱 친화적인 서비스로 성장했을 것이다! 이 내용을 통해 변화를 불편하지 말고 받아들이자는 생각을 하게 되었다.

하지만 우리는 변경이 어떻게 일어날 지 개발을 하면서 알 수 없다. 그래서 우리는 변경을 예측하는 것이 아닌, 변경에 대응해야 한다.
 

변경에 대응하기

출처 - toss
출처 - toss
제품은 보통 이렇게 만들어진다.
  1. 작은 컴포넌트를 제작
  1. 작은 컴포넌트를 합친다.
  1. 서비스가 커지면 적당히 분리한다.
여기서 중요한 포인트는 “적당히”이다. 적당히라는 기준이 어느정도일까? 이 기준은 딱히 없다.
  • 중복이 많아서?
  • 단순히 코드가 많아서?
 
notion image
여기서 중요한 것은 규모가 커진 컴포넌트를 보고 어디서부터 고쳐야 할 지 어렵다는 점이다. 해당 컴포넌트를 분리하기 위해서 프로젝트 코드 전부를 살펴봐야 하는 일이 발생할 수도 있다.
이 컴포넌트는 어쩌다 이렇게 만들어졌을까?
  1. 컴포넌트를 제작하다보니 커졌고,
  1. 적당히 덜어내면서 완성.
적당히라는 애매모호한 기준을 일반화 시킬 수 없을까?

변경에 대응할 수 있는 컴포넌트의 특징

컴포넌트는 어떤 역할을 해야하나?

notion image
  1. 데이터를 관리한다.
  1. 그 데이터가 사용자에게 어떻게 보여질지 정의. → User Interface
  1. 해당 UI를 기반으로 사용자와 어떻게 상호작용할지 정의.
notion image
어떻게 보여질지 정의하는 부분은 디자인에 의존한다. 그러니 디자인을 관리하는 UI와 컴포넌트가 관리하는 데이터를 분리하면 어떨까?

1. Headless 기반의 추상화 하기

변하는 것 VS 상대적으로 변하지 않는 것
notion image
위에서 생각했던 방안으로 데이터 부분과 UI부분을 분리하였다. 달력을 구성하는 필요한 데이터 계산을 useCaledar hooks에 위임한 것이다. 이렇게 컴포넌트를 구상하면 UI를 관심사에서 제외할 수 있다. 오로지 데이터에만 집중해서 모듈화를 할 수 있다. 이러한 패턴을 Headless라고 한다!
notion image
 

2. 한 가지 역할만 하기

또는 한 가지 역할만 하는 컴포넌트의 조합으로 구성하기
복잡한 컴포넌트를 만들때는 어떻게 해야할까?
notion image
흔한 select 컴포넌트를 만들 때 이런식으로 코드를 작성했을 것이다. 하지만 이 컴포넌트는 재사용성이 낮은 컴포넌트이다. 다른 곳에서 해당 컴포넌트를 사용한다면 어떻게 될까?
  1. 일단 Label을 바꾸기가 어렵다.
  1. InputButton 컴포넌트 대신 다른 컴포넌트를 사용하고 싶을 때 어떻게 대응할 것인가?

아까 배웠던 Headless 패턴을 통해 데이터와 UI를 분리해보자.
  1. 먼저 select가 보여지는 isOpen을 분리할 수 있다.
  1. 해당 select가 보여지게 하는 상호작용도 따로 관리 해보자.
  1. option도 isOpen데이터에 따라 노출여부가 결정되기 때문에 컴포넌트로 제작해보자.
  1. 또 option 하나하나의 Item을 분리하여 상호작용을 담당하도록 구성해보자.
notion image
다루고 있는 데이터를 기준으로, 담당하고 있는 역할을 기준으로 분리한다면 유연하게 관리할 수 있을것이다.
notion image
재구성한 코드는 다음과 같다.
Select 컴포넌트와 trigger로 전달한 InputButton은 서로의 존재에 대해 알지 못한다. 서로의 변경이 서로에게 영향을 끼치지 않게 된다는 것이다. 그러니 각각의 컴포넌트들이 의존성이 낮아, 유연한 컴포넌트가 되어 재사용성을 높일 수 있다.
 

3. 도메인 분리하기

도메인을 포함하는 컴포넌트와 그렇지 않은 컴포넌트 분리하기
일반적인 인터페이스로 분리하기
재사용성이 높은 컴포넌트를 제작하기 위해선 Props 네이밍을 일반적이게 변경한다. 도메인 맥락을 제거한다는 말이다.
notion image
컴포넌트 인터페이스는 일반적일수록 이해하기 쉽다. → 사람은 무언가를 볼 때 기존에 알고있던 내용을 바탕으로 파악하기 때문이다. 배경지식으로 무언가를 해석한다.
사람마다 알고있는 것이 다르기 때문에 최대한 많은 사람들이 알만한 것으로 표현해야 의도를 드러내기 쉽다.
notion image
비지니스 로직을 스스로 처리하되 UI로직을 위임하는 방식이다.
 

액션 아이템

인터페이스를 먼저 고민하기

구현해야하는 기능이 이미 만들어져 있다고 가정하고, 그것을 사용하듯이 작성해보자. UI에 속지말고 데이터의 흐름을 파악한다면 쉽게 구조를 잡을 수 있다. 만들고 나서 사용하려고 하면 사용하는 입장에서 봤을 때 의도가 파악하기 어려운 문제가 있었다.
  • 의도가 무엇인가?
  • 이 컴포넌트의 기능은 무엇인가?
  • 어떤 데이터를 관리하는지?
  • 어떻게 표현되어야 하는지?
이러한 문제는 인터페이스를 먼저 정의하면 해결할 수 있다.
 

컴포넌트를 나누는 이유?

컴포넌트를 나누기 전에 이유를 다시 한번 생각해보는 습관을 가져야 한다. 우리는 본능적으로 많은 로직이 한곳에 있다면 파악하기 힘들다는 것을 알고있다. → 그래서 하나의 서비스를 여러 개의 컴포넌트로 나누어 개발한다.
그리고 반복되는 부분을 모듈화 하면 좋다는 것을 알고있다.
notion image
“서비스를 나눈다.” “모듈화한다.”
지금 우리가 하는 컴포넌트를 분리하는 것이 복잡도를 낮추기 위하는 것인지, 재사용하기 위함인지, 꼭 분리해야하는 컴포넌트인지 한번 고민해볼 필요가 있다.
 

마무리

잘 만든 컴포넌트는 이미 해결한 문제를 또 해결하지 않아도 되니 미래의 나에게 큰 도움이 될 것이다. 변경이 유연한 코드는 안정적으로 비지니스를 운영하면서 빠른 속도를 유지하는데 필수적인 요소이다!

느낀점

복잡한 컴포넌트를 만들려면 한자기 역할만 하는 컴포넌트를 조립하는 형식으로 구성한다면 조금 더 유연하고 쉽게 접근할 수 있는 것 같다.
가장 기억에 남는 내용은 구현하려는 컴포넌트가 이미 있다고 가정한다는 것이다. 이미 구현된 기능이라고 생각해보고 구현한다면 내가 사용하기 좋게 만들려고 할 것이다. 항상 모듈화하거나 복잡한 로직을 처리하려고 한다면 “이유”에 대해 곰곰이 생각해보고 다른 사람이 보아도 한눈에 파악할 수 있는 좋은 코드인지 확인해보는 습관을 길러야겠다!!

References

Video preview