개발일지 (7월 회고)

2022. 7. 31. 20:47Developer History

 

 

Back to Basics

최근 우연한 계기로 React Fiber, Hook에 대한 질문들을 받으면서 "나 프론트엔드 개발자인데 React에 대해서 얼마나 알고 있지?"에 대한 질문을 스스로에게 던져보게 되었고, 생각보다 너무 모르고 있는 것 같다는 결론을 내리게 되었다. GCP Migration이 바빠서, Backend Domain도 알아야 하니까, 프로젝트 일정도 맞춰야 하니까 와 같은 여러 변명들을 할 수도 있지만, 어쨌거나 React에 대해 잘 모르는 개발자라는 사실은 변하지 않으니 돌아오는 8월부터는 조금 정신 차리고 React를 조금 깊이 공부해보고자 한다. 좋은 기회로 React를 Code Level에서 상세하게 분석해서 올려주신 블로그를 알게 되었고, 꼼꼼히 읽어보면서 "실제로 컴포넌트에서 useState를 호출했을 때 어떤 일들이 일어나는지"를 reconciler, scheduler, 의 관점에서 다시 공부해보고자 한다. 공부한 내용은 블로그 포스팅 시리즈로 연재할 계획이다. (요즘 에세이 쓰느라 기술 블로그를 너무 안 올린 듯하다.)

 

비슷한 관점에서 Nextjs도 매번 쓰던 것만 쓰느라 정작 Next가 어떻게 구현되어 있고, 내부적으로 어떻게 동작하는지를 자세히 알지 못한다는 느낌이 들었다. 내부 구현은 둘째치고 Next가 제공하는 기능들도 다 모르는 느낌이다. 실제로 Nextjs 코드를 보면 의외로 Hard-Code 된 부분들이 꽤 있는데 (이를테면, GoogleFonts는 아예 도메인이 하드 코딩되어 Font Optimization의 Opt-In 대상이라던가, 다른 도메인의 이미지를 next/image를 사용해서 최적화하는 경우 Response Header의 Cache-Control이 max-age=0; must-revalidate로 온다던가) 이런 부분들을 사내 스터디를 통해서 조금 더 꼼꼼하게 보완해볼까 한다. (이번 Web Dev 스터디가 굉장히 유익했다.)

 

 

Backend

저번 달부터 백엔드 도메인의 이해도를 높여 의사 결정에 조금 더 도움이 되고자 하는 생각에 무작정 백엔드 공부를 시작했었다. 근무시간이 10시부터라 8시쯤 출근해서 2시간 정도 내가 담당하고 있는 프로젝트의 백엔드 코드를 다운로드하여서 한 줄씩 읽어나가기 시작했다. 기본적으로 사내 백엔드는 Spring + Webflux로 구성된 경우가 많고, 좋은 백엔드 개발자분들이 많으셔서 아키텍처가 어느 프로젝트를 가나 비슷하게 잘 읽히도록 짜인 느낌이 들었다. 첫날 백엔드 코드 두줄 읽느라 2시간을 썼던 기억이 나는데, 코드 한 줄을 읽기 위해 Spring의 DI방식과 IoC 컨테이너의 동작 방식, 그리고 Webflux의 CoroutineRepository, 코틀린의 코루틴, 코틀린 기본 문법, 백엔드의 클린 아키텍처를 이해하고 있어야 했다. 처음에는 어질어질했지만 한 달을 반복하다 보니 이제는 어느 정도 코드가 어떻게 돌아가는지는 볼 수 있게 된 것 같다. (어디까지나 "읽는" 수준이고 직접 작성하거나 디버깅을 할 만한 수준은 못 되는 것 같다.)

 

백엔드 코드가 비동기 요청들을 처리하기 위해 요청마다 스레드를 생성하던 방식 대신 코루틴을 사용하는 것을 보면서, 자바스크립트의 이벤트 루프와 거의 동일하다는 느낌을 받았다.(사실 async / await도 내부적으로는 generator를 사용해 동작하고, 이 또한 코루틴이 아닌가) 결국 백엔드 / 프론트엔드 나눌 것없이 "문제를 정의하고 해결"하는 방식에는 Computer Science Level에서의 깊이 있는 이해와 통찰력이 필요하다는 것을 많이 느꼈던 것 같다. 코루틴이 앞에 "코"가 붙어서 그런지 코틀린 Specific한 기능이라고 오해하는 사람들이 있는 것 같은데 코루틴 또한 50년도 더 된 오랜 개념이 아닌가. 문제를 해결하는 다양한 방법. 특히 Backend Side에서의 방법을 엿볼 수 있게 된 것 같아 개인적으로는 굉장히 유익한 시간이었고, 이러한 호기심의 충족이 복학을 앞당기는(?) 기제로 작용하게 된 것 같다.

 

Google AIPs

회사에서 Google API Improvement Proposal을 도입하기로 하면서 Protobuf로 정의된 message와 service를 Typescript Client에서 사용할 수 있는 SDK로 빌드해서 GCP의 Artifact Registry에 올리고, 이를 사용해서 개발하는 프로세스를 만들어 달라는 요청을 받았다. 기존에 gapic-generator-typescript를 통해서 protobuf를 로컬에서 Typescript SDK로 빌드하는 방법은 알고 있었기 때문에 이를 Pipeline화 하는 방법이 필요했다. 

 

우선 gapic-generator-typescript 라이브러리를 fork 해서 실행 가능한 도커 이미지로 만들어 사내의 GCP Image Registry에 업로드하고, 사내 공용 API message & services가 정의된 레포의 특정 패키지에 업데이트가 일어나면 CloudBuild가 트리거 되어, 이 이미지를 사용해서 SDK를 빌드하면, 이를 사내의 Artifact Registry로 npm publish 하고, 개발할 때, 이 registry로부터 패키지를 내려받아 사용하는 식이다. 

 

도커 이미지 만들기, 포크 하기, CI / CD 환경에서 npm version patch & publish 하기 등등 파이프라인을 만들기 위해서 굉장히 많은 일들을 해야 했지만, GCP에 대한 경험이 많이 없었던 상태에서 제일 골치 아팠던 건 권한 관리(IAM)이었다. 사내 공용 API가 있는 프로젝트와 Artifact Registry가 있는 프로젝트가 달랐고, 한 프로젝트의 Cloudbuild에서 다른 프로젝트의 Artifact Registry로 publish 하기 위해 필요한 권한들, 그리고 이를 로컬에서 테스트하기 위한 impersonate 권한 등 권한 문제로 꽤 많은 시간을 썼던 기억이 난다. (거기다 npm registry가 아닌 private registry를 사용하다 보니, 이를 내려받기 위한 scope와 권한 관리를 해결하는 데에도 많은 시간을 사용했다.) 하지만 8월이 되기 전에 이 파이프라인을 완성했고, 의도치 않게(?) googleapis와 google 공식 라이브러리인 node-gax등에도 여러 번 이슈를 남기며 contribute 하는 기회도 얻게 되었다. (다음에는 code contribution을 위해 PR도 만들어봐야겠다.)

 

gapic-generator-typescript를 통해 만든 SDK 라이브러리는 node runtime에 최적화되어있어 번들 사이즈도 크고 next환경에서 바로 사용하기가 어렵다는 문제가 있었다. (CSR을 사용했을 때는 Create React APP에서 웹팩 설정을 이것저것 넣어줘서 잘 되긴 해서 번들 사이즈 최적화가 우선순위가 아닌 Admin에서는 이걸 사용해서 개발하고 있긴 하다.) 따라서 3분기 때는 Fork 한 라이브러리를 조금 고쳐서 트래픽을 많이 받는 실제 Production에도 적용할 수 있기를 기대한다. 

 

https://github.com/googleapis/gapic-generator-typescript

 

GitHub - googleapis/gapic-generator-typescript: Generate Typescript API client libraries from Protocol Buffers.

Generate Typescript API client libraries from Protocol Buffers. - GitHub - googleapis/gapic-generator-typescript: Generate Typescript API client libraries from Protocol Buffers.

github.com

 

 

GCP Migration

Product Development Division의 올해 가장 큰 과제 중 하나였던 GCP Migration이 적어도 프론트엔드 애플리케이션에 한해서는 어느 정도 마무리가 되었다. 회사의 전체 프로덕트들을 무중단으로 AWS에서 GCP로 트래픽을 틀어 이전하는 방식이었는데, 애플리케이션을 새롭게 빌드하고 배포하는 것과는 또 다른 고려사항들이 많았다. 이전 과정에서 문제는 없는지, 이전 후 장애가 나거나 예상과는 다른 동작들을 하지는 않는지를 확인하기 위해 여러 지표들을 모니터링해야 했고, 실제로 지표상의 문제들이 발견되어 이를 실시간으로 고치고 대응하기 위해 알고 있는 모든 지식을 짜내어 대응했다. 

 

2시간이면 끝날 줄 알았던 마이그레이션 작업이지만, 실제로 AWS의 CloudFront(CF)가 해주던 역할을 100% 동일하게 해주는 GCP의 기능이 존재하지 않아서 생각보다 많은 시간을 쏟았다. 유저의 트래픽이 애플리케이션이 떠있는 파드의 컨테이너로 바로 들어가는 것이 아니라 앞단의 CDN, Gateway, Virtual Service 등등을 통과하면서 들어오기 때문에 의도하지 않은 Cache Control Header가 Overwrite 되어서 들어오거나, 혹은 Overwrite 되지 않은 상태로 들어오는 경우가 있었고, 이를 해결하기 위해 상당한 시간을 사용했다. 게다가 콴다라는 애플리케이션이 제공하고 있는 웹뷰가 상당히 많아서 옮겨야 하는 웹 서비스들도 굉장히 많았는데, 이를 하나하나 체크하면서 모니터링하는 것은 또 다른 (힘든) 새로운 경험이었다. 

 

다행히도 마이그레이션 이후로 프론트엔드 프로덕트는 큰 문제없이 GCP에서 모든 트래픽을 받으며 잘 서빙되고 있고, 이제 AWS / GCP 동시 배포를 위해 마련해두었던 설정들 중 AWS에 대한 설정들을 제거하는 잔여 작업들이 남아 있는 상태이다. 이 부분들은 어렵지 않게 진행할 수 있을 거라 생각한다.

 

Cache Control 문제로 배포 직후 3XX Status Code의 비중이 비정상적으로 높았던 일이 있었고, 이를 Infrastructure 딴에서 해결했다.

 

 

Books Books Books

백엔드 공부하랴, GCP 마이그레이션 준비하랴 정신없었던 한 달이지만, 그래도 책을 그래도 일주일에 1~2권을 읽으려고 했고, 실제로 이번 달에 8권 정도의 책을 읽은 것 같다. (물론 발췌독도 포함이다;;) 책 권수도 권수이지만, 요즘 들어 여러 책들을 동시에 읽으면서 이 책들이 보여주는 서로 다른 점들을 재미 삼아 이어 보는 것들을 많이 해보고 있다. 이를테면 노자 인문학에서의 "무위"라는 개념을 멀티플라이어에서 소개하는 "리더십과 성장"의 측면에서 생각해본다던가 하는 일이다.

 

이번 달에도 비슷하게 일주일에 1~2권의 책을 읽어보려고 하는데, 최근에 "철학이 사회와 시대에 미치는 영향력"을 실감하면서 "철학의 깊이가 사고의 깊이이며, 사고의 깊이가 그 시대의 패러다임을 결정한다"는 생각을 많이 하고 있다. 앞으로 일어날 일들을 연역적으로 추론하기가 점점 더 어려워지는 시대를 살아가고 있는데, 이런 관점에서 모든 것을 "하나의 본질"로부터 연역적으로 추론해 나가는 "이성적"인 서양 철학도 좋지만, "실제 삶의 경험, 즉 실재"로부터 모든 것들을 "관계"로 해석하는 동양철학, 특히 노자의 도가 철학에 조금 더 관심을 가지고 독서를 해보려 한다.

반응형

'Developer History' 카테고리의 다른 글

개발일지 (9월 회고)  (0) 2022.10.03
개발일지 (8월 회고)  (2) 2022.08.28
개발일지 (6월 회고)  (0) 2022.07.03
개발일지 (5월 회고)  (1) 2022.06.05
개발일지 (4월 회고)  (0) 2022.05.05