- Published on
FECONF - 바퀴 대신 로켓 만들기
- Authors
- Name
- 정윤호
FECONF 2024 - 바퀴 대신 로켓 만들기
소개
- 발표자 양의현
- 리액트, interface, 협업, 영감을 주는 주제에 관심
- 토스 페이먼츠의 FE 개발자
- 어드민 프로덕트 팀 ~ 어드민 개발 주력
문제
맥락
- 데이콤 -> LG U+ PG -> 토스페이먼츠
- 팀은 신생이나, 긴 기간 동안의 유산...
- 레거시, jsp, euc-kr
- 결제 시장의 혁신 해볼까 했으나, 레거시들이 발목을 잡는 사태
- 레거시 청산..!
- 400개 이상의 페이지, 6개월 안에, 4명의 개발자, 10년 이상 지속 가능
- 불가능해 보이는 과제
- 디자인 프로토 타입, 서버 준비, 요구사항 분석
- 어드민 화면을 바로 개발하기 어려운 상황
- 커뮤니케이션을 많이 할 수록, 시간적 자원 요구
- 팀은 신생이나, 긴 기간 동안의 유산...
FE 개발자가 접할 병목 3가지 (디자인 프로토타입 / 서버 API / 요구사항 분석)
디자이너와의 병목을 어떻게 끊을까
- 6개월 동안 400개 화면에 대해 최적화된 유저 경험을 고려한 디자인 프로토타입을 만들어주세요
- 이걸 누가 어떻게...
- 디자인 비효율을 줄일 도구 -> 디자인 시스템
- BUT 토스 디자인 시스템은 범위가 너무 넓어 (토스의 모든 프로덕트)
- 토스 페이먼츠만을 위한 디자인 최적화가 불가능
- 디자인 시스템 특)
- 장점이 많은 좋은 도구
- 아토믹한 형태 제공, 다양한 기능 조합해서 활용 가능
- 유연하고 재사용 가능
- 단점
- 반복되는 코드
- 작성하는 사람마다 다른 구현체
- 화면을 구성하는 제품의 코드가 늘어날 수록 구현 의도를 이해하기 어려움
- 장점이 많은 좋은 도구
- 페이먼츠만을 위한 시스템
- 강점
- 반복되는 기능과 형태를 패턴으로 정의
- 동일한 패턴은 동일한 구현체를 사용
- 닫힌 인터페이스로 패턴과 일치하지 않은 상황에서 사용 방지
- 가장 작은 단위부터 큰 영역까지 다양한 레이어에 대응
- 단점
- 상대적으로 떨어지는 유연성과 재사용성
- 상대적으로 한정적인 기능
- 패턴에 대한 학습 비용
- 예시: DateRangePicker
- 한 눈에 들어오는 인터페이스로 개선
- 예시: Select
- 작성하는 사람마다 서로 다른 구현체
- 누구는 prop으로 옵션 내리고, 누구는 합성으로 옵션 처리
- 취향 차이고 정답은 없어
- 다만, 다르다는게 문제
- 일관성 있는 단일 구현체를 제공해, 다른 구현체 만들 필요 없게함
- 작성하는 사람마다 서로 다른 구현체
- 특정 라이브러리 (훅 폼) 과 UI 요소와의 결합으로 군더더기 없는 코드 구현
- 유지 보수의 어려움
- 화면의 역할이 무엇인지 직관적으로 확인 어렵
- 영역이 적절히 분리되어 있지 않아 오류 발생 시 원인 파악에 오랜 시간
- 화면의 공통 변경사항 반영 시 N 번의 수정을 반복해야 함
- 아토믹 단위 말고, 다양한 레이어의 구현체
- 해당 페이지가 무슨 역할인지 한 눈에 보이게
- 강점
- 결론 (W/프로덕트 패턴)
- 아토믹한 구조를 추구하기 보다도, 구체적인 맥락이 들어가더라도 반복 사용하기 좋은 형태
- 서로 다른 인터페이스로 구현할 가능성 방지
- 명확한 역할의 컴포넌트를 정의하여 가독성과 유지보수성 향상
- 개발자가 패턴을 이해하고 있다면 디자이너이 도움 없이 화면 구현 가능
백엔드 개발자와의 의존성 끊기
- 서버 API가 완성될 때 까지 기다려야 할까?
- 우리가 서버에 필요한 것은 서버에 대한 구체적인 구현이 아닌 인터페이스 (엔드포인트, 메서드, request params, 응답 데이터)
- API Spec ~ 스웨거 등의 스펙을 이용하는 것에도 비효율
- 스펙을 확인 -> TS 코드로 이관 -> 메서드 호출 -> 스펙 호출
- 이 과정의 끝 없는 반복
- API Spec ~ 스웨거 등의 스펙을 이용하는 것에도 비효율
- 우리가 서버에 필요한 것은 서버에 대한 구체적인 구현이 아닌 인터페이스 (엔드포인트, 메서드, request params, 응답 데이터)
- OpenAPI Code Generator
- 유용하지 그런데, api client 없이 스펙 정보만 자동 생성 가능? zod로 요청 파라미터와 응답 데이터 파싱 가능? 커스텀 transform 조건 쉽게 주입 가능? 학습비용 없이, zero config로도 결과물 생성 가능? -> 이러한 요구사항 백프로 충족하는 도구 없어
- 그럼 우리가 필요한 도구를 직접 만들자
- TossPayments Codegen
- OpenAPISpec 읽기, 원하는 형식으로 코드 다듬기(TS, zod), 파일 쓰기
- Resource
- 하나의 파일에서 관리 가능한 api 명세 객체
- API에 대한 정보가 소스코드 전역에 퍼지는 현상 방지
- 필요에 따라 리소스에 정의한 스키마 파서로 데이터 정합성 확인 가능
- 리소스 이름을 기준으로 필요한 파라미터와 응답 데이터 추론 기능 제공
- 사용된 도구
- CodeGen 구현
- 스웨거에서 json 뽑아오고 이걸 다듬어서 자동으로 스키마 파일 생성
- paths 의 경우에도 똑같이 자동으로 resource의 형태로 자동 생성
- CodeGen 의 효과
- 구현 시간 1주일
- 2,000개 이상의 endpoints 자동화
- 10초 남짓의 시간으로 자동 생성
- 재사용 가능한 타입과 스키마
- 스펙 싱크 신경쓰지 않아도
- 기존의 스펙과의 지지부진한 관계를 벗어버리고, codegen 실행 -> 메소드 호출 간단한 과정으로 축소
- 결론
- 개발자가 api 문서 보고 한땀한땀 코드를 옮길 필요 없음
- API 오류 발생시, 옮기는 과정의 실수인지 잘못된 구현인지 추적할 필요 없음
- 우리의 유즈 케이스에 맞게 가공 가능한, 100% 제어 가능한 도구
- API가 반환하는 인터페이스가 바뀌어도 변경 사항을 즉시 싱크할 수 있음
제품 요구사항과의 의존성은 끊어낼 수 없어 -> 그럼 개발 자체의 비효율을 줄여볼까?
- 개발 생태계가 너무 풍부해서 생기는 비효율
- 좋은 라이브러리로 만들어내는 결과물들은 개발자마다 달라
- 다른 결과물들을 만드는 것은 바퀴를 만드는 행위의 반복
- 이것 보다는 일관성 있고 지속 가능한 코드를 생산하는 기반이 필요
- 코드를 하나의 방식으로 통일할 Pramework 가 필요
- Refine 이라는 툴 사용
- 오픈소스 리액트 어드민 툴
- headless: 특정 UI와 결합되지 않음
- resource: API 명세를 한 곳에서 객체로 관리
- provider: 필요한 기능들을 provider에 주입 가능
- Refine 이라는 툴 사용
- 어드민 제품 만들 때 가장 많이 반복되는 행위 (Data Fetching / Form Control / Table / Loggin)
- Data Fetching
- api에 대한 맥락을 한 곳에서 제어 (resource)
- 리소스와 api client를 react context로 주입
- 행위에 대한 훅을 제공하여 보다 선언적인 방식으로 데이터 사용
- 리소스 이름을 기준으로 필요한 요청 파라미터와 반환되는 응답을 추론
- Form Controls
- 리소스에 정의한 api 호출하고, default Values 로 주입
- 쿼리 파아미터 파싱하여 default Values 로 주입
- form 제출, 초기화를 쿼리 파라미터 업데이트 방식으로 실행
- Table
- 리소스에 정의한 api 호출, 테이블 형태로 렌더링
- jsx 반복 작성하는 대신 테이블 모델 주입하여 가독성 향상
- 페이지네이션, 열 번호, 체크박스와 같은 요구사항 처리
- 복잡하고 읽기 힘든 트리 방식을 제고 -> 반복되는 구현을 공통 옵션으로 제공
- Logging
- Log Client 를 컨텍스트로 주입
- Logger 로 wrapping한 TDS 컴포넌트를 사용하여 별도 처리 없이 로깅 실행
- Data Fetching
- 결과
- 몇 명의 개발자가 구현해도 일관성 있고 유지보수 가능한 서비스를 만드는 FE로 진화
결과
- 서로 다른 어드민 제품, 400 페이지 이상의 메뉴를 연차에 따라 편차 없이 화면 구현 시간을 하루에서 한 시간으로 단축..!
- 업무 중 비효율 적인 부분을 발견한다면, 작은 단위에서부터 변화를 꾸려라