웹 브라우저를 기반으로 하는 웹 프론트엔드 기술은 높은 서비스 구현 유연성과 앱 업데이트 없이 가능한 배포, 두 가지 장점으로 모바일 서비스 개발에서 큰 한 축을 담당하고 있습니다. 하지만, 유연한 만큼 관리하기 힘든 복잡성과 앱 업데이트 없는 배포로 배포의 상황 관리가 어려운, 두 가지 단점으로 개발하기 어려운 면도 있습니다. 타다에서는 장단점이 뚜렷한 웹 프론트엔드 기술을 어디에서 어떤 스택으로 개발하고 어떻게 배포하는지 소개하겠습니다.

웹 프론트엔드 서비스

타다에서는 크게 내부 운영 서비스인 어드민과 고객과 직접 대면하는 대외 서비스, 두 곳에서 웹 프론트엔드 기술을 사용하고 있습니다.

web-fontend-service

  • 어드민 서비스

    • 메인 어드민 : 내부 직원을 위한 운영 모니터링 및 관리를 위한 서비스로 차량 관리부터 결제 내역 관리까지 총괄하는 서비스입니다. 타다 운영에서 사용하는 모든 기능을 제공하는 중요한 서비스입니다.

    • 비즈니스 어드민 : 타다에서는 업무 목적으로 타다를 이용하는 분들을 위해 타다 비즈니스를 운영하고 있습니다. 임직원들이 탑승한 내역을 쉽게 확인하고 결제할 수 있도록, 기업의 담당자를 위한 어드민 페이지를 제공합니다.

    • 프리미엄 법인 어드민 : 타다 프리미엄 법인 업체에서 운영하는 프리미엄 서비스의 모니터링과 관리 기능을 제공하는 서비스입니다. 법인에서 확인하시기 편하도록 차량별 실시간 위치, 드라이버 정보 관리 그리고 서비스 평가까지 폭넓은 서비스를 제공합니다.

  • 대외 서비스

    • 예약상품 : 공항에서 또는 공항으로 이동할 때 제공하는 타다 AIR 서비스와 특정 시간부터 일정 시간 동안 타다를 제공하는 타다 PRIVATE 서비스를 제공하는 서비스입니다. 다양한 차종과 다양한 서비스의 조합으로, 수십 가지의 상품을 고객에게 제공합니다.

    • 구독상품 : 특정 기간마다 타다 서비스를 일괄로 저렴하게 구매할 수 있는 구독상품을 제공하는 서비스입니다. 다양한 구독상품의 상태와 조건을 고객에게 안내하고 판매합니다.

    • 안심 메세지 : 타다를 이용할 때 이용자의 실시간 위치를 링크를 통해 가족 및 친구 등에게 제공하는 서비스입니다. 사용자의 위치정보는 중요한 개인정보이기 때문에 보안과 편의성 두 가지에 초점을 맞추어 서비스를 제공합니다.

기술 및 배포 스택

제한된 개발 인원으로 빠르고 안정적인 개발을 하기 위해서는 높은 수준의 자동화 구성과 외부 서비스를 이용한 낮은 유지 관리 비용이 중요합니다. 타다에서는 이 두가지를 위해 오랜 기간, 여러 시행착오를 거치며, 신중하게 기술 스택과 외부 서비스를 선택했습니다. 어떤 기술 스택과 외부 서비스로 빠르고 안정성 높은 개발을 유지했는지 설명하겠습니다.

web-fontend-stack

  • Angular : Angular는 Typescript 기반의 오픈 소스 프론트엔드 웹 애플리케이션 프레임워크입니다. 타대 내 모든 웹 프론트엔드 서비스는 Angular를 마이크로프레임워크로 사용합니다. 여러 오픈소스 라이브러리들을 이용해서 웹 프론트엔드를 개발하면 라이브러리 사이의 연결 관리하기 어렵고 오픈소스 특성상 각 라이브리러 별로 꾸준한 지원을 기대하기 어렵운 문제점이 있습니다. Angular에서는 이 문제를 해결하기 위해 하나의 라이브러리로 여러 기능들을 선별 및 통합하여 꾸준한 코드 관리되는 통합된 개발환경을 제공합니다. 또한 오랫동안 개발한 만큼 수 많은 사용자들의 레퍼런스가 공유되어 있고 자세히 설명된 공식 개발 문서도 제공합니다. 이 두가지 장점은 낮은 진입장벽이 되어 개발자 누구라도 쉽게 개발에 참여하고 리뷰를 할 수 있게 도와줍니다.

  • TypeScript : TypeScript는 Javascript의 슈퍼셋인 오픈소스 언어입니다. Javascript 보다 더 엄격한 문법을 적용하여 Javascript 유연함에서 발생하는 버그 가능성들을 해결하고 강점을 더욱 살린 언어입니다. 마이크로소프트에서 만들어 관리하고 구글에서 사내 표준 언어로 선정할 만큼 신뢰성 높은 문법을 제공합니다. 신뢰성 높은 문법으로 버그 감소 효과를 크게 본 타다에서는 기본적인 TypeScript의 엄격함에서 더 나아가 strict null checks 옵션을 활용하여 더욱더 엄격한 문법으로 개발하고 있습니다.

  • ESlint : ESlint는 코드에서 발견 된 문제 패턴을 식별하기위한 정적 코드 분석 도구입니다. 다수의 개발자가 참여하는 프로젝트에는 반드시 읽기 편하도록 통일된 코드 컨벤션이 필요합니다. 하지만 코드 컨벤션이 아무리 통일되어도 모든 코드에 동일하게 적용하고 유지하기란 어렵습니다. 타다에서는 어려운 컨벤션 유지를 해결하기 위해 ESlint를 적극 활용하고 있습니다. 잘못된 컨벤션으로 작성한 코드를 Git에 올리면 CI에서 ESlint를 실행하여 교정할 부분을 개발자에게 통보합니다. 통보된 내용을 바탕으로 다시 코드를 수정해야만 개발 브랜치에 올라갈 수 있게하여 컨벤션 유지를 하고 있습니다.

  • SCSS : SCSS는 CSS pre-processor로서 CSS의 한계와 단점을 보완하여 보다 가독성이 높고 코드의 재사용에 유리한 CSS를 생성하는 CSS의 확장입니다. CSS는 단순한 문법만큼 시작하기 쉽지만, 시간이 지날수록 지원하는 언어의 한계로 인해 복잡도가 높아져 관리가 어렵습니다. 이 부분을 해결하기 위해서 CSS 문법을 기반으로 다양한 기능을 제공하는 스타일 확장인 SCSS을 사용합니다.

  • Protobuf : Protobuf는 구조화된 데이터를 직렬화하는 방식인 IDL입니다. 타다에서는 서버와 네이티브 클라이언트 간의 통신 규약을 정할 때 별도의 문서를 만들어 공유하지 않고 IDL 중의 하나인 Protobuf 파일을 공유합니다. Protobuf 파일을 공유하는 것만으로, 따로 문서를 작성할 필요도, 규약을 기반으로 각자 코드를 작성할 필요도 없습니다. Protobuf로 자동으로 만들어진 TypeScript 코드로 서버와 HTTP 통신을, 네이티브 클라이언트와 브릿지 통신을 간단하게 연결만 하면 되기 때문입니다.

  • GitHub Actions : GitHub Action는 Github에서 제공하는 CI/CD 툴입니다. 타다에서는 ESlint를 실행하거나 특정 브랜치에서 커밋 될 때 배포 자동화하는 데 사용합니다. 배포 자동화를 하면 개발과 결과물이 평행을 이루어 QA, PM 팀에서 현 개발 상황을 이해하기 용이합니다.

  • Firebase Hosting : Firebase Hosting은 Google의 글로벌 콘텐츠 전송 네트워크를 기반으로 하는 정적 에셋 호스팅 서비스입니다. Angular로 만들어진 SPA 에셋을 배포하는 데 사용됩니다. 강력한 CLI 명령어를 지원하여 build 한 결과물을 굉장히 쉽고 빠르게 배포 및 롤백 할 수 있습니다. 쉬운 배포와 더불어 높은 수준의 인증서와 global CDN이 제공되어 세계 어디서나 높은 수준의 보안과 속도를 보장합니다.

프로젝트 설계 구조

제한된 개발 인원으로 빠르고 안정적인 개발을 하기 위해서는 중복을 없애고 통합에 집중한 설계 또한 중요했습니다. 여러 설계 방향 중에 '하나의 레포지토리에 여러 프로젝트를 관리하여 한 맥락을 유지하는 Monorepo 전략'이 적합하다고 판단했습니다. 대표적인 타다 웹 프론트엔드 레포지토리 중의 하나인 tada-web 구조를 중심으로 Monorepo 전략을 어떻게 설계했는지 설명하겠습니다.

web-angular-stack

  • Core library : 공통으로 사용하는 코드들로 구성된 라이브러리입니다. Angular library 기능으로 만들어져 관리됩니다. 시간, 가격을 표현하는 함수, 공통 Font asset, 공통 Stylesheet까지 모든 프로젝트에서 필수로 사용하는 코드가 담겨 있습니다.

  • Protobuf : 서버와 네이티브 클라이언트와 통신할 때 사용하는 규약을 담은 IDL 코드입니다. protobuf.js 라이브러리 코드를 통해 TypeScript로 자동 생성하여 상위 레이어의 모든 프로젝트에 제공됩니다.

  • Bin : 배포 스크립트, 번역 서비스와의 연동 스크립트까지 수행 코드와 관련 없는 도구 코드로 구성되어 있습니다.

  • Firebase : 각 프로젝트별로 배포할 때 사용하는 firebase Hosting 설정 정보가 포함되어 있습니다.

  • App module : 프로젝트에 제공되는 기본적인 모듈입니다. 프로젝트에서 사용되는 모듈 및 서비스 그리고 컴포넌트들을 로드하고 관리하는 역할을 합니다.

  • Shared module : 프로젝트 사이에서 공통으로 사용하지 않지만, 프로젝트 안에 있는 모듈들 사이에서 자주 사용되는 공통 코드들을 제공합니다. 예를 들면 예약상품 프로젝트에서는 인천공항의 주소와 GPS 정보를 제공하는 코드가 Shared module에서 제공됩니다.

  • Routing module : 서비스 내 링크 주소별로 로딩할 모듈과 컴포넌트를 지정하는 모듈입니다. Angular에서 제공하는 lazy module을 활용하여 모듈을 필요할 때만 로딩합니다. preload all module 설정도 함께 사용하여 IDLE 상태일 때 다른 모듈을 미리 로딩하도록 설정 했습니다.

Angular에서 제공하는 기능을 바탕으로 각 프로젝트별로 공통 코드는 Core library, 프로젝트 내에 모듈별로 공통인 코드는, Shared module로 통합하였습니다. 통합한 코드는 적은 수정만으로도 여러 프로젝트에 동시에 영향을 주기 때문에, 개발을 빠르게 하고 실수를 줄이는 역할을 합니다.

배포 전략

개발만큼이나 중요한 단계는 배포입니다. 배포 방법도 굉장히 중요하지만 명확한 배포 전략도 이 못지않게 중요합니다. 명확한 배포 전략은 개발자, QA팀 그리고 PM팀이 서비스와 코드의 상황과 상태를 쉽게 예상하게 하고 잘못된 배포를 통한 이슈 예방과 빠른 이슈 대응에 큰 도움이 되기 때문입니다. 타다의 배포 전략에서 사용되는 주된 브랜치를 설명하고 어떤 전략으로 배포하는지 설명하겠습니다.

  • Develop 브랜치 : 개발자들이 평소에 개발하는 브랜치입니다. 각자 포크하거나 체크아웃하여 개발한 후에 Develop 브랜치를 향해 풀리퀘스트를 보냅니다. 보내진 풀리퀘스트는 팀원의 리뷰를 받고 스쿼시 머지를 통해 브랜치를 성장에 기여합니다. 여러 커밋을 하나로 묶어서 머지하는 스쿼시 머지를 하면 브랜치 이력에 중요한 커밋만 남습니다. 중요한 커밋을 기준으로 브랜치를 관리하면 배포관리에 도움이 되고 신규 개발자가 코드를 이해하는데 도움이 됩니다.

  • TEST 브랜치 : 일정 수준 이상의 개발이 완료되어 QA를 받고자 할 때 사용되는 브랜치 입니다. 개발자들은 주로 QA에서 발견된 이슈들을 해결하며 브랜치에 기여합니다. 또한 커밋이 생길 때마다 GitHub Actions을 통해 자동으로 테스트 환경에 배포합니다.

  • MASTER 브랜치 : 실 서비스 환경 배포를 위해 사용하는 브랜치입니다. 실 서비스 환경에서 이슈가 발생하면 이 브랜치에서 이슈를 해결하여 핫픽스로 재배포합니다.

tada-web-deploy-strategy

  1. 개발 : 개발자가 포크한 브랜치에서 Develop 브랜치 방향으로 풀리퀘스트를 보내고 팀원 리뷰를 통해 머지합니다.

  2. QA : 일정 수준 이상으로 develop 브랜치에서 개발이 완료되면 test 브랜치로 풀리퀘스트를 보냅니다. 보내진 풀리퀘스트가 리뷰를 통해 머지되면 테스트 환경에 자동으로 배포하고 이때 부터 QA 팀에서 QA를 시작합니다. 그리고 지속적으로 QA팀에서 찾아주신 이슈들을 해결하며 브랜치에 기여합니다.

  3. 배포 : QA팀이 알려주신 이슈들이 해결되면 실 서비스 환경 배포를 준비합니다. test 브랜치에서 master 브랜치를 방향으로 풀리퀘스트를 보내, 팀원들에게 배포를 알리고 리뷰를 요청합니다. 리뷰가 끝나 승인을 받으면 머지하면서 실서비스에 배포합니다. 이때, develop 브랜치에도 머지합니다.

  4. 핫픽스 : 실서비스에서 이슈를 발견하게 되면 master 브랜치에서 수정하여 풀리퀘스트, 리뷰 그리고 머지를 통해 관리하고 배포합니다. 만약 간단한 수정으로 해결할 수 없는 문제가 발생하면 러버트 커밋을 통해 이전 배포 상태로 실 서비스 환경에 배포 하고 처음 부터 단계를 다시 거쳐 배포합니다.

앞으로

이전까지는 앞서 설명한 자동화, 외부 서비스 적용, 통합된 개발 맥락 설계 그리고 탄탄한 배포 전략으로 웹 프론트엔드 발전 방향을 잡았었습니다. 앞으로는 더 높은 안정성과 성능 그리고 생산성을 위해 세가지를 방향으로 잡았습니다.

  1. 테스트 코드 도입 : 앞서서 TypeScript와 ESLint를 통해 강력한 코드 스타일 통합을 이루었습니다. 부족하다고 판단되는 부분은 더 나아가 직접 ESLint에 기여하며 보강하기도 했습니다. 여기에 더 높은 안정성을 위해 테스트 코드를 추가하여 비즈니스 로직 코드까지 안정성을 확대할 예정입니다.

  2. 로딩 속도 개선 : SPA 를 고려해서 개발했기 때문에 맨 처음 첫 로딩이 일반 웹 서비스보다 조금 느립니다. 처음에 로딩되는 코드를 최대한 정리하고 lazy loading를 적용하여 속도 개선에 큰 효과를 보았습니다. 여기에 서버 렌더링 Angular universal 를 적용하여 더욱 더 빠르게 할 예정입니다.

  3. 웹 프론트엔드 개발자 채용 확대 : 오랜기간 시행착오 끝에 최근에 와서 웹 프론트엔드 개발의 탄탄한 기틀이 마련되었습니다. 이제는 좋은 분들을 모실 수 있는 환경이 되어, 편한 마음으로 타다 웹 프론트엔드 개발자 채용을 채용 과정에 추가했습니다. 확대된 채용을 통해 더욱더 빠르고 안정적인 웹 프론트엔드 기술과 개발 문화를 만들어가고자 합니다.

마치며

빠르게 늘어나는 웹 프론트엔드 수요를 해결하기 위해서는 여러 방법이 있습니다. 그 중에서 가장 쉬운 해결 방법은 개발자를 더 많이 채용하는 것입니다. 하지만 좋은 프론트엔드 개발 환경이 마련되지 않은 상태에서 단순히 팀원을 늘리는 것이 올바른 방향이 아니라고 생각했습니다. 쉬운 방법으로 이루어진 팀들이 끝없는 무의미한 시도를 반복하며 방황만 하다 정리조차 하지 못하고 쉽게 무너지는 경우를 많이 보아왔기 때문입니다. 개발자도 불행하고 함께 일하는 동료들에게도 미안하며 회사 성장에도 발목을 잡는 상황이 되지 않길 바랐습니다.

따라서, 타다 개발팀은 성장과 개발자의 만족감, 두 가지를 얻을 수 있는 우리만의 어려운 방법을 찾기로 했습니다. 일 년 넘는 기간 동안 여러 시행착오를 겪으며, 쉽고 빠르게, 그리고 핵심에 집중하여 개발하는 방법을 고민해 왔습니다. 좋은 결과가 나오면 추가적으로 고민해서 더 발전시키고 목표에 미달한 결과가 나오면 원인 분석과 반성을 통해 다른 방향 나아갔습니다. 그리고 이제는 자랑스럽게 우리의 방법을 통한 웹 프론트엔드 개발이 즐겁다고 이야기 할 수 있습니다.

새로운 이동의 기준을 제시하는 모빌리티를 향해 나아가는 타다 웹 프론트엔드 팀에 탑승하세요.