May 16, 2020

8년 간의 개발자 생활 회고 (3)

SK C&C (2018. 7 ~ )

새로운 시작

첫 입사날 내게 비친 풍경은 자리가 군데군데 비어있는 사무실이었다. 나중에 알고보니 여름휴가 시즌이라 길게 자리를 비우신 분들이 많았고, 내가 소속된 파트의 파트리더도 휴가중이었다. 그래서 처음 몇 일은 노트북을 지급받고 회사 시스템과 분위기를 익히는 데 썼다.

휴가를 떠났던 파트리더님이 돌아와 현재 우리 파트에 대한 설명을 들었다. 우리가 가지고 있는 기술 스택과 목표로 하는 일 등에 대해 자세히 설명을 들었다. 정말 생소하기 짝이 없는 아키텍처였다. 관계형 데이터베이스가 여기선 단순한 메타성 데이터 저장소 용으로 사용되고 있었고, 대신 InfluxDB 라는 시계열 데이터베이스가 굉장히 헤비하게 사용되고 있었다. 또한 TICK 스택이라 불리는 솔루션들과 더불어 KafkaKubernetes 같은 써본 적 없는 기술들이 즐비하게 사용되고 있었다. 나름대로 리서치도 하고 주변 동료들에게 물으면서 전체 인프라 스택을 머리속에 정리해나갔다. 아무래도 생소하기는 했다. 하지만 앞으로 그걸 다루는 게 내 일이었고 경력직 개발자로서 나는 빠른 시간 내에 팀에 전력이 되어야 했다.

사실 새로운 스택을 익히는 데에 있어서 어려움만 있었던 것은 아니다. 오히려 어려움보다 기술적인 흥미가 더 컸다. 사실 일반적인 웹 아키텍처는 인터넷을 좀만 뒤지면 여러 레퍼런스를 찾기 어렵지 않다. 하지만 시계열 데이터를 다루는 이런 도메인에 대한 아키텍처는 레퍼런스를 찾기 어려운 편이다. 특히 Kubernetes 가 이제 막 container orchestrator 의 de-facto 가 되가던 시점이었기 때문에 한 번 배워야겠다는 생각을 하고 있던 차 이기도 했다. 그리고 역시 이런 기술 스터디는 필드에서 직접 맨땅에 헤딩해가면서 배우는 게 제일 효과적이다. 기본적으로 새로운 기술을 접하는 걸 좋아했기 때문에 초반 소프트랜딩 과정이 꽤 즐거웠다.

새로운 언어들

새로운 언어를 사용하는 기회가 되기도 했다. 특히 취미로만 사용해오던 Go 언어를 현업에서 사용할 수 있게 되었다. 해결하고자 했던 문제가 Go 언어의 동시성 기능이 필요한 부분이기도 했고, Java 로 짜기엔 다소 무거웠다. 이 팀에서 일하면서 Go 언어를 정말 다양하게 사용했는데, 배치성 코드, 간단한 API 서버, 메트릭 수집 모듈, 그리고 Agent 들을 모두 Go 언어로 작성하였다.

Typescript 도 이때 처음 다루게 되었다. 간단한 백 오피스를 만들어야 해서 처음에는 Javascript 를 이용해서 백엔드는 Koa, 프론트엔드는 React 로 만들었다. 하지만 점차 기능이 이것저것 붙기 시작하면서 언어적인 한계에 자주 부딪혔고 그에 대한 대안으로 Typescript 를 고려하기 시작했다. 기본적인 문법을 익히고 조그만 토이 프로젝트에 적용해봤다. 그 결과 이건 꼭 도입해야 하는 물건이라는 생각이 들었다. 새로운 언어를 배워야 한다는 러닝커브를 제외하면 도입하지 않을 이유가 없었다. 곧바로 백엔드와 프론트엔드 코드를 모두 Typescript 로 포팅하였고, 그 결과 더 안정적이고 유지보수하기 좋은 코드들이 나왔다.

Koa 의 대안으로 NestJS 를 살펴보기도 했다. 이전까지는 node.js 를 백엔드 서버로 사용하는 경우 express 가 대세였다. npm trends 를 보면 지금도 활발하게 사용되고 있긴 하다. 하지만 개인적으로 express 웹 프레임워크 라기 보다는 라이브러리 느낌이 강하기 때문에 규모가 있는 코드를 express 로 작성하기에는 특별한 이점이 없는 것 처럼 느껴졌다. 내 경우에도 express 대신 koa 를 많이 사용하긴 했지만 koa 역시 한계가 명확하고 활성도 조차 높지 않은 프로젝트였다. 그러던 차에 Typescript 를 도입하면서 알게 된 프레임워크가 NestJS 였다. expresskoa 에 비교하여 여러가지로 next-generation framework 라는 인상을 주었고, 토이 프로젝트에서 사용해본 결과 사용성도 확연히 좋았다. 하지만 끝내 팀 프로덕션 코드에 도입하지는 못했는데, 레거시 코드를 버리고 프레임워크를 교체하는 큰 공수를 들여서 얻을 수 있는 프로핏이 상대적으로 그리 크지 않았고, 이를 가지고 팀원들을 설득할 자신이 없었기 때문이다. 하지만 다음에 다른 프로젝트를 Typescript 로 진행해야 한다면 그때는 고민하지 않고 NestJS 를 선택할 것 같다.

오픈소스 코드 기여

이 때에 오픈소스 프로젝트에 처음으로 코드 기여를 해보기도 했다. 앞서 이야기 했듯이 우리 팀에서는 TICK 스택을 적극적으로 사용하고 있었고, 그 중 특히 메트릭 수집 에이전트인 Telegraf는 소스 레벨까지 파악해가면서 사용하고 있었다.

한번은 윈도우에서 설치를 하는데 정상적으로 기동되지 않는 문제를 겪게 되었다. 트러블슈팅을 해본 결과 default 로 탑재되는 설정 파일에 문제가 있음을 확인하게 되었다. 라인 몇 줄만 수정하면 되는 간단한 이슈였기 때문에 금방 수정본을 만들어 Pull Request 를 올렸고, 큰 문제없이 머지되었다. 이 경험을 하면서 이왕 Telegraf 에 대해 소스레벨까지 파악하고 있던 차에 코드 기여까지 해봐야 겠다는 생각이 들었다. 다행히 Telegraf 이슈 페이지에는 당시 약 500여개의 많은 이슈들이 등록되어 있었다. 그 중 간단한 버그 픽스 이슈부터 시작하여 나중에는 기능 추가 PR 도 올릴 수 있게 되었다.

이 기능 추가 PR 이 내게는 꽤 뿌듯한 경험이었는데, Telegraf 같은 경우는 기능 추가를 한 컨트리뷰터에 대해서 릴리즈 페이지에 “어떤 기능을 어떤 사용자가 추가했다”고 계정을 같이 포함해준다. 내가 기여한 코드가 릴리즈될 때 역시 추가된 기능에 대한 설명 옆에 내 Github 계정명이 같이 올라가게 되었다.

그래도 Telegraf 프로젝트의 코드 기여를 하면서 가장 좋았던 것은 Go 언어 에서의 유닛 테스트에 대한 경험을 쌓을 수 있다는 것이었다. Telegraf 프로젝트는 PR 을 올릴 때 추가된 코드에 대한 테스트 코드가 없으면 통과가 되지 않는다. 또한 테스트 코드가 부족하거나 추가되어야 할 케이스가 있는 경우에는 메인테이너가 직접 이런 부분들을 요청하곤 한다. 때문에 부득불 테스트 코드를 빡세게 작성할 수 밖에 없었다.

Tech Soft-Landing

우리 팀에도 새로운 구성원들이 계속해서 합류했다. 그동안 내가 주로 작업하던 코드들도 같이 다루게 되었다. 하지만 여기서 문제가 발생했다. 새로운 구성원은 웹 개발에 대한 경험이 전혀 없었고, 당연히 웹 전반의 프론트엔드 / 백엔드에 대한 어느정도 이해를 필요로 하는 소스코드를 이해하는 데에 어려움을 겪게 된 것이다. 특히나 당시 공유해야 하는 코드가 ES6 기반의 Node.js + React 코드라서 고민이 더 어려웠던 것 같다. 사실 이 쪽 생태계는 다른 언어 생태계에 비해 좌충우돌로 이리저리 부딪혀가면서 성장해온 감이 좀 있다. 그래서 같은 기술 스택을 쓰고 있다고 하더라도 코드 스타일이나 필요로 하는 기반 지식들이 많이 다른 경우들이 있다. 또 사이드로 알아야 하는 지식들이 많이 흩뿌려져 있는 편이다. 따라서 초심자의 입장에서는 처음 접할 때 더 큰 혼란을 겪겠다는 생각이 들었다.

Node.js 의 구조상 비동기 처리가 필수적이라는 것은 그렇다 쳐도 비동기를 처리하는 방법이 callback 부터 시작해 generator, promise, async / await 까지 제각각이다. 현재 코드는 async / await 을 기준으로 작성되어 있으나 어느 시점에는 promise 나 callback 에 대한 기본적인 이해를 필요로 하기 마련이다. 더불어 Javascript 라는 언어 자체가 명령형 패러다임과 함수형 패러다임을 모두 가지고 있으며, destructuring 같은 축약형 표현도 다양하고, 변수를 선언하는 키워드만 해도 var, let, const 세 개나 되고, null 과 undefined 의 차이, ===== 의 차이, commonjs 와 es6 의 모듈을 다루는 방법의 차이 등등 초심자를 혼란스럽게 하는 요소들이 넘쳐난다. 언어만 해도 이정도인데 npm 이나 babel 같은 에코시스템부터 시작해 브라우저 호환성 이야기까지 나오면 사실 게임오버인 셈이다. 뭐 사실 하나하나 들여다보면 그리 어려운 개념들도 아니긴 하지만 초심자 입장에서는 “어디서부터 어디까지 얼마나 알아야 하는가?” 라는 고민이 가장 크게 다가올 것이다.

이에 나는 원활한 기술 소프트랜딩을 위해 10개의 세분화된 스테이지 형 과제를 준비했다. 첫 번째 스테이지는 Node.js 로 hello world 를 찍는 서버를 만드는 것이었다. 이후에 ES6 문법 적용, RESTful 개념과 레이어 분리, 간단한 클린 코드 적용과 ORM 을 이용한 데이터베이스 연동, Typescript 포팅과 Docker 이미지 빌딩 및 Kubernetes 배포까지의 내용을 차례차례 각 스테이지별로 과제에 담았다. 과제는 Github Issue 를 통해 올렸고 Pull Request 를 통해 리뷰를 하고 머지를 하는 방식을 이용했다.

매 스테이지 별로 달성해야 하는 목표와 그에 따라 “꼭 알아야 하는 개념”, “알아두면 좋을 내용”, “지금은 몰라도 되지만 나중에 한 번 보면 좋을 내용” 정도를 나눠서 제공했다. 특히 각 내용에 대해서는 “어디까지 알아야 하는지”를 같이 명시하였다. 인터넷 검색으로 쉽게 얻을 수 있는 정보는 뭘로 검색해야 하는지에 대한 키워드를 제공하는 정도에서 그쳤고, 인터넷에 잘 나오지 않는 정보는 직접 설명을 하기도 했다. 그리고 검색을 해서 얻을 수 있긴 하지만 내용이 방대한 경우에는 대강적인 summary 를 정리해서 제공했고, 추가적인 내용을 보려면 어디서 뭘 봐야 하는지에 대한 링크 정도를 제공했다.

추가적으로 중점을 뒀던 부분은 “왜”에 대한 부분이었다. 왜 이 기술을 선택했는지, 왜 여기선 코드를 이렇게 했는지에 대해 최대한 설명하려고 했다. 더불어 새로운 기술을 공부하게 될때 “왜 이 기술이 필요한지, 타 기술 대비 어떤 장단점들이 있는지”를 한번씩 고민해보기를 추천한다고 코멘트를 덧붙였다. 개발 트렌드는 빠르게 변하고, 매일 새로운 기술들이 빠르게 밀려오기 때문에 뭐가 똥이고 뭐가 된장인지를 판단하는데에 있어 이러한 종류의 습관이 도움이 될 것이라고 생각했다.

Dig into Kubernetes

이 회사에 들어오기 전까지는 Kubernetes 를 위시한 container orchestrator 에 대해서는 들어본 바만 있었을 뿐이었다. 기껏해야 Docker 정도만 써봤고, 그마저도 혼자 공부하면서 써본 정도가 전부였다. 처음 이 팀에 합류했을 때도 사실 Kubernetes 는 기술 스택에 없었다. 모든 인프라는 IaaS 기반의 VM 위에서 운영되고 있었다. 그러다 Kubernetes 가 도입되기 시작했고, 중요도가 덜한 서비스부터 Kubernetes 위로 옮겨가기 시작했다. 지금은 일부 서비스들을 제외한 대부분의 서비스들이 Kubernetes 클러스터 위에 올라가 있다. 사실 내가 만지고 있는 코드들은 전부 Kubernetes 로 배포 및 운영을 하고 있긴 하지만, 그렇다고 Kubernetes 에 대한 이해도가 깊냐고 하면 그렇다고 말하긴 어렵지 싶다. 몇 번이고 공식 홈페이지의 Documentation 을 보긴 했지만 알면 알수록 더 갈 길이 멀어보이는 느낌이다. Cloud Native 패러다임에서 사실상 새로운 OS 역할을 할꺼라고 이야기되는 만큼 앞으로 더 깊게 파야 할 부분 중 하나다.