*FEConf2024에서 발표한 <바퀴 대신 로켓 만들기>를 정리한 글입니다. 발표 내용을 2회로 나누어 발행합니다. 1회에서는 개발자가 직면하는 ‘디자인 프로토타입’ 병목 현상과 그 해결 방법에 대해 알아봅니다. 2회에서는 ‘백엔드 API’, ‘요구 사항’ 병목의 해결 방법에 대해 알아봅니다. 본문에 삽입된 이미지의 출처는 모두 이 콘텐츠와 같은 제목의 발표 자료로, 따로 출처를 표기하지 않았습니다.‘바퀴 대신 로켓 만들기’양의현 토스페이먼츠 개발자 바퀴 대신 로켓 만들기 (1)바퀴 대신 로켓 만들기 (2)안녕하세요. 저는 ‘바퀴 대신 로켓 만들기’라는 제목의 발표를 진행할 양의현입니다. 저는 주로 리액트를 사용하여 개발하고, 인터페이스나 협업, 영감을 주는 활동에 관심이 많습니다. 지금은 토스 페이먼츠라는 회사의 프론트엔드 개발자로 일하며, 어드민 프로덕트 팀에서 어드민 제품을 주로 만들고 있습니다. 제가 이 팀에서 경험하며 얻은 것들을 이번 발표를 통해 들려드리려고 합니다. 레거시 청산토스 페이먼츠가 짊어진 유산본격적인 설명에 앞서 배경 설명을 먼저 하겠습니다. 토스 페이먼츠라는 회사는 5년 정도 된 신생 기업이지만, 사실 데이콤이라는 회사부터 시작해 LG U+ PG라는 회사를 거쳐, PG 업계에서 30년 넘게 경험을 쌓아온 회사입니다. 스타트업이지만 꽤나 긴 기간 동안 업을 이어오면서 많은 유산을 상속받았습니다.토스 페이먼츠가 처음 법인을 설립한 당시에는 시장을 혁신해보자라는 자신감이 넘쳤습니다. 하지만 그 유산 속에 존재하는 다양하고 방대한 레거시 서비스들이 성장에 대한 발목을 잡고 있습니다. JSP, EUC-KR 등 생소한 것들이 이곳저곳 지뢰처럼 존재하며 비즈니스의 발전을 막고 있다고 생각합니다. 회사 전사 차원에서도 이 문제를 중요하게 생각하며, 24년 상반기에는 특히 이 레거시들을 꼭 청산해야 한다는 의견이 급부상했습니다. 이로 인해 제가 속한 팀에서도 레거시 청산 업무가 굉장히 많아졌습니다. 무려 400개가 넘는 어드민 화면이 레거시로 존재하고, 6개월 내에 팀에서 관리 가능한 수준과 형태로 이관하는 프로젝트가 필요했습니다. 하지만 주어진 6개월은 짧은 시간이었고, 할당된 FE 개발자는 4명이 전부였습니다. 또한 단순히 이관하고 끝나는 것이 아니라, 우리가 만든 제품이 ‘10년 이상 지속 가능한 제품이 되도록 만들어야 한다’는 목표가 있었기 때문에 부담감도 컸습니다. 장애물처음에는 한정적인 리소스와 높은 목표로 인해 ‘불가능하지 않을까?’라는 생각이 많이 들곤 했습니다. 당장 개발을 시작하기에도 여러 장애물들이 있다고 생각했습니다. 개발하는 도중 협업을 위한 커뮤니케이션 과정으로 개발 속도는 점점 느려질 것이라고 생각했고, 개발해야 하는 물리적인 양도 굉장히 많았습니다. 개발이 끝나더라도 유지 보수에 들어갈 리소스를 무시할 수 없었습니다. 이런 장애물들과 더불어 프론트엔드 개발자의 개발을 막는 병목 현상이 있습니다. 개발 업무를 시작하려면 먼저 아래와 같은 것들이 갖춰져야 합니다. 디자인 프로토타입서버 API요구 사항 분석 프론트엔드 개발자가 온전히 업무를 시작하려면 요구 사항 분석을 바탕으로 한 디자인 프로토타입도 준비되어야 하고, 서버 API도 개발되어야 했습니다. 짧은 프로젝트 기간에도 이런 병목들로 프론트엔드 개발자들이 당장 개발을 시작할 수 없는 환경이었습니다. 위 3가지가 충족되어야 개발 출발점에 설 수 있지만, 완료되기까지 가만히 기다려야 하는 기존 방식으로는 절대 목표를 달성할 수 없다고 판단했습니다. 일하는 방식을 바꿔보자결국 ‘이런 장애물에 구애받지 않고 목표를 달성하기 위해 일하는 방식 자체를 바꿔볼 수 있지 않을까’라는 생각을 했습니다. 일하는 방식을 바꾼다면 병목으로부터 벗어나 조금 더 효율적으로 일할 수 있을 거라 생각했습니다. 1. ‘디자인 프로토타입’에 의한 병목먼저 3가지 병목 중 첫 번째 병목, 디자인 프로토타입을 없애야 한다고 생각했습니다. 만약 디자이너들에게 ‘6개월 동안 400개 화면에 대해 최적화된 유저 경험을 고려한 디자인 프로토타입을 만들어주세요’라는 요청을 하면 어떻게 생각할까요? 직접 표현은 하지 않더라도 속으론 이 회사를 떠나야겠다는 생각을 했을 것 같습니다. 즉, 이런 디자인 프로토타입 자체가 우리에겐 병목이고, 업무를 효율적으로 진행하려면 이 병목이 없어야 한다고 생각했습니다. 다른 많은 회사에서도 이런 병목을 줄이기 위해 다양한 방법을 도입하고 있을 거라 생각됩니다. 토스는 ‘토스 디자인 시스템’이라는 디자인 시스템을 활용해서 이미 많은 디자인 작업에 대한 병목을 줄이고 있습니다. 하지만 이 디자인 시스템은 토스 내 모든 계열사에서 사용해야 하고, 계열사들의 모든 요구사항을 반영해야 한다는 목적을 가지고 있습니다. 그렇기 때문에 이 디자인 시스템도 결국 한계가 있다고 생각했습니다. 디자인 시스템디자인 시스템 자체는 굉장히 많은 장점을 가진 도구라고 생각합니다. 토스 디자인 시스템을 기준으로 보면, 시스템은 아토믹한 형태를 제공하고, 다양한 기능을 조합해서 활용할 수 있습니다. 즉, 유연하고 재사용이 쉬운 도구라는 장점을 가지고 있습니다. 하지만 반복되는 코드가 자주 생기고, 작성하는 사람마다 서로 다른 구현체를 만들어 내는 경우가 생깁니다. 또, 화면을 구성하는 코드가 늘어나면 늘어날수록 구현 의도를 파악하기 어려워지는 비효율이 발생하기도 합니다. 토스 페이먼츠 프로덕트 시스템이러한 비효율을 극복하기 위해 디자이너분들과 함께 토스 페이먼츠에서 사용할 별도의 개념을 생각했습니다. 온전히 토스 페이먼츠 시스템에 포커스를 맞춰 최적화된 패턴을 정의하고, 이를 기반으로 단일 구현체로 만들기 시작했습니다. 시스템으로 동일한 패턴에 대해서는 동일한 구현체를 제공함으로써 개별 구현을 방지했습니다. 그리고 폐쇄적인 인터페이스를 구현해서 권장하지 않는 패턴과 맞지 않는 사용을 원천적으로 방지했습니다. 또, 단순히 아토믹한 단위에서 벗어나서, 아주 작은 영역부터 스크린이라는 가장 큰 영역까지 넓은 영역에 대응하도록 레이어를 만들었습니다. 물론 디자인 시스템의 장점이 프로덕트 시스템의 단점이 될 수도 있습니다. 상대적으로 유연성이 떨어져서 재사용이 힘들어지고, 기능이 한정적일 수 있습니다. 하지만 이런 단점이 제품을 개발하는데 치명적이지는 않았습니다. 디자인 시스템(Design System) vs. 프로덕트 시스템(Product System)예를 들어 보겠습니다. 아래는 날짜를 선택하는 DateRangePicker를 각각 두 가지 방법으로 구현한 것입니다. 왼쪽 그림이 디자인 시스템의 구현 결과이고, 오른쪽은 프로덕트 시스템의 구현 결과입니다. 디자인 시스템의 구현체를 보면 굉장히 장황하고 의도가 무엇인지 이해하기 힘들어 보입니다. 반면에 프로덕트 시스템은 굉장히 단순하고, 한눈에 들어오는 인터페이스로 구현되어 쉽게 사용할 수 있습니다. 다른 예시도 보겠습니다. 셀렉트 박스를 구현할 때는 구현하는 사람마다 다르게 구현하는 경우가 쉽게 생깁니다. 어떤 사람은 옵션을 props로 처리하고, 어떤 사람은 합성으로 옵션을 처리하기도 합니다. 이러한 처리 방식은 개인의 취향마다 다를 수 있기 때문에 정답은 없지만, 이렇게 구현 방법이 다르다는 자체는 문제라고 생각됩니다. 이 문제를 해결하기 위해 프로덕트 시스템에서는 단일 구현체를 제공함으로써 여러 명의 사람이 구현을 하더라도 서로 다르게 구현되지 않도록 했습니다. 아래와 같이 일관성 있고 간결한 단일 구현체를 제공하기 때문에 서로 다른 구현체들을 만들어낼 필요가 없습니다. 컴포넌트 조합다음으로는 더 자세히 들어가, 다중 컴포넌트 조합에 대해 알아보겠습니다. 디자인 시스템에서는 커버하지 않는 다중 컴포넌트 조합을 프로덕트 시스템에서는 자유롭게 구현할 수 있습니다. 아래와 같이 칩과 셀렉트를 조합한 칩필터라는 개념을 만들고 이것에 대한 패턴을 정의하면, 별도의 컴포넌트 구현체로써 기능을 만들 수 있습니다. 이렇게 정의된 구현체를 모든 개발자들이 공통으로 사용하면 생산성이 올라갈 것이라고 생각했습니다. 개발 생산성을 높이기 위한 또 다른 예시도 있습니다. 폼 데이터를 다룰 때는 react-hook-form이라는 라이브러리를 많이 사용하고 있습니다. 새 시스템에서는 아래와 같이 react-hook-form과 토스의 UI 요소들을 결합해 코드의 군더더기들이 생기지 않도록 방지하고 있습니다. 유지보수의 어려움여러 명의 개발자가 이러한 프로덕트 시스템 없이 각각 화면을 구현하면 천차만별 다른 모습이 나오기 쉽습니다. 이런 화면이 400개 이상이나 있다면, 유지 보수는 당연히 어려워집니다. 아래 코드는 화면이 어떤 역할을 하는지 직관적으로 알기 어렵고, 영역 분리가 적절하게 되어 있지 않습니다. 따라서 오류가 발생했을 때 어느 부분을 보고 원인을 파악해야 하는지 알기 어렵고 시간도 오래 걸립니다. 게다가 화면의 공통 변경 사항이 발생하여 수정하고 반영할 때 여러 번의 수정이 반복되는 불편함도 있었습니다. 이런 어려움을 해결하기 위해, 새로 만든 프로덕트 시스템에 단순히 아토믹한 컴포넌트라는 틀에서 벗어나 다양한 레이어로 구성된 구현체를 만들었습니다. 이때는 아래처럼 섹션이나 스크린과 같은 넓은 단위의 커버리지를 가진 패턴을 만들어서 제공했습니다. 또한 자주 반복되는 패턴이 있다면 이 패턴에 최적화된 별도의 컴포넌트를 제공했습니다. 컴포넌트들은 가볍게 훑어보기만 해도 어떤 역할을 하는 컴포넌트인지 바로 알 수 있습니다. 테이블 목록을 그릴 때 아래 오른쪽 그림과 같이 프로덕트 시스템을 사용하면 컴포넌트의 역할이 무엇인지 명확하게 알 수 있습니다. 첫 번째 진화 : 토스페이먼츠 프로덕트 시스템내용을 요약하면, 기존 디자인 시스템에서 벗어나 구체적인 맥락이 들어가더라도 아토믹한 구조를 벗어나서 반복 사용하기 좋은 형태의 컴포넌트를 만들었습니다. 서로 다른 인터페이스로 구현하는 상황이 없도록 방지했고, 명확한 역할의 컴포넌트를 정의해서 가독성과 유지 보수가 용이하게 했습니다. 이렇게 개발자가 패턴을 이해하고 있다면, 디자이너의 도움 없이 화면을 구현할 수 있습니다. 여기까지, 디자인 프로토타입에 대한 의존성에서 벗어나기 위해 활용한 방법에 대해 알아봤습니다. 다음은 백엔드 개발에 의한 병목을 해결하는 방법입니다. 2. 백엔드 개발에 의한 병목프론트엔드 개발자는 백엔드 API가 준비되어야 개발을 시작할 수 있습니다. 그렇다면 반드시 백엔드 API가 완성되어야만 프론트엔드 개발을 시작할 수 있을까요? 그렇지는 않다고 생각합니다. 개발을 시작하는 단계에서는 실제로 서버 API가 구체적인 구현을 했는지 사실 보다는, 프론트엔드에서 요청할 HTTP 요청의 엔드 포인트와 리퀘스트 파라미터, 응답 데이터와 같은 인터페이스가 필요합니다. 팀은 이미 이런 협업을 위해 인터페이스에 대한 정의 문서인 API 스펙 문서를 전달받아 이 문서를 기반으로 개발하고 있습니다. 하지만 이 스펙 문서만으로는 조금 부족하다고 생각했습니다. 스펙 문서를 보며 기능을 구현하는 과정에 비효율이 많이 발생했기 때문입니다. 초기 단계에는 스펙 문서를 확인하고, 스펙을 기반으로 타입 스크립트 코드를 작성하고, Data Fetcher를 통한 메소드를 호출했습니다. 다만 이러면 호출한 데이터에 문제가 있을 때마다 다시 스펙 수정을 기다려야 했고, 스펙 수정이 끝난다 해도 과정을 다시 반복하게 됩니다. 저는 이런 비효율적인 과정을 줄이고자 했습니다. OpenAPI Code Generator앞서 설명한 비효율을 줄이기 위해 생각한 방법이 바로 OpenAPI Code Generator입니다. 실제로 활용할 만한 도구들은 많이 있습니다. 단 아래의 요구사항이 충족되어야 했습니다. API 클라이언트 생성 없이 스펙 정보만 자동 생성할 수 있는가?zod로 요청 파라미터와 응답 파라미터를 파싱 할 수 있는가?상황에 맞게 커스텀 transform 조건을 쉽게 주입할 수 있는가?별도의 학습 비용 없이 사용하거나, zero config로도 원하는 결과를 생성할 수 있는가? 아쉽게도 이 요구사항을 100% 만족하는 오픈소스는 찾지 못했습니다. 그래서 이런 도구를 깊이 분석하기 보다, 요구사항을 완전히 구현할 수 있도록 직접 만들자는 결론을 내렸습니다. 지금까지 프론트엔드 개발자가 만나는 병목에 대한 내용과 ‘디자인 프로토타입에 대한 병목’과 이를 해결한 내용에 대해 알아봤습니다. ‘서버 API에 대한 병목’ 역시 문제점까지 알아봤습니다. 다음 글에서는 Codegen을 직접 구현해 서버 API에 대한 병목을 해결한 방법과 마지막 병목에 대해 알아보겠습니다. 바퀴 대신 로켓 만들기 (1)바퀴 대신 로켓 만들기 (2) 요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.