외주 레거시로부터의 여정 3편 - API 개편

백엔드 개편

API

외주 개발사가 개발한 API는 그야말로 순수한 Express에 자체 미들웨어로 중무장한 상태였다. 겉으로 포장만 안했지 일종의 외주사 전용 프레임워크라고 해도 무방했다. 그런데 말입니다.

유닛 테스트가 없다

테스트가 없으니 물론 커버리지도 0%였다. 테스트가 없는 여파는 내가 합류한 3월부터 슬슬 찾아오기 시작했다. 초반에는 비즈니스 검증 때문에 기능이 수시로 변한다. 대표가 외주에게 몇 번 변경을 요청했는데 여지없이 잔버그가 우수수 떨어지기 시작했다. 고민의 시간이 찾아왔다. 여기다가 유닛테스트를 붙일 것인가. 근데 코드를 보니 컨트롤러에 비즈니스 로직이 잔뜩 있어서 supertest로 API테스트를 붙여야만 테스트 커버리지를 올릴 수 있었다. 게다가 타입이 없는 동적언어인 자바스크립트 특성 상 커버리지를 90%정도까지는 올려야 안정적으로 돌아갈 수 있었다.

게다가 비즈니스 로직이 생각보다 복잡했다. 테이블 70개가 괜히 생긴게 아니었다. 컨테이너 종류만도 17가지 종류나 되었고 국가 간의 무역거래조건인 인코텀즈만 해도 10종류가 넘었다. 게다가 컨테이너, 인코텀즈 외에도 수 없이 많은 요소가 있었고 각 요소마다 처리하는 로직도 다 달랐기 때문에 발을 살짝만 잘못 디뎌도 순식간에 골로가는 아주 좋은(?) 조건이었다.

타입스크립트 도입

여기서의 결심은 타입스크립트 도입이었다. 그렇다고 전면 재개발은 아니었다. 나는 넷스케이프의 전철을 밟을 생각이 전혀 없었다. 다행히 개발된 코드가 ES6라서 코드 복붙 70% 정도로 API를 구성할 수 있을 것 같았고, 실제로도 그러했다. 타입스크립트 도입 시 NestJS를 비롯한 각종 타입스크립트 프레임워크를 좀 물색했는데, 최종적으로 Typescript-rest를 도입하기로 하였다. 가장 큰 이유는 나에게 주어진 시간이 많지가 않았기 때문에 바로 실전 투입할 수 있는 프레임워크여야 했다. Typescript-rest는 전 회사에서도 써서 러닝커브가 없었고 무엇보다 NestJS처럼 특정 구조를 강제하지도 않았다. NestJS가 틀에 박힌 노드판 스프링이라면 Typescript-rest는 그나마 Express에 가까운 친구였다.

소스코드를 옮기는건 힘들었지만 꽤나 재미있는 작업이었다. 보통 아래와 같이 작업을 했다.

  1. Typescript-rest에서 API 컨트롤러를 만들고 여기에 기존 소스코드를 그대로 붙인다.
  2. 물론 타입이 없기 때문에 그대로 붙지는 않는다. 한 번 붙일때마다 VSCode 화면은 공산혁명이라도 일어난듯이 온통 빨간줄이 쫙쫙 그어지곤 했다. 대부분은 타입 문제였고 일부만 코드 문제였다. 타입이 없으면 일단 any로 메꾸고 number, string, boolean 같은 Primitive 타입만 대체하는 방향으로 컨트롤러 내 API를 구성했다.
  3. API 만들때 당연히 모델도 필요했다. API 만들때마다 모델을 몇 개씩 만들기도 했다.
  4. 컨트롤러에서 비즈니스 로직을 떼어낸다. Service를 만들고 컨트롤러에 DI(Dependency Injection)했다.
  5. 최종적으로 컨트롤러에서는 Request, Response, Validation에 대한 책임만 지고, 비즈니스 로직은 서비스에서 담당하게 된다.
  6. 서비스를 상대로 유닛 테스트를 만든다.

이렇게 해서 한 달만에 거의 대부분의 소스코드를 옮겼고 커버리지도 70% 이상을 달성했다. 여기에는 우리 인턴님의 지대하신 공헌이 있었다. : >

그 외 Pub/Sub 모델 도입, Notification, Scheduling 등의 주제는 별도의 포스트를 통해서 소개하도록 하겠다.

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×