외주 레거시로부터의 여정 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 등의 주제는 별도의 포스트를 통해서 소개하도록 하겠다.

외주 레거시로부터의 여정 2편 - 개발팀 구성

팀 꾸리기

소프트웨어 개발은 혼자 할 수 없다. 더욱이 8~9개월 가까이 외주에서 진행된 프로젝트를 이어 받아야 하는 입장에서는 더더욱 그렇다. 이런 초창기 개발팀일수록 2인자 테크 리더의 역할이 굉장히 크다. 2인자는 나의 오른팔로서 내가 모자란 부분을 채워주고 때에 따라서는 적어도 2~3명의 개발자를 매니징 할 수 있을 인재여야 한다. 경험상 보통 3~4년차 개발자부터 이 역할을 맡을 수 있다.

나는 연차나 학력으로 개발자를 평가하지 않는다. 1년 차 고졸 개발자라도 굉장히 실력이 좋은 경우도 드물지만 존재하며, 20년차 개발자라도 과거의 영광에 사로잡혀 구닥다리 방식대로만 일을 하는 사람도 있다. 다만 짬밥(?)을 무시하지 못하는게 보통 3~4년차 개발자는 평균적으로 어느 정도의 기술적인 기반을 다져놨기 때문에 내가 원하는 2인자 - 테크 리더일 가능성이 굉장히 높았다.

문제는 이 3~4년차 개발자들이 시장에서 가장 잘팔리고, 가장 자만심이 높을때라 이렇게 듣보잡(분하지만 지금은 그렇다…) 스타트업에 지원할 가능성이 굉장히 낮다. 이 분들은 주로 한 회사에서 주니어 개발자로 경력을 쌓고 그 다음 회사로 배민이나 토스, 네이버, 카카오같은 테크 대기업에 지원하고 있으리라. 혹시나 하는 마음에 개발자 구합니다 - 라고 로켓펀치에 올렸으나 결과는 대실패였다. 외국인 개발자 한 분만이 지원했을 뿐 아무도 지원하지 않았다. 게다가 개발자들에게 생소한 “물류” 분야의 스타트업이라 더더욱 힘들었다. 예를 들어 킥보드 스타트업이다 한다면 개발자들도 대충 뭔지는 안다. 도심을 활보하는 킥보드를 타본 적은 없을지언정 뭔지는 알고 있다. 실버 케어 스타트업이다 한다면 개발자들도 대충 뭔지는 안다. 다들 할아버지 할머니가 있거나 있었거나 없어도 뉴스 등을 통해서 간접적으로 접했을테니까. 근데 택배도 아니고 수출입물류입니다 - 인코텀즈 아세요? 20피트 드라이는요? 그럼 급정색하고 “안녕히계세요” 이러고 집에 갈거다.

여기서 내가 취할 수 있는 선택지는 단 2개였다.

  1. 오른팔이 될 수 있는 3~4년차 개발자를 계속 찾는다.
  2. 주니어를 뽑아서 멱살잡아 끌고가서라도 중니어로 만든다.

1번이 이루어지면 확실하게 개발팀에 큰 힘이 된다. 다만 “언제”라는 측면에서 불확실성이 매우 컸다.
2번 - 주니어 채용은 확실히 쉽다. 다만 주니어 특성상 똥인지 된장인지는 겪어봐야 알고 소프트웨어 개발자로서의 성공 의지에 따라서 발전 속도의 차이가 너무 심하다. 그리고 멱살잡고 끌고가는 사람도 보통 힘든게 아니다.

결국 나는 2번을 택하기로 했다. 모든 비즈니스에서는 ‘시간’이 매우 중요하다. 전설 속의 유니콘과 같이 언제 올지 모르는 테크 리더급 개발자 채용을 기다리다가 개발을 그르칠 수 있었다. 개인적으로 불확실한 최선보다는 확실한 차선을 선호한다. 게다가 Node.js 백엔드, AWS 인프라 정도는 나 혼자 할 수 있고 리액트도 다시 공부하면 되긴 된다. 근데 이놈의 리액트는 잠깐 손놨더니 최신 코드는 죄다 React Hooks 일세?

내가 상대적으로 모자란 부분인 프론트엔드 (특히 스타일링)쪽을 강화시켜줄 개발자가 절실했지만, 어쩔 수 없이 지금 현재 주니어 프론트엔드 개발자와 백엔드 인턴으로 팀을 만들었다. 그리고 이 어린 동료들은 입사하자마자 불행히도 벌써부터 공부거리를 받고 4월 말까지 검사를 받아야 한다.

인턴에게는 인터넷 기본(HTTP, Cookie, Session)에 대한 발표를 주니어 프론트엔드 개발자에게는 DNS(호스팅, DNS, 도메인네임, google.com을 쳤을 때 뒷단에서 벌어지는 흐름)관련 내용을 공부해오라고 했다. 참고로 앞으로 공부할 커리큘럼도 짜놨다. HTML, CSS, Javascript(쪽은 좀 더 세분화), Git 심화(PR, Merge, Rebase, Cherrypick), 보안, 주석, CSS 레이아웃(Flex, 반응형, Styled Component), 테스팅, Database, OS, 자료구조, 인증, CI/CD, 개발/설계, 아키텍쳐 패턴, 도커 그 외 Devops 관련된 모든 사항이다.

외주 레거시로부터의 여정 1편 - 기존 레가시 파악

시작

2020년 1월 중순, 서울시 광화문의 어느 술집에서 남자 셋이서 술을 마시고 있었다. 셋은 기분이 좋은지 상 위의 안주는 거들떠보지도 않은 체, 술만 마시고 있었다. 두 사람은 좀 더 나이들어 보이는 어떤 남자에게 연거푸 고맙다는 인사와 함께 계속 잔을 부딪혔다. 이렇게 좀 더 나이많은 남자는 셀러노트 CTO가 되었다. 그리고 그 남자는 3월 중순에 본격적으로 판도라의 상자를 여는데…

심심해서 도입부를 소설 형태로 적어보았다. 아내가 봤으면 무슨 똥글이냐고 욕했겠지만 마침 몇 시간동안 자리를 비운지라 거침없이 글을 쓴다 : >

암튼 그 판도라의 상자를 여는 남자는 바로 나, 자신이다. 첫 임무는 외주사가 개발하고 있는 셀러노트의 물류 플랫폼 서비스 쉽다를 자체개발로 돌리는 일이었다. 외주는 다행히 PHP로 개발하지 않고 node.js 로 개발을 했다. 아마 PHP로 했었으면 CTO 자리를 정중히 거절했을거다. PHP자체가 나쁜건 아니다. 아니 아직까지 PHP 5.x로 개발했다면 그건 나쁘다고 단언할 수 있다. 허나 PHP도 7부터는 속도도 어느정도 빨라지고 상당히 괜찮은 물건이 된건 알고 있으나, $투성이인 코드가 싫다는 말도 안되는 핑계로 PHP를 거부하고 있고 앞으로도 사용하지 않을 예정이다.

4월 13일부로 입사한지 1달이 지났다. 지난 1달 간은 레거시를 바탕으로 좀 더 나은 시스템으로 만드는 과정의 연속이었다. 이를 회고 겸 경험 공유 차원에서 시리즈로 연재할 예정이다.

진짜 시작

입사는 3월이지만 소스 코드와 AWS는 입사 전인 2월 중순부터 살펴볼 수 있었다. 외주 개발물에 대해 파악한 내용을 개인적인 감상/비평은 최대한 자제하고 그냥 사실만 적도록 하겠다.

기 개발 기간

외주 개발자들이 2019년 7월부터 2~3명의 인원이 붙어서 작업했다. 단순 M/M만 따져봐도 2월 당시엔 최소 14M/M가 된다.

백엔드

서버 코드는 천만 다행으로 ES6+를 사용하고 있었고 node.js/Express 상에서 동작했다. 코드를 보니 미들웨어가 상당히 많았는데 이는 다년간 node.js 프로젝트를 진행했고 외주 회사에서 어느정도 프레임워크로 갖춰놓았다는 얘기가 된다. ESLint를 적용하진 않았고 유닛테스트가 없다. ㅠㅠ

인증

인증은 JWT였다. OIDC나 OAuth0 썼을까 살짝 기대했는데 그건 아니고 생짜 인증키로 토큰을 만들고 내려주는 형태였다.

Database

데이터베이스는 MySQL 8.0이었다. ORM을 쓰지 않고 생짜 MySQL Driver를 사용했다. 근데 테이블이 70개가 넘었다.

프론트엔드

React.js 다. ES6+를 사용했고 Redux로 전역 상태관리를 했다. 일부 컴포넌트는 Styled Component를 사용했으나 전체 스타일은 7000줄에 달하는 거대한 CSS가 담당하고 있었다. 스토리북으로 뭔가 테스트를 도입하려고 한것 같은데 테스트가 3개밖에 없다. 하다가 중단한듯 하다. 어드민 페이지는 별도의 프로젝트로 있었는데 Material UI로 만들어져 있었다.

인프라

AWS를 사용했다. dev/prod 로 각각 EC2를 띄워서 사용했는데 이상하게 EC2가 4대나 되었다. 잘 살펴보니 Frontend Serve용 dev/prod 2대, Backend용 dev/prod 2대 이렇게 4대였다. DB는 하나의 EC2에 넣지 않고 AWS RDS를 사용하고 있었다. 오토스케일링 설정은 하지 않았고 Elastic IP를 받아서 Route53에서 A레코드에 해당 IP를 매핑하는 식으로 웹 서비스를 구성했다. 주로 사용하는 서비스는 사실 이게 다였다. 프론트엔드 웹서버는 serve 를 사용하고 있었고 API 서버는 nginx를 사용하고 있었다.

배포

프론트엔드/백엔드 모두 배포는 CI/CD는 없었고 로컬 컴퓨터에서 스크립트로 배포했다. 단계는 아래와 같다

  1. npm run build로 빌드
  2. docker build 도커 이미지를 만들고 태깅한다.
  3. ECR에 올린다
  4. EC2에 SSH로 접속해서 Docker Pull을 땡긴다
  5. scp를 사용해서 docker-compose파일을 EC2로 복사한다.
  6. docker-compose 실행
  7. 기존 이미지를 지운다

물론 대부분 다시 손을 봐야된다. 허나 이 정도만 되도 굉장히 감사한 편이다.
지인의 요청으로 기존에 만들어놓은 외주 프로젝트를 본 일이 여러 번 있었는데 PHP 5.x로 코드이그나이터도 안쓰고 짠 소스 + 무식하게 큰 EC2 한 대에 웹서버 + 디비까지 같이 넣어놔서 오토스케일링도 못하게 만든게 제일 최악이었다. 거기에 비하면 이 정도는 사실 감사하다고 인사하고 써야할 것 같다.

자, 이를 어떻게 바꿀지는 3편부터…

Your browser is out-of-date!

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

×