May 10, 2020

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

개발자의 길로 들어선 것이 어느덧 8년이다. 처음 직장 생활을 시작하던 20대 후반의 나와 지금의 내가 얼마나 달라졌는지는 사실 잘 모르겠다. 그래서 지난 8년 간의 기록을 여행기 쓰듯이 써보려고 한다. 다른 분들이 많이들 하시는 신년맞이 지난해 회고를 난 한 번도 한 적이 없으니, 8년치 회고를 한꺼번에 하는 셈이다.


Igloosec (2013. 1 ~ 2016. 6)

신입 개발자

처음 개발자로써 사회 생활을 시작한 것은 2013년 1월 이었다. 첫 회사는 이글루시큐리티였고 보안 솔루션들을 만드는 회사였다. 주력 솔루션은 통합보안관제솔루션(이하 ESM) 이었는데, 운 좋게 이 캐시카우를 만드는 팀에 신입으로 입사를 하게 되었다. 사실 캐시카우인 만큼 레거시 코드도 많고 순수 개발 외 고객사 지원 업무도 많아 편한 포지션이라고 하기는 어렵다. 그럼에도 불구하고 운이 좋다고 표현한 것은 주니어 엔지니어 시기에 그런 하드한 환경에서 쌓은 경험치들이 나중까지 도움이 많이 되었기 때문이다. 물론 좋은 선배들도 많이 만나게 되었다.

2013년 1월 2일, 내 첫 출근일이었다. 아직도 그 풍경이 생생히 기억난다. 면접 때 입었던 불편하기 짝이 없는 정장을 입고 사수의 뒤를 쫄레쫄레 따라 자리에 앉았다. 썰렁해보이는 책상 위에는 두꺼운 책을 한 권 있었다. ESM 매뉴얼이었다. ESM 을 구매한 고객사에게 나가는 용 이었는데 두께가 왠만한 백과사전 만큼이나 두꺼웠다. 내 첫 업무는 이 책을 참고하여 ESM 의 대략적인 기능을 익히는 것이었다.

그 날 오후 쯤에는 두 번째 임무가 주어졌다. 서버실에 있는 테스트 용 서버에 CentOSOracle, 그리고 ESM 을 설치하는 것이 그것이었다. 당시 쌩 신입이었던 내게 이 일은 꽤 어렵게 느껴졌다. 일단 리눅스 환경 자체가 익숙치 않았고, Oracle 설치도 툭하면 알 수 없는 오류가 발생하여 롤백을 몇 번이나 반복해야 했다. ESM 설치도 쉽지 않았다. 단일 프로세스 형태가 아니라 여러 모듈들이 함께 설치되는 구조였고, 각 모듈간의 정상적인 연결을 위해 꽤 복잡한 설정을 거쳐야 했다. 이 일에 약 1주일 정도를 매달렸다. 이후에는 사수로부터 ESM 의 아키텍처와 전반적인 흐름에 대해 면대면으로 교육을 받았다. Standalone 구조는 그런대로 이해를 금방 했는데, Master - Slave 형태의 분산 구조에서 꽤 해맸던 기억이 있다.

위의 과제들을 모두 끝낸 후에야 처음으로 소스 코드를 마주했다. 팀에서 내가 소속된 파트는 미들웨어 파트였고 주 언어는 Java 였다. 당시 기준으로도 8년 이상 유지되던 소스 코드라 레거시의 양이 어마무시했다. 그리고 무엇보다 Spring 같은 프레임워크를 사용하지 않은 쌩 Java 코드 였다. 이 미들웨어의 역할은 실시간으로 유입되는 데이터들을 기반으로 time window 단위 통계 관리, 설정 관리, 분산 노드 간 데이터 동기화 등의 기능을 담당하고 있었다. 신입 입장에서 곧장 파악하기에는 기능도 코드도 너무 복잡했다. 때문에 일단은 전체 구조만 숙지한 상태로 특정 기능에 대한 이슈가 발생했을 때 마다 딥하게 파는 방식으로 배웠다.

트러블 슈팅 단련기

앞서 이야기했듯 당시 회사의 ESM 솔루션은 꽤 많은 고객사들이 사용하고 있었다. 그 수가 물경 세 자리에 달했다. 당연히 연구소에서 직접 이 많은 고객사와 커뮤니케이션하지는 않았고, 설치 및 유지보수, 장애 조치 등을 담당하는 엔지니어 조직이 따로 있었다. 자주 발생하거나 단순한 장애의 경우에는 엔지니어 조직 내부에 매뉴얼화가 되어 있었기 때문에 자체 대응이 가능했다. 하지만 그렇지 못한 이슈 들은 연구소로 많이 토스되었다. 말하자면, 연구소까지 넘어온 이슈들은 대부분 이전에 발생한 적이 없고 원인을 파악하기 어려운 이슈들이었다. 고객사가 워낙에 많아 이런 식으로 연구소가 대응해야 하는 이슈가 많게는 일주일에 두세 건씩 발생했다.

오랜기간 사용되면서 충분히 안정화된 솔루션임에도 불구하고 이렇게나 이슈가 많았던 이유는 주로 환경의 다양성 때문이었다. 고객사 서버에 직접 설치되는 형태이다보니 네트워크 구성부터 서버 환경들이 서로 천양지차였다. OS 도 대개는 CentOS 였지만 IBM AIX, HP UX, SolarisJVM 이 구동 가능한 환경은 전부 지원했고, 데이터베이스도 기본은 Oracle 이었지만 고객사 환경에 따라 DB2MSSQL, Tibero 를 사용해야 하는 경우도 있었다. 당연히 각 OS, Database 별로 버전 들도 다양했기 때문에 아무리 코드를 잘 짜고 테스트를 꼼꼼하게 해도 장애는 발생했다.

이러한 환경에서 배우게 된 점이 두 가지 있었다. 첫째는 자연히 예외상황에 대한 처리를 빡세게 하게 되었다. 일반적인 환경에서는 정상 동작할 코드에 대해서도 “데이터 유입량이 갑자기 늘어난다면?”, “DB 서버와의 레이턴시가 늘어난다면?”, “동시성 이슈가 생긴다면?”, “스토리지 접근에 일시적으로 문제가 생긴다면?” 등등 여러 예외상황들을 미리 가정하고 설계하다보니 비교적 보수적으로 코딩을 했다.

둘째는, 장애 대처 경험이다. 물론 당시에 했던 Oracle 설정 튜닝이나 마이너한 운영체제 상에서의 디버깅 경험이 전부 기억나지는 않는다. 다만 장애상황시의 요령과 촉이 늘어났다고 생각한다. 대체적으로 장애 처리는 탐정의 추리와 비슷한 면들이 있다는 생각을 했다. 이상 징후를 보이는 단서들을 펼쳐놓고 장애 원인에 대한 여러가지 가설을 세운 후 검증한다. 가설을 세우기 어려울 정도로 단서가 없을 때에는 각 단계를 쪼개서 어느 단계, 어떤 종류의 데이터에서 문제가 생겼는지를 최대한 한정하고 다시 가설을 세운다. 이때 시스템 레벨의 지식이 부족하면 가설을 세우기가 힘들다. 예를 들어, inode 의 존재에 대해 몰랐을 때엔 용량이 충분한데 발생하는 “no space left on device” 에러 앞에서 할 수 있는 일이 없다.

새로운 모듈 개발

미들웨어 외에도 두 개의 모듈을 더 개발했었다. 첫번째는 내부적으로 extension 이라고 불리던 모듈이었는데, ESM 에서 경보가 발생했을 때 고객사별 커스터마이즈된 수단으로 경보를 전달하는 모듈이었다. 주로 문자나 이메일 연동을 많이 했는데 고객사 별로 사용하는 문자 전송 솔루션, 원하는 메일 템플릿이 달랐기 때문에 매번 해당 스펙에 맞춰 추가개발을 해야 하는 모듈이었다.

구현해야 하는 로직은 단순했고 틀도 어느정도 정해져 있어 난이도가 쉬웠기 때문에 주로 신입에게 배정되는 모듈이었다. 입사와 동시에 내가 맡아서 퇴사 전까지 담당하였다. 고객사 보안 이슈 때문에 직접 사이트로 방문하여 개발해야 하는 건수가 간간이 있었고 이를 핑계삼아 한번씩 사무실을 탈출해 외근을 가곤 했다.

새로운 모듈, 맨땅에서부터

두 번째 모듈은 SpDbReader 라는 모듈이었는데, 이 모듈은 초기 설계부터 혼자 담당해서 진행했었다. 아마 2년차 혹은 3년차 정도의 때 였던 것 같다.

당시 고객사에서 ESM 도입을 하게되면 인프라 내에 구성된 보안솔루션(ex. FW, IPS, IDS, UTM …)들에 Agent 가 설치되어 여러 보안 이벤트를 수집하는 구조였다. Agent 는 성능 상의 이유로 C언어 로 구현되었다. 하지만 고객사에 설치된 보안솔루션의 종류들은 매우 다양했고 그 버전과 환경마저 매번 다르다보니 이를 맞춰주기 위한 Agent 파트의 업무 부담이 대단했다. 실제로도 팀에서 가장 야근이 많은 파트이기도 했다.

기존 Agent 연동 과정은 아래와 같았다. 먼저 고객사에 엔지니어가 나가서 사이트의 환경과 고객의 요구사항을 수렴하여 개발팀의 Agent 파트로 보낸다. Agent 파트는 그에 맞춰서 기존 Agent 소스에 새로운 로직을 추가하거나 수정하여 빌드한다. 빌드된 결과물을 받은 엔지니어는 현장에서 바로 설치하고 테스트를 진행한다. 여기서 정상적으로 작동을 하면 문제가 없지만 사소한 문제들이 발생하는 경우들이 다반사였다. 이런 경우에 엔지니어는 다시 현상과 로그들을 수집하여 개발팀으로 보낸다. 개발팀에서는 이에 맞춰서 다시 소스를 수정하는 일의 반복이었다. 이 과정에서 현장에 있는 엔지니어도, 본사에 있는 개발팀도 필요 이상으로 Agent 연동에 시간을 많이 쏟곤 했다.

이를 타개하기 위한 방안으로 여러 가지가 시도되었고 그 중 하나가 내가 담당했던 SpDbReader 였다. 이 모듈의 구조는 간단했다. Java 로 만들어진 데몬이 하나 뜨고 그 데몬에서 Javascript 파일을 읽어 실행한다. 이 Javascript 파일은 고객사 환경별로 서로 다른 로직들이 들어있었다. 정확히는 보안솔루션 로그를 어디서 어떤 방식으로 수집하여 어떻게 가공한 후 어디에 보내야 하는지가 기술되어 있었다. 이 Javascript 코드에서 필요한 공통 로직이나 함수들은 다시 Java 로 구현되어 있었다. 이를 통해 JDBC 같은 Java 전용 인터페이스를 통해 DB 접근도 쉽게 할 수 있었다. 또한 OS 별로 소스를 수정할 필요 없이 jar 파일 하나로 대부분의 환경에 대응이 가능했다. 하지만 무엇보다 가장 효과적이었던 건 Javascript 파일 자체가 인터프리터 언어이기 때문에 고객사 현장에서 환경에 맞춰 바로바로 수정해서 사용할 수 있다는 것이다.

SpDbReader 가 개발된 이후로 여러차례 엔지니어들에게 이 모듈의 사용법에 대해서 교육을 했고, 엔지니어들은 이제 현장에서 SpDbReader 를 가지고 직접 연동 수정을 할 수 있게 되었다. 이를 통해 Agent 파트의 업무 경감은 물론 Agent 연동에 소요되는 시간 자체도 꽤 많이 줄었다.

물론 퍼포먼스는 C언어로 작성된 Agent 의 속도를 따라갈 수는 없다. 따라서 이벤트 발생량이 많거나, 리소스를 적게 써야 하거나 하는 경우에는 기존의 방법을 그대로 이용했지만 그게 아닌 경우에는 대부분 이 모듈을 이용하는 방식으로 많이 진행을 했다.

회사 밖의 기술 탐구

이 시기쯤에 나는 회사 밖의 기술에 눈을 돌리기 시작했던 것 같다. 바야흐로 때는 빅데이터 라는 키워드가 핫하게 떠오르면서 하둡 에코 시스템들이 발전하기 시작한 때였다. 당시 핫하던 Spark 도 한 번 파보고 Scala 언어 스터디에 나가면서 새로운 언어를 배워보기도 했다. Scala 가 마음에 들어 기존 Java 코드들을 포팅해볼까 싶기도 했지만 Scala 코딩이 가능한 인력을 보충하는 게 사실상 불가능할 것 같아서 채념했던 기억이 있다.

React 를 배웠던 것도 이때가 처음이었다. 당시는 정말 React 초창기여서 이제 막 React.createClass 대신 ES6 의 Class 를 막 사용하기 시작했던 즈음이었던 것 같다. 개인적으로 현업에서 웹 개발을 했던 경험은 없었고 웹의 근간을 이루는 HTML, CSS, Javascript 에 대해서는 기초적인 지식 정도만 겨우 가지고 있었다. 때문에 웹 프론트엔드는 내게 항상 딴 세상 이야기였다. 그러던 와중에 React 가 제시한 컴포넌트 기반의 개발 방식을 처음 보고 완전히 매료되어 한동안 열심히 팠다. 이 즈음에 결혼을 하게 되었는데 당시 배웠던 React 를 가지고 직접 모바일 청첩장을 만들어보기도 하였다.

Go 언어를 공부하게 된 것도 이쯤이다. 이전까지는 주력 언어가 Java 였는데 결과물이 바이너리가 아닌 바이트 코드로 나온다는 게 조금 마음에 들지 않았다. Java 언어를 바이너리로 바로 컴파일해줄 수 있다는 GCJ 같은 것도 살펴보기는 했지만 영 마음에 들지 않았다. 거기다가 GCJ 는 당시 기준으로도 사실상 죽은 프로젝트나 마찬가지기도 했고. 그러던 중에 Google 에서 Go 라는 새로운 언어를 만들었고 아직 초기 단계의 언어이기는 했지만 국내에서도 여러 스터디가 만들어지기도 했다.

당시 회사에서 C언어로 구현된 수집 엔진이 있었는데, 이를 새롭게 재설계하는 단계에서 Go 언어 사용이 고려되기도 했다. 그 때문에 Go 언어를 새롭게 배우기 시작했는데 그동안의 목마름을 많은 부분에서 해결해주는 언어였다. 일단 바이너리로 컴파일된다는 부분이 마음에 들었고, Java 에 비해서 동시성이나 리소스 사용량에 있어서 많은 이점을 가지고 있는 언어였다. 무엇보다 system call 을 언어 자체에서 지원을 하면서도 C/C++ 보다도 생산성이 좋다는 부분이 마음에 들었다. 하지만 결국 수집 엔진을 Go 로 재구현하는 방안은 어른의 사정으로 엎어지고 말았다. 다만 혼자 이런저런 유틸성 프로그램들을 짜봤던 기억이 난다. 경력으로 약 3년차 정도의 일이다.

첫 번째 이직

이직을 해야겠다는 생각을 했다. 사실 이직 생각은 이전부터 계속 있기는 했다. 하지만 제대로 준비해야겠다는 생각은 3년차 정도에 했던 것 같다. 당시 회사에서는 사원에서 주임으로 막 승진을 한 참이었다. 하지만 어디로 가야 할지를 구체적으로 생각해놓지는 못한 상태에서 RIDI 의 기술 블로그를 보게 되었다. 이 기술 블로그를 보면서 처음 느낀 RIDI의 인상으로는 새로운 기술들을 좋아하는 내 성향과 맞겠다는 생각이었다.

사실 기존 이글루시큐리티에서는 새로운 기술에 대해서 매우 보수적인 접근을 할 수 밖에 없는 상황이었다. 그 차이는 아무래도 서비스 회사냐 솔루션 회사냐의 차이에서 기인하는 것이라고 본다. 내가 만든 코드를 내가 관리하는 서버에 올리는 서비스 회사들은 생산성이나 여타 다른 부분들에 도움이 된다고 하면 새로운 기술, 그리고 다소 안정성 검증이 덜 된 기술이라고 해도 필요하다면 트레이드 오프라고 생각하고 올려볼 수 있을 것이다. 하짐나 내가 만든 코드가 고객사의 서버에서 올라가고 한 번 장애가 나면 장애보고서를 써서 고객에게 제출해야 하는 환경에서는 아무래도 새로운 기술을 접목시키기가 쉽지 않다. 그러다보니 기존 회사 구성원들도 새로운 기술을 좋아하는 사람들이 많지 않았다.

사실 이 부분 외에도 RIDI 에서 일해보고 싶다는 생각을 들게 한 이유는 몇 가지 더 있었다. 일단 B2C 서비스 개발을 해보고 싶었다. 이글루시큐리티는 B2B 솔루션을 하기 때문에 아무래도 서비스에 대한 애착이나 고객들의 피드백을 받기 쉽지 않았다. 그런 면에서 RIDI 는 완전히 대척점에 서있는 회사였다. 기본적으로 B2C 이기도 했고, 고객으로부터의 피드백을 굉장히 중요시하는 회사였다. 매일 아침 9시마다 TOC (Tears of Customer) 라고 해서 고객들의 칭찬이나 불만사항들을 구성원들에게 공유하는 시간이 있었다. 그만큼 고객의 반응을 중요시한다는 반증일 것이다. 그래서 나는 RIDI 로 이력서를 냈다.

내가 지원을 했던 공고는 지금생각해보면 참 어처구니없게도 데이터 팀이었다. 3년 이라는 짧은 커리어는 데이터 팀과 매칭되는 부분이 하나도 없었다. 그럼에도 불구하고 용감무쌍하게도 이력서를 냈다. 당시 내 심정은 “이력 들여다보고 쓸만하면 뽑아서 쓰겠지” 하는 심정이었던 것 같다.

재미있게도 1차 면접을 보러오라는 메일을 받았다. 1차 면접은 데이터 팀 구성원들과 보게 되었는데 그동안 내가 회사에서 했던 일들에 대해 묻고 간단한 코딩 테스트를 봤다. 면접은 나쁘지 않은 느낌이었고 무난히 합격하여 2차 면접으로 넘어가게 되었다. 2차 면접은 CTO 님을 비롯하여 세 분 정도 들어오셨는데 확실히 면접 과정 속에서 지원자를 배려해주는 느낌을 강하게 받았다. 하지만 역시 데이터 처리 관련 이력이 없는 부분에 대해서 고민하는 눈치셨다. 잠시후에 내게 데이터 팀이 아니라 서점 팀에서의 웹 개발 포지션은 어떻냐는 제안을 주셨다. 그리고는 서점팀이 무슨 일을 하는지, 어떤 기술들을 다루는지 설명해주셨다. 나는 수락을 했고 며칠 후 최종 합격 통보를 받게되었다.

다니고 있는 회사에 퇴직 사실을 알렸다. 신입으로 들어왔던 첫 회사를 떠나는 일은 아무래도 어색했다. 그동안 담당해왔던 일들을 문서로 정리하고 소스코드와 함께 후임 담당자에게 인수인계했다. 깔끔하게 떠나고 싶어서 인수인계에 꽤 공을 들였다. 그리고 퇴사 후에 약 1주일을 쉬고 새로운 회사로 출근을 했다.