2023/08 - 2023/10 회고

milkboy2564·2023년 10월 30일
3

회고

목록 보기
1/8
post-thumbnail

원래 2달에 한번은 내가 무엇을 했나 복기하면서 회고글을 작성하자고 스스로에게 약속했지만 결국 8개월만에 약속을 깨버렸다..ㅜ

그래 이왕 이렇게 된거 10월까지 한 번에 작성하고 11월과 12월 회고 그리고 올해를 깔끔하게 마무리 하는 1년 회고를 작성하면 되지 라는 안일한 생각으로 스스로를 위로하면서 컴퓨터 앞에 앉았다.

글을 쓰는 이 시점은 여름이 가고 완연한 가을이 찾아온 것 같다.

아침에 일어나려 할 때마다 추워서 이불을 꽉 쥐고 안 일어난다. 꼴랑 5분 더 자고 매일 아침 허겁지겁 지하철 타러 뛰어가는 내 모습이 한심하지만 그래도 어쩌겠는가.
아침의 그 5분은 참혹한 출근길을 맞이하기 전 내가 할 수 있는 유일한 반항이기에 어쩔 수가 없다^^;

각설하고 8, 9, 10월 업무적으로도 개인적으로도 새로운 부분을 많이 하게 됐고 역시나 바쁘게 보냈다.
(일을 벌려놓는 스타일이라 주워 담을 때 항상 후회하는 나,,)

개인적으로는 개발적인 욕심이 아주 많이 생겼고 이 과정에서 참으로 많은 우여곡절이 있었던 기간이었다.

1. 회사

1) Web View 떼내기

우리 서비스는 웹 이외에도 두 개의 네이티브 앱이 존재하기 때문에 업무 특성 상 웹뷰를 작성해야 하는 경우가 많았다.

여기서 내가 의아했던 부분은 웹뷰를 기존 웹 서비스 내의 하나의 라우터(Ex./mobile) 내에서 관리하고 있던 부분인데 이렇게 관리하게 되면 여러 문제가 있다고 생각했다.

일단 메인 서비스의 프로젝트 크기가 불필요하게 커진다.

오직 웹뷰만을 위한 컴포넌트, 설정, 여러 정적 파일 등 메인 서비스와 관련이 없는 파일들로 인해 프로젝트 크기가 커진다. 웹뷰 작업은 계속해서 생길 것이고 시간이 지나면 점점 더 커지게 될 거라고 생각했다.

또한 Dependency가 메인 서비스에 의존적으로 변하게 된다.

메인 서비스에서 사용하고 있는 Dependency와 웹뷰에서 사용할 Dependency를 따로 관리하거나 사용할 수 없기 때문에 웹뷰에서는 무조건 메인 서비스 Dependency에 맞춰서 개발을 진행해야 한다.
물론 필요한 라이브러리를 설치해서 사용해도 되지만 이렇게 되면 하나의 프로젝트의 차트 관련 라이브러리가 3개씩 존재하는 바람직하지 않은 상황이 생기기도 한다.

마지막으로 배포 또한 메인 서비스에 의존적이다.

웹뷰에서 발생한 Hotfix나 웹뷰만 작업을 하는 경우에도 메인 서비스가 함께 배포가 된다. 웹뷰 관련 부분 이외의 변경 사항이 없다고 하더라도 함께 배포가 되는 것은 문제가 있다고 생각했다.

위와 같은 여러 문제가 있다고 생각했고 내가 모르는 여러 문제점이 분명히 또 있을거라고 느꼈고 언젠가 웹뷰를 분리해야지라는 생각을 하고 있다가 이번에 진행을 하게 됐다.

분리 작업은 프로젝트 생성 -> 기존 코드 옮기기 -> 테스트 -> 배포 순서로 진행했다.

먼저, 기존 코드를 옮기는 작업에서 Next.js 버전이 달라(12->13) 에러가 발생하는 부분을 수정해줬다.

새 웹뷰 프로젝트는 Next.js v13의 app router를 사용했기 때문에 기존에 사용하던 next/routeruseRouter Hook을 사용할 수가 없었다. 따라서 해당 부분을 next/navigationusePathname, useSearchParam, useRouter를 사용하는 방식으로 수정했다.

또한 다국어 작업 또한 next 13에서는 새로운 방식으로 해줘야 했는데 기존과 다르게 언어가 url에 포함(Ex./ko/example/page)이 되도록 작업을 해줬다.

추가적으로 변경된 프로젝트에 맞춰 웹뷰를 띄우려면 일일이 URL에 언어를 추가해줘야 했기에 브라우저나 모바일 디바이스의 언어 설정에 따라 자동으로 URL에 언어를 추가해주는 미들웨어를 만들어 앱 개발자분들의 변경사항을 최소화 하려했다.

그 외의 자잘한 변경 사항(Ex.서버 컴포넌트, URL naming convention 통일 등)을 수정하고 배포를 했다.

그런데 이게 웬걸 배포를 하고 테스트를 하는데 이상하게도 렌더링 속도가 로컬에 비해 말도 안되게 느려졌다. 로컬에서 빌드를 하고 테스트를 해봤을 때는 TTFB(Time To First Byte)가 1s가 넘는 페이지가 하나도 없었는데 배포를 하고 테스트를 해보니 3s가 넘는 페이지도 생겨버렸다.

뭐가 문제일까하고 여러 방면에서 원인을 찾기 시작했다.

URL을 추가해주는 미들웨어에서 시간을 많이 잡아먹는건가 해서 확인해보니 평균적으로 150ms 이내에 Redirect가 완료됐기에 원인이라고 생각되지는 않았다.

아니면 정적 파일 다운로드가 오래 걸리는걸까 해서 기존 img 태그를 next/image로 모두 변환시켜주어서 이미지 최적화를 진행하고 폰트 최적화 또한 진행해줬다. 그리고 테스트를 진행해보니 TTFB와는 큰 관련이 없는걸로 확인됐다.

우리 서비스는 Vercel로 배포하고 있었는데 Serverless Function의 Region이 문제인가 해서 기존의 Washington으로 되어 있던걸 Seoul로 바꿔서 테스트를 해봤는데 이 역시 드라마틱한 개선이 이루어지지는 않았다.

오케이 이렇게 해도 안된다고? 그럼 배포 환경을 바꿔보면 어떤데?라고 생각하여 Vercel 말고 EC2로 배포하고 테스트를 해봤더니 믿을 수 없게 빨라진걸 확인할 수 있었다. 해결을 하기는 했지만 무언가 찝찝한 마음이 남아있는건 왜 그러는걸까 ㅎ

왜 Vercel로 배포를 하니 렌더링 속도가 느려진건지 아직 정확한 원인을 찾지는 못했다. 추측하기로는 Serveless Function의 cold start 문제가 아닐까 생각하고 있는데 이와 관련해서는 조금 더 살펴봐야 될 거 같다ㅠ


2) SNS 로그인

현재 회사 내에서는 여러 개의 서비스를 동시에 운영하고 있는 상황이었고 이번에 새롭게 런칭이 되는 서비스의 경우 외주 개발자분들이 선작업을 해주셨다.

서비스가 늘어남에 따라 하나의 계정으로 모든 서비스를 이용할 수 있는 통합 로그인을 지원하게 되었는데 여기서 문제가 발생했다.

그동안 SNS 로그인의 경우 각 Provider(EX.naver, kakao, apple)가 지원하는 SDK를 가지고 앱 내에서 자체적으로 토큰과 유저 정보를 받아 처리하고 있었고 새 서비스의 경우에도 이와 같은 방식으로 SNS 로그인을 처리하고 있었다.

그러다가 모바일 개발자 분이 이렇게 각각의 앱 내에서 SNS 로그인을 처리하게 되면 같은 계정임에도 Bundle Id가 서로 달라 같은 사용자로 판단하는게 불가능하다고 말씀을 해주셨다. 하지만 웹을 통해서 로그인을 하게 되면 같은 사용자로 판단할 수가 있어서(Bundle Id가 같음) SNS 로그인 작업을 앱에서 웹으로 변경하는 작업을 진행하게 됐다.

쉽게 얘기해서 기존 앱에서 사용하던 SDK의 기능을 웹에서 구현하면 되는 상황이었다.

NextJS를 사용하고 있었고 시간이 충분하지 않았기 때문에 OAuth2.0 프로토콜 기반 SNS 로그인을 쉽게 이용할 수 있게 도와주는 NextAuth를 사용하기로 했다.

Naver와 Kakao 로그인의 경우 공식문서에 나와있는 가이드를 따라 아주 쉽게 구현을 할 수 있었는데 Apple 로그인이 큰(귀찮은) 문제가 됐다.

Apple 로그인을 구현하면서 문제가 됐던 점은 아래와 같다.

  1. http를 지원하지 않는다.
  2. 리다이렉트가 정상적으로 이루어지지 않았다.

먼저 http를 지원하지 않는다는게 가장 귀찮은 문제였다.
http를 지원하지 않는다는건 localhost에서 테스트를 해볼 수 없었다는 것이기에 처음에는 코드를 수정하고 개발 환경에 배포를 해서 테스트를 하는 방식으로 진행했었다.

이렇게 하다 보니 배포에 드는 시간만큼의 병목이 꾸준하게 발생을 했고 ngrok을 통해 로컬 환경을 https로 외부에서 접근할 수 있게 만들어줘서 해결했다.

또 NextAuth를 사용하면 환경 변수에 기본적으로 웹 사이트의 URL을 환경 변수로 설정해줘야 하는 NEXTAUTH_URL라는 값이 있는데 http://localhost:3000로 설정해둔 값을 애플 로그인을 구현할 때마다 매번 바꿔줘야되서 진짜 너무너무너무너무너무 귀찮았다.(이거 때문에 엄한 곳에서 안되는 원인을 찾느라 시간을 버려서 그러는건 아니다^_^)

두 번째 문제로 내가 설정한 리다이렉트 URL로 리다이렉트가 이루어지지 않았다.
이 문제는 NextAuth 설정에서 cookie 값을 세팅해주는 방식으로 해결했다.

 cookies: {
     pkceCodeVerifier: {
         name: 'next-auth.pkce.code_verifier',
         options: {
             httpOnly: true,
             sameSite: 'none',
             path: '/',
             secure: true,
        },
     },
 },

추가적으로 네이버, 카카오 로그인과 애플 로그인의 다른 점은 clientScrect 키를 내가 직접 생성해야 한다는 점이었다. 이를 위해 Apple Private Key를 발급받고 이걸 통해 clientSecret을 생성해서 제공해줬다.

App Store에서 SNS 로그인 기능이 심사에 통과하려면 필수적으로 Apple Login을 제공해야하는데 사파리부터 SNS 로그인까지 애플은 참 개발자들을 힘들게 하는거 같다..............


3) 다국어

한참 높은 분의 왜 우리 서비스는 외국에서도 한국어로 나와? 한마디에 다국어 작업이 시작됐다.

이번에 처음으로 다국어 작업을 해봤는데 한마디로 표현하면 단순반복이었다. 프로젝트 내에 존재하는 모든 텍스트를 추출하고 번역을 요청했고 이를 언어 설정에 따라 자동으로 변환하여 보여주도록 처리를 했다.

일반적인 단순 반복 작업이라 큰 어려움은 없었지만 까다로웠던 부분이 텍스트 사이사이에 HTML tag가 삽입되어 있던 부분이었다. 번역 작업을 요청하기 위해서는 문장의 흐름이 깨지면 안됐기 때문에 tag까지 포함하여 텍스트를 추출했고 이를 화면에 올바르게 보여주기 위해 html-react-parser를 이용하여 html tag를 react element로 변환시켜줬다.

또한 ko 라는 디렉터리 안에 존재하는 모든 json 파일을 엑셀로 추출하도록 만들었고 이 엑셀 파일 안에 (번역이 안된) 영어와 인도네시아어까지 추가가 되도록 설정해줬다. 이를 통해 한국어 텍스트만 json 파일로 추출하여 스크립트를 돌리면 자동으로 번역이 안된 영어와 인도네시아어가 포함된 엑셀 파일을 생성할 수 있다.

그리고 번역 작업이 완료되면 완료된 엑셀 파일을 업로드하고 스크립트를 통해 번역이 된 파일을 영어(en)와 인도네시아어(id) 디렉터리 안에 한국어와 같은 구조로 매핑시킨 json 파일을 자동 생성해주는 코드를 추가해줘서 자동화를 시켜줬다.

추가로 Next12와 Next13은 다국어 설정하는 방식이 달라가지고 두 배로 고생을 했다.(😱😱😱버저닝의 중요성)

아직 번역 작업이 끝나지 않아 번역본이 오면 언어마다 UI가 깨지는 부분을 수정해야 하는 작업이 남은거 같은데 무사히(적은 수정) 끝내길 바란다.


4) Vite, React18, React Router Dom V6

대부분의 프로젝트가 next.js로 이루어져 있는데 backoffice의 경우 react(v17)로 구성이 되어 있었다.

굳이 Next로 바꿀 필요성을 느끼지 못해 그동안 변경하지 않았었다.
근데 ReactReact Router Dom 메이저 버전이 업그레이드 됐고 Webpack을 Vite로 변경하고 싶어서 관련된 작업을 진행했다.

Webpack -> Vite

Webpack은 지금도 많이 쓰이는 번들러로 여러 장점을 가지고 있다.

  • 10년 동안 개발, 관리되며 Plugin, Loader 등 생태계가 잘 갖춰져 있다
  • Code Splitting이나 Tree Shaking 등을 잘 지원한다
  • 모듈을 IIFE 방식으로 묶어주어 여러 브라우저를 지원할 수 있다
  • 다양한 Boilerplate에서 쓰고 있어 자료가 많다 (CRA 등)

그럼에도 불구하고 Webpack을 Vite로 변경하고 싶었던 가장 큰 이유는 성능이였다.

Vite을 사용해야 하는 이유에서 나오듯이 기존의 Webpack과 같은 번들러는 보통 번들링을 하며 다양한 작업이 동시에 이뤄진다. 예를 들어, TS → JS로 트랜스파일링하거나, 플러그인과 폴리필(Polyfill)을 적용한다. 대부분의 번들러는 NodeJS 기반으로 돌아가며, 번들링 중 진행되는 트랜스파일링 등 역시 대부분 NodeJS로 돌아간다. 문제는 NodeJS는 싱글 스레드 구조다보니 이로 인한 처리 한계가 발생한다.
참고

실제로 Webpack으로 구성된 프로젝트의 경우 개발 서버를 로드하는 시간 또한 꽤나 느렸었고 빌드 시간 또한 평균적으로 80초가량 소요가 됐었다.

Vite으로 변경을 한 후 개발 서버 로드 시간이 개선됐고 결정적으로 빌드 시간이 약 80초에서 30초로 대폭 단축됐다.

하루에 10번 배포가 이루어진다고 가정한다면 500초, 약 8분 20초의 시간을 벌게 된 것이다.
지금보면 8분 20초가 되게 우습게 느껴지는 숫자일 수 있지만 계속해서 프로젝트가 커지면 이 차이는 더욱 확실하게 느낄 수 있게 될 것 같은 강한 느낌이 들기에 변경하기를 잘한것 같다는 생각이 든다.


5) npx로 간지나게 프로젝트 초기 설정하기

나는 반복적인 작업이 싫었다. 매번 프로젝트를 생성할 때마다 ESLint, Prettier, Husky, 의존성 설치, 파일 컨벤션용 .gitKeep 파일 추가 등 반복적으로 진행해줘야 하는 작업이 있다.

처음에는 원대한 꿈을 가지고 우리의 프로젝트를 하나의 모노레포로 구성해보고자 했었다.
그러나 부족한 인력과 익숙하지 않은 기술을 프로덕션까지 적용하기에는 많은 리스크가 있을거라고 생각이 들어서 결국 모노레포까지 구성은 하지 못했다.

그런 다음 차선책으로 들었던 생각이 바로 프로젝트 초기 세팅을 npm에 배포를 하는 것이었다.

위에서 말했던 프로젝트 초기 설정에 필요한 여러 설정들(Ex.ESLint, Prettier, Husky 등)을 진행한 프로젝트를 생성했고 우리가 사용하고 있는 채택한 공통 라이브러리를 설치하여 npm에 배포를 했다.

아직 실제로 사용한건 한 번밖에 없긴 하지만 앞으로 프로젝트가 있으면 CLI로 간지나게 초기 세팅을 할 수 있게 배포까지 했고 다른 사람이 쓰게 된다면 쉽게 이해할 수 있게 문서도 꼼꼼하게 작성하려고 노력을 아주 많이 했다. 나 말고 다른 사람이 얼른 사용해봤으면 좋겠다 ㅎㅎ


profile
FE 개발자

0개의 댓글