이 발표는 토스페이먼츠가 어떻게 ‘프론트엔드 개발 답답 3형제’를 해결했는지에 대한 내용이었다.
여기서 프론트엔드 개발 답답 3형제는
- 디자인 프로토타입
- 서버 API
- 요구사항 분석
이다.
프론트엔드 개발을 할 때, 해당 요소들이 완성될 때까지 기다리는 것이 보통이지만, 계속 기다리기에는 답답하다.
토스페이먼츠는 어떻게 이 문제를 해결했을까?
1. 디자인 프로토타입
디자인 시스템을 통해서 디자인 비효율을 줄일 수 있다.
디자인 시스템의 Strength
- 재료로써 다양한 기능과 형태를 제공
- 유연한 구조, 재사용이 쉬움
하지만 단점도 있는데,
디자인 시스템의 Weakness
- 반복되는 코드가 자주 생김
- 작성하는 사람 마다 서로 다른 구현체를 사용 → 누구는 prop으로, 누구는 합성으로 옵션을 처리함
- 화면을 구성하는 제품의 코드가 늘어날 수록 구현의도를 이해하기 어려움
토스페이먼츠는 디자이너분들과 따로 협의해서 TossPayments Product System을 제작했다!
Product System의 Strength
반복되는 기능과 형태를 패턴으로 정의
동일한 패턴은 동일한 구현체를 사용
닫힌 인터페이스로 패턴과 일치하지 않은 상황에서 사용을 방지
가장 작은 단위(컴포넌트)부터 가장 큰 영역(스크린)까지 다양한 레이어에 대응
Product System의 Weakness
상대적으로 떨어지는 유연성과 재사용성
상대적으로 기능이 한정적임
→ Design System 대신 Product System을 사용했을 때 단순하고 직관적으로 사용할 수 있다.
더 자세히 설명하자면,
Design System을 활용하면 유지보수의 어려움이 발생한다.
- 화면의 역할이 무엇인지 직관적으로 확인하기 어려움
- 영역이 적절히 분리되어있지 않아 오류 발생시 원인 파악에 시간이 오래 걸림
- 화면의 공통 변경사항 반영 시 N번의 수정을 반복 해야함
→ Product System에서는 Section 단위 디자인 정의 / 특정 패턴의 화면 표현에 최적화되어 유지보수에 유용하다.
Product System에 대해서 최종적으로 정리하자면 다음과 같다.
- 아토믹한 구조를 추구하기보단 구체적인 맥락이 들어가더라도 반복 사용하기 좋은 형태
- 서로 다른 인터페이스로 구현할 가능성 방지
- 명확한 역할의 컴포넌트를 정의하여 가독성과 유지보수성 향상
- 개발자가 패턴을 이해하고 있다면 디자이너의 도움없이 화면 구현 가능
2. 서버 API
서버 API가 꼭 필요한가? → 서버 API가 완성될 때까지 기다려야 할까?
API Spec(Swagger, Rest Docs)은 피곤하다.
스펙문서 확인 → 스펙 TS 코드 이관 → 메소드 호출 via Data Fetcher → 스펙 수정의 과정을 거쳐야 한다.
API Spec은 왜 피곤한지 AI에게 물어봤다.
- 스펙문서 확인:
- 개발자는 Swagger나 REST Docs와 같은 도구로 생성된 API 문서를 확인합니다.
- 이 과정에서 엔드포인트, 파라미터, 응답 형식 등을 파악해야 합니다.
- 문제점: 문서가 최신 상태가 아니거나 불완전할 수 있어 신뢰성 문제가 발생할 수 있습니다.
- 스펙 TS 코드 이관:
- API 스펙을 TypeScript 인터페이스나 타입으로 변환합니다.
- 요청 파라미터, 응답 데이터 구조 등을 수동으로 코드화합니다.
- 문제점: 시간 소모적이고 오류가 발생하기 쉬운 반복 작업입니다.
- 메소드 호출 via Data Fetcher:
- 정의된 타입을 사용하여 API 호출 메소드를 구현합니다.
- Axios나 Fetch 등의 라이브러리를 사용하여 실제 데이터를 가져오는 로직을 작성합니다.
- 문제점: API 마다 반복적인 코드 작성이 필요하며, 에러 처리나 캐싱 등 추가 로직도 구현해야 합니다.
- 스펙 수정:
- API 변경 시 위의 모든 과정을 다시 거쳐야 합니다.
- 문서 업데이트, 코드 수정, 테스트 등이 필요합니다.
- 문제점: 변경 사항을 놓치기 쉽고, 프론트엔드와 백엔드의 동기화가 어려울 수 있습니다.
이러한 과정이 피곤한 이유:
- 반복적인 수동 작업: 많은 부분이 자동화되지 않아 개발자가 반복적인 작업을 해야 합니다.
- 동기화 문제: API 스펙 변경 시 여러 곳을 수정해야 하며, 누락될 위험이 있습니다.
- 시간 소모: 실제 비즈니스 로직 구현보다 이러한 설정과 동기화에 많은 시간을 소비합니다.
- 오류 가능성: 수동 작업 과정에서 타이핑 오류나 누락이 발생할 수 있습니다.
- 유지보수 어려움: API가 많아질수록 관리해야 할 코드와 문서가 늘어나 유지보수가 어려워집니다.
OpenAPI Code Generator를 활용하면 어떨까? 다음과 같은 사항들을 고려해봐야 한다.
- api client 생성 없이 스펙 정보만 자동 생성할 수 있는가?
- zod로 요청 파라미터와 응답 데이터를 파싱할 수 있는가?
- 우리 상황에 맞는 커스텀 transform 조건 쉽게 주입 가능?
- 별도의 학습비용없이 사용 가능하거나 zero config로도 원하는 결과물을 생성할 수 있는가?
OpenAPI Code Generator를 활용할 때 고려해야 하는 점들이 무슨 뜻인지 몰라 AI에게 물어봤다.
API 클라이언트 생성 없이 스펙 정보만 자동 생성할 수 있는가?
이는 OpenAPI 명세서로부터 API 호출을 위한 클라이언트 코드를 생성하지 않고, API의 구조, 엔드포인트, 데이터 모델 등의 스펙 정보만을 자동으로 생성할 수 있는지를 묻는 것입니다. 이는 API 문서화나 서버 측 구현에 유용할 수 있습니다.
Zod로 요청 파라미터와 응답 데이터를 파싱할 수 있는가?
Zod는 TypeScript용 스키마 선언 및 유효성 검사 라이브러리입니다. 이 질문은 생성된 코드가 Zod를 사용하여 API 요청의 파라미터와 응답 데이터를 자동으로 검증하고 파싱할 수 있는지를 묻고 있습니다. 이는 타입 안정성과 런타임 유효성 검사를 향상시킬 수 있습니다.
우리 상황에 맞는 커스텀 transform 조건 쉽게 주입 가능?
이는 생성된 코드에 사용자 정의 변환 로직을 쉽게 추가할 수 있는지를 묻는 것입니다. 예를 들어, 특정 데이터 형식을 변환하거나, 비즈니스 로직을 적용하는 등의 커스텀 동작을 생성된 코드에 쉽게 통합할 수 있는지를 의미합니다.
별도의 학습비용 없이 사용 가능하거나 zero config로도 원하는 결과물을 생성할 수 있는가?
이는 도구의 사용 용이성에 관한 질문입니다. 'zero config'는 별도의 복잡한 설정 없이 기본 설정만으로도 원하는 결과를 얻을 수 있는지를 의미합니다. 또한, 도구를 사용하기 위해 많은 시간을 들여 학습할 필요 없이 빠르게 적용할 수 있는지를 묻고 있습니다.
이러한 고려사항들은 OpenAPI Code Generator를 프로젝트에 도입할 때 개발 효율성, 코드 품질, 그리고 유지보수성을 평가하는 데 중요한 기준이 될 수 있습니다.
zod에 대해서 더 자세히 설명을 AI에게 부탁했다.
Zod는 TypeScript를 위한 스키마 선언 및 유효성 검사 라이브러리입니다. 주요 특징과 용도는 다음과 같습니다:
- 타입 안정성: Zod는 TypeScript의 타입 시스템과 긴밀하게 통합됩니다. Zod로 정의한 스키마는 자동으로 TypeScript 타입으로 추론됩니다.
- 런타임 유효성 검사: 컴파일 시간뿐만 아니라 런타임에도 데이터의 유효성을 검사할 수 있습니다.
- 스키마 정의: 객체, 배열, 원시 타입 등 다양한 데이터 구조에 대한 스키마를 정의할 수 있습니다.
- 복잡한 유효성 검사: 단순한 타입 체크뿐만 아니라 길이 제한, 정규식 패턴, 커스텀 유효성 검사 등 복잡한 규칙을 적용할 수 있습니다.
- 파싱 및 변환: 입력 데이터를 파싱하고 필요한 경우 자동으로 타입을 변환할 수 있습니다.
- 에러 처리: 유효성 검사 실패 시 상세한 에러 메시지를 제공합니다.
사용 예시:
import { z } from "zod";
// 스키마 정의
const UserSchema = z.object({
username: z.string().min(3).max(20),
email: z.string().email(),
age: z.number().min(18).optional()
});
// 타입 추론
type User = z.infer<typeof UserSchema>;
// 유효성 검사
function createUser(data: unknown) {
const user = UserSchema.parse(data);
// user는 이제 User 타입으로 간주됩니다
console.log(user.username);
}
// 사용 예
createUser({ username: "john_doe", email: "john@example.com", age: 25 }); // 성공
createUser({ username: "jo", email: "invalid-email" }); // 실패: 유효성 검사 오류
이러한 특성으로 인해 Zod는 API 요청/응답 데이터 검증, 폼 유효성 검사, 설정 파일 파싱 등 다양한 상황에서 유용하게 사용될 수 있습니다. OpenAPI Code Generator와 함께 사용될 경우, API 스펙에 따라 자동으로 Zod 스키마를 생성하여 타입 안정성과 런타임 검증을 동시에 제공할 수 있습니다.
스키마를 정의한다는게 무슨 뜻인지 AI에게 물어봤다.
'스키마를 정의한다'는 것은 데이터의 구조, 타입, 제약 조건 등을 명시적으로 기술하는 것을 의미합니다. 이는 데이터의 형식과 규칙을 미리 정해두는 작업이라고 볼 수 있습니다.
스키마 정의의 중요성과 의미를 좀 더 자세히 설명해드리겠습니다:
- 데이터 구조 설명:
- 어떤 필드(속성)가 있는지
- 각 필드의 데이터 타입(문자열, 숫자, 불리언 등)이 무엇인지
- 필수 필드와 선택적 필드는 무엇인지
- 유효성 규칙 설정:
- 문자열의 최소/최대 길이
- 숫자의 범위
- 날짜 형식
- 이메일, URL 등의 특정 형식 준수 여부
- 관계 정의:
- 객체 간의 관계 (예: 한 객체가 다른 객체를 포함하는 경우)
- 배열의 요소 타입
- 기본값 및 변환 규칙:
- 특정 필드의 기본값 설정
- 입력값을 다른 형식으로 자동 변환하는 규칙
예를 들어, 사용자 데이터에 대한 간단한 스키마를 Zod로 정의하면 다음과 같습니다:
typescript
Copy
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
username: z.string().min(3).max(20),
email: z.string().email(),
age: z.number().min(0).max(120).optional(),
createdAt: z.date()
});
이 스키마는 다음을 정의합니다:
- 'id'는 숫자여야 함
- 'username'은 3-20자 길이의 문자열이어야 함
- 'email'은 유효한 이메일 형식이어야 함
- 'age'는 0-120 사이의 숫자이며, 선택적(optional) 필드임
- 'createdAt'은 날짜 형식이어야 함
이렇게 스키마를 정의함으로써:
- 데이터의 일관성을 유지할 수 있습니다.
- 잘못된 데이터 입력을 방지할 수 있습니다.
- 자동화된 유효성 검사가 가능해집니다.
- API나 데이터베이스 설계 시 명확한 기준을 제공합니다.
- 문서화 효과가 있어 다른 개발자들이 데이터 구조를 쉽게 이해할 수 있습니다.
스키마 정의는 데이터를 다루는 많은 영역(데이터베이스, API, 폼 유효성 검사 등)에서 중요한 역할을 하며, 코드의 안정성과 신뢰성을 높이는 데 기여합니다.
토스페이먼츠는 직접 ‘TossPayments Codegen’을 만들었다.
TossPayments Codegen을 통하여 다음과 같은 효과를 볼 수 있다.
- 하나의 파일에서 관리 가능한 api 명세 객체
- API에 대한 정보가 소스코드 곳곳에 퍼지는 현상 방지
- 필요에 따라 리소스에 정의한 스키마 파서로 데이터 정합성 확인 가능
- 리소스 이름을 기준으로 필요한 파라미터와 응답 데이터 추론 기능 제공
만들기 위해 사용한 supporters는 다음과 같다.
- swagger-parser, openapi-types
- openapi-jsonschema-parameters
- json-schema-to-zod
- handlebars
- clipanion
각 supporters에 대해서 설명을 AI에게 부탁했다.
- swagger-parser와 openapi-types:
- swagger-parser: OpenAPI (이전의 Swagger) 명세를 파싱하고 유효성을 검사하는 도구입니다. JSON 또는 YAML 형식의 OpenAPI 문서를 JavaScript 객체로 변환합니다.
- openapi-types: OpenAPI 명세의 TypeScript 타입 정의를 제공합니다. 이를 통해 파싱된 OpenAPI 문서를 TypeScript에서 타입 안전하게 다룰 수 있습니다.
- openapi-jsonschema-parameters:
- OpenAPI 명세의 파라미터 부분을 JSON Schema 형식으로 변환해주는 도구입니다.
- API 요청 파라미터의 유효성 검사에 사용될 수 있는 JSON Schema를 생성합니다.
- json-schema-to-zod:
- JSON Schema를 Zod 스키마로 변환해주는 라이브러리입니다.
- OpenAPI에서 생성된 JSON Schema를 Zod의 유효성 검사 및 타입 추론이 가능한 형태로 변환합니다.
- handlebars:
- 템플릿 엔진으로, 동적 콘텐츠를 HTML이나 다른 텍스트 형식으로 쉽게 생성할 수 있게 해줍니다.
- 코드 생성 시 템플릿을 사용하여 반복적인 코드 구조를 쉽게 만들 수 있습니다.
- clipanion:
- 명령줄 인터페이스(CLI) 애플리케이션을 만들기 위한 TypeScript 라이브러리입니다.
- 복잡한 명령줄 도구를 쉽게 구현할 수 있게 해주며, 타입 안전성을 제공합니다.
이러한 도구들을 조합하여 사용하면 다음과 같은 워크플로우를 구현할 수 있습니다:
- swagger-parser로 OpenAPI 명세를 파싱합니다.
- openapi-jsonschema-parameters를 사용해 파라미터를 JSON Schema로 변환합니다.
- json-schema-to-zod로 JSON Schema를 Zod 스키마로 변환합니다.
- handlebars를 사용해 생성된 Zod 스키마와 API 클라이언트 코드의 템플릿을 만듭니다.
- clipanion으로 이 전체 프로세스를 실행할 수 있는 CLI 도구를 만듭니다.
이렇게 하면 OpenAPI 명세로부터 타입 안전한 API 클라이언트 코드를 자동으로 생성하는 도구를 만들 수 있습니다. 이는 앞서 언급된 "피곤한" 프로세스를 상당 부분 자동화하고 간소화할 수 있습니다.
진행 과정
- swagger docs url로부터 open api spec 객체를 생성
- spec.components로부터 request body와 response에 대한 zod 스키마 생성
- spec.paths로부터 api endpoint를 비롯 각종 스펙을 원하는 객체 형태로 가공
- 위에서 만든 결과물들을 원하는 위치에 ts로 생성
cli 구현 기간: 1 week
cli로 생성한 api: 2000+ endpoints
생성에 사용하는 시간: 10 seconds
정리하자면 Tosspayments Codegen을 통해,
- 개발자가 API 문서를 보고 한땀한땀 코드를 옮길 필요 없음
- API의 오류가 발생했을 때, 옮기는 과정의 실수인지 잘못된 구현인지 추적할 필요 없음
- 우리의 유즈 케이스에 맞게 가공 가능한, 100% 제어 가능한 도구
- API 반환하는 인터페이스가 바뀌어도 변경 사항을 즉시 싱크할 수 있음
과 같은 효과를 누릴 수 있다!!
3. 요구사항 분석
FE 개발의 비효율을 개선할 수 없을까?
비효율은 개발 생태계가 너무 풍부해서 발생한다. → 새로운 바퀴들이 계속 생성된다.
토스페이먼츠는 오픈소스 React 어드민 툴인 Pramework를 만들었다.(Inspired by Refine)
- Headless: 특정 UI와 결합 X
- Resource: API 명세를 한 곳에서 객체로 관리
- Provider: 필요한 기능들을 provider에 주입 가능
FE가 어드민 제품을 만들 때 가장 많이 반복하는 행위는 무엇일까?
- Data Fetching
- Form control
- Table
- Logging
Data Fetching
- api 스펙을 리소스 객체로 분리 - api에 대한 맥락을 한 곳에서 제어
- 리소스와 API Client를 React Context로 주입
- 행위에 대한 훅을 제공하여 보다 선언적인 방식으로 데이터를 사용
- 리소스 이름을 기준으로 필요한 요청 파라미터와 반환되는 응답을 추론
→ useItem 등..
Form Controls
- 리소스에 정의한 api를 호출하고 defaultValues로 주입
- 쿼리 파라미터를 파싱하여 defaultValues로 주입
- form 제출, 초기화를 쿼리 파라미터 업데이트 방식으로 실행
→ useForm, useBrowseParams 등…
Table
- 리소스에 정의한 api를 호출하고 테이블 형태로 렌더링
- JSX를 반복 작성하는 대신 테이블 모델을 주입하여 가독성 향상
- 페이지네이션, 열 번호, 체크박스와 같은 요구사항 처리
→ DataTable, PaginatedDataTable, useTable 등…
Logging
- Log Client를 React Context 주입
- Logger로 wrapping한 TDS 컴포넌트를 사용하여 별도 처리 없이 로깅 실행
위 내용들에 대하여 AI한테 설명을 부탁했다.
이 프레임워크는 프론트엔드 개발자가 관리자 페이지(어드민 제품)를 만들 때 자주 반복되는 작업을
간소화하고 효율적으로 만들기 위한 것입니다. 주요 기능을 네 가지 영역으로 나누어 설명하겠습니다:
- 데이터 가져오기 (Data Fetching):
- API 정보를 한 곳에서 관리합니다.
- React의 Context를 사용해 API 관련 기능을 앱 전체에서 쉽게 사용할 수 있게 합니다.
- 'useItem'과 같은 간단한 Hook을 제공해 개발자가 쉽게 데이터를 가져올 수 있게 합니다.
- 폼 관리 (Form Controls):
- API에서 가져온 데이터로 폼을 쉽게 채울 수 있습니다.
- URL의 쿼리 파라미터를 이용해 폼의 초기 값을 설정할 수 있습니다.
- 폼 제출이나 초기화 시 URL 쿼리 파라미터를 자동으로 업데이트합니다.
- 'useForm', 'useBrowseParams' 등의 Hook을 제공해 이러한 기능을 쉽게 사용할 수 있게 합니다.
- 테이블 (Table):
- API에서 가져온 데이터를 자동으로 테이블 형태로 보여줍니다.
- 개발자가 테이블 구조만 정의하면 자동으로 테이블을 생성합니다.
- 페이지 나누기, 행 번호 매기기, 체크박스 등 자주 사용되는 기능을 자동으로 처리합니다.
- 'DataTable', 'PaginatedDataTable', 'useTable' 등의 컴포넌트와 Hook을 제공합니다.
- 로깅 (Logging):
- 로그 기록 기능을 앱 전체에서 쉽게 사용할 수 있게 합니다.
- 특별히 제공되는 UI 컴포넌트를 사용하면 자동으로 사용자 행동을 로그로 기록합니다.
이 프레임워크의 주요 장점은 반복적인 코드 작성을 줄이고, 개발자가 비즈니스 로직에 더 집중할 수 있게 해준다는 것입니다. API 통신, 폼 관리, 테이블 생성, 로깅 등 자주 사용되는 기능들을 미리 구현해 두고, 개발자가 쉽게 가져다 쓸 수 있게 만들었습니다. 이를 통해 개발 시간을 단축하고 코드의 일관성을 유지하며, 버그 발생 가능성을 줄일 수 있습니다.
결론
기능 개발 소요 기간 2달
총 4개의 어드민, 400페이지 이상의 메뉴를
0~10+년차 개발자 6명이 코드의 편차 없이
화면 구현 시간을 하루에서 한 시간으로
유지보수와 확장 가능한 구조로
'Event' 카테고리의 다른 글
‘엔비디아 RTX AI PC 캠퍼스 세미나’를 다녀오고 개념 정리하기 (3) | 2024.11.27 |
---|---|
[2024 FEConf] 'React Native와 Web이 공존하는 또 하나의 방법' 내용 정리(feat. AI) (0) | 2024.08.30 |
큐시즘 전시회 - ENGAGE ENERGY 갔다온 후기 (4) | 2024.06.08 |
[GDSC Konkuk kprintf] React 19 업데이트 강의 정리 + 후기 (1) | 2024.04.06 |
동아리에서 주최한 해커톤 참여 후기 (1) | 2023.12.21 |