I. 들어가며


안녕하세요. 헤렌의 웹프론트 개발자 톰입니다. 작년 7월 헤렌 입사 이후 가장 큰 프로젝트를 맡아 진행한 과정을 공유하고자 합니다.

헤렌은 현재 공비서 CRM 서비스를 운영하고 있습니다. 공비서 CRM 서비스는 뷰티 샵주분들이 고객관리 및 예약관리, 매출 정보 등록을 손 쉽게 이용할 수 있도록 비즈니스 성장에 도움을 드리는 CRM 서비스로, 2017년 출시 이후 큰 폭의 성장 중에 있습니다.

그러나 서비스 런칭 후 5년이 지난 2022년 지금, 새로운 경쟁사의 등장으로 인한 경쟁 심화와 서비스의 성능과 디자인의 노후화에 대한 우려가 있었습니다. 그래서 프로덕트 개선을 목표로 삼고 리뉴얼을 진행중입니다.

스크린샷 2022-07-06 오후 6.27.29.png

II. 5년이 지난 레거시 프로덕트의 문제


5년 간 개발해온 공비서 CRM은 여러 문제가 있었습니다. 먼저, 공비서 CRM은 JSP를 통해 개발되었습니다. JSP란 HTML과 XML Template, 그리고 Server 플랫폼에 독립적인 Java코드를 이용하여 동적으로 사용자에게 제공하는 Page를 생성하기 위한 Framework입니다.

그러나 2022년 현재를 기준으로 JSP는 레거시 기술로 평가받으며 실무에서 JSP의 사용 빈도는 점점 줄어드는 추세입니다. 또한 JSP 프로젝트를 유지보수 하기 위해서는 Server Side Template에 대한 이해와 Java 언어에 대한 학습이 필요한 상황입니다. Typescript와 React 기반의 기술스택을 보유하고 있는 헤렌의 웹프론트 개발 파트에서는 JSP를 학습하는 비용이 마이그레이션 비용보다 더 크다고 판단했습니다.

그리고 기존 레거시 프로젝트에서 스타일을 담당하는 CSS 코드가 10,000 라인짜리 하나의 파일에서 관리되고 있는 등, 새로 충원된 Front End 개발자에게 우호적이지 않은 개발 환경으로 구성되어 있었기 때문에 프로덕트 관리가 쉽지 않았습니다. 이는 개발팀 전체의 생산성 저하로 이어졌습니다.

결국 백엔드 파트와 프론트 파트 간 역할 분담에 대한 필요성이 대두되었고, JSP로 구성된 프로덕트를 갈아 엎자는 계획을 세웠습니다. 백엔드 개발자는 API에 집중할 수 있는 환경을, 프론트엔드 개발자는 렌더링 프로세스 및 어플리케이션에 집중할 수 있는 환경을 만들기 위해 마이그레이션 계획을 세웠습니다.

III. 프론트엔드 마이그레이션 착수


2022년 1월, JSP 코드를 React.js로 마이그레이션 하는 작업을 착수했습니다. 5년간 서비스된 공비서 CRM의 기능이 워낙 방대해서 모든 페이지를 한 번에 마이그레이션을 할 수 없었고, 신규 개선 프로젝트마다 차례차례 점진적인 마이그레이션을 진행하기로 계획했습니다.

마이그레이션 방식에 대해 고민이 많았습니다. React.js외에는 정해진 것이 아무 것도 없었기 때문입니다. CTO님은 SEO와 SSR 방식 도입에 대해 긍정적으로 생각하셨고, Next.js 도입을 권장하셨습니다. 또한 프론트 분리에 필요한 많은 자료를 공유해주셨습니다. 그리고 CTO님이 공유해주신 자료 중 로토님의 블로그 컨텐츠에서 영감을 받아 작업을 착수했습니다.

CTO님의 공유해주신 참고자료들

CTO님의 공유해주신 참고자료들

저희는 Apache Proxy를 활용한 마이그레이션을 진행하기로 결정했습니다. 기존 레거시 코드는 건드리지 않고, 레거시 페이지에서 마이그레이션이 완료된 url로 접근하면 Apache에서 라우팅만 수정하여 마이그레이션 프로젝트로 proxy하는 방법입니다.

이 방법은 레거시의 라우팅 수정만으로 렌더링 처리를 하기 때문에 신규 프로젝트를 독립적으로 개발할 수 있는 좋은 선택지라고 판단했습니다.

IV. 프론트엔드 마이그레이션의 문제들


그러나 그 과정이 그리 순탄치는 않았습니다. 생각했던 것 보다 훨씬 더 많은 문제들이 도사리고 있었기 때문이었는데요. 그럼에도 마이그레이션 과정 중 가장 어려울 것으로 예상된 Proxy 문제는 공비서의 백엔드 개발자 우디님의 피나는 노력으로 무사히(?) 해결할 수 있었고, 프론트 서버 배포 과정은 웹프론트엔드 개발자 이든님의 수고로 완료했습니다. 이 외 여러 문제가 있었으나 저희가 마이그레이션 과정에서 난관에 부딪힌 수 많은 문제 중 2가지에 대해 적어보았습니다.

1. SESSION 방식 인증 방식

기존 JSP 어플리케이션에서는 SESSION을 통한 인증방식을 채택하고 있습니다. 때문에 로컬 서버 환경에서 웹프론트 개발자들이 로그인 후 세션을 가져올 방법이 없었습니다. 여러 방안들에 대한 논의가 있었고, 그 중 간단하게 해결할 수 있는 방법은 테스트 계정의 JWT를 직접 환경변수에 넣어두고 API 호출 시 사용하여 문제를 해결했습니다.

2. 공통 메뉴 개발

기존 JSP의 영역 중 새로 개발하는 React 프로젝트에서 공통으로 개발해야 하는 영역이 있었습니다. 이는 컴포넌트 단위로 갈아 끼우는 방식이 아니라, 페이지 단위의 교체 작업으로 진행했기 때문에 공통 영역을 다시 만들어야 하는 작업은 거의 필연적이었습니다. 공통으로 사용하는 컴포넌트로는 Global Navigation Bar, Local Navigation Bar, Floating Button, Footer 영역이 있었는데, 이 부분들을 개발하며 많은 시행착오를 겪었습니다.

제가 담당한 영역은 footer영역과 샵주와 공비서 예약 사용 중인 고객 간 채팅방 floating button 영역이었습니다. footer 영역은 무리없이 작업을 완료했지만 채팅 영역에는 여러 기술들에 대한 이해가 필요했습니다 공비서의 기존 채팅 서버 (Websocket 서버)의 통신 브로커는 STOMP 프로토콜로 구현되어 있었습니다. STOMP는 클라이언트에서 웹소켓 커넥션을 맺고 클라이언트에서 특정 Topic을 구독합니다. 그리고 웹소켓 서버는 실시간 통신으로 들어온 메시지를 Topic 단위로 연결된 클라이언트들에게 모두 전달하게 되는데, 이를 기존 레거시와 똑같이 만드는 과정을 진행했습니다. 개발하며 기존 레거시의 형태를 점검할 수 있었고, 같은 기능을 다른 코드로 작성하는 과정에서 Web Socket에 대한 학습의 기회가 있었습니다. 마이그레이션이지만, 이 또한 좋은 발전의 과정이었다고 생각합니다.

V. 마이그레이션과 함께 진행한 것들


1. 프론트엔드 파트 개발환경 구성

JSP 마이그레이션 작업은 다시 말해 Next.js로 구성된 프로젝트를 처음부터 개발하는 작업이기도 합니다. 그래서 초기 개발 환경을 다시 꾸리는 것에 대해 여러 이야기를 나눴습니다. 그리고 개발 환경을 구성하는 데 필요한 전략과 방법, 양식에 대한 문서를 작성했습니다.

1) Git Branch 전략 수립

공비서 웹프론트 개발파트는 Gitlab Flow Branch 전략의 변형된 방식을 사용중입니다. develop branch를 default branch로 설정하고, develop branch를 기준으로 feature 브랜치를 생성합니다. feature 브랜치는 Jira의 Epic 단위를 기준으로 생성된 branch이며, 작업자들은 feature 브랜치를 기준으로 sub feature 브랜치를 생성할 수 있습니다. sub feature branch는 Jira의 Task 단위를 기준으로 브랜치명을 명명하고 개발을 완료한 뒤 feature branch로 merge 합니다. 이후 테스트와 프로젝트가 완료된 브랜치는 develop branch에 merge되어 배포를 기다립니다.

%%{init: { 'logLevel': 'debug', 'theme': 'default' } }%%
      gitGraph
        commit type:HIGHLIGHT
        commit
        branch develop
        checkout develop
        branch feature
        checkout feature
        commit type:HIGHLIGHT
        checkout main
        commit type:NORMAL
        checkout develop
        commit type:REVERSE
        checkout feature
        commit
        branch SubFeatureA
        commit
        checkout feature
        commit
        branch SubFeatureC
        commit
        checkout SubFeatureA
        commit
        checkout feature
        merge SubFeatureA
        checkout SubFeatureC
        commit
        commit
        checkout feature
        merge SubFeatureC
        commit
        branch SubFeatureB
        commit
        commit
        checkout feature
        merge SubFeatureB
        checkout develop
        merge feature
        commit tag:"v22.7.6"
        checkout main
        merge develop

2) Convention 및 코드 스타일 설정

Git Branch전략과 함께 컨벤션 및 코드 스타일에 대한 논의를 진행했습니다. 컨벤션은 Git Commit Convention과 Coding Style Convention을 구성했고, 이를 위해 Husky, ESLint, Prettier 등의 툴을 사용했습니다.

(1) Git Commit Convention

Git Commit Convention은 기본적으로 Angular Commit Convention의 방법론을 따르기로 정했습니다. 커밋 메시지의 형식은 아래 설명과 같습니다.

<type>(<scope>): <short summary>
  │       │             │
  │       │             └─⫸ 현재 작업에 대한 요약을 작성합니다. 대문자를 사용하지 않고, 마침표를 사용하지 않습니다.
  │       │
  │       └─⫸ Commit Scope: JIRA의 카드번호를 Scope로 사용합니다.(GBIZ-0000)
  │
  └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test

즉 커밋 컨벤션은 git hook을 통해 커밋 메시지를 관리하고, 컨벤션에 어긋난 커밋 메시지는 commit이 되지 않습니다.

(2) 코드 스타일 정의 및 정적 분석

코드 스타일 정의와 정적 분석을 위해 3가지 툴을 사용했습니다. prettier와 editorconfig, eslint를 사용했습니다. prettier는 개발 시 코딩 스타일을 자동으로 formatting하는 라이브러리입니다. prettier홈페이지를 참고하여 프론트파트에서 설정한 내용은 다음과 같습니다.

{
	"parser": "typescript",
	"useTabs": true,
	"tabWidth": 4,
	"printWidth": 120,
	"singleQuote": true,
	"bracketSpacing": true,
	"bracketSameLine": false,
	"arrowParens": "always",
	"endOfLine": "lf",
	"semi": false
}

또한 저희는 editorconfig를 사용했습니다, editorconfig 설정을 사용하면 IDE에 관계없이 들여쓰기 스타일, 탭 너비, 줄 끝 문자, 인코딩 등 일관된 코딩 스타일 및 설정을 유지할 수 있습니다. 그리고 마지막으로 Javascript 및 Typescript의 문법 오류를 감지하기 위해 eslint를 사용했습니다.

(3) 코드리뷰 PR TEMPLATE

PR을 올리기 전 어떤 기능을 개발 했는지 개발 내용을 요약하여 리뷰어가 이해하기 쉽도록 Template에 미리 작성하고 있습니다.

## 개요
- 요구사항
- 기획
- 디자인
- 다이어그램 
- ...

## 변경사항
- 
- 

## 테스트
- [ ] 
- [ ]  

## 체크리스트
- [ ] 리뷰 요청하기 전 체크 리스트
- [ ] ex) 이해하기 어려운 부분에 주석을 단다.
- [ ] ex) 주요 기능에 대한 테스트를 진행한다.

2. 코드리뷰를 통한 컴포넌트 개발 과정

컴포넌트를 개발하며 React Component Pattern을 찾아봤습니다. 그 중 Compound Component를 활용하여 제작했습니다.

Compound Component로 구성한 하나의 컴포넌트는 특별한 역할을 하지 않지만 내부에 특정 엘리먼트가 들어와 결합하는 경우에 동작하는 컴포넌트를 의미합니다. 이는 또한 내부의 state를 공유하는 provider pattern을 활용할 수도 있습니다.

이를 구현하기 위한 개발 과정에는 수 많은 코드 리뷰가 있었고, 코드리뷰 과정을 진행하며 개발한 Radio Component의 제작 과정을 소개드립니다.

스크린샷 2022-07-04 오후 6.23.49.png

처음 Radio Component를 개발했을 때는 React.cloneElement를 활용하여 개발했으나, 이는 2depth 이상에서 사용하게 되는 경우 속성이 잘못 주입되는 경우가 있을 수 있다고 리뷰해주셨고, 이후 render Props 패턴을 활용하여 수정하도록 가이드를 받았습니다. 그리고 코드 리뷰 끝에 Radio Component를 수정하고 승인 리뷰를 받게 되었습니다. 코드 리뷰를 통해 컴포넌트를 발전시키면서 컴포넌트 개발의 즐거움을 느낄 수 있었습니다.

스크린샷 2022-07-04 오후 6.25.28.png

이렇게 완성된 Component는 Notion에 API 명세를 적어 신규 입사자들이 확인할 수 있도록 컴포넌트를 관리하고 있습니다.

스크린샷 2022-05-05 오후 2.43.31.png

VI. 나오며


JSP 마이그레이션 작업은 작성한 포스팅 내용보다 더 많은 노력과 시간이 투입된 커다란 작업이었습니다. 저는 그 중에 작은 부분을 담당했을 뿐이고, 마이그레이션을 위해 애쓴 헤렌의 공비서 개발자들의 노력을 모두 담을 수 없다는 게 아쉽습니다. 이번 마이그레이션을 초석으로 삼아 레거시를 완전히 걷어내는 결과를 얻으면 좋겠습니다.

공비서 개발팀은 좋은 사용성과 개발 생산성을 개선하였고, 공비서 이용자 분들게 좋은 서비스를 제공하기 위해 노력하고 있습니다. 웹 프론트엔드 개발 파트의 기술 스택은 현재 Typescript와 Next.js을 사용중이며 이를 기반으로 서비스를 제공하고 있습니다. 저희 공비서 개발팀은 효율적인 방법과 개선 방향을 찾으며 발전중에 있습니다. 저희와 함께 더 좋은 서비스 경험을 고민하고 싶다면, 아래 공고를 확인해주세요. 감사합니다.

헤렌 채용 │ HERREN CAREERS

https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https://0909.notion.site/5-JSP-Next-js-Migration-01633e17d012438bba465f904d9197b1