개발자 이민재입니다.

POSTS

2024년 4월 회고

9min read

Overview

    4월엔 개인적인 공부보다는 회사 일에 더 집중했습니다.

TDD 연습

    이전부터 jest 프레임워크를 사용해서 테스트코드들을 작성해오긴 했습니다. 다만 모듈에 포함된 기능이 유틸함수(문자열, 날짜 처리)처럼 내부적인 로직이 복잡하지만 의존성은 단순한 경우에만 많이 작성했고, 모듈 기능 자체가 복잡하고, 외부 의존성도 많이 얽혀있는 경우엔 테스트코드를 작성하기가 어려워서 대부분 손 놓고 있기도 했습니다. 하지만 회사에서 필수적인 로직들은 대부분 후자에 속했습니다. 당연히 기능의 안정성은 많이 떨어졌고, 어쨌든 해결은 해야 했습니다.
    마침 이번에 맡은 새 기능에 시간이 생각보다 넉넉하게 주어졌고, TDD를 연습하기에도 적절하다 싶어서 도전했습니다. 테스트를 먼저 생각하고 코드를 작성하다보니, 자연스럽게 이전보다는 테스트하기 좋은 코드를 작성하게 된 것 같습니다. 결국 복잡하고 의존성이 얽힌 클래스는 테스트하기 어려워지므로, 복잡한 로직을 처리하는 역할, 의존성만 부르는 역할을 나누게 됐습니다. 이렇게 분리하는 과정에서 필요한 의존성만 호출해서 테스트 속도를 빠르게 만들기도 했습니다. 테스트만으로 자연스럽게 좋은 아키텍처를 구성하게 되는 것 같아 신기한 경험이었습니다.

회사 모노레포 구조 개선

    현재 회사에서 개발할 때 생산성을 가장 떨어뜨리고 있는 것이 중복성입니다. 미처 반영되지 않은 변경사항으로 인한 장애로 최근에도 몇 차례 배치 서버가 셧다운됐었고, 각종 사소한 오류들이 코드의 중복으로 나타나고 있는 상황이었습니다.
    이는 초기 단계에 쌓아둔 기술부채가 계속 남아있는 것으로, 서비스를 검증하는 단계였기 때문에 기능이 필요하면 그때그때 전체 패키지나 로직을 복사해서 기능을 배포했습니다. 이를테면 비즈니스 모델 클래스나 서비스 레이어 계층의 코드들이 배치를 담당하는 패키지, api 패키지 등 여러 패키지에 걸쳐 복사된 상태로 있었습니다. 이 시기는 기능 배포 사이클이 하루 단위였기 때문에, express 기반 서버에 db 간단히 붙여서 작업하는 방식과 같은 최소한의 형태로 개발하는 것이 당연했습니다. 복잡하게 레이어를 나눌 필요도, 시간도 없었습니다.
    검증 단계를 성공적으로 지나, 서비스에 사용자가 몰려드는 시점부터는 기능이 복잡해졌습니다. 이 시기부터는 중복성으로 발목잡히면 이전의 속도를 유지하기가 힘들어지기 때문에, 이 구조를 청산해야 했습니다. 그래서 도입한 것이 모노레포였습니다. 서버, 웹 코드 모두 한 저장소에 담아 관리해서 공통으로 사용되는 코드 중복을 줄이고, 개발할 때 공통모듈을 편리하게 관리하자는 것이 목적이었습니다.
    당연하지만 공통모듈을 추출한 레이어들, 이를테면 엔티티와 유틸성 함수들의 코드 중복은 확연히 줄었습니다. 문제는 공통모듈을 공개 레지스트리에 등록하고 버전을 관리했는데, 이것이 개발 구현 시에 많은 오버헤드를 발생시켰습니다. 공통모듈을 변경하고, 공개 레지스트리에 배포한 다음에 그 모듈을 사용하는 패키지에서 공통모듈의 최신 버전을 받아서 다시 사용하는 방식이었습니다. 이 오버헤드 때문에 모노레포를 도입한 것이었는데, 전체 코드로 범위를 구성한 까닭에 배포 등에서 해결하지 못한 문제들이 있었습니다. 원래 의도는 패키지간 의존성을 관리해주는 도구(yarn workspace, turborepo) 등을 적절히 활용해서, 개발 시에는 바로 사용하고, 배포 할 때는 배포 파일에 공통모듈 의존성이 자동으로 들어가야 했는데 그러지 못했던 것입니다.
    결국 이 구성은 코드 중복성으로 고통받을 것이냐, 공통모듈의 버전관리로 고통받을 것이냐 두 문제로 귀결됐습니다. 개발 시간 코스트를 실제로 측정해보면 어떨지 모르겠지만, 중복성은 유지보수 기간에 코스트를 부과할 것이고, 공통모듈은 개발 구현기간에 코스트를 부과합니다. 개발자 체감 상 구현하는 동안 오버헤드에 불만을 가질 수 밖에 없었고, 일단 버전관리를 쉽게 하기 위해 패키지를 분리하는 방법을 선택했습니다. 서버와 프론트의 코드를 분리한 뒤 각각 모노레포 구조를 갖게 되어 기존에 의도했던 아래 세 가지 기능을 동시에 달성할 수 있었습니다.

  1. 코드 중복 제거
  2. 개발 시 자동으로 공통모듈의 변경사항 반영
  3. 배포 시 공통모듈 의존성 해결

4월에 읽은 책

    저번달에 읽었던 '가상 면접 사례로 배우는 대규모 시스템 설계 기초'라는 책의 후속작도 있어서 바로 구매했고, 읽기 시작했습니다. 위치 서비스, Kafka 같은 분산 메시지 큐, 지표 모니터링 시스템 등 여러 시스템을 구축해나가는 과정을 살펴볼 수 있었습니다.
    특히 지표 모니터링 시스템에서 해당 시스템의 부하가 어떤 패턴인지 고민하고 설계하는 것이 인상깊었습니다. 이를테면 모니터링 지표는 지속적인 쓰기가 많고, 지표의 읽기는 짧은 시간 연산량이 높은 요청이 많이 들어옵니다. 이런 분석을 바탕으로 기술을 선택해나가는 과정과 그 근거들을 볼 수 있었습니다.