개발자 연봉이 올랐어요!

넥슨에서 쏘아올린 개발자 연봉인상이라는 공이 전체 업계에서 요동을 일으키고 있다. 분명 작년 말에 연봉 협상은 이미 끝났는데, 자고 났더니 연봉이 1,000 ~ 2,000이 급상승하는 마법같은 한해를 시작하신 분들이 많다. 개인적으로 한국 게임 업계는 높은 노동 강도에 비해 낮은 연봉으로 악명이 높았다. 오죽 게임쪽 개발자들의 꿈과 희망이 네이버나 카카오로 이직하는 것이라는 말이 나왔을까. 많은 분들이 이번 조치로 꿈을 이루기 위해 희생했던 각자의 연봉도 함께 찾는 시발점이 됐으면 좋겠다.

시작은 게임 업계에서 출발했지만, 이제 주류 기업들이 개발자 연봉 인상에 동참했다. 어느 분야든 마찬가지지만 숙련된 인력은 사실 많지 않다. 엔지니어링 부분, 특히 개발 분야의 숙련된 엔지니어는 경험만이 아니라 현재(대)의 기술을 사용할 수 있어야 한다. 때문에 연륜과 꾸준한 학습과 적용 능력을 갖춘 사람들이라고 본다. 당연히 이런 사람들의 분포는 정규 분포의 끝자락에 있겠지.

한쪽에서 이런 사람들을 땡기기 시작하면 결국 제로섬 게임이 되버린다. 개발과 코딩을 제대로 할 수 있고, 원하는 것(Business)를 이해하고 만들 줄 아는 사람과 함께해야지 일이 돌아간다. 특히나 코로나 이후로 촉발된 비대면 사회에서 해볼 수 있는 사업 기회는 온라인으로 시작해 오프라인으로 이어지는 모델이 주류다. 그만큼 시작점을 만들어줄 수 있는 사람들이 시대적으로 절실한 상황이다. 고무줄처럼 늘릴 수 있는게 아니라 정해진 파이 크기다.

나눌 크기의 파이가 아니니 결국 남의 것을 빼앗아 올 수 밖에 없다. 그리고 합법적으로 쟁취할 수 있는 가장 좋은 도구이자 무기는 “큰 보상“이다. 소프트웨어 개발자라고 하더라도 이 사람들이 어떤 도메인에 있는지에 따라 이미 처우가 달랐다. 보상의 불균형의 시대에서 더 많은 자원을 확보하기 위한 보상이 치솟고 있다. 자본주의 시대는 모두에게 동일한 평평한 운동장을 제공하지 않는다는 것을 안다. 그 운동장에서 열심히 달리고 있는 1인으로써 금전적인 높은 고지가 존재할 수 있다는 것 또한 새롭다. 하지만 뭔가 좀 불편하다.

엔지니어링 마인드

작년말부터 현재까지 개발자의 몸값은 말그대로 “금값”이다. 코로나와 함께 비대면/온텍트라는 새로운 시대가 열렸다. 새로운 시대는 새로운 기회다. 이 기회를 잡을려면 개발자가 필요하다. 금값이 될만하다.

자 그래서 개발자분들은 어떨까? 톡까놓고 이야기해서 지금이 기회다. 처우와 보상의 개선 찬스를 놓치고 싶은 사람은 없다. 더 좋은 처우를 제공해주고, 개발자라는 이력만 있으면 이직할 수 있다. 와중에 모셔가겠다는 곳이 줄을 선다. 맘에 들지 않는다면? 이곳에서의 연봉을 Stepping stone 삼아서 더 높은 보상을 제시하는 곳을 뛰어 오를 수 있다. 모든 건 협상이다!

개발자가 역량 혹은 능력으로 평가받기보다는 협상으로 평가받는 시절이 지금 시절이다. 좋은 개발 역량을 가진 사람보다는 현재의 시장은 개발을 할 수 있는 사람이면 “역량”은 충분하게 생각하는 듯 하다. 요즘 환경에서는 좋은 협상 능력이 좋은 개발과 성장에 대한 욕구보다는 훌륭한 개발자의 역량이지 않을까? 와중에 2년 혹은 3년 사이에 이직을 두번만 할 수 있다면 아마도 보상은 수직 상승할 것으로 기대한다.  2~3년 전의 역량과 능력은 동일한데 연봉이 두 배로 뛴 친구를 본적이 있다. 만나면 흥미로운 주식과 투자 이야기를 전해준다. 개발 이야기를 할라치면 그건 걍 하면 되는거 아니냐고 말한다. 음… 머… 그렇지.

 

닷컴 버블의 재현

국내 개발 환경은 2000년대 초반에 맞이한 닷컴 버블의 효과를 오래동안 겪었다. 물론 요즘 취업하시는 분들이 90년대 후반 세대가 있으니까 뭔 호랑이 담배물던 시절 이야기인지도 모르겠다. 세월이 참 빠르긴 하다.

재미있는건 오늘의 IT, 개발 활황기와 닷컴 버블의 시점이 아주 많이 닮아있다는 것이다. 당시에도 인터넷 광풍이었고, HTML로 웹 페이지만 만들 수 있어도 개발자로 인정받았다. 지금보면 웹 페이지 쪼가리 정도인데도 불구하고, 성공적인 투자를 이끌어낼 수 있는 아주 호시절이었다. 4 ~ 5년정도 대유행의 시절이 있었다. 많은 젊은이들이 IT의 장미빛 미래를 당시에 보았다. 너도나도 개발에 뛰어들었고, 대학에서도 유래없는 전산 관련 학과의 정원이 늘었고, 인재들의 지원이 있었다.

하지만 버블이었다는 것이 판명되었다. 수많던 스타트업들이 버블이 터지면서 사라졌다. 일로써 이 분야에서 일확천금을 노리던 사람들의 자리가 순식간에 사라졌다. 회사들과 개발자들은 생존을 위해 소위 막노동판인 SI 업계로 향할 수 밖에 없었고, 저가 수주 경쟁과 낮은 임금에 시달리게 되었다. 소위 “제대로 된 개발자가 없다!“는 말이 이 시점부터 나오기 시작했다. “제대로 된” 개발자들은 안정적인 직장을 향해 네이버와 다음(현 카카오)로 향했고, 그럼에도 꿈을 이루고 싶은 사람들은 자신이 원하는 곳에서 버텼다.

젊은이들의 꿈의 이상향이었던 IT는 더 이상 그들이 원하는 곳이 아니었다. 3D라는 단어가 이들 머리속에 각인되기 시작했고, 함께 대학, 대학원의 전산 관련 지망자들이 급격히 줄어들었다. 학교는 취업이라는 학생들의 당면한 문제 해결을 위해 기본보다는 응용에 초점을 맞춘 교육 과정을 제공했다. 문제가 문제를 야기하면서 결국 시장에서 “제대로 된” 개발자, 특히나 신입 개발자를 찾기가 더욱 어려워졌다. 도대체 Process와 Thread의 차이를 묻는 질문이 언제까지 유효한 면접 질문이 되어야 할지 궁금하다.

앱을 통한 새로운 기회가 나타나기 시작하면서 다시금 이 분야에도 서광이 비치기 시작했다. 하지만 이미 10년 가량의 시간이 흘러버렸다. 개인적으로는 다행이고 산업적으로는 불행이겠지만 대략 이 10년 동안 제대로 된 개발 기초 교육과 성장을 위한 기회를 제공받은 개발자를 찾기가 매우 어렵다. 2021년 현재의 나이로 보면 38 ~ 45세 사이 구간 정도? 하긴 한국의 개발 문화에서 이 나이에 개발한다고 하면 좀 이상하게 보긴 한다. 경력자 면접에서 TDD, Microservice architecture, RESTful 등을 질문하면 근본을 기대한 답을 못한다. 경험을 갖춘 시니어가 끌어줘야 하지만, 되려 이론으로 무장한 주니어에게 가름침을 받을 상황이다. 노땅이 무조건 잘해야 한다는 이야기는 아니니 오해말자.

이전 세대의 10년 공백은 버블과 함께 터져버린 기대, 밤샘을 강요하는 과도한 일정과 사람 갈아넣기, 정당하지 못한 대우 등등이 겹치면서 발생했다. 기존에 있던 사람들은 이 길을 포기하고 치킨집 창업의 길로 뛰어들었고, 사회 생활을 시작하기 위해 준비하는 학생들은 전산 전공을 기피했다. 똘똘하다면 당연히 의대와 한의대였다. 빈자리를 채워주는 사람이 없으니 존버모드가 가능했다. 정말 꿈만 같았던 40대 개발자의 모습을 현실에서 실현하고 있으니까. 물론 성장은 정체됐고, ActiveX에 기대긴 했지만 IT 강국에서 소프트웨어는 빈사 상태가 되고 반도체만 남았다.

현재의 시점에 갖는 우려는 개발할 줄 아는 사람, 즉 경력자만 찾는다는 것이다. 쉽게 이야기하면 신입을 뽑을 이유가 사라져버렸다. 빠르게 만들어서 치고 나가야 하는 시간 싸움에서 갓 대학 졸업한 사회 새내기를 가르칠 수 있겠는가? 보상은 경력자 위주로 돌아가고 그들의 리그가 되며 그 Pool에서 제로썸 게임이 이뤄진다. 그나마 큰 기업이라는 네이버와 카카오마저도 “코딩만 할 줄 알면 뽑는다!“는 구인 광고를 내며 저인망식으로 경력자만을 쓸어담았다. 물론 최근에 신입 사원을 다시 뽑겠다고 이야기를 하긴 했지만. 저인망식으로 경력 개발자들을 싹쓸이하는 모습이 훌륭한 모습이라 생각되진 않는다. 부디 이번에 새로 뽑는 새내기 개발자들을 잘 성장시켜줬으면 마음도 바래본다.

우려되는 모습은 새내기로 시작할 수 있는 제대로 된 회사들이 많지 않은 현실이다. 결국 전산 전공자들이 성장하면서 자신의 가치를 키울 수 있는 자리가 한정된 상황이다. 그 자리를 얻지 못한 친구들이 생길 것이고, 이런 모습은 후배들 혹은 Computing, Programming 분야에 대한 학생들의 의욕을 저하시킬 것이다. 다른 이유긴 하지만 몇 년의 시간 후에 새로운 피는 없어지고, 버티면 이기는 세상에 한번 더 오지 않을까 우려가 든다

요즘의 이 흐름이 버블때와 마찬가지로 일시적인 흐름일지 혹은 건강한 생태계로의 자연스러운 전환인지 알지 못한다. 시간이 이야기하주겠지. 지금의 30대 초반의 개발자가 10년 후 나랑 같은 생각을 하는 일은 없었으면 한다.

보상의 유리 경계

보상은 외부에서 봤을 때 사람을 평가하는 일종의 측정값이다. 두루 좋은 역량을 갖춘 개발자(혹은 엔지니어)도 역시 좋은 보상을 받는다. 아니 받아야 한다. 그럼 개발자들의 역량 분포는 어떻게 될까? 왜곡되지 않았다면 정규 분포를 따라갈 것이다. 경력과 개개인의 역량등을 두루 고려했을 때 이 분포 곡선을 따라가는 것이 어느 정도 합당해보인다.

그렇다면 보상은 어떨까? 당연히 능력이 뛰어난 인재는 그에 합당하는 보상이라는 대우를 받아야한다. 반대로 능력이 대비해서 비교되는 사람이라면 낮은 금액이 주어지는게 우리가 살고 있는 자본주의 논리다.

자 그렇다면 지금과 같은 개발자이 몸값이 금값인 현재는 어떤 모습일까? 분포와 보상 그래프를 겹쳐보면 딱 아래 그림과 같지 않을까?

능력에 따라 이뤄지던 합당이 보상의 그림은 아이러니하게 사라진다. 보상을 능력이라는 기준으로 환산해서 개발자 분포를 다시 보면 아래 그림과 같다.

소위 능력있는 개발자들이 모두 마지막 구간에 몰려있다. 경력직을 채용할 때 이전 회사에서 받는 그 사람의 연봉이 그 사람의 능력을 평가하는 측정값이 된다. 이정도 받는 사람은 이 정도의 능력이 되겠지!? 하지만 이렇게 또이또이 몰려있는 상황에서 정말 그 사람이 원하는 능력을 보여준다고 확신할 수 있을까? 기술 면접에서 잘 걸러주겠지? 글쎄다.

두번째 문제는 능력과 성과에 대한 보상이다. 성과와 의미있는 결과를 만들어낸 사람에게는 적절한 보상이 있어야 한다. 월급은 상시 비용(Cost!)이다. 회사는 계산에 능숙하고 상시 비용을 줄이길 원한다. 고로 회사의 총 보상은 월급과 인센티브가 적절한 조화를 추구한다.  조화로운 비율이 어찌됐던, 주는 쪽보다는 받는 쪽에게 연말 한방 인센티브는 보상 관점에서 매우 큰 의미를 갖는다. 많은 인센티브를 받기 원한다면? 성과가 좋을 것 같은 알짜 프로젝트를 고르자. 물론 그 중에서도 때깔나게 표나는 일을 해야한다. 물론 그 프로젝트에 참여하기 위해서는 좋은 인적 네트워크를 활용해야 한다. 인센티브 잘 받을려면 여의도 정치를 회사에서도 잘 해야한다.

웃프다.

자본의 불균형

현재 닥친 상황에 가장 난감한 분들은 이제 개발자들이 필요한 Business를 시작한 분들이 아닐까 싶다. 현실을 놓고 보면 같이 할 파트너 가운데 개발자가 반드시 있어야 한다. 없다면 낭패다. 요즘처럼 귀한 몸이 되버린 개발자분들 가운데 이 좋은 조건들을 포기하고 가시밭 길을 걷겠다는 분을 찾아야 하니까.

좋은 개발자를 못나가게 붙잡을 수 있는 회사는 자본이 있는 회사다. 줄만큼 돈이 있어야 하니까. 네이버, 카카오, 삼성? 아 쿠팡이랑 현대도 있겠구나. 결국 좋은 개발자를 많이 보유하고 사업적인 다양성과 유연함을 보여줄 수 있는 회사는 돈이 있는 회사다.

새로운 뭔가를 해볼 중소, 중견 기업들은 앞으로 새로운 아이디어에 도전해볼 기회조차 잡기 어려운 상황이 올 것이다. 온/오프 Mix가 앞으로 몇 년 사이의 주류 사업 모델인데, 온라인을 구현하지 못하면 결국 말짱 도루묵이다. 결국 팀을 만들 수 있겠지만, 좋은 팀으로 발전하는 건 더욱 힘든 도전일 것이다. 재원의 수준에 따라 결정된 팀은 결과와 성장의 균형보다 오직 “결과” 그 하나에 집중할 것이다. 슈퍼스타가 있다면 그 사람이 해결할 것이고, 없다면… 글쎄. 잘 모르겠다. ㅎㅎ

문화따위는!

자본주의를 살아가는 1인으로써 돈은 중요하다. 나를 포함한 모든 개발자에게도 마찬가지다. 개인으로 보자면 그렇지만 조직으로 봤을 때는 어떨까?

누구나 이야기하지만 혼자 만들 수 있는 Product 혹은 서비스는 없다. 결국 팀이고 협업이다. 건강한 조직의 협업이 그만큼 성과를 낼 수 있고, 그만큼 양질의 서비스를 만들어낸다고 믿는다. 그리고 이를 지탱해주는 것은 암묵적으로 “우리는 이렇게 일한다.” 라는 조직의 문화다. 소통하고 토론하고 결과를 만들어내기 위해 주장하고 양보하는 것이다. 그것이 문화다.

돈이라는 요인이 이 과정에 들어오게 되면 참으로 난감하다. 누구나 좋은 평가를 통해 좋은 보상을 받고 싶다. 이건 결국 이기적 동물인 인간의 본성을 드러낸다. 숨기고, 상대방을 꺽고, 너의 것은 틀렸다고 이야기한다. 이게 말이 되나 싶긴 하지만 인간은 이기적이다. 어떤 면에서 보면 동물보다 더 동물적이다. 보상을 위해 결국 결과를 만들어낸다. 과정이야 어떻든. 건강한 조직일까? 서로 경계하고 헐뜯는 사이에 만신창이로 병들어 있을 것이다.

개발자로서 정신적인 고통받지 않으면서 즐겁게 일하기 위해서, 은퇴 이후를 넘어서 개발로서 일할려면 좋은 문화의 회사에 있는게 좋다. 개인적으로. 물론 어느 정도 위험을 감수하고 주식 대박의 길을 가겠다면 그것도 물론 응원한다. 해볼만하다. 하지만 있는 문화까지 망가트리면서 보상을 추구하지는 않았으면 좋겠다.

 

이번 기회가 기울어진 운동장이 어느 정도는 자리를 잡는 기회가 되었으면 좋겠다. 포털, 게임, 그리고 SI 분야를 포함해 역할과 능력 그리고 노력에 부합하는 개발쪽의 보상 체계가 잡혔으면 한다. 그리고 닷컴 버블의 10년 공백이 제로썸 게임을 통해 되풀이되지 않길 바란다.

직장인인 개발자는 당연히 결과를 만들어내야 하고, 당연히 회사는 이걸 요구해야 한다. 다만 개인의 성장은 당연히 회사의 성장에게 큰 밑거름이 된다는 사실도 잊지 말았으면 좋겠다. 큰 회사와 작은 회사 각각에서 할 수 있는 영역이 있을 것이고, 그것들이 모여지면 좋은 개발자 사회를 만들어낼 수 있지 않을까 싶기도 하다.

– 끝 –

 

Updating AWS CodeDeploy agent

DNS 서버 설정 변경 때문에 프로세스들을 재실행시켜야 했다. 서비스 프로세스는 별 문제가 없는데, 구시대적인 Code Deploy 체계는 예외다. 이건 음… 마찬가지로 재실행시켜줘야 한다. 아니라면 ec2 instance를 rebooting 시키던가. 하는 김에 업데이트까지 해보자.


sudo service codedeploy-agent status
sudo service codedeploy-agent stop
sudo /opt/codedeploy-agent/bin/install auto
sudo service codedeploy-agent start
sudo service codedeploy-agent status

크게 이상이 없다면 stop하는데 약간 지연이 있고, 나머지 과정들은 후다닥~ 처리될 것이다.

당시에는 이것밖에 없어서 이걸 사용했지만, 쓸만한 것들이 AWS Seoul Region들에 들어오고나니 적폐가 되버렸다. 후다닥 적폐 청산을 해야하는데 말이다.

2021년의 계획 – 오바하지말자

“내년에는 뭘할까?”를 고민했던게 얼마 전인 것 같은데 벌써 그 내년의 2월 중순을 지나고 있다. 벌써 한달이나 훌쩍 지나갔네. 연말에는 새로운 기술적인 시도에 대한 꿈과 진취적(?!!!)인 프로젝트에 대한 구상도 있었다. 한달이 지나 전반적인 플래닝을 팀과 해보니 이것 또한 과하다… 라는 생각이 든다. 인간이 가진 욕심은 어쩔 수 없는가보다. 버리자고 했지만 제대로 버려지지 않는다. 원래 그런 인간이 바뀔리가 없지. ㅋㅋㅋ

팀들에는 1년 계획을 분기별로 세워달라고 요청했다. 어정쩡한 수의 구성원들이다보니 내가 다 챙길수도 없다. 다 챙길려고 딱 한번 시도해봤지만, 역시 되도 않는다는 것을 실증했다. 원래 팀의 크기는 정해져있는데 그걸 넘어서 뭔가를 할 수 있다고 생각하는 건 오바다. 쪼개고 나눠서 위임을 했다고 했다. 그럼에도 직접 챙겨야 하는 사람들이 10명 가까이다. 많다…

1년 단위 계획을 세우는게 의미가 있나? 음… 솔직히 1년 계획을 세워서 그대로 실행된다고 절대 믿지 않는다. 연초에 만든 1년 계획을 곧이 곧대로 실행하는 것도 맞는 건가? 이게 맞다면 정말 엄청난 예지력이다. 이런식이면 와 계획을 세우라고 했을까? 팀장이 팀원들에게 갑질한건가???

팀에 요청한 연간 단위 계획은 “마일스톤(Mileston)” 개념으로 수립해달라고 했다. 물론 알고 있다. “마일스톤”이라… 거창하다. 그 이상의 세부적인 계획은 당장 필요없다. 365일짜리 Gantt Chart를 그리는 부질없는 짓을 할 이유는 없다. 딱 4Q(작대기 4개)의 시간 공간에서 팀은, 우리는, 무엇을 원하는지를 알고 듣고 싶었다. 원하는 것과 필요한 것의 사이를 매꾸는 역할. 그거이 아마도 매니저의 역할 아닐까?

계획은 계획일 뿐이다. 그럼에도 계획은 필요하다. 그래야 우리가 향해할 방향으로 키를 잡을 수 있으니까. 우리는 “라이엇 코리아”라는 배가 성취할 목표를 향해 나아갈 Direction이 필요하다. 필요한 계획은 방향성만 제시하면 된다. 바람이 불고 비가 오는 상황에서 뭘 해야하는지 그 상황이 답해줄 것이다. 그 방향으로 “성취“하고 “성취” 할 것이고, 그리고 개인과 회사 모두가 원하는 목표에 도달할 수 있다. 언젠가는.

원하는 건 “성과“가 아니라 “성취“다.

“오바하지 말자!”

올해 팀에 강력하게 주문한 문구다. 작년에 많은 일들이 있었고, 어렵게 해쳐서 2021년을 맞았다. 아직도 어려운 시국이고, 몸과 마음을 회복했다! 말하기 어렵다. 아니 불가능하지 않을까?

때문에 나아감에 있어서 “성과”를 추구하기보다는 “성취”를 달성하길 희망한다. 작은 성취가 모여서 나의 자신감이 되고, 다시 이것들이 모여 조직/팀/회사에 보탬이 된다라는 순리를 믿는다.

– 끝 –

 

Test is always right.

Coding을 하면서 많은 것들을 고민하지만, 테스트만큼 고민스러운 것도 없다. 논리적으로 도움되고, 유지보수를 위해서라도 반드시 필요하다. 하지만 빨리 만들어서, 고쳐서 내보내야 한다는 심리적인 압박감이 강해지다보니 넘어가자. 바쁜데… 라는 합리성을 부여해버린다. 그래놓고 장애나면 급 후회를 하긴 하지. 언제나 그렇지만, 코딩/개발 단계의 시간보다 장애 대응하면서 보내는 시간이 훨씬 길다.

개발자의 입장에서 테스트는 반드시 필요하니 꼭 작성해두길 바란다. 한번 쓰고 버릴 일이 아니라면 말이다. 개인적으로 TDD 애찬론자이기도 하고, 테스트의 가치에 대해서도 백퍼 공감한다. 하지만 타협을 요구하는 현실이 당장의 우리의 현실인 것도 부정 못한다. 그 안에서 타협점을 찾아내고, 올바른 길로 개발자를 이끄는게 좋은 개발 리더가 아닐까 싶다.

글을 쓸려고 보면 사설이 길다. ㅋㅋ

Java coding을 하다보면 써야하는 테스팅 프레임웍이 JUnit이다. 이전 포스팅에서 5가 나왔다는 이야기를 했지만, 실제로 사용해보니 4보다는 확실한 버전업이 된 것 같다. 특히 Spring framework과 결합된 단위 테스트 속도를 확실히 보장할 수 있는 점이 체감되는 것 같다.

0. Performance

이전 JUnit에 비해서는 테스트 실행 성능이 좀 빨라진 느낌이다. 기분탓인가? 성능상에 영향을 미칠 수 있는 변경점은 Java8 이후부터 지원하는 Lambda가 보편적으로 구현에 사용됐고, 여러 라이브러리들로 쪼개져서 지금 내가 사용할려고 하는 테스트에 필요없는 모듈들을 런타임에 로딩하지 않는다는 정도? 뭐 이 두가지만 효과적으로 다뤄준다면 빨라진 걸 이해할만한 것 같기도 하다.

상세한 변경 점들에 대한 설명은 Major difference page에서 확인할 수 있다.

1. Enhanced unit testing in the spring-framework

확실히 스프링과의 통합은 JUnit4 보다는 개선된 것 같다. 특히 단위 테스트 측면에서. Spring project에서 테스트하다보면 내가 만드는 테스트가 Unit test인지 Integration test인지 헷갈린다. 특히나 실행시킬때보면. 겁나 느리다. 이렇게 느리면 단위 테스트 작성할 맘이 안생긴다. 걍 한방에 Integration Test로 검증하고 말지… 하지만 Integration Test는 상황 제어를 Mocking 가지고 하는게 아니기 때문에. 짜기 싫어지는 경우가 더 많아진다. (그러다가 걍 포기. ㅠㅠ)

JUnit5와 결합된 Spring-test에서는 이 부분을 완전 속시원히는 아니지만, 이전보다는 훨씬 더 개선된 형태로 사용법을 잡아줬다. 설정의 구태의연함이 있지만, 그럼에도 이제 Controller 수준에서도 Mocking을 활용한 단위 테스트를 제대로 작성할 수 있다.

@ExtendWith(SpringExtension.class)
@Slf4j
public class ValueV3ControllerUnitTest {
    @MockBean
    ValueService valueService;

    @InjectMocks
    ValueV3Controller controller;

    MockMvc mvc;

    @BeforeEach
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(controller)
            .addFilter(new CharacterEncodingFilter(Charsets.UTF_8.name()))
            .build();
    }

    @Test
    public void shouldQueryByKeyContainFederatedInfo() throws Exception {
        // given
        final String givenKey = "1111-2222-3333-4444";
        final Value value = Account.builder()
            .key(givenKey)
            .identities(Arrays.asList(new String[] { "google" }))
            .build();

        given(valueService.value(givenKey))
            .willReturn(account);

        // when
        mvc.perform(get("/api/v3/value/" + givenKey))
            .andExpect(status().isOk())
            .andExpect(content().json(new Gson().toJson(value)));

        // then
        verify(accountService, times(1)).value(givenKey);
    }

JUnit4 기반의 spring-test의 경우에는 Controller 테스트를 실행할 때 테스트와 무관한 다른 초기화 모듈들(Filter 혹은 Configuration 객체들)이 실행되었다. 인간적으로 지금 코딩할 부분도 아닌 부분에 뭔가를 해줘야 하는 것도 좀 찜찜하다. 하지만 그것보다도 더 짜증났던 건 테스트 실행 시간이 5초 혹은 10초 이상 걸리는 경우가 생긴다. 특히 그 초기화 블럭에서 JPA와 같은 부분이 있다면 상당히 시간을 잡아드신다. 수정하고 빠르게 테스트를 돌려서 확인하고 싶은데 이렇게 시간 걸리는게 쌓이면 전체 단위 테스트를 돌리는데 5분 이상도 걸린다. (거의 10년 다되가지만, 네이버때 테스트 돌리는 시간이 5분 가까이 되서 빡돌뻔!)

여기 설정에서 핵심은 아마도 이 부분이지 않을까 싶다.

@BeforeEach
public void setup() {
    MockitoAnnotations.initMocks(this);
    mvc = MockMvcBuilders.standaloneSetup(controller)
        .addFilter(new CharacterEncodingFilter(Charsets.UTF_8.name()))
        .build();
}

Controller 자체를 standalone 방식으로 초기화하고, 동작중에 필요한 filter 부분도 선별적으로 추가할 수 있다. 실제 서비스에는 해당 필터가 들어가겠지만, 당장 테스트할 부분은 로직에 대한 부분이니 집중해서 테스트를 작성할 수 있다. 필터에 대한 테스트가 필요하다면 그 부분만 따로 단위 테스트를 작성하면 되니까.

2. Nested: grouping tests with a purpose

하나의 객체에 여러 책임과 역할을 부여하지 말자라는게 아마도 OOP 좀 해봤다라는 분들의 공통된 의견일 것이다. 하지만 객체는 객체다보니 외부와 상호 작용할 수 있는 2~3개의 Public Method 들은 필수다.

각 method의 구현을 진행하면서 계속 단위 테스트를 추가한다. 하나 구현을 완료하고, 다음꺼를 구현할 수 있다면 좋겠지만, 객체 상태라는게 한 메소드에 의해서만 좌우되는거는 아니니까. (그래서 역할을 명확하게 해서 객체당 메소드의 개수를 줄이는게 필요하다.) 구현하는 객체의 메소드야 그렇지만, 이에 대한 테스트는 뭔 죄냐? 객체의 상태 변경에 따라 methodA, methodB 에 대한 테스트가 한 테스트 클래스에 뒤죽박죽 섞인다.

예전에는 methodA에 대한 테스트 케이스가 여기저기 널려있는게 보기 싫어서 경우가 많아지는 경우에 아예 테스트 클래스 자체를 분리했었다. 사실 이것도 나쁜 대안은 아닌 것 같다. 단점은 테스트 대상 클래스를 초기화하는 과정이 중복되거나 뭔가 빠지는 부분이 생긴다는거. 이걸 극복할려면 대상 클래스를 초기화하는 Builder 혹은 Factory 클래스를 테스트 패키지쪽에 만들어줘야 한다. 이론적으로는 백퍼 맞는 이야기지만 흐름을 잃지않고 메인 로직의 개발을 이어가고 싶은 사람의 입장에서는 맥 끊어버리는 일이다.

@Test
public void shouldTwoIdentities_WhenDefaultValueAndFederatedIdentityExist() {
    // given
    DefaultIdentity identity = RiotIdentity.builder().defaultValue("default").build();
    givenAccount.setDefaultIdentity(identity);
    final List givenIdentities = Arrays.asList(new String[] { "google" });
    givenAccount.setFederatedIdentities(givenIdentities);

    // when
    final Account actualAccount = V3Factory.create(givenAccount);

    // then
    assertThat(actualAccount.getIdentities().size()).isEqualTo(2);
}

@Nested
@DisplayName("Flat Tests")
class FlatizeTest {
    @Test
    public void shouldMakeFieldsFlat_ForGovtFields() {
        // given

        // when

        // then
    }
    ...

“@Nest” annotation은 그 관점에서 한 테스트 클래스에서 여러 테스트들을 관심 그룹에 맞춰서 묶을 수 있는 기능을 제공한다. 테스트 대상 객체에 대한 초기화 부분도 물론 공유할 수 있을 뿐더러 하나의 상태 변경 요소가 다른 메소드의 동작에는 어떤 Break를 줄 수 있는지도 바로 확인할 수 있다. 깨지면 어느 부분이 어떻게 깨졌는지도 계층 트리를 통해서 직관적으로 확인할 수 있다는 건 덤이다.

근데 좀 get/set 하는 함수 좀 그만 만들었으면 좋겠다. 경력 10년 20년 다 되가는 분들도 이런 식의 naming을 하던데, 정말 안타깝다. 객체의 state change를 유발하는 동작을 일으키는 method일텐데, 그 동작이 set 혹은 get 이라는 동사로 시작하지는 100% 아닐텐데 말이다. 생각이라는게 싫은건지 아니면 영어로 된걸 읽어본지 한참이 지나서일 것이다.

3. DisplayName

Test method 이름을 어떻게 할지를 결정하지 못했다면 요 annotation을 활용하면 좋다. Super natural language를 이용해서 달아둘 수 있다. 물론 가급적 테스트 메소드 자체에 대해서 DisplayName을 다는 건 바보같은 짓이라고 생각한다. 개발자라면 당연히 테스트 메소드의 이름이 테스트 의미를 가지도록 해야 나중에 테스트를 수정하더라도 이름을 맞게 고칠테니까 말이다. 이건 테스트 메소드말고도 서비스단의 메소드 이름을 짓는 경우에도 마찬가지다.

하지만 이게 쓸모있는 경우는 위에서 이야기했던 “@Nest”와 같은 보조 도구들과 함께 사용할때다. Test Grouping을 하거나 정말 부가적인 설명이 필요한 경우에, 이를 설명하기 난해한 경우가 있다. 이 경우에 활용하면 뱅뱅 헷갈리지 않고 테스트를 읽거나 실행하는 사람이 그 결과를 해석하는데 헷갈리지 않을 것 같다.

라이엇게임즈 코리아에서 개발자분을 모십니다.

라이엇게임즈 코리아에서 개발자분(들)을 모십니다.

백엔드 개발자 채용 공고가 나가긴 했지만, 아무래도 “한국의 퍼블리싱 조직에서 뽑는 개발자가 하는 일이 뻔하지 않아?” 라고 생각하시는 분들이 많으실 것 같습니다.  이렇게 이야기하는 것에 대해 십분 공감합니다. 대부분의 글로벌 게임 회사의 국내 법인에서 개발이라고 하는 것들의 대부분이 퍼블리싱 용도의 웹 개발이 전부인 경우가 허다하니까요.

하지만 라이엇은 좀 다르지 않을까요?

네, 단언코 이야기하는데 라이엇 게임즈의 한국 개발팀은 다릅니다. 한국 개발팀에서는 한국에 특화된 플랫폼 서비스를 개발합니다. 게임을 직접 개발하지는 않지만, 운영을 지원하기 위한 필수 시스템들을 개발합니다. 여러분들도 아시다시피 한국의 법률 환경은 타 국가에 비해 보다 엄격한 규격 준수를 요구합니다. GDPR을 표방하는 유럽보다 더 강력한 규정을 정의하고 있습니다. 또한 한국만의 PC방 문화는 독특한 비즈니스 모델을 가능하게 합니다. 물론 한글의 다양성은 플레이어간의 채팅에서 여타의 머신러닝조차도 떨게 만들죠.

한국 개발팀은 이와 같은 한국만의 특징을 글로벌 시스템과 통합될 수 있도록 관련된 서비스들을 개발하고 글로벌 개발팀과 협력합니다. Microservice Architecture 기반의 서비스 개발을 지향하여 빠르고 유연한 시스템 개발을 진행하고 있습니다. AWS 및 자체 IDC를 통한 서비스 배포 및 운영 능력을 갖추고 있으며, 여타 게임 혹은 인터넷 포털에서 경험해보지 못한 대용량 Traffic을 무중단 서비스하는 환경에서 서비스를 개발합니다. 물론 국내 법규를 최대한 준수하면서 다양한 사업을 지속 가능하게 지원하기 위해 DI(Dependency Injection)와 IoC(Inversion of Control) 기술은 기본 덕목으로 활용하고 있습니다.

물론 퍼블리싱 조직이기 때문에 웹과 관련된 기능도 지원합니다. 대부분의 퍼블리싱용 웹 개발은 협력 파트너를 통해 개발됩니다. 한국 개발팀은 이렇게 개발된 웹 컨텐츠들이 담당 비즈니스 매니저의 결정에 따라 자동으로 퍼블릭 환경에 노출될 수 있는 환경을 개발합니다.

한국 개발팀에서는 다음의 분야에서 일해주실 개발자분을 모십니다.

  • Loyalty service(Full Time, Backend) – PC방 비즈니스를 위한 혜택 시스템 개발
  • Accounts serivce(Freelancer, Backend) – 한국 계정 운영 시스템 개발
  • Frontend Engineer(Freelancer) – 한국 계정Mobile Store 기능 개발

Backend 엔지니어는 각 3년 이상의 경력과 Java 개발과 관련된 기본 역량이 필요합니다. 물론 객체지향과 SOA 개념은 필수입니다. Freelancer분은 1년(혹은 6개월, 본인 희망에 따라)이 기본 계약 기간입니다. 프리랜서분께는 경력 대비 업계 최고 대우를 해드릴 예정입니다.

아래 기술들은 현재 라이엇 코리에서 활용하고 있는 기술들이며, 해당 기술들에 익숙하거나 경험이 있다면 강점이 되실 수 있습니다.

  • Reactive Java
  • Kafka and asynchronous stream processing
  • Docker and K8S
  • NoSQL (MongoDB, DynamoDB 등)
  • ReactJS, Redux, Recoil, Jest and Serverside Redering
  • AWS 전반

라이엇게임즈 코리아에서 과감한 행보를 보여주실 분들의 많은 관심과 지원 부탁드립니다. 프리랜서로 지원하실 분들은 지원시 “프리랜서 지원“을 꼭 표시해주시기 바랍니다.

 

퇴사하는 친구와의 Farewell

센트럴 친구랑 업무 이외로 콜을 하는건 참 드문 일인데, 퇴사라는 이유는 더욱 낯선 것 같다.

떠나는 친구는 업무적으로 인연이 좀 있는 친구다. 회사의 고난과 역경의 시기가 2016년에 찐하게 있었다. 정말 미국 본사와 다방면에서 찐하게 불편하게 지내는 시절이었다. 그 시기의 한복판에서 한국팀과 미국팀의 일원으로 태평양을 사이에 두고 심각하게 불편한 사이였으니까. 미국팀 친구들한테 너네가 와서 좀 느껴봐라 이야기를 했더니, 정말 왔다!!! 일주일 남짓 사이에 많은 이야기를 나눴고, 소주도 많이 먹었다. 이메일과 Conference call로만 떠들던 서로의 차이에 대해 완전한 이해는 아니지만 적어도 차이가 있다는 걸 알게는 됐다. 그리고 문화와 환경의 차이를 본인들이 단기간에 메꿀 수 없다는 것도 알았다. 차이를 인정하고, 서로가 어떻게 Player Focus를 해야할 지 방향을 잡은 다음부터는 일이 착착 진행되었다. 이전과 같은 충돌도 더 이상은 없어졌다. 한국팀이 하고자 하는 방향과 미국팀의 방향 사이에 절충점을 찾았고 서로 합을 맞춰가면서 썩 훌륭한 소위 콜라보를 했던 것 같다.

그 미국팀의 실질적인 개발자였다.

이후 미국 출장때면 항상 자리에 찾아가 얼굴도 보고, 지나가다가도 반갑게 인사를 했던 것 같다. 이 친구는 꾸준히 업무를 담당했고, 한국팀이 “도와줘~” 라고 이야기하면 어김없이 등장했다. 그치… 이러면 정말 친구라고 이야기할 수 있지. 그러고 보면 정말 친구였구나… ㅋ

인수인계하면서 솔직히 제일 컨텍스트를 잘 아는 너가 없어져서 솔직히 걱정된다고 우려를 전했다. 하는 만큼, 아는 만큼 끄집어내서 다음을 책임질 친구에게 넘겨준다고 했다. 이 친구도 이야기를 했지만 머리속에 있는거랑 마음속에 있는 거랑은 분명 다르다. 심정적으로 이해하던 친구가 아닌 머리로 이해하는 다른 친구와 앞으로 일을 해야하는구나 생각하니 머리가 아프다. 아무래도 그쪽 일을 담당하는 친구는 골치 좀 썩겠구나 싶다.

젊은 친구다. 이제 30대 초반이다. 좋은 시점이고 Microsoft로부터 투자까지 받은 회사라고 한다. 새로운 시도를 하는 친구들이 항상 부러운 시절이다. 더구나 기존에 하던 분야와 다른 분야라니.

잘 해보라고 이야기했다. 잘 성장하고 자기 개발/발전 잘 해서 이 시절이 지나면 한번 얼굴 보자구 이야기를 했다. LA가 아니라 시애틀로 간다는게 함정이긴 하지만. 뭐 언제 시애틀 갈 기회가 있지 않을까? 되면 연락해서 얼굴보면 되겠지.ㅎㅎ

그나저나 내가 그 시점까지 과연 버틸지가 의문이네~~~?

콜 마지막에 그 친구가 끊기전에 한 말이다. 좋았다.

Bye bye, my friends~

Spring-security를 활용한 JWToken 인증하기

퍼블릭 환경에서 제공되는 API 서비스를 만들 때 가장 고민되는 부분은 보안이다. API가 제공하는 기능이 민감한 정보가 아니라면 개발자 입장에서 행복하다. 하지만 값어치가 나가는 유료 정보나 개인 정보 혹은 개인화 기반 정보가 제공되는 경우에는 고민이 깊어진다.

General Web Security

보안 정책을 웹 환경에서 구현하는 방법은 여러가지가 있을 수 있다. 보호 대상의 성격에 따라 다를 수 있고, 서비스 혹은 시스템의 연계성에 의해서 방법이 변경될 수 있다. 그럼에도 큰 맥락에서 2가지 기능으로 이 보안 정책은 구현된다.

Authentication

인증은 말 그대로 접근할려는 사용자 혹은 시스템이 맞는지 확인하는 절차다. 일반적으로 ID/Password를 이용한다. 요구되는 보안 사항이 높지 않은 경우, 이것만으로도 충분하다. 물론 이것보다 간단하게 생각되는 방식이 API Key 방식이다. 하지만 ID/Password나 API Key나 따지고 보면 같다. 개발자 관점에서 값을 하나를 사용할지 두개를 쓸지 차이뿐.

인증은 서비스에 접근한 존재가 누군지 알 수 있려준다. 여기에서 좀 더 복잡한 그 다음 프로세스를 원한다면 인증이 성공했다를 알려준다. 이 알려준 값은 권한(Authorization) 체크 용도로 활용될 수 있다. System vs. System 사이의 연동이라면 인증 처리만으로도 충분히 권한까지 함께 처리할 수 있다. 만약 사용자에 관련된 이슈라면?

Authorization

권한은 간단히 이야기하면, 인증을 요구하는 요청이 적합한지, 실행 권한이 적절히 부여되어 있는지 확인하는 절차다. Authorization이란 단어를 생각하면 “권한”을 먼저 생각하겠지… 하지만 현실에서는 올바르게 인증된 경우를 체크하는게 일반사다. 실제로 권한을 체크할려면, 권한 관리 시스템(모듈)을 통해 권한 클라이언트가 필요로하는 권한을 가지고 있는지 요청해야 한다. 권한 여부에 따라 True/False 결과만 확인하면 된다. 얼핏 이야기했지만 상당히 복잡하다. 복잡하다는 건 확인을 위한 Operation Cost가 많이 든다는 걸 의미한다. 그래서 이와 같은 권한 체크는 일반 사용자보다는 어드민 혹은 관리 시스템들에 한해 적용한다. 관리 시스템은 통상 내부망에서 동작하기 때문에 이런 복잡성을 굳이 가질 필요가 없다. 쉬운 방법을 충분히 찾을 수 있다.

결론적으로 일반 사용자, 그리고 대용량 사용자 대상 서비스의 경우에는 요청이 올바른 인증 정보를 포함하고 있는지만 확인하는 것만으로도 충분하다.

OAuth and JWT – JSON Web Token

이와 같은 인증 및 권한 관리 체계의 대표적인 모델이 OAuth 모델이다. 이를 구현하기 위해 적용된 기본 기술이 JWT이다. 예전에 JWT가 뭔지 어떻게 활용하면 되는지 정리한 글이 있으니, 더 궁금한 분이 있다면 참고한다. OAuth에 대해 안다고 주접떨기 보다는 아래 2개 링크를 참고하자.

  • https://ko.wikipedia.org/wiki/OAuth – OAuth wikipedia, 기본 개념정도는 이해 가능.
  • https://oauth.net/2/ – OAuth 2.0 standard

간단히 동작되는 Architecture를 머리 속에 그려보면 아래와 같다.

OAuth Authorization Architecture

간단히 그려보면 아래와 같은 일반 구조와 같다.

JWT를 만드는 역할을 Service에서 할 일은 아니지만, Authentication Service에서 만들어준 JWT 값을 가져오고, 올바른지 확인하는 역할은 Client Service의 역할이다. 헤더에서 이걸 가져오고 Public Key를 관리해서 이걸 검증하는 동작은 비슷한 패턴이다. 각 서비스에서 이를 구현하는 건 반복적인 코딩이 될 수 밖에 없다. 그래서 이걸 Spring-Security에서 좀 더 쉽게 할 수 있도록 지원한다.

 

Validating with Spring Security

자, 그래서 인증이 올바른지 체크하는 Spring Security 모듈을 처리해보자.

Maven setting

pom.xml

 

Configuration in Action

Configuration coding in the spring-boot project
이렇게 설정이 준비되면, spring 코딩을 마무리할 시점인갑다.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeRequests().antMatchers(whitelistedUriPatterns()).permitAll().and()
                .authorizeRequests().anyRequest().authenticated().and()
                .oauth2ResourceServer().jwt();
    }

    private String[] whitelistedUriPatterns() {
        return new String[] {
                "/health",
                "/swagger*/**", "/webjars*/**", "/v2/api-docs"
        };
    }
}

이렇게 처리하면 된다.

주목할 점은 특정 URI들의 경우에는 Load balancing과 내부 테스트등을 위해서는 별도의 인증을 타지 않도록 설정해야 한다는 점이다. 여기에서는 /health endpoint가 대표적이다. 만약 이걸 예외처리하지 않으면 L7 Switch의 경우, 설정된 endpoint가 비정상(401을 반환할 것이기 때문에)이라고 판단해서 Target group에서 이를 빼버리기 때문이다. 예제에서는 Swagger 관련 설정도 예외 처리를 했다.

application.yml

Configuration과 관련된 코딩을 반영했다면, 내부적으로 JWT Token의 Validation을 위한 Public Key endpoint를 추가로 잡아준다. spring.security.oauth2.resourceserver.jwt.issuer-url 속성에 Public Key가 존재하는 URL을 설정해주면 된다.

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://auth.games.com/public

 

물론 이렇게 하지 않고, 별도로 따로 Filter를 하나 만들어서 손수 체크할 수도 있다.

Authorization JWT handling

이렇게 설정을 하고 나면, JWT 객체안에 있는 특정 필드 혹은 객체 정보를 @AuthenticationPricipal annotation을 활용해 끄집어낼 수 있다. JWT내의 특징 필드를 끄집어낼때는 해당 field의 이름을 지정해서 추출한다. 아래 예제에서 subject라는 필드는 JWT의 기본 Claim에 포함된 sub 필드를 의미한다.

@PostMapping("/access/product/{productId}")
public SecurityAction verifyClientExecution(@AuthenticationPrincipal(expression = "subject") String id,
                                            @PathVariable("product") String product,
                                            @RequestBody SecurityInfo info) {
...
}

만약 JWT 전체 값을 참조하고 싶은 경우에는 아래와 같이 Jwt 클래스(org.springframework.security.oauth2.jwt.Jwt)를 파라미터로 지정해서 사용 가능하다.

 

Appendix

 

Hi~ there

새로운 시도라는 건 항상 두려움이다. 있던 틀 안에서의 나는 안전하다. 그 안전함을 벗어나 미지로 향하고 싸워야한다는 건 괴롭기도 하고 어떤 때는 정말 하기 싫다.

와중에 모든 일이 생각만큼 순조롭지도 않고, 별 생각하지도 않았던 곳에서 장애물이 튀어나마 마음도 괴롭고 몸도 괴롭게 한다. 요즘이 아마도 딱 이런 형국이다. 업무적으로도 개인적으로도.

아마도 살아오면서 성공보다는 좌절이 많았고, 그냥 주저앉아서 한걸음도 움직이기 싫은 적도 있었다. 마음대로 되지 않고, 하고 싶어도 할 수 없었다. 그럼에도 어떻게든 일어나 지친 걸음을 내딛었고, 정말 걷기 싫은 걸음을 내딛어 걸었다. 그래서 지금 여기에 있다.

Hi~ There.

어렵지만 그래도 가야겠지. 결론은? 글쎄 해피 엔딩일지 새드 엔딩일지 모른다. 그럼에도 다른 사람이 결론을 내주는 것보다는 성격상 내가 결론을 내는게 좋다. 부디 해피 엔딩이어야 하는데 말이다.

현실에서의 재택 근무

지난 3월 초에 재택 근무에 대해 간단히 글을 적었는데, 어느새 원격 근무를 5월 중반까지 해오고 있다. 회사 전체적으로는 2월말부터 원격 근무를 시작했으니 어느 덧 만 3개월을 다 채워가고 있다. 이 정도의 기간을 재택으로 지내다보니 얼추 이런 근무 형태도 할만하다는 생각이 든다. 업무만 봤을 때 해야할 일들이 거의 적절하게 진행되고 있는 느낌이긴 하니까.

재택 근무의 일상을 정리해보면.

출장을 못가다보니 본사쪽과 일은 지속적으로 챙겨야 한다. 슬랙으로 이야기가 잡다하게 길어질 것 같으면 아침에 콜을 잡지만, 그렇지 않은 경우에는 커뮤니케이션 하는 타이밍을 잘 잡아서 끊어지지 않게 해야한다. 말 그대로 이야기 줄기가 끊어지면 잊혀진다. 끊어진 걸 다시 이어 붙이려면 어렵기도 하고 투자해야할 시간도 많이든다.

그래서 아침 기상 시간은 재택 전과 비슷하게 6시 반이나 7시 사이를 유지한다. 전날 보내 둔 메시지에 대한 답글을 확인하고, 우리쪽 채널에 올라온 요청들이 있는지를 휴대폰으로 확인한다. 일상 다반사가 항상 바쁜 건 아니지만, 답을 얻어야 하거나 논쟁중인 사안이 있다면 후다닥 노트북 앞에 앉는다. 지금 내가 이야기를 던져야지 그 친구들이 답한다. 본사쪽은 오후 4시 근방이라 아직 일하고 있을 시간이다. 30분, 한시간 가량 본사 친구들과 이야기를 하고, 우리가 챙겨야 할 사항들이 있다면 관련 팀 채널에 내용을 전달한다.

출근 준비

8시 즈음에 시작하는 뉴스를 본다. 전에는 다음 뉴스에서 주로 새소식을 들었다면 재택 이후에는 YTN이다. 종종 쉬는 시간에도 가까이에 있는게 TV다 보니 정말 자주 보는 것 같다. 어제 발생한 코로나 이슈들을 중심으로 이야기를 듣는다. 참 세상 개념없는 인간들이 많다라는 걸 이번 사태를 겪으면서 다시금 확인한다. 국내, 국외 모두.

이쯤되서 와이프가 아침먹으라고 힘찬 소리를 들려주신다. 온라인 수업으로 등교해야만 하는 딸네미가 허우적 거린다. 처음 온라인으로 수업이 진행될 때만해도 짜증 대마왕이었다. 하지만 최근에는 동영상 스트리밍도 안정화된 것 같고, 한번 들은 수업을 다시 들어야하는 경우는 없어진 것 같다. (LG, MS 에저 화이팅!) 재택하면서 딸과 같이 밥먹는 시간이 많아졌다는 건 정말 좋다. 물론 전에도 아침은 매번 같이 먹긴 했지만 6시 반에 먹어야만 하는 아침밥이 딸에게 기분좋은 식사는 아니었을테니까. 온라인 수업 시간의 아침밥 먹는 시간은 8시에서 8시 반이다. 이정도만 되도 거의 짜증이 없었다. 전에는 왜 7시 반까지 등교하라고 한거지? 걍 9시까지 등교하라고 해도 충분할 것 같은데. 학교와서 책상에 코박고 잘께 뻔한 걸.

밥 든든하게 먹고 출근 준비한다. 양치하고 면도하고 샤워하고. 단장하고 근무복으로 갈아입는다. 이제 준비 완료!

완전 아재스럽다. 그렇다고 꽃중년도 아니니 걍 스킵. 부장님이 세미정장입고 근무하자라는 인터넷 짤을 보고 아이디어를 얻은 건 아니다. -_-;;; 하지만 넘 편하면 Naive해지는 건 어쩔 수 없이 부장님에게 동의. 전에도 이렇게 입었는데 걍 근무복이라고 생각하자. 사실 미팅하다보면 난닝구(메리야쓰???)부터 잠옷, 샤워 가운까지 다양하게 등장한다. ㅎㅎ; 일만 잘하면 되지, 복장은 편한 스타일대로 입는거지 뭐.

출근해서 업무 시작

회사에 출근했을 땐, 커피 머신에서 내려먹거나 바리스타분께 부탁드려 한잔 먹는게 습관이었는데, 그 습관 버리기 힘들다. 재택에서는 내가 바리스타.

이렇게 내린 커피는 전자렌지의 도움을 받아서 오후까지 먹는다. 물론 그 사이에 믹스도 두봉지쯤은 달달하게 타 먹지만. 막 내린 커피들고 이제 출근한다. 아드님께서 학교로 가버린 이후에는 아들 방이 내 근무처다. (탱큐~ 아들!) 좀만 제대로 된 공간이었다면 더 좋았을걸 하는 아쉬움도 있긴 하지만. 거실 한켠에서 쪼그려서 일하던 때보다는 한결 낫다. 9시 반에서 10시 사이에 자리에 앉아서 이제 본격적으로 근무를 시작한다.

오전 근무는 밤새 온 이메일들을 정리하고, 어제 퇴근 이후에 한국쪽에서 이야기된 내용들을 살펴보는 것으로 시작한다. 대부분 슬쩍 훝어보고 지나가지만, 간간히 참견해야할 내용들이 이메일로 온 경우가 있다. 필요한 것들에 대해서만 회신한다. 메일과 슬랙 훑어보는게 끝나면 이제 아침 데일리전에 해야할 코드 작업이나 할당 작업들을 한다. 데일리에서 공유할 내용들 대부분은 어제 해두긴 했지만 간간히 미진하거나 마무리 못한 꺼리가 있다. 아침 이 시간이 집중이 잘 되기 때문에 나름 일할만 하다. 마무리가 됐다면 Jira Ticket을 Done으로 marking한다.

데일리(Daily)

오전 근무의 하이라이트는 데일리(Daily)다. 에자일을 고집하는 분들이나 전문가들이 이야기하는 Daily는 아니다.Jira 보드 놓고 한일/할일 혹은 넋두리를 한다. 어찌보면 딱 아침 조회다!! ㅎㅎ

11시가 되면 5~7명쯤 개발팟 인원들이 행아웃에서 모인다. 가장 연장자 분이 BGM을 깔아놓으면 사람들이 모일동안 감상의 시간을 갖는다. 얼추 참석자들이 모이면 진행자가 순서대로 Jira 보드에서 담당자를 선택하면 업무 이야기를 공유한다. 오늘 할일이나 어제 겪었던/논의했던 이슈나 Blocker들에 대해 이야기한다. 진도를 많이 빼신 분은 Backlog에서 할만한 일이나 Sustaining꺼리를 물어본다. 동료가 봐줬으면 하는 걸 이야기하면 그걸 도와주거나 아님 팟 리드가 처리되어야 할 꺼리를 백로그에서 뽑는다. 두루두루 이야기하고, 마지막으로 팟 리드가 어떤 일들이 있으면 챙겼으면 좋겠다는 것으로 마무리한다.

형식을 보면 에자일식은 아니고 칸반 스타일인가? 오피스에서 모여서 이야기할 때는 15분안에 끝내는게 목표였고, 대부분 그 시간안에 마쳤던 것 같다. 하지만 온라인으로 진행하면서 전체 시간이 좀 오래 걸린다. 이건 꼭 데일리 뿐만 아니라 거의 모든 회의들이 오피스 미팅룸에서 모여서 하던 것보다는 전체적으로 길어졌다. 한번에 여러 사람이 한꺼번에 이야기할 수 없다는 제한이 있기 때문이기도 하고 같이 얼굴 맞대고 이야기할 기회가 없다보니 다들 한 두마디씩 더 하는 것 같다. ^^;

Work & Break in the afternoon

정리하고 데일리에서 나온 것들 가운데 바로 F/U해야할 꺼리를 봐주고 하다보면 12시다. 12시라고 꼭 밥 시간은 아니다. 하지만 2시간 정도 일했으니 쉬는 시간이 맞긴 하다. 닫혔던 방문 열고 거실로 나가서 가족들과 잠깐 이야기도 하고 새로 나온 코로나 확진자 수도 확인한다. 최근에는 거의 자리수가 한자리 수라서 다행이라는 생각이 든다. 하지만 백신과 확실한 치료제가 나오기 전까지는 끝나도 끝난게 아니라는거.

내가 때를 챙기지 않더라도 따님 덕분에 1시 되기 전에는 거의 점심을 먹는 편이다. 물론 삼시세끼를 다 챙기느라고 와이프 고생이 많다. 와중에 나는 미팅중, 딸은 온라인 수업중이라 와이프만 쥐죽은듯이 거실이나 침실에서 꼼짝도 못한다. 얼떨결에 같힌 신세가 되버렸다. 원래 집에서 낮시간은 와이프의 공간과 시간이었는데, 난데없이 딸과 내가 이걸 빼앗아버렸으니…

점심 먹고, 커피 한잔 후 다시 문닫고 업무 복귀. 데일리를 빼고 하루에 보통 1~2개의 미팅이 있다. 한국팀과 미팅은 거의 한시간을 꼬박 채운다. 참석하는 사람도 좀 많은 편이고 사람당 두서너 마디 이야기가 돌고나면 훌쩍 1시간을 채우는게 다반사다. 미팅 끝나고, 메일이나 슬랙 메시지 보내다보면 두시간쯤이 훌쩍 간다. 거북 형상으로 목이 뻣뻣해질 때쯤이면 거의 3시 근방이다. 쉴때다.

오후에는 한두번쯤은 아파트 주위를 3~4번쯤 돈다. 3월부터 거의 빼먹질 않았다. 덕분에 시간이 이렇게 가고 자연이 이렇게 변해가는걸 눈으로 본다. 그 전에는 제대로 느끼지 못했던 새로움이다. 그러고보니 겨울의 끝자락에 이 생활을 시작해서 이제 여름으로 접어든다.

산보에서 복귀 후 다시 일을 시작한다. 대강 요 무렵이면 집안일의 갱킹이 들어온다. 5시나 6시 근방이면 쓰레기를 버리거나 분리 수거에 관련된 업무 요청이 들어온다. 잘 보여야 후환이 없기 때문에 정 급하지 않으면 바로 처리해야 한다. 그래도 이 시간 타임이 가장 일을 많이 하는 시간대다. 2~3시간 연속으로 몰입해서 일할 수 있는 시간이 많다. 최근 2~3주 사이에는 코딩 이외의 다른 행정 업무들이 많아서 이런 시간을 갖기가 어려웠는데, 대강 마무리해서 다시 코딩에 복귀하고 있다. 이렇게 중간에 쉬어버린 시간이 많으면 예열에도 시간이 오래 걸린다. -_-;;; (몸은 못 속이나?)

퇴근

6시 반이나 7시쯤되면 따님이 “퇴근했어?“고 물어본다. 상황따라 약간씩 잔업이 있긴 하지만 대부분은 그 시간 즈음이면 슬랙 채널에 “퇴근합니다.” 라고 이야기한다. 슬랙 알람은 7시가 지나면 자동으로 Off된다. 바꿀 수도 있지만 굳이 그러지않는다. 일단 해야만 하는 일들은 처리했고, 해야할 일들은 Calendar에 적어두거나 Ticket으로 정리해뒀다. 이제 정말 놓친 일들이나 내가 하고 싶은 것들을 한다.

오후 내내 놓친 뉴스를 좀 보기도 하고, 못읽은 책을 읽는다. 책을 읽는다고 이야기를 해봐야 하루에 한시간 남짓이 될까말까다.

와이프와 딸과 저녁먹고, 최근 재미있는 드라마나 예능 보면서 이야기를 나눈다. 이전에는 가족과 이야기하는 시간이 평균 30분 넘을까 말까였다면 재택 이후로는 적어도 1시간 이상이 되니까 고건 참 바람직하다. 특히 딸과의 대화 시간이 많이 늘어난 건 개인적으로 기쁜 일이다.

 

재택. 하다보니.

일하는데 있어서 몇가지 보이는 것들이 있긴하다. 일단 준비된 재택 근무를 하기 위해서는 필요한 것들이 많다. 그 가운데서 가장 큰 문제는 가족으로부터의 동의와 협조가 무엇보다도 필수적이라는 것이다. 집에서 일하는 것에 대한 가족의 인식과 협조가 없다면 재택은 불가능하다. 특히 현재의 재택 상황을 봤을 때 더욱 그렇다.

챙김이 필요한 육아를 본인이 병행해야하는 상황에서의 재택은 불가능하다. 차라리 휴가를 내는게 본인의 정신 건강을 위해서 낫다.

커뮤니케이션에서 진심이 보여야 한다. 그래서 온라인 화상 통화에서 얼굴은 가급적 보여줘라. 정장을 입고 있으라는 이야기가 아니다. 말 그대로 얼굴을 보여주라는 것. 대화에서 표정과 제스처는 생각 이외로 많은 것들을 전달한다. 이건 수화에서 왜 표정이 중요한 역할을 하는지와 어찌보면 같은 맥락일 것이다. 한국팀은 그래도 본사 친구들과 콜을 많이 해서 기본적으로 얼굴을 보여줄 것이라고 생각했는데 이외로 거의 보여주지 않는다. 보여주지 못한다면 못하는 그것 자체에 문제가 있다. 육아 관련 예외를 빼고 나머지는 이유가 안된다.

명확한 근무 시간을 명확히 하고 알려야 한다.  본인을 위해서도 협업하는 동료들을 위해서도. 종종 재택이라고 근무 시간을 본인들의 작의적으로 정해버리는 경우가 있다. 근무 시간을 정하는 이유는 협업을 위해서다. 당연히 한국 상황만 놓고 본다면 9시부터 6시 사이를 근무 시간으로 정한 이유는 그 시간이 보편적으로 연락 가능하고 협업이 가능한 시간임을 모두가 암묵적으로 동의하기 때문이다. 메신저 뒤에 숨어서 페이크치다 걸리면 쪽팔린다. 재택이라고 하더라도 근무 시간이 변경된 건 없다. 가능하면 지켜야 하고 못지키면 이야기해서 협업에 방해되지 않도록 알려야 한다.

부재는 알려라. 오피스 공간에서 근무를 선호하는 이유는 고개 돌리면 동료가 옆에 있고, 이야기할 수 있기 때문이다. 온라인으로 일을 하는 경우에도 마찬가지 환경이 되야 한다. 오피스에도 자리 비운다면 자리 비운다고 동료에게 이야기한다. 마찬가지로 행동하면 된다. 재택이라고 다르지 않다.

팀을 생각해야 한다. 재택은 공간적으로 팀을 배제한다. 혼자있는데 뭔, 팀… 때문에 더욱 더 개인화된다. 같은 공간에 팀이 모여있는 공기와 자신만의 공간에서 느끼는 공기는 당연히 틀리다. 팀이 팀으로 느껴지는 이유는 공간적인 이유가 크다. 하지만 재택은 이를 분리한다. 이런 거리감을 인위적으로 줄일 수 없다. 강제로 줄여봐야 파열음만 난다. 스스로 팀원이어야 한다. 자발적으로 팀의 상황을 이해하고 팀의 발전을 위해 기여해야 한다. 정해진 일만 하겠다면 재택과 맞지 않는다. 아니 되려 팀 플레이 자체가 맞지 않는거 아닐까도 싶다.

••••••

재택은 팀 플레이를 시험한다고 보여진다. 공간으로 분리된 상황에서 개인이 팀이라는 인위적인 공동체를 유지할 수 있을 것인가? 이 과정에 스스로 있기도 하고, 결과가 어떻게 나올지 기대된다. 본사에서도 실패했고, 때문에 공간을 중심으로 팀을 유지하는 것이 현재 정책이었다. 이제까지 나도 이에 동감했고, 크게 바뀌지 않았다.

하지만 기대 이외의 결과를 보고 싶다. 당장 재난 형국을 넘어서기 위해서도, 그리고 먼 미래를 위해서도 ^^;

 

원격 근무(Remote working) – 꿈과 현실의 차이

2020년은 파란만장하게 시작했다. 그리고 3월의 어느 시점을 관통하는 지금 개인을 넘어 전세계적으로 “코로나19 바이러스“로 혼란의 도가니 안에 있다.

바이러스의 습격은 한국 기업에게 원격 근무를 선택지로 강요하고 있다. 한 공간에 사람이 모이는 것 자체가 감염의 근거를 제공하기 때문에 업무를 이어가기 위한 어쩔 수 없는 선택이 되버렸다. 몇 일 전직원 휴가를 쓸 수 있겠지만, 그 기간은 몇 일을 못 넘긴다. 감당이 된다면 직원들이 사장님 “쵝오!!!” 를 외칠텐데 말이다.

나도 현재 원격 근무를 시전중이다. 불가항력적인 몇몇 부서를 제외하고는 오피스에 속한 모든 사람들이 원격 근무를 하고 있다. 다른 팀들과 비교했을 때 개발팀은 해외 팀들과 그동안 협업을 해왔고, 그 팀들은 어떤 식으로 원격 근무를 하는지를 봤었으니까… 협업할려고 본사갔더니 이 친구가 원격 근무하는 친구라서 삼실에 안나온다는… 뱅기타고 힘들게 날라왔는데, 정작 만나는게 행아웃(Hangout)이면, 거참…

Nomad?

개발자라면 한번 쯤 원격 근무를 생각해봤을 것이다. 태국의 어느 한 동네에서 호젓하게 자신만의 코딩 세계에 빠져서 일하다가 무더위에 지칠 무렵이면 바다가에서 수영으로 스트레스를 날려버리는. 그리고 늦은 석양을 바라보며 PR 날리고 함께 즐기는 친구들과 바에서 맥주 한잔? 걍 생각만 해도 멋있네.

Financial Case Study: Kim and Ryan Desmond, CodingNomads

하지만 실상은 이렇지 않을까? 서로 갈린 시차로 오해가 생긴 슬랙으로 인해 팀원들과 오해가 쌓인다. 문자의 한계를 벗어나 화상 회의로 진행할려 했으나 화질은 뚝뚝 끊어지고, 웅웅대서 뭔 소리를 하는지 하나도 알아들을 수 없다. 와중에 원격에서 참가한 사람들이 많다보니 서로 이야기할 순서를 못잡는다. 결국 눈치보다가 해야할 이야기를 못하고 마무리된다. 이미 해는 저물어가는데 느려터진 VPN 때문에 PR을 날릴 수가 없다. 이럴거면 때려치라는 매니저의 얼굴이 아른거린다.

Culture of society

각자가 일하는 방식이 있기 때문에 원격 근무는 호불호가 갈린다. 특히 사회 분위기와 관련이 깊달까? 미국처럼 개인 문화가 발달한 곳에서는 원격 근무가 잘 받아들여진다. 개인이 해야할 일을 잘 해내기만 하면 된다. 다른 사람 일은 신경쓸 필요없이 계획된 일들 가운데 자신이 하기로 한 일만 잘 하면 된다. 이런 분위기에서는 원격 근무가 되려 더 좋은 결과를 낼 수 있을 수도 있다. 같은 공간에서 팀으로 일할 때는 업무 외적으로 시간이 소모되는 경우가 크니까.

이에 반해 한국처럼 조직을 우선시하고, 계층적 조직 문화가 발달한 곳에서는 원격 근무가 힘들다. 보고를 우선시 해야하고, 그 사람과 면대면으로 이야기를 해야 일 파악이 순조롭다. 팀이 빠른 협업으로 일을 해나간다는 측면에서 같은 공간에서 함께 일하는 방식이 더욱 효율적이다. 상대방의 얼굴보면서 하는 커뮤니케이션은 화상보다 몇 배는 더 좋은 결과를 만들어낼 수 있으니까. 더구나 슬랙이나 메신저를 통해 이야기를 하는 것보다, 잠깐 등돌려 이야기하는게 속도와 진정성(특히)에서 백배 낫다. 누군가의 뻘소리를 기록하기 위해서 메신저로 이야기하는게 정신 건강에 좋다고 말하지만, 그럴거면 그 사람이랑 일을 말아야지. 정신 건강까지 생각하면서 일을 해야하는거면 일을 안하는게 되려 정신 건강에 좋다.

그럼에도 출근 못한다

어쩔 수 없는 이번 원격 근무는 어쩔 수 없이 재택 근무를 해야한다.

나도 주말에 노트북들고 커피 가게에서 책읽고, 오랫동안 코드짜고, 블로그 글 쓰는걸 좋아하지만… 갈 수 없다. 못 간다. 집에서 어떻게든 일을 해야한다. 얼추 애들이 컷으니까 일하는데 별 지장없는 내 입장이만, 유치원이나 초등학교 다니는 애들이 있는 집은 애들도 함께 쉬고 있다!! 단언컨데 절대 애들이 간만에 집에 있는 아빠, 엄마를 가만두지 않는다. 이 좋은 기회를 어떻게 날릴까. 애들은 본인들은 방학이고 아빠, 엄마는 집에 함께 있는 휴가 기간인데. ㅋㅋㅋ 워킹맘, 워킹대디면 걍 휴가를 내는게 되려 이래저래 눈치 안볼 방법일 수 있다. 하지만 이마저도 쉽지 않은게 역설 ㅠㅠ;;;; 이건 한국만의 현실이 아니라 글로벌 이슈다. 애 있는 집에서는 원격을 못한다.

뭐 꼭 애들있는 집만의 문제는 아니다. 집이라는 공간은 원래 휴식을 위한 공간이다. 누구든 그 공간 안에서 열심히 일할려고 애쓴다고 하더라도 결국은 휴식의 유혹에 시달려야 한다. 소파가 나를 땡기고 침대가 나를 땡긴다. 거기다가 주말이면 항상 눈을 고정하고 있던 TV가 나를 유혹한다. 와중에 아무도 나를 열일하라고, 결과는 어디에 있느냐고 닥달해대는 사람도 없네!

이런 유혹들을 이기고 일을 해야한다. 직장인으로써 해야할 일은 있으니까. 그래서…

  • 집에 계신 분들께 선언을 해둬야 한다. 일하는 시간과 장소를.
  • 팀원들과 일하는 시간을 정한다. 소위 말하는 Core Working 시간을 정해야 한다. 시도때도 없이 연락오는 것에 매번 즉각적으로 응답할 수 없다.
  • 명확해야 할일과 해야할 일들을 스스로 관리해야 한다. 스스로 Loose해지면 망한다.
  • 인상 관리 측면에서 세수랑 머리는 감자.
  • 메신저보다는 화상 회의를 잘 사용할 줄 알아야 한다. 같은 언어권에서도 텍스트는 자칫 오해를 부르기 십상이다.
  • 애가 회상 회의에 갑자기 뛰어들면!!! 놔두고 아저씨, 아줌마들 얼굴 알아두도록 하자. 나중에 용돈 챙길려면 이번 기회에 용모 파악을 잘 해둬야 한다.

 

그래서 개발의 원격 근무는?

원격 근무는 서울에서 일하는 직장인에게 좋은 옵션이 될 수 있다. 당연히 여러 좋은 장점들이 있으니까. 출퇴근에 시간 안버려도 되고, 장소만 적절하다면 집중과 몰입을 만들어내서 더 효과적으로 일할 수 있을테니까. 시간을 조절할 수 있으니 소위 말하는 일과 삶의 균형(??)을 맞출 수 있을지도.

단, 팀의 속도와 성과를 저해하지 않는다는 전제가 담보되어야 한다. 같은 공간에 있음으로써 얻는 가장 큰 장점은 빠른 커뮤니케이션이다. 특히 요즘과 같이 소수로 팀이 만들어지는 경우에는 더욱 더 빠른 소통과 의사 결정이 중요하다. (아마도 이게 제일 중요하지 않을까?) 누구 한명이 커뮤니케이션을 함께 하지 못하면 그 사람을 기다려야하거나 혹은 없는 상태에서 진행해야 한다. 긴급하게 논의해야할 내용이 있어서 메시지를 보냈는데 그 사람이 10분내로 응답하지 않는다면? 그렇다고 찾아볼 수 있는 공간에 있는 것도 아닌 원격에 있는데. 커뮤니케이션이 담보되지 않은 상태는 팀의 업무 진행이 담보되지 않았다는 것과 어떻게 보면 같은 맥락이다. 개발자 3명 ~ 4명 정도가 최선의 개발팀이라고 생각할 때, 누구 하나 제대로 이야기에 어울리지 못하면 개인도 팀도 망가질 가능성이 크다.

Face-To-Face Communication: 6 Reasons to Lead in Person

그래서 혼자 일해도 되는 직종의 경우에는 이 방식이 더 좋은 개인적인 성과를 낼 수 있을지도 모른다. 하지만 개발자는 혼자 일하는 사람이 아니다. 최근에는 더욱 더. 혹자는 스펙만 정해지면 그거 개발하면 되는거지… 라고 이야기하는 사람들이 더러 있다. 가만보면 그런 사람들이 에자일, XP 이야기를 참 열심히 하는 것 같다. “함께 다 같이 잘 해보자!“가 에자일이지, “나만 잘 하면되지!“는 아니다.

원격 근무는 상당히 매력적이다. 그만큼 도전해야할 부분들도 많고. 좋은 방안을 찾을 수 있다면 좋겠다.

– 끝 –

 

참고 글