본문 바로가기

카테고리 없음

1년 8개월 - 회고

지금 회사에 입사한 지 1년 8개월.

처음엔 일을 하면서 블로그 글도 많이 쓰려고 노력 많이 했지만, 어느 순간부터 이런 저런 핑계를 대며 글을 잘 못쓰고 있다.

그래도 일 하면서 알게된 것들은 사내에서 만큼은 많이 공유/전파하려고 노력은 하고 있다.

경기도 양평으로 이사간 후, 평일 매일 서울 강남으로 출퇴근하는 와중 간만에 혼자 서울에서 아내를 기다리고 있는 시간이 되어서, 뭘 할까 고민하다가 기술적인 글을 하나 쓰는 것보다 이런 회고 글을 적는 게 더 마음이 편하고 그냥 손이 가는대로 써도 될 것 같아서 쓰게 되었다.

일단, 회사에 처음 입사할 당시에는 Spring Boot 로 백엔드를 개발하는 포지션이 내 자리였다. 스타트업 특성(a.k.a. 인력 부족)에 따라 내 업무는 점차 확장되어 갔다.

### 인프라 업무

입사 후 약 4주간의 온보딩 프로세스(책읽고 분위기 파악)가 끝나고 며칠 뒤에 회사에 오래 계신 분이 cloud 에 elasticsearch 가 뭔지도 모르는 나에게 elasticsearch 노드가 1대 더 필요하니 구축해달라는 요청을 받았다. 일단, 기존에 2대가 돌아가고 있다고 했으니 그걸 보고 참고해서 하면 되겠다 싶었고, 역시 개발자라면 까만 콘솔 화면에서 흰 글씨를 타이핑 하는 것이 본연의 모습이라고 생각하던 때였고, 들어온지 얼마 되지 않았기 때문에 나의 역량을 드러내고 싶었다는 둥의 여러 이유로 그냥 알겠다고 했다. 다행히 레퍼런스도 많고, 생각보다 간단한 작업이어서 1시간 정도 만에 거의 다 끝냈는데, 사내의 복잡한 인프라(VPN, IDC, cloud 네트워크의 복잡함)때문에 routing 테이블을 못찾은 상태에서, "거의 다 한 것 같은데 클러스터에 추가가 안 된다. 이유가 뭔지 모르겠다" 라고 말씀드리고 마무리는 선임이 지어주셨다.

이렇게 시작한 나의 인프라 업무는 입사하고 4개월 뒤, 60GB 가 넘는 IDC에 있는 mysql database 를 cloud 환경으로 이전을 하는 것을 포함해 현재는 legacy인 복잡한 네트워크 구성을 간단한 구성으로 줄이는 작업을 하고 있고, 장애 발생 시 대응을 하고 있다. (10억건이 넘는 테이블에 ALTER 를 수행하는 것은 짜릿짜릿, pt-online-change-schema 가 없으면 online 으로 수행하는 것은 거의 불가능이었다.)

이 과정에서 리눅스 기반의 환경에 좀 더 익숙해졌고, 좀 더 빠른 대처를 하기 위해 별거 아니지만 bash 만 쓰던 서버들에 zsh + plugin 을 도입하여 다른분들에게도 0.1초씩이라도 좀 더 빠른 타이핑을 지향하실 수 있도록 했다. 특히, iptables, routing 설정을 비롯하여 일부 커널 설정이 무슨 역할을 하는지 이전보다 좀 더 깊게 공부할 수 있는 계기가 되었다. 아직도 모르는 것이 많지만, 향후 내 커리어가 어떻게 될 지 모르는 상황에서 백엔드 개발자로서의 인프라 지식은 어플리케이션 코드를 짜는 것에도 가끔 도움이 될 때가 있는 걸 보면 꽤 좋은 업무인 것 같다.

그리고 여전히 까만 화면에 흰 글씨를 타이핑 하는 것이 가장 즐겁다.

### 프론트엔드

처음 맡은 poc 목적의 프로젝트가 통째로 무산되면서, 두번째 프로젝트로 아주 거대한 legacy back-office 를 새로운 시스템으로 교체하는 것을 맡게 되었다. 백엔드 로직을 내가 하고, 프론트 엔드 개발은 다른 분이 하는 것으로 알고 개발을 시작을 했고, 새로 오신 프론트엔드 개발자 분이 React 로 개발을 하신다는 말을 듣고 그 분을 위해 프로젝트를 리액트로 세팅을 해드리는 게 좋겠다고 생각을 했다. 그게 나의 삽질 of 삽질을 하게 된 서막이었음을 그 땐 알지 못했다. javascript 의 객체 리터럴도 모르던 내가 무작정 jQuery 로 개발을 하겠거니 생각했었는데 npm, webpack, react, es6 등을 프로젝트 안으로 들이기엔 너무나도 많은 에너지와 시간이 필요했다. 그래도 한 번 설정해놓은 프로젝트 구조는 이후 사내에서 신규 프로젝트들은 모두 내가 만들어 놓은 프로젝트 구조를 갖추도록 하게 될 정도로 탄탄한 뼈대의 모습을 하게 되었다. 대신, 그만큼 진입장벽은 좀 생겼다.

그리고 리액트...

신선한 jsx 의 문법과 state, props 의 어플리케이션 상태 관리 기법이 너무나도 어렵게 느껴졌다. 어렵게 느껴졌다기 보다는 완벽히 이해하는 데 걸린 시간이 많았다. 그러다 프론트엔드 코드 뭉치들이 점점 커짐에 따라 순수 state, props 만으로는 깔끔한 코드를 유지하기에 어려움 - 사실, 지금 돌아보면 깔끔한 코드도 아니었다 - 이 생기기 시작했다. 그래서 react 개발자라면 누구나 도입을 한다고 알려진 redux 를 도입해보기로 했다. 새로 오신 신입 프론트엔드 개발자분과 같이 1~2일 정도 동안 기존 코드를 redux 를 사용한 코드로 열심히 전환을 해봤는데, 코드는 돌아가게 되었지만 "잘 모르면서 쓰는 코드"가 생기기 시작했다. 그 분께서 나에게 "이렇게 잘 모르는 상태에서 도입을 하기엔 좀 어려움이 있는 것 같다."고 하신 말에 깊은 공감을 느끼며 코드를 revert 하게 되었다.

끝내 redux 는 프로젝트에 들어오지 못했다. 그리고 mobx...

마침 새로 오신 약 4년차 안드로이드 개발자 분이 여러 경험이 있는 지라 mobx 라는 것을 알려주셨고, mobx 는 쌩 신입인 나와 프론트엔드 개발자 분에게 빛이 되었다. 아주 손쉬운 사용법과 개념, 그리고 몇개 없는 API만을 갖고 상태 저장소(store)를 앱에 도입할 수 있었다. 그리고 최근에 성능 이슈를 겪으며 알게된 API 하나가 있는데 @observable.ref 라는 것이다. redux 를 사용할 때 immutablitiy 를 지키며 코딩해야하는 것과 비슷하게 쓸 수 있는 API 이고, 내가 지정한 상태값(변수)에만 필요(입맛)에 따라 dynamic 하게 쓸 수 있어서 상당히 유연한 API 였다. @observable 은 default 로 @observable.deep 인데 할당한 변수를 모두 mobx 의 observable 객체로 변환을 하게 만드는 비용이 아주 큰 함수이다. 적은 양의 데이터는 현대의 대부분의 pc 에서는 체감하기 어려울 정도로 비용이 느껴지지 않겠지만, 실제로 1000개 이상의 배열 데이터만 되더라도 체감이 가능할 정도로 observable 변환 비용이 아주 크다. 이걸 간단히 해결해주는 게 바로 observable.ref 인데, mobx 로 프론트엔드 애플리케이션 상태를 관리를 하는데 모르는 사람이 있다면 꼭 알려주고 있다. 실제로 코딩할 때도 배열 안의 요소의 속성에 직접 접근하여 값을 바꾸는 코딩 방식은 좋지도 않고, 잘 쓰지도 않았기 때문에 처음부터 @observable.ref 를 쓰면 되는 것들이 너무나도 많았다.

쓰다 보니 mobx 찬양하는 글이 되어가고 있음을 느끼고, 다시 이 회사에서의 프론트엔드 업무로의 확장에 대한 얘기로 다시 돌아간다. 그렇게 어렵게 진입장벽을 넘고 나서는 다른 프론트엔드 개발자분보다 내가 해당 프로젝트에서의 프론트엔드 개발을 하는 양이 훨씬 많아졌다. 다른 분은 다른 프로젝트에 투입되어야 했기에. 그래도 es6 이상을 쓰며 자바스크립트의 참맛과 재미를 느끼며 코딩을 하는 것이 즐거웠다. 그래서 아직도 해당 프로젝트의 유지보수/운영을 하며 리액트를 개발하고 있다.

이젠 단순히 객체의 값을 복사하여 하나의 새로운 객체로 만들기 위한 꼼수로 var b = JSON.parse(JSON.stringify(a)) 같은 건 하지 않아도 된다는 걸 알고 있단 자체가 재미있다. (저 코드는 어디선가 볼 때마다 내가 js를 하나도 모르던 그 때를 떠올리게 한다... ㅋㅋ)

### 백엔드 : 원래 업무

백엔드는 원래의 내 업무였기 때문에 다른 업무를 하게 됐다 하더라도 소홀히 해서는 안 되는 성역과 같은 영역이다. "인프라/프론트 하느라 백엔드 못했어요"라는 생각과 말은 스스로 나를 평가하기에도 미천하고도 쓸 데 없는 것이었다. 사실, 이 회사에 오기전엔 Spring boot 로는 개발을 한 것은 입사 전 toy project 가 전부였다. spring boot 에서 대부분의 것들을 "알아서" 해주니까 몰라도 된다고 생각했던 것들이 너무나도 많았다. 뻔한 레퍼토리처럼 controller, service, repository 를 만들며 그냥 코딩하면 된다고 생각했다. 그렇게 도메인/비즈니스 로직/서비스 레이어/객체지향 등등을 다 무시하며 온갖 getter/setter 가 난무한 코드를 만들고 있었다. 지켜보시던 CTO 께서 보다보다 못 참으셨는지 코드 리뷰를 해주기 시작했다. 사실, "이렇게 하면 안 된다"라는 위주의 리뷰여서 "그렇다면 어떻게 해야 하는 지"에 대한 인사이트는 많이 얻지 못했지만, 퇴근 후 짬짬이 읽었던 Effective Java 와 Clean Code 책을 읽고 나서부터는 다른 개발자분들도 "이제 코드가 읽힌다"는 평가를 해주시는 수준까지는 되었던 것 같다. 그 이후에도 지속적으로 "좋은 코드"에 대한 갈망과 팀 내에서의 받는 좋은 자극들(코드 리뷰 포함)로 인해 리팩토링을 계속 하고 있다.

사내의 복잡한 네트워크와 NFS 를 마운트해서 쓰는 시스템 덕에 (NFS 가 잘못은 아님) 특정 조건(환경)에 걸리면 NFS 쪽이 병목구간이 되고 있었기 때문에 이 NFS를 떼어 내기 위해 s3로의 online(no-down-time) migration을 하는 업무도 있었는데, 이 때 spring webflux 를 이용하여 도입을 했고(많은 반감과 우려가 있었지만 어느정도의 막무가내와 사내의 reactive 개발을 지향하는 다른 개발자 - 아까 언급했던 안드로이드 개발자 - 를 믿으며 도입을 했다), 파일들을 마이그레레이션 하면서 DB에 저장되어 있는 file path 를 수정하는 작업을 할 땐 처음으로 spring batch 를 써보았다. 우아한 형제들의 유명한 이동욱님의 spring batch 정리 글이 많은 도움이 되었다. 그러나 마이그레이션 이후 DB 에 저장된 path 는 바뀌었는데 실제로는 s3로 이전(업로드)이 되지 않은 파일들이 발견되기 시작했고, 원인을 추적해보았다. 원인은 어설프게 도입한 spring webflux 였다. 비동기-논블로킹 방식의 코딩은 디버깅, 예외 처리, 로깅 등이 동기-블로킹 방식에 비해 좀 더 쉽지 않다고 알려져 있긴 했던 것 같은데, 예외 처리를 잘못하여 모든 Request 에 대해 HttpStatus.OK 를 return 하도록 잘못 코딩을 해놨던 것이 문제가 된 것. 곧바로 제대로 된 예외 처리를 추가하고, 하는 김에 손쉽게 reactor 에서 retry 하는 로직을 구현할 수 있어서 같이 도입을 하고, 곧바로 또 다른 batch 프로그램을 작성했다. aws-s3-sdk 에서 제공하는 API 와 spring batch 를 이용하여 구멍 난 파일들을 모두 s3로 이전시키는 데 성공했다. 이 과정에서도 "잘 모르고 쓰는 것"이 얼마나 위험한 일인지 다시 한 번 깨닫게 되었고, 이 사건(?) 이후로 약간 보수적/방어적인 코드에 대하여 고민하며 코드를 짜게된 것 같다. 약 100만건이 넘는 이미지 파일을 spring batch 를 이용하여 마이그레이션 한 경험은 spring batch 를 좋아하게 된 계기가 되었다.

얼마전엔, 컬럼 수가 60개가 넘는 테이블을 새 시스템을 위한 새 테이블로의 실시간에 준하는 마이그레이션을 하기 위해서도 spring batch 프로그램을 짰는데, (사내에서는 나 빼고는 batch 프로그램을 별로 좋아하진 않는 것 같지만) 이 과정에서 mysql 의 auto_increment 에 hole 이 생기는 원인도 알게 되고, 이를 해결하기 위한 몇가지 workaround 를 조합하여 원하는 방식의 데이터 동기화를 구현하였다. mysql 에서 default value 가 auto_increment 이면서 PK인 컬럼과 별도의 unique constraint 를 가진 컬럼이 있을 경우 "insert into ~ on duplicate key update" 구문을 쓸 때, "replace into", "insert ignore into" 구문을 쓸 때, 일단 duplicate 가 발생하면 auto_increment 는 미리 증가한다. auto_increment 는 값이 작아지지 않고 증가함을 보장하기 위한 것이지 sequence 를 보장하기 위한 것은 아니기 때문인데 이 부분에 대해서도 간과하며 지내고 있었던 것이다.

여튼 개발을 하면서 알아야 할 것들은 너무나도 많은 것 같다. 그렇기 때문에 여러명의 개발자가 필요하고, 서로서로 지식을 공유하는 건 중요한 것 같다. 특히, 시간이 지나면 지날 수록 정확하지 않은 기억이 뇌에 깊이 자리매김을 하게 되는 경향이 있는데, 이런 경우 개발자들끼리의 불필요한 논쟁이 생기기 때문에 그런 불씨는 빨리 꺼뜨리는 게 장기적으로 좋은 것 같다.

지금은 "참조 기반의 데이터 조합 모델"이라고 부를 수 있는 '어떠한 것'을 개발하고 있는데, 머리는 아프지만 각 구현단계마다 성취감은 좀 높은 편인 것 같다.

그러고보니 올해 2월 쯤엔 Python 으로 Apache Spark 를 이용하여 elasticsearch log 기반으로 문자열을 parsing 하여 사내의 데이터팀이 필요한 데이터로 가공하여 mysql에 저장하는 프로그램의 추가 기능을 개발하기도 했는데, spark 로 본격적인 개발을 하게 된다면 상당한 양의 공부가 필요할 것 같다.

### 컨퍼런스 : Naver Deview, Okky TDD

작년에 처음으로 개발자들이라면 다 가본다는 Naver Deview 에 갔다. 그 다음주에 Okky 에서 주최한 TDD 컨퍼런스에도 참석했다.

앞으로 한.. 3년동안은 웬만한 자발적 관심이 생기지 않고서는 컨퍼런스를 다니지 않을 것이다. (이유는 여러가지...)

### 잘 하는 것을 더 잘 하고, 못하는 것은 잘 하도록

못하고 있는 것 : TDD, Test coverage, 좀 더 효율적인 알고리즘 등등

특별한 일이 없다면 여러 이유로 앞으로 이 회사에 x년 y개월은 더 다닐 계획이다. 그리고 내 꿈은 full time remote developer 인데 (github, gitlab, pivotal 등등 회사에서 일 해보고 싶다) 그 꿈을 실현하기 위해 지금 잘 하고 있는 것은 더 잘 할 수 있도록하고 못하는 것들은 잘 하도록 하며 지금 회사의 발전과 나의 발전의 맥을 같이 할 수 있도록 부지런히 건강관리도 하고 공부도 좀 해야겠다.

 

끄읕.

반응형