Bullshitting Blog

개소리하는 블로그

회고록 - 10. 미래

퀄리파이어에 대한 걱정은 산더미지만, 지금 난 나름 행복하다. 한국의 골문을 지킬 후배들이 4명이나 나타났다. 덕분에 난 은퇴 다음의 스텝을 고민하고 있다. 내가 할 수 있는 것은 무엇인가.

사실 난 내가 나이가 더 많고, 이미 더 성공해 있었으면 좋겠다는 생각을 자주 한다. 오키나와 오픈을 시작으로, 대회 준비에 집중하기 위해 퇴사까지 감행하는 수준의 열정있는 이들이 우후죽순 생겨나고 있다. 하지만, 그런 열정에 대한 보답을 해줄 수 있는 사람이 지금은 없다. 그들 스스로 헤쳐나가야 한다. 사실 그들이 퇴사할 때 나도 퇴사하고 싶었다. 하지만 이미 몸이 맛이 가고 있는 지금, 은퇴가 가까워지고 있음을 느끼고 있었고, 은퇴 후에도 기여할 수 있는 사람이 되기 위한 준비를 하는 것이 더 맞다고 생각했다.

꽤 많은 동료들은 지금 사회로 나오기 위해 알을 까는 시기에 있다. 불경기라서 계속 눈에 밟힌다. 나에게 이들을 지원하고 끌어줄 수 있는 더 큰 힘이 있었더라면 하는 아쉬움이 크다. 난 그런 역경들을 좀 일찍 맞이해서 괜찮은 경제 사이클 위에서 나름의 연착륙을 했지만, 이들은 지금 불경기 사이클 위에서 겪고 있다. 물론 모두들 강하고 능력있는 사람들이고, 충분히 이겨낼 사람들이다.

사회의 성인으로 성장하고 독립해서 자리를 잡기 위해 필히 수반되는 일들은 언제나 더럽게 힘들고, 불안하고, 자존심이 상하고, 우울한걸 알기에 좀 측은하다. 내가 지금 할 수 있는건 그저 그들이 안정될 때까지 믿고 기다리면서, 말하고자 하는걸 듣고, 말하기 싫은걸 묻지 않으며, 그들이 하고자 하는 일을 능력껏 돕는 것 뿐이다. 마치 내가 대학교 생활을 버텨낼 수 있도록 도와줬던 수많은 사람들처럼 말이다.

난 지금 가진건 별로 없지만, 어차피 라크로스에 인생을 빼앗긴 김에, 살면서 할 수 있는 최대를 해보고 싶다. 빼앗긴 인생이라도, 그 인생이 의미를 가지면 그만 아닌가. 그 의미를 준게 지금 동료들이다. 내가 가진걸 이용해서 내가 원하는 세상을 사고 싶다. 인간은 죽지만, 세상은 남는다. 내가 원하는 세상을 사려면 가진 것이 많아야 한다. 그러려면 많이 가져야 한다. 어떻게 많이 가질 수 있는지는, 머리로는 대충 안다. 이룰 줄 몰라서 문제일 뿐. 일단 월급쟁이로는 불가능하다. 하지만 뭐, 그건 나중에 가서 생각할 예정이다. 지름길따윈 없다. 지금은 그저 지금 할 수 있는 것을 하고 있다. 일단은 후배들의 열정을 사는 일을 시도중이다. 물론 선택은 후배의 몫이지만, 약간의 염원과 기대를 담아.

역경 탈출법

서론

난 삶의 등락이 뚜렷한 편이다. 그리고 지금은 낙의 시기에 있다. 건강이 무너지면서 브레이크가 제대로 걸렸다. 파열된 디스크만 회복하면 되는 줄 알았는데, 신우신염이 온 것도 모자라 폐에 물이 차더니, 코로나까지 꼽사리 껴서 협공을 당하는 중이다. 가히 나당연합군에 뚜드려맞는 고구려의 신세와 유사하다 할 수 있겠다. 이정도 신호는 모든 것을 멈추고 쉬어가라는 신호다. 물론 이런 낙의 시기는 처음이 아니다. 고등학교 때 한 번, 대학교 때 한 번, 사회초년생 때 한 번, 이미 총 3번 겪었고, 지금이 4번째다. 때문에 어떻게 헤쳐나가야 하는지 이미 알고 있다. 하지만 그와 별개로 역시 힘들긴 더럽게 힘들다. 뭐 그래도 이정도인게 어디인가. 암같은 뒤끝 지독한 질병이 아님에 감사하다.

난 보통 고난의 시기를 맞이하는 시점을 스스로의 선택이나 정신적 번아웃으로 맞이하기보다는, 몸이 못버텨서 얻어맞는 방법으로 맞이한다. 정확히는 인식을 그 시점에 한다는 것이 맞을 것 같다. 고등학교땐 위출혈, 대학교땐 신기능 저하와 혈뇨, 사회초년생땐 요로결석, 이번엔 신우신염이 그 시점이었다. 디스크 파열은 시발점이긴 하지만, 이때까지 난 완전히 낙의 시기라고 인식하지 못하고 있었다. 이때까지 그냥 쉬면 다 해결됐기 때문에, 그냥 두번째 요로결석처럼, 슥 지나가는 기우인 줄 알았다.

매번 이렇게 건강 문제로 무너지다보니, 하루이틀 사이에 급격히 안좋아진다. 대신 몸만 회복되면 알아서 잘 회복되는 편이다. 그리고 몸이 회복될 때 진행하는 일련의 과정이 항상 있었다.

1. 사람을 만나지 않는다.

안 괜찮은데 괜찮다고 하는 것도 일이다. 사람을 만나면 필히 그 이를 안심시키기 위해 에너지를 쓰게 된다. 그렇다고 안 괜찮다고 떠벌리고 다니는 것도 스스로에게 스트레스로 다가온다. 주변에도 스트레스를 전파하는 일이 될 수 있기 때문이다. 가장 가까운 몇몇에게 안 괜찮음을 알리고, 이후부턴 말을 아끼고 고독에 익숙해져야 한다. 그리고 고독을 즐기는 것은 후에 자신의 능력이 될 것이다. 내가 군자녀로서 잦은 이사와 이별을 유년시절부터 겪어 오며 단련되었듯 말이다. 혼자 있는 시간에 엄습하는 불안은 실체가 없고, 근거도 없고, 쓸모도 없다.

2. 생각하지 말고 몸이 이끄는 대로 생활한다.

자고싶으면 자고, 먹고싶으면 먹고싶은걸 먹는다. 억지로 생활 습관이니 뭐니, 보양식이 어쩌니 영양제가 어쩌니 요란하게 챙기지 않는다. 그런거 알아보고 계산하는 것이 더 스트레스다. 몸은 필요한게 뭔지 스스로 알고 있다. 이상하게 땡기는 음식을 놓치지 않고 먹는다. 난 이번에 아프면서 바깥 음식이 별로 땡기지 않았다. 몸이 알아서 염분을 거부하고 있었던 것이다. 그러더니 항생제를 먹기 시작하고 신우신염 증상이 완화하니 뜬금없이 닭강정이 땡기고 식욕이 올랐다.

보통은 자신을 망가뜨린 원인은 휴식을 하면서 차단되므로 이미 충분한 조치가 이루어졌다. 보통 사람의 의지력으로는 몸을 완전히 회복 불가능한 죽음의 사이클로 올려놓기 어렵다. 왠만하면 회복 사이클이 해결해 준다. 각종 생각은 버리고, 그저 조금 긴 감기에 걸렸다 생각하며 꿀같은 휴식을 온전히 즐겨야 한다. 자신을 믿어야 한다.

3. 집중력을 회복의 척도로 삼는다.

집중력이 크게 저하되어 있는 상태일 것이다. 하지만 이런 위기가 찾아온다는 것은, 그간 열심히 살았기 때문이다. 그렇게 살아왔던 관성에 의해 앞으로도 하고 싶은 것들이 산더미인 상태일 것이다. 하지만 몸상태는 이를 받쳐주지 못한다. 떨어진 집중력이 본인의 의지력이라 오판해서 자괴감이 들기 십상이다. 하지만 초조해 하지 않아도 된다. 이야기했다시피, 생각을 멈춰야 한다. 어차피 당장 안될거다. 악담이나 저주가 아니다. 팩트다. 어차피 안될 일에 스트레스 받는 것은 어리석은 짓이다. 그 일은 회복되고 나서 해도 전혀 늦지 않는다. 회복을 빠르게 하는 편이 더 이득이고, 회복을 가속하기 위해서는 불필요한 스트레스를 차단해야 한다. 대신 자신이 평소 좋아하고 재밌어하는 일들 중에서 기한없는 목표를 하나 정해 놓고, 하고 싶을 때 툭툭 건드려 보며 집중력을 체크하면 현재 상태를 진단할 수 있다. 스트레스도 받지 않으면서, 언제 자리를 박차고 일어나야 하는지 알 수 있다. 어느날 갑자기 의욕이 돋으면서 일을 손에 잡더니 시간 가는 줄 모르고 집중하고 있는 상태에 도달한다면, 몸은 스트레스를 다시 받아들일 준비가 되었다는 신호를 주고 있는 것이다. 그 일에 집중하다 보면 어느새 일상을 찾아가게 된다.

4. 인생에 대해 회고를 진행한다.

최고 속력을 내기 위해선 앞만 보고 달려야 한다. 때문에, 멈춰선 지금은 뒤를 돌아볼 절호의 기회이다. 이럴 때가 아니면 언제 뒤를 돌아보나. 그리고 이 과정을 통해 인생의 터닝 포인트가 생긴다. 회고를 진행하다 보면, 그동안 놓치고 있었던 것, 인생의 우선순위 등이 정리된다. 우선순위가 명확해지면 앞으로의 일에 있어 판단 기준을 세우는데 큰 도움이 된다. 때로는 성격까지 크게 변화하기도 한다. 회고는 언제 진행하면 되냐고? 3번이 힌트를 줄 것이다. 어느날 갑자기 하고싶어지면 하면 된다. 자신을 믿어라.

회복 후

회복이 되었다는 판단은 스스로 할 수 있을 것이다. 일상으로 복귀하고, 하고싶은 일을 하는데 거리낌이 없는 상태가 바로 회복이 완료되었다는 증거이다. 하지만, 비슷한 고난은 여러번 찾아온다는 것을 기억하고 있어야 한다. 사람이 사는 방식은 쉽게 변화하지 않는다. 내가 매번 건강 이슈가 터져서 더이상 앞으로 갈 수 없는 시점이 되어야 멈춰서는 것처럼, 같은 방식으로 또다시 고난이 찾아올 것이다. 왜 또 이런 시련이 주어지는가에 대해 한탄하지 말고, 그냥 “아 또 쉴 때가 됐군!” 하고 회복 사이클을 돌려라. 원래 반복된다. 그리고 그 때 제대로 쉬고 싶다면, 평소에 열심히 살아서 이럴 때 제대로 쉴 기회를 얻을 수 있도록 준비를 해두는걸 추천한다. 직장인으로서는 이번이 처음인데, 디스크 파열이라는 신호탄이 터졌을 때 팀에서 비로소 나에게 몰려 있던 버스펙터를 높이기 위한 급진적인 개혁이 이뤄졌다. 좀 늦어서 고생이긴 했지만, 그래도 그 개혁에 힘입어 이번에 완전히 무너졌을 때 휴가를 마음놓고 쓸 수 있었다(심지어 돌발적으로). 2년 근속 때 받는 리프레시 휴가를 라크로스 국제대회 때 사용하겠다고 1년 넘게 안쓰고 아껴 뒀던 것도 이번에 큰 도움이 됐다. 국제대회는 연차로도 충분하지만, 혹시 모를 일에 대비해 계속 쟁여뒀었다. 그 리프레시 휴가, 정말 리프레시하기 위해 사용하고 있다.

이 글이 올라왔다는 것은?

맞다. 난 지금 무사히 회복 중이고, 방금 집중력 회복이라는 강력한 신호를 받았다. 현재시각 새벽 3시 43분이다. 잠을 자다가 불편한 호흡, 흉통, 기침으로 뒤척이던 중, 갑자기 떠올라 글을 써내려갔다. 일단, 지금 매일밤 찾아오던 발열 증상이 멎었다. 잠을 청할 때만 해도 열이 났는데, 지금은 열이 내렸다. 이 시간에 쉬어도 모자랄 판에 왜 각잡고 글을 쓰냐고? 몸이 이끄는 대로 했다. 어차피 숨이 불편하고 열이 나서 잠을 잘 수 없는 상태였다. 이제 열도 내렸으니 다시 잠을 청하고, 눈떠지면 일어날 것이다. 이번 휴가는 이번주 내내이다. 강력한 회복 신호는 받았지만, 꿀같은 휴가를 더 신나게 누려서 확실히 회복할 생각이다.

Arch Linux를 사용할 때 각오해야 하는 것

오늘 아침에, 리눅스를 업데이트했다. 그리고 재부팅 하는 순간, 모니터 하나가 죽어버림.

리눅스 상에서 인식은 되고, 작동은 다 되는데, 한가지, 화면만 안나온다. 커널 업그레이드 과정에서 하드웨어쪽이 깨졌음을 알 수 있다. 참고로 업그레이드된 버전은 6.6.37-1-lts 이다.

그래픽카드 드라이버 재설치

  • 그래도 안됩니다.

롤백

  • 싫은뒈?

위의 이유로, 그냥 모니터 두개만 쓰는 중이다. 해결될 때까지 매일 업글 돌려야지.

아치리눅스를 이용한다면, 이건 각오해야 한다. 만약 모니터 세 개가 다 죽었다면, usb로 부팅해서 ssd 드라이브에 있는 커널을 롤백해줘야 하는데, 그게 아닌게 어디인가.

인생이 지루할 때 쯤이면 한번씩 안 지루하게 해줘서 좋다. (!@$#!$)

왜 계속 쓰는지 궁금할 것이다. 예전엔 재미있어서라고 답했을텐데, 지금은 그냥 남이 이해할 수 없는 재미의 존재에 대해 길게 설명하기 귀찮아서, 스스로를 변태로 간주하고 대충 넘기는 중이다.

죽은 FIX 라이브러리 살려내기

회사에서 리드 역할에 더 충실하기 위해 실제 작업은 팀원에게 넘기고 그 전에 계획하고 개발 후에 리뷰 및 관리하는 역할로 차차 넘어가고 있다.

이번엔 FIX 프로토콜을 개발해야 한다. FIX 프로토콜은 금융 거래에서 사용되는 하나의 표준 프로토콜이다. 처음엔 그냥 머리속에서, DMA 프로토콜을 개발하면서 짜내려간 코드를 재활용하면서, TagValue 인코딩만 구현하면 되겠다고 생각하고 있었다. 그런데, 실제로 팀원이 수행하도록 업무를 구상하려 하니, 가장 쉬운 방법을 고민하게 됨. 결국 FIX는 표준이므로, Rust 라이브러리 또한 존재했다.

문제는 이 라이브러리가 관리되지 않고 있다는 것이다. Rust 1.29부터 deprecated되는 문법들을 그대로 둔 채... 현재 Rust 버전은 1.79다. 결국 현재 사용이 불가한 상태다. 그럼 여기서 포기해야 하나 했는데, 사용법을 보니 너무 편해서 고치고 싶다는 생각이 들었다. 고치기만 하면, 개발 업무는 개꿀이 될 것이라는 확신이 들었음.

그래서 달려들었다. 매크로가 굉장히 많아서 디버깅이 좀 힘들긴 했는데, 그래도 새로 짜는 것보다는 분명 낫다. 오늘 약 2-3일쯤 되었는데, 역시 하다가 익숙해지니 속도가 붙어서 방금 끝났다. 꽤 재밌었다. 매크로를 이렇게 맛깔나게 쓰다니, 감탄하면서 고쳤다. 그냥 고친거 갖다 써도 되지만, 겸사겸사 오픈소스 기여도 할 겸 PR을 올려 뒀다.

통증 민감도 문제

2015년 겨울, 발목에 연골이 찢어져서 수술로 제거하고 뼈에 미세천공술을 받았었다. 마취가 깼는데, 진통제를 놓아 줄까요? 하는 간호사의 말에 아무 고민 없이 "아니요"라고 대답했다. 그냥 발목이 좀 삔 것 같은 느낌이었다. 물론 아무 생각 없이 발을 딛었다가 번개침.

2019년 가을이였나, 속이 안좋으면서 허리도 많이 뻐근해서 시름시름 하다가 밤에 잠을 잘 수가 없어서 응급실에 방문했다. 통증강도를 찍으라길래 6정도를 찍었다. 그런데 요로결석이었다.

2021년이었나? 또 요로결석이 발생했는데, 속이 안좋으면서 날카로운 통증이 옴. 하지만 재택근무로 일 다 했다.

2022년에는 허리가 좋지 않아 검사를 받았는데 요추뼈 몸체 모서리가 부러진 채 한참 지났다는걸 알게 되었다. 쉬몰결절도 있고, 디스크의 수핵이 완전 빠져나간 뒤였다. 뼈가 충격을 다 받는 바람에 허리 통증이 자주 발생하기 시작했고, 번개도 자주 쳤다.

딱히 치료가 안된다 하여, 그냥 버티다가 결국 올해 4월엔 문제되는 요추뼈 아래의 디스크가 터져버렸다. 4월이 맞나 싶긴 하다. 원인이 되는 날짜가 두개 정도 예상되는데, 어디서 결정적으로 터진건지 모르겠음.

3월 대회 마지막날에, 진통제 가지고 있는걸 다 털어먹고 경기를 뛰었다. 경기 다 끝나고 나서 긴장이 풀렸더니, 위가 꼬여서 급하게 가지고 있던 진경제를 먹음. 이후 일정 끝나고 파한 후 호텔로 가는데, 진통제가 풀리면서 허리가 끊어질 것 같은 느낌이 났다. 거긴 일본이었는데, 다짜고짜 약국을 찾아가서 진통제 코너 물어보고, 느릿느릿 일본어를 읽어가며 어떻게든 제일 쎄보이는 진통제를 사다 먹음. 아 이거, 신기한데, 일본의 소염진통제에는 카페인무수물이 첨가되어 있다... 자야 하는데? 그래도 일단 통증을 잡는게 우선이므로 약 먹고, 그날 잠 거의 못잠.

아 그리고 당시 새끼손가락도 부러져 있었는데, 의외로 이 손가락은 아무 느낌이 없었다. 그냥 땡땡하게 부었다. 한국 돌아와서 검사해보니 쪼개져 있었음. 올...? 허리 아프고, 손가락 부러진 와중에 회사 갈 것 다 가고, 훈련도 갔다. 그러다가 회사에서 한 번 더 체크메이트 당했다. 사무실에서 자리 이동을 해야 해서 PC를 다시 설치해야 했다. 책상 밑으로 들어가 앉아서 선을 꽂고 나서, 자리에 앉았는데, 뭔가 잘못되었음을 크게 느꼈다. 바로 퇴근. 이후 좀 나아지는 것 같던 허리통증이 다시 극심해졌다.

근데 그 와중에, 오른쪽 엄지발가락쪽 앞꿈치에 석회가 생겼다. 어릴 때 팽이를 밟았을 때 그 느낌이 났다. 가장 심할 땐 발가락이 터질 것 같았다. 하지만 역시 할 일은 다했다. 발날로 운전하고, 발날로 걸어다니고, 회사도 다 가고, 어떻게든 돌아다님.

결국 그러다가 한쪽 다리가 마비되어서, 좀비모드로 돌아다닐 권리마저 빼앗겼다. 다행스럽게도 쭉 마비된건 아니고, 완전 마비의 경우 일시적으로 한 1~2분 정도 발생했고, 그 이후엔 감각마비가 지속되면서 방사통이 발생했던 듯 하다. 근데 이 방사통도 원래는 많이 아프다고 들었는데, 오히려 방사통이 나한텐 허리통증보다 나았음. 그냥 탄산수에 다리를 담궈둔 듯한 느낌이었다. 감각마비 덕인가? 근데 일단, 이건 제대로 잘못된게 맞다는건 확실했다. 그래서 바로 가장 빠른 일정으로 MRI 촬영 진행. 파열 진단을 받았다.

통증 인식 체계 변경

이렇게 통증의 최대치가 통상적인 기준보다 아래인 상황에서 신체의 오랜 사용을 위해 캘리브레이션을 진행하기로 했다.

위의 사례 중 가장 큰 통증은 "번개가 친다" 혹은 "끊어질 것 같다"이다. 둘 사이에 우열을 가리기는 조금 힘들다. 왜냐하면 번개는 정신을 못차릴 정도의 큰 통증이 갑자기 훅 치고 빠지는 식이다. 순간 통증 자체의 크기는 제일 크다. 반대로 끊어질 것 같은건, 끊어질 것 같아서 못움직이는데, 최대한 덜 아픈 자세를 찾아서 안움직이면 또 괜찮음. 그래서 둘 사이에 우열을 가리기는 조금 힘들다.

이 번개가 치거나 끊어질 것 같은 통증은 이제 제대로 잘못되었다고 보고 병원 진료를 받아야 하는 것으로 이해하기로 했다. 추가로, 속이 안좋을 때인데, 난 이게 그동안 위염이라고 생각했다. 하지만 내시경은 깨끗함. 다들 있는 표재성 위염 정도? 이번에 허리 통증이 심할 때 속도 같이 아프거나 안좋아지는 현상을 발견해서, 속이 안좋을 때 또한 허리에 문제가 아닌지 감별해 봐야 하게 되었다.

다음은 욱씬거리는 통증인데, 주로 안에서 뭐가 터지거나 손상을 받아서 부을 때 발생한다. 추가로, 현재 디스크 회복기에 들어간 것 같은데, 가끔 무리해서 허리가 아프면 이런 박동성 통증이 온다. 허리에서 맥박이 뛰는 느낌이 남. 그리고 그건 바로 오늘이다. 재활운동 중에, 안전을 위해 허리 보조기 차고, 수건 말아서 허리 받치고, 스미스 머신에서 벤치프레스를 35kg로 했음. 위로 좀 던져지길래 괜찮은 무게인가보다 하고 그대로 12개씩 4세트를 했음. 이후 사이드 래터럴 레이즈를 하던 도중 허리 통증이 발생했다. 내생각엔 35kg를 한 것보다 35kg를 던지면서 한게 문제인 것 같은데, 혹시 모르니, 허리통증 회복 후 운동 땐 30kg로 던지지 말고 해야겠음. 아니 근데 몸통에 힘 하나도 안줬는데? 왜...? 뭐 여튼, 이런 욱씬거리는 통증은, 뭐되기 전에 경고하는 통증이라고 봐야 할 듯 하다.

다음은 뻐근한 통증이다. 이중에서도 묵직하고 둔탁하면서 불편한 느낌이 있고, 근육통일 때처럼 거칠게 당기는 느낌이 있다. 후자는 근육통. 환영. 전자는 통증 자체의 크기는 크지 않은데, 무시하면 안된다. 방사통이었다. Iliac crest, 꼬리뼈 위쪽 좌측 엉덩이로 통증이 주로 온다. 딱 L2, L3 척추신경이 연결되는 부위인 듯 함. 좀 더 진행되거나, 다리쪽으로 가면, 또 탄산수처럼 청량(?)한 느낌이 난다. 그런거 보면 아마 감각마비 때문에 다리쪽은 통증이 안 심했구나 싶다. 다만 이거, 평소에 올 때는 그냥 묵직하니 불편한 정도인데, 심하게 오면 마치 곧 폭발할 것 같은 느낌이 나서 움직이지 못한다. 끊어질 것 같은 느낌과 폭발할 것 같은 느낌의 차이는, 끊어질 것 같은 느낌은 아주 날카로우면서 속이 울렁거리는 증상이 같이 오는데 반해, 폭발할 것 같은 느낌은 말 그대로 폭발할 것 같은 느낌이다. 움직이면 마치 공기가 가득 차서 터질 것 같은 풍선을 발로 차는 듯한 느낌이 난다.

마지막으로 얼얼한 통증이다. 멍들면 발생함. 신경 안써도 됨. 물론 따가운 통증도, 보통 눈에 보이는 곳에 발생한 상처로 인한 것이므로 신경 안써도 된다. 근데 가끔 신기하게도 따가운 통증이 속에서 날 때가 있음. 지금 욱씬거리는 그 허리가 따가운 느낌도 같이 난다. 근데, 욱씬거리는 통증을 센싱할 것이므로 따가운건 무시할 예정이다.

이렇게 해서 나름의 통증 인식 체계를 만들어가야 할 듯 함. 못버티기 전에 알아서 중단해야 하는걸 알게 되었음. 심지어 다리 마비가 올 때까지 어떻게든 요래조래 돌아다니고 일상생활을 다한 것을 보면, 이건 꽤나 중요한 문제인 것 같다.

해당 문제의 득과 실

비가역적인 상태가 되고 나서야 문제를 알아채는 경우가 많다. 발목 또한, 연골이 찢어진지 2년이 지나서 알았고, 결국 수술로 제거. L3 모서리가 골절된건 심지어 도대체 언제 그랬는지조차 모름. 그래서, 의외의 문제가 있다. 상해보험 처리를 못받고, 이미 만성화가 다 진행되고 나서 생돈을 들이며 처치를 받는 편이다.

하지만 득도 있다. 인체는 어차피 소모품이다. 결국 언젠간 죽을텐데, 이때의 고통이 덜해질 것이기 때문에 꽤나 큰 득이다. 게다가 조금 더 핑계대고 나태해지는 방법으로 나름 건강도 찾을 수 있다. 감당할 수 있는 고통의 그릇은 큰데, 좀더 느긋하게 적은 통증을 느끼며 편안한 여생도 누릴 수 있으니, 일석이조임. 그걸 늦게 알아서 좀 고통받긴 했지만 ㅋㅋㅋ. 아 그리고 노인이 되면 어차피 여기저기 고장나 있을텐데, 이때 어떻게든 일상생활 누리기 스킬이 빛을 발할 것이다. 장수의 비결이다. 아니 근데 오래 살 생각은 없는데...?

허리 디스크 파열

L2-3 사이 디스크 회복 불가한 퇴행으로 인해 후관절증후군과 통증으로 고생하던 중, 결국 응당한 대가를 치르게 되었다.

예측된 결과이다. 다음 차례는 L3-4라고 했으니. 그 L3-4 사이 디스크가 결국 파열되어 왼쪽 다리로 가는 신경에 문제를 일으켜서 왼쪽 다리가 일시적으로 완전히 마비되었다. 다행히 완전 마비는 잠시 후 풀렸지만, 감각이 무디고 마치 탄산수에 다리를 담궈둔 듯한 느낌이 계속 났음.

지금은 약 6-7주째이다. 다행히 마비는 생각보다 빨리 회복되어 수술 없이 치료중이다. 다음에도 터지면 다시 3-4번이 될 예정. 3-4번이 2-3번처럼 되면 그 다음은 4-5번이 터진다.

디스크 파열로 인해 훈련을 못나가는 것은 물론, 운전, 대중교통까지 금지되었다. 직업적인 이유로 무조건 회사를 출근해야 했다면, 사실 휴직을 했어야 하는 상태. 하지만 다행스럽게도 재택근무 제도가 있어서 집에서 일하고 있다. 근데 프로젝트 마감 갑자기 땡겨저서 근무시간 치솟고 1시간 마다 누워서 찜질하던 루틴이 다 깨져서 회복 더뎌진건 안비밀 ㅋㅋㅋ. 다행스럽게도 마비 어느정도 회복되고, 좀 버틸만 할 때 치솟아서 추가적인 마비나 사고는 없었다. 어느정도 마무리된 지금, 다음주 1주간 휴가를 냄.

정선근 교수의 책도 세트로 사서 읽었다. 걷기, 렛풀다운, 힙업덕션 운동을 조금씩 하는 중인데 혹시나 하여 푸시업을 해볼까? 하고 엎드려 뻗치는 순간 뭔가 느낌이 이상하더니 지금 통증으로 벌받는 중이다. 그래서 지금 단계는 걷기, 렛풀다운, 힙업덕션만 가능한 상태이다. 이것도 많이하면 좀 힘듦. 근데 훈련 복귀하려면,
가능한 선은 계속해야 함.

재밌는건, 대회 가기 전에 자꾸 경기 중에 몸이 마비되는 꿈을 꿨다. 뇌의 신비. 그래도 꿈에선 온몸이 마비되었는데, 현실에선 다리만 마비됨. 물론 허리 문제로 온몸이 마비될 일은 없으니 꿈쪽이 호들갑이다. 그리고 실제로 터지고 나니까 그 꿈은 더이상 안꿈.

크런치 모드로 인해 한동안 깨졌었지만, 회복을 위해 진행하던 루틴은 아래와 같다.

  1. 오전 8시 기상
  2. 아침식사 후 물 크게 한 컵 마시면서 약 복용
  3. 자세 신경쓰면서 산책: 현재 1.5km가 상한
  4. 귀가 후 허리에 쿠션 대고 누워서 온찜질 20분, 원하는 만큼 휴식
  5. 재택으로 업무 및 1시간 마다 눕기 + 가능하면 온찜질도
  6. 점심식사 및 물 크게 한 컵
  7. 저녁식사 및 물 크게 한 컵 마시면서 약 복용
  8. 랫풀다운, 힙업덕션 적당히(양 정해두지 말고 상태 따라서 조절)
  9. 23시 취침(이거 좀 많이 어려움. -> 그래서 기상을 8시로 해둠)

지금 힘든건, 통증도 통증이지만 체질적으로 혈압을 높일 만한 무언가(즉 운동)을 하지 않으면 기립성 저혈압이 심해진다. 일어날 때 어지럼증이 좀 오고, 잘못 일어나면 앞이 깜깜해지는 것에 더해서 숨이 멈췄다가, 잠시 후 돌아오는데, 이때 심장도 엄청 빨리 뛰면서 숨을 몰아쉼. 그래서 이거 해결하려면 음... 딴생각 하지 말고 그냥 허리 빨리 회복이나 하자 ㅋㅋㅋㅋㅋㅋㅋㅋ. 나름 저런 문제 때문에 행동을 조심하게 되니, 회복 가속 스킬이라고 봐도 될 듯 함. 이번에 디스크도 회복이 된다는 것을 알게 되었더니, 나름 인체에 믿음을 가지게 되었음. 암이 아니라면 그냥 쉬면 알아서 해결되는 것 같음. 안쉬는게 문제지.

뽀개짐

2024-03-14 ~ 2024-03-17에 진행된 라크로스 오키나와 오픈, 내가 보기에 이건 인생 마지막 대회였던 것 같다. 아니, 사실은 그렇지 않기를 바란다. 하지만, 너무 강한 단서가 나를 괴롭힌다.

사실, 과로를 했던 이후 아직도 몸이 온전히 회복되지 않은 상태로 대회에 나갔던 차이다. 그래서 마지막날엔 허리통증이 극에 달했다. 아침에 눈을 뜨자마자 그날이 마지막이라는 기분이 강하게 들었다. 오전 경기엔 통증으로 인해 참전하지도 못했다. 하지만 경기가 만족스럽지 않게 끝나 팀원들이 모두 기가 죽어버렸다. 마지막 경기마저 그렇게 찝찝하게 끝나면 절대 안된다. 그런 경험을 팀에서 극복하는덴 몇 년이 걸린다. 그리고 난 그 때 주장이었다. 그래서 결정했다. 이왕 마지막일 수도 있는거, 모든 것을 불태우기로 했다. 가방에 있던 진통제를 다 털어먹고 몸을 인정사정 없이 제대로 풀었다. 그런데 마지막 경기 직전의 슛업(슈팅을 실제로 받아내는 웜업) 과정에서 오른손 새끼손가락이 골절됐다. 뼈나 인대가 나간 것은 확실한데, 난 이미 아드레날린에 쩔어 있었다. 툴툴 털고 마지막 경기를 뛰었다.

초반 공세를 막으며 버틴 끝에 경기 분위기가 우리 쪽으로 넘어왔다. 결국 5:2로 승리했다. 경기 종료 후, 마지막 단체사진을 찍자마자 난 위가 꼬여 드러누워 움직이지 못했다. 물론 그 상황도 이미 다 대비가 되어 있었다. 팀원에게 내 가방의 진경제를 가져다달라고 부탁해서 그 약을 먹고 잠시 후 살아났다.

한국에 돌아오고 나서 병원에 가서 손가락 엑스레이를 찍었더니, 관절면끼리 부딪히면서 쪼개졌다고 했다. 일단 자기 위치를 아직 벗어나지 않아서 수술은 킵하고 경과 지켜보되, 건이 붙는 자리라서 깁스로 손목까지 고정하고, 꼼짝도 하지 마라고 했다. (근데 그 상태로 경기도 뛰었는데, 원래 안벗어날 골절이 아닌가?)

뭐 여튼 꼼짝도 하지 마라고 하니, 일단 오른손은 팔걸이에 쳐박아 두고 살아보기 시작했다. 문제는, 허리 통증도 다시 엄청 심해졌다는 것이다. 좀 있으니 오른쪽 발 앞꿈치에 석회도 생겼다. 뭐 그건 그냥 아픈거고, 문제는 허리를 못쓰는 와중에 손도 못쓴다는 것이었다. 일단, 운전이 문제였다. 시동, 내비게이션, 변속, 사이드브레이크, 안전밸트 체결부 모두 오른쪽이다. 그래서 며칠간 운전을 못했다. 그러다 허리가 영 안되겠다 싶어서, 태릉쪽에 있는 병원에 가기 위해 방법을 찾았다.

  1. 오른쪽을 바라보고 운전석 사이드에 걸터앉아서 왼손으로 안전밸트를 체결
  2. 시동을 걸고, 내비를 설정
  3. 변속기 변경
  4. 고쳐앉기
  5. 액셀 밟으면 사이드브레이크 풀리는 기능 이용

이렇게 해서 병원에 갔다. 돌아오는 길에는, 집으로 가기 음성인식으로 네비 설정이 가능하다. 페달은, 발날로 밟았다…

추가로 터치펜과 펜을 붙여서 길이 연장해서 제대로 앉고 나서도 왼손으로 내비게이션 조작 가능하게 해봤다. 근데 터치 감도가 좀 별로라서 결국 허리 써야 해서 실패. 대신 안전밸트 풀 때 이걸로 푸니까 허리 안돌려도 돼서 좀 편해졌다. 시동도 이거로 켜고 끈다.

여튼 병원에서 여느 때처럼 신경차단술을 받았는데... 이번엔 뭔가 해결이 안된다. 계속 아프다. 속도 뒤집어질거같고 그냥 뭐 어떻게 저떻게 시간은 흘려 보낸거같은데... 뭐 그건 그렇다 치고, 밥줄...! 오른손 없는 개발자라니? 그와중에 허리 아프다고 조기퇴근 남발?

그래서 일단은 코파일럿을 VIM에 설치했다. 그렇게 어떻게 저떻게 버티다가, 뜬금없는 희소식이 발생했다. 손 치료받던 동네 병원에서, 허리 물리치료도 받고 있는데, 견인치료 중에 갑자기 속에서 뭔가 뚝 하고 뒤틀리는거같더니, 통증이 확 줄어들었다. 아니 뭔 회당 8만원 16만원 하는 주사치료로도 안되던게, 8천원짜리 물리치료로 확 괜찮아다지다니? 그리고 왜 이 간단한 치료는 그동안 아무데서도 안해줬는지?

다만 한가지 문제점은 있는데, "안좋아지면 물리치료 오세요" 하길래 금요일에 신난다! 하고 안가고, 진통제도 안먹었더니 퇴근하는데 또 안좋아졌다. 그래서 다시 약먹고 물리치료를 갔다. 이건 거의 뭐 신장 투석 환자마냥 일일 활동권을 병원에서 끊어와야 하는 듯 하다. 뭐 그래도 방법을 찾은게 어디인가.

여튼 그 몸 상태 좋아진 그날, 너무 신나서 코드를 5천줄 넘게 썼다. 코파일럿과의 합도 잘 맞아지고, 완전 날아갈거같았다. 마침 지금 개발하는게 프로토콜쪽이라서 노가다성이 짙은데, 코파일럿이 너무 좋아한다. 특기분야인 듯 하다. Private repo 접근 권한 안주고, 회사가 아닌 개인 계정으로 결제해서 기능에 한계는 있겠지만, 일단 초반에 시범으로 좀 짜주고 나면, 이후부터는 척척 추천해준다. 게다가, Rust랑 궁합도 좋다. 컴파일러가 strict할수록 코파일럿이 삽질했을 때 더 잘 잡아줄 것이기 때문일 듯 하다. 코파일럿은 언어를 이해하기보다, 단순히 이런 케이스의 코드가 어떻게 짜여졌는지에 대한 패턴을 학습하는 듯 하다. 그래서 예시로 짜주지 않은 형태는 스스로 유추하지 못한다. 아직 그냥 코더이다. 내 밥그릇은 아직 남아있는 듯 하다.

난중일기

1

2024년 1월 22일, 특정 마이크로서비스에 큰 변화를 가하는데 아주 무리한 일정이 내려왔다. 하루하루 한 단계가 해결되지 않으면 다음 단계를 넘어가지 못하는데 다음 단계로 한 번이라도 못넘어가면 바로 일정을 지킬 수 없는 수준이었다.

그렇다고 그걸 미룰 수도 없었다. 당장 새 모델의 성능에 악영향을 끼칠 것이었고, 새 모델의 배포 또한 ASAP인 상태였기 때문이었다.

러시한지 4일차, 다음날이 배포인 상황. 고객사에서 연락이 왔다고 한다. 미루자고. 모델 배포와 함께 진행하기로 한 타 회사의 기능 개발이 부진한 탓이었다. 무엇 때문에 이렇게 달린 것인가...

여튼 우여곡절 끝에 스프린트 마지막날에 배포하면서 마무리되었다. 시간이 더 생긴 만큼 테스트도 더 많이 진행됐다.

2

그리고, 해당 서비스는 내 담당 서비스는 아니었다. 그래서 내 담당 서비스의 신규 버전 개발 Task도 그대로 남아있었음. 물론 결국 다른 일들에 밀려 일시정지되었다....

이런 식으로 일 중단되는거 제일 싫어한다.... 그래도 공통 라이브러리 모으는 task는 첫주에 다 진행함. 다른 서비스에도 영향이 있으므로 좀 러시했음.

3

그리고, 고객사에서 요청한 피쳐의 반영도 해야 했다. 그건 퇴사한 전 팀장님의 서비스에서 처리해야 하는 일인데, 내가 또 이런거 땜빵 전문이다. C#으로 되어 있지만 다행히 예쁘게 짜서 유지보수하는데 어려움은 딱히 크지 않다.

4

이와중에 예전에 고객사에서 서비스 장애 시 SMS 알림을 해달라고 하며 추후 API 호출 방법을 보내주겠다고 했는데, 그 메일이 왔다. 심지어.... 담당자가 없어서 API 호출을 못열어준다며, 그냥 직접 소켓 연결해서 붙어서 메시지 쏘는 C 코드를 툭 던져줌. 그리고 그 코드는 include문들도 다 빼먹고, 직접 선언해서 사용했을 함수도 포함되어 있지 않았다. 그와중에, 내부에 들어가는 정보는 보안상 알려줄 수 없다며 그날 가져오면 정보 채워주겠다고 함. C로 가져가야 거기서 빌드할 수 있겠다 판단, 일단 C인 상태로 진행하고 추후 바꿔도 된다면 유지보수 가능하도록 Rust로 재작성하기로 함. 일단 근데 C언어이므로, 내가 진행해야 했다.

반환 타입, 함수 파라미터, 예상되는 결과값 유추해서 빈칸들 끼워맞춰서 개발 완료했음. 개발 완료되었다며, gcc 있는지 확인해달라고 하니, 없다고 함(롸?). gcc 없는데 c 파일을 준다고? 그럼 진작에 Rust로 만들었지... 여튼 그래서 debian 이미지에 gcc, build-essentials 깔아서 가져가서 정보 받고 빌드해서 쏴봄. 안됌. 왜냐하면? 개발계에는 세팅을 안했다고 한다. 운영계에서 테스트 하라고 함(와우). 그래서 또 쏴봄. 안됌. 왜냐하면? 방화벽을 안열어 놨다고 한다. 요쪽에선 자주 있는 일이라 이제 놀랍지도 않다. 대충 처음에 가져가면 안될걸 예상했기 때문에, 테스트 가능하도록 SMS send는 send만 하고, 장애 모니터링도 따로 짜서 가져갔기 때문에, SMS send 테스트 방법 알려준 후 넘기고 옴.

5

그리고, 새 모델을 개발하고 테스트하기 위해 부산 IDC에 서버를 넣기로 했는데, 이게 또 일정이 가까이 다가왔다. VPN 세팅 등을 더이상 미룰 수 없어서 인프라팀과 계속 이것저것 주고받는데 생각보다 이 망대망 연결을 하기에 사내 네트워크가 너무 개떡같았다(네떡이라고 부르심...). 그도 그럴게 30명 규모였던 회사 규모에서 별다른 준비도 없이 80명 규모로 인원을 뽑아댔고, 당시 인프라 전담 팀도 없었기 때문에 그 네떡이 80명규모인 지금까지 넘어왔던 것이다.

여튼 그 네떡 위에서 문제가 된 것은 VLAN 설정이다. 현재 네트워크 토폴로지는 그냥 방화벽 밑에 스위치 3개가 데이지체인으로 엮여있는 방식인데, 스위치 3개에 아무 호스트가 막 연결되어 있는 방식이다. 제일 먼저 방화벽에서 VLAN Switch 밑에 VLAN 대역을 추가했는데, 역시나 호스트에서 그 VLAN으로 연결 안됨. 왜 안되는지 찾기 위해 난리를 쳤다. 심지어 네트워크 작업은 아무리 빨라도 일단 증권 거래가 이루어지지 않는 장 마감 후에 진행해야 한다. 그러다 결국 속도를 내기 위해 네트워크 장비들 어드민 패스워드까지 받게 되었다.

여튼 원인을 열심히 파보니, 밑의 스위치들이 그 VLAN의 존재를 모르기 때문이라는 의심이 가장 많이 들었다. 내가 알기로 방화벽은 방화벽일 뿐 실제로 VLAN은 Layer 2이다. 스위치가 그 VLAN을 알고 있어야 한다. 그래서 스위치에서 arp cache를 조회하여 내 호스트가 어느 스위치의 어느 포트인지 파악해서 해당 포트에서 vlan id에 새 vlan을 이용하도록 설정함. Tag에 대해서 모르고 있었기 때문에 그냥 Untagged port를 vlan으로 할당해버림.

네 안됩니다. 다른 스위치에도 다 설정해야 함. 그런데 문제가 있다. 스위치끼리 연결한 인터페이스(1/2/1)에 Untagged Port VLAN을 적용해버리면, 전체 스위치의 vlan이 바뀌어버릴 것 같아서 건드릴 수가 없었다.

해결한 방법은, IEEE Tag를 이용하는 것이다. 원래 패킷 상에 vlan id는 안들어가는데, 이걸 들어가게 할 수 있다. 그럼 스위치는 해당 tag를 보고 vlan id를 읽을 수 있게 됨. 그래서 전체 포트에 대해 tagged라면 새 vlan을 사용하도록, untagged라면 defalut vlan을 이용하도록 설정했다. 여기서, 호스트에서는 그 IEEE Tag를 패킷에 심어줘야 한다. 그건 VLAN 인터페이스를 생성하면 된다. 여기서 VLAN ID를 주면 그 태그에 들어감.

6

그와중에 갑자기 2월 1일 밤에, 회사 서버실의 에어컨이 고장나서 서버실 온도가 치솟았다. 연락을 받고 우리팀 서버에 필요한 파일만 후다닥 백업한 후 싹 긴급정지했다. 네트워크 장비도 그 서버실에 있어서, 혹시 작업 중에 죽어버릴까봐 설정 원복 후 작업 중단했다. 그리고 다음날 다시 켰더니 결국 한 서버가 커널 패닉을 내며 부팅 실패... 하지만 지금 급한건 이 서버가 아니였어서 다음 스프린트 때 볼 예정.

7

일이 너무 동시에 끝없이 진행되고, 일만 끝나면 집에 와서 뻗어자고 눈뜨면 바로 샤워하고 출근을 하다보니, 집에서 점심을 챙겨가던 습관까지 무너지고, 점심시간을 놓치는게 일상이 되었다. 사실 아무때나 먹어도 상관 없는데, 점심시간이 지나면 또 이런저런 일로 계속 호출된다. 저녁도 보통은 일이 계속 질질 끌리다가 야근을 해버리기 때문에 까먹는 경우가 많다. 저혈당으로 어지러우면 급한대로 회사 냉장고에 있는 요거트를 먹거나 해서 해결.

시간이 없는건 한가지 사례로 바로 알 수 있는데, 저번주 토요일에 회식자리에서 고기를 먹은 후, 패딩에 고기냄새가 심하게 났는데, 그걸 처리할 방법을 찾을 시간이 없어서 패딩을 못입고 다녔다. 꽤 추웠다.

승전보

  • 오늘 낮에 극적으로 VLAN 설정 해결책을 발견, 적용하면서 이번 전쟁은 끝났다.

결과

  • 2주만에 체중 5kg이 빠졌다.
  • 치매와 비슷한 증상이 나타났다. 기억도 잘 안나고, 기억을 끄집어내는데 오랜 시간이 걸린다. 마치 기억들을 정리되지 않은 창고의 문을 열고 냅다 던져놓고 바로 닫아둔 느낌이다. 다행스럽게도, 이 증상은 목요일부터 완화되는 중이다. 그간 계속 3-4시간 자다가 수요일 밤에 결국 부정맥이 왔는데 멈추질 않아서 강제로 밤에 잠을 잤기 때문이다.
  • 허리 통증 악화, 5분 이상 서있기 힘든 상태이다. 내일 병원에 갈 예정이다.
  • 대회 전에 러시해서 허리 나갈 가능성을 방지하려고 대회 전에 4영업일 간 더 휴가를 냈다.
  • 하지만 고쳐야 할 것은, 일을 눈앞에 두고 자리를 못뜨는 습관을 좀 버려야 한다. 평시에도 밥은 일하면서 먹는다. 한손엔 점심, 한손은 키보드에 있음. 이 습관이 무서운게 그 한손에 점심이 들려있지 않으면, 점심을 먹으러 나가는게 아니라, 점심을 안먹어버린다.

커널 패닉으로 인한 부팅 불가 현상 해결하기

어제, 정말 기괴한 일을 했다. 리서치용 서버에 서버행이 떠서 재부팅을 했는데 커널 패닉이 반복되며 부팅이 안되는 현상이 발생함. 그리고 이걸 고치는 과정에서 세상 강제적인 방법을 다 동원했다.

시스템

  • 우분투 20.04
  • 다른건 알 필요 없음. 다만 이 문제를 잘 야기하는 하드웨어에는 리얼텍 NIC가 있다고 함.

문제 원인

  • 하드웨어를 인식하는 과정에서 잘못된 메모리 참조
  • 아치리눅스 부팅USB로 부팅해서 살펴보니, /dev에 ssd, hdd, 기타 디바이스 모두 없었음

해결방법

  • 하드웨어는 누가 잡는다? -> 커널 -> 커널을 업데이트
  • 커널을 어떻게 업데이트? -> apt upgrade하면 편한데 -> 부팅USB로 부팅한 후 파티션을 /etc/fstab과 맞춰서 마운트 -> chroot -> apt update && apt upgrade
  • 네임서버 설정 안됨 -> apt source url을 /etc/hosts에 강제로 박아넣고 진행

결과

  • 깔끔-
  • 이게 된다고???

후기

  • 다덤벼

crates.io 배포

자체 개발하여 업무 및 개인 용도로 사용하고 있던 actor 라이브러리를 crates.io에 배포했다(xan-actor).

원래 이 라이브러리는 업무용으로 필요한 기능만 구현해서 사용하고 있었는데, tokio를 너무 애용하는 바람에 main 함수를 async 함수로 만들어야 하는 단점이 있었다. 이게 async 키워드만 붙인다고 되는게 아니라 tokio::main을 이용해야 한다. 따라서 tokio를 쓰고싶지 않은 사람도 tokio를 이용해야만 이 라이브러리를 사용할 수 있었음. 그런데 또 비동기에 사춘기가 들어서 그런지, 동기 메인함수를 이용하고 싶었다. 그래서 동기로 만드는데, 이김에 tokio도 걷어내보고 싶어서 걷어내다 보니, 전체 구현를 tokio 없이 할 수 있는 피쳐가 만들어졌다.

근데, 매번 이 라이브러리를 add하는데 Cargo.toml에 깃허브 리포를 매번 넣어주는게 귀찮아오던 참에 crates.io에 배포해 보기로 했다. 보니까 4년째 관리 안하는 actor 라이브러리도 떡하니 자리를 잘 차지하고 있는데, 나라고 안될까.

일단 이걸 하면 편해지는건 그냥 cargo add xan-actor 하면 라이브러리가 add된다는 것이다. 개꿀.

배포 방법

Crates.io에 크레이트 배포하기

Rust의 모노리포 - 개꿀

내가 속한 조직은 각 구성원이 믿을 만한 사람들로 구성되어 있다. 따라서 요구조건을 전달하고, 상대방이 어려워하는 경우 힌트만 좀 공유해서 이해시키면 됨. 그래서 마이크로서비스 구조로 잘 지속되어 왔다.

하지만 이것은 한계에 봉착하고 있다. 현재 우리 제품은 지속적으로 개선을 하고 있기 때문에 업데이트 빈도가 매우 빠르다. 그 업데이트들은 DB 스키마까지도 변경될 수 있을 정도로 큰 경우가 빈번하다. 심지어 개발속도도 빨라서 개발 중에 다른 서비스에 큰 변화가 생기는 경우도 발생한다. 또한 cargo update를 깜빡해서 버전에 안맞는 코드를 작성했는데, Cargo.lock파일 또한 커밋되지 않았으므로 CI 테스트를 그냥 통과하는 경우도 발생했다.

최근엔 작업 관리 서비스와 엔드포인트 서비스를 통합하는 과정에 있다. 그래서, 통합하는 김에 모노리포를 채택하기로 하였다. Rust에서 모노리포? 그거 아주 쉽다.

Rust에는 cargo라는 패키지 툴이 있다. cargo로 컴파일, 빌드, 라이브러리 import 모두 진행한다. 이뿐만이 아니라 workspace라는걸 이용하면, 최상위 디렉터리에서 여러 개의 cargo workspace를 구성하고 상호간 라이브러리처럼 import할 수 있음. 각 마이크로서비스는 마이크로서비스로 그대로 가져가지만, 리포만 하나로 통합할 수 있다. 이렇게 되면 다른 마이크로서비스의 버전 변화가 있을 때, 그냥 pull만 당겨주고 맞춰서 작업하면 됨. 브렌치 머지할 때도, conflict가 있는지 볼 수 있고, CI를 하는 것도 용이해진다. 또한, 각 마이크로서비스에서 이용하는 라이브러리의 버전도 자연스럽게 통합된다. 각 workspace의 Cargo.toml파일을 따로 세팅하긴 하지만, 최상위 디렉터리의 Cargo.lock파일에서 싸그리 관리하기 때문이다. 추가로, 이건 사소해 보이긴 하지만, 수정이 있을 때마다 깃허브 알림설정이 모두에게 날아가게 될 것이다. 자기 서비스에만 신경쓸 땐, 일부 리포는 알림이 안되어 있는 경우가 생기기 때문에, 따라가기 힘들 때가 있었는데, 해결될 듯 하다.

여튼 그래서, 아주 쉽게 모노리포 구성해서 작업중이다. 개꿀.

기술적 분석

허리도 괜찮아지는 중이고, 뭔가 최근들어 머리가 팽팽 도는 상태이다. 이유는 모른다. 허리 아프다고 안쓴게 보관되나. 아 그러고보니, 불면증이 해결되는 중이구나.

여튼 그래서 오늘은 훈련 가기 전에 서적의 기술적 분석 부분을 다시 복습했다. 이미 수치 계산은 trading-toolkit에 만들어 놓은 상태였는데, 이때는 계산식 자체를 구현하는데 초점이 맞춰져 있었다면, 이번엔 기술적 분석을 통한 거래 방법에 초점을 맞추고 읽었다.

참고로 서적은 아래와 같다.

나의 트레이딩 룸으로 오라! - 알렉산더 엘더

조금 공격적인 느낌의 이름이긴 하다. 근데 뭐 영어로 "Come to my trading room"이면 그렇게 들리진 않을듯? 각설하고, 읽은 내용을 요약해 보겠다.

종목 선택 - 무엇을 살 것인가

일단 기본적으로, 채널이 넓어야 한다. 채널이 넓지 않으면 많이 못먹기 때문. 이게 그냥 단순히 많이 못먹는게 문제가 아니다. 트레이딩의 성적을 계산할 때에는 이 채널에서 얼마나 많이 먹었는지를 기준으로 한다. 따라서, 채널이 좁은 경우, 아무리 좋은 성적을 내도 이득을 크게 보지 못한다. 그리고 거래비용을 지불해야 함. 남좋은 일만 하는 꼴이다.

또 한 가지, 많은 종목을 전체적으로 보기보다, 주종목으로 할 몇몇 종목을 골라서 그것만 파는게 유리하다고 함.

이동평균선을 통한 추세 파악 - 지금 어떤가

이동평균선, 그 중 지수이동평균을 권장함. 여튼 이 선을 이용해서 상승장인지 하락장인지 추세를 파악하면 된다.

예상되는 추세 반전 지점이 있는지 확인 - 특별한 기회가 있나

MACD 히스토그램. 이 중 다이버전스를 포착한다면 좋은 기회가 될 수 있음. 다이버전스는 여러번 읽고 나서야 이해할 수 있었다. 상승 다이버전스는 가격이 두 번 이상 저점을 찍을 때, MACD 히스토그램의 두 바닥을 비교하면 상승하는 경우이다. 하락 다이버전스는 가격이 두 번 이상 고점을 찍을 때, MACD 히스토그램의 두 천정을 비교하면 하락하는 경우. 이 다이버전스의 경우, 자주 있는 일은 아니지만, 일어나는 경우 꽤 좋은 신호가 된다고 함. 약간 이벤트같다고 해야 하나.

매수/매도 시점 파악 - 언제 사고 팔 것인가

책의 저자가 개발한 강도지수라는게 있다. 이걸 이용해서 이동평균을 구하면 매수/매도 시점을 파악하기 좋다고 함. 2일 강도지수 이동평균을 이용했을 때, 만약 상승장의 경우 이 값이 음수인 경우 매수 타이밍, 반대로 하락장에서 이 값이 양수인 경우 매도 타이밍이라 함. 일시적으로 반전이 일어나는 케이스를 포착할 수 있음.

추세 재개여부 파악 - 지금 이 상태는 일시적인 것인가

이 역시 책의 저자가 개발한 엘더-레이라는게 있다. 반전이 포착되었을 때, 이전의 추세를 여전히 가져갈것인가를 알 수 있다고 함. 상승추세에서 매도 강도가 음수에서 양수로 올라가는 경우 상승이 재개되고, 하락 추세인데 매수강도가 양수에서 음수로 전환되는 경우 하락이 재개된다. 그냥 보면 당연해 보이기도 하다.

아 참고로, 매도강도는 작을 수록 강한 것이다.

위험요소 회피 - 이 포지션을 취해도 괜찮을 것인가

스토캐스틱이라는 지표가 있다. 이 지표는 과매수/과매도 상태를 나타낼 수 있음. 저자는 주로 극단적인 상황을 막기 위해 이 지표를 본다고 한다. 마지막 단계에서 이용하면 될 것 같다. 예를 들어, 매수하고 싶은데 스토캐스틱의 상단기준선 위로 올라가 있다면 매수하지 않는다. 반대로 공매도하고 싶은데 스토캐스틱의 하단기준선 아래라면 하지 않는다.

펀더멘털에 의한 변수

아무리 다이버전스를 포착하고, 매수/매도 시점 찾고 스토캐스틱으로 검증한다고 해도, 결국 기본적인 펀더멘털의 변화가 심하면 이 신호들이 의미없게 되는 경우가 있다고 한다. 저자는 이럴 때 반대 포지션을 즉시 취한다던가 하는 트레이딩적 노하우를 맛보기로 소개해 줬는데, 나같은 쩌리는 그냥 펀더멘털에 큰 변화가 찾아올 만한 주식은, 트레이딩이 아니라 투자적 관점에서 바라봐야 할 듯 하다.

Linux에 카카오톡 설치

리눅스의 최대 단점은 바로 카카오톡이 아닐까 싶다. 그동안 카카오톡 설치가 번거로워서 PC로는 이용 안하고 있었는데, 최근 업무 중 윈도우 어플리케이션을 돌릴 일이 있어서 wine을 좀 파보게 되면서, 다시 자신감이 붙음. 다 덤벼라.

그래서 다시 카카오톡 설치에 도전했다. 아주 가장 간단하고 기본에 가깝게. 방법은 아래와 같다.

wine, wine-mono, wine-gecko 설치

배포판은 신경쓰지 말자. wine은 말그대로 wine, wine-mono는 wine의 .NET 프레임워크 이용을 위한 패키지, wine-gecko는 Internet Explorer를 위한 패키지이다. IE에 대한 본능적 거부감에 일단 wine-mono까지만 설치하고 카톡 실행을 해봤더니, 결국 안돼서 이것도 마저 설치했음.

wine 환경설정

winecfg

winecfg

위의 커맨드를 실행하면 뭔 창이 하나 뜰 것이다. 그냥 OK 하면 wine 환경이 구성됨. 구성되는 환경은 아래와 같다.

$HOME/.wine

여기를 들어가보면 매우 익숙한 구조가 나옴. 맞다. 말그대로 윈도우의 디렉터리구조가 보인다.

한글 폰트 추가

카톡을 설치할 때, 설치 프로그램에서 한글이 깨지지 않게 나오게 하고싶다면, 한글 폰트를 설치하자.

방법은 간단하다. $HOME/.wine/system.reg에 들어가서 MS Shell Dlg 항목을 한글 지원되는 폰트 이름으로 바꾸면 된다. 폰트 리스트는 해당 라인 위로 올라가면서 쭉 보면 있을 것이다(리눅스에서 한글을 사용하는 이상 아마 있을 것).

한글 입력 활성화

wine reg add "HKEY_CURRENT_USER\\Software\\Wine\\X11 Driver" /v InputStyle /t REG_SZ /d root /f

아, 참고로 kime 입력기를 이용하는 경우, kime-xim이란걸 이용해야 하는데 후술하겠다.

또, 카카오톡 설치할 때 한글 버전으로 안하고 영어 버전으로 했는데, 기본 폰트가 Arial로 되어 있어서, 한글 입력 시 다 깨졌다. 혹시 한글 입력이 안되는 문제가 있다면 카톡 설치 후 설정에서 폰트 변경하자.

카카오톡 설치

지금부터 wine이 어떻게 도는지 간결하게 이해할 필요가 있다. wine <exe file> 를 실행하면, 아까 구성된 $HOME/.wine 디렉터리 내에서 윈도우 환경처럼 exe 파일을 실행하게 된다. 아 물론, 정확히 코드 까보거나 공식문서 정독한건 아니지만, 실행하는덴 이 정도 이해만 하면 된다. 그럼, 이제 어떻게 해야 하는지 슬슬 눈치챘을 것이다.

카카오톡 설치파일 다운로드 및 실행

카카오톡 PC버전 설치파일을 다운로드하고 해당 exe 파일을 wine으로 실행한다. (wine KakaoTalk_Setup.exe)

카카오톡 실행파일 실행

설치 중에 특별히 설치 디렉터리를 변경한게 아니라면 아마 $HOME/.wine/drive_c/Program\\ Files\\ (x86)/Kakao/KakaoTalk/ 디렉터리에 KakaoTalk.exe 실행파일이 들어가 있을 것이다. 이걸 그냥 wine으로 설치파일 실행한 것과 동일한 방법으로 실행하면 된다.

난 매번 찾기 귀찮아서 스크립트로 빼놨다.

#!/bin/bash
wine "$HOME/.wine/drive_c/Program Files (x86)/Kakao/KakaoTalk/KakaoTalk.exe"

kime 사용자 한글입력 문제 해결

카카오톡 실행 전에 kime-xim을 실행해 놓아야 한다. 그렇지 않으면 한글 입력이 안됨.

슬슬 귀찮아질 것이다. 귀찮으면 조금만 더 힘내서 서비스로 등록하는걸 추천한다.

Rust의 개꿀 라이브러리들

개인적으로 개발을 할 때, 당장 어떻게든 만들어내는건 어렵지 않게 하지만, 개발 도구를 맛깔나게 활용하지는 않는 편이다. 그냥 '요래요래 하면 될거같은데?' 하고 손부터 가는 타입. 그래서 개꿀 라이브러리를 놓치고 깡으로 손으로 짜는 경우가 많다.

그러던 중, CTO가 관리하던 코드를 물려받게 되었다. 코드가 아름답다고 한다면 이런 것일 것이다. LSTM + 강화학습 모델의 학습 인프라를 구성하는 코드리포인데, 시뮬레이션은 기본, 데이터 프로세싱까지 모두 담겨있다. 마이크로서비스를 섣불리 도입해서 삽질을 하지도 않고 바로 모노리포 구조로 잘 짜여 있었다. 여튼 개쩐다는 표현은 대충 이쯤에서 마무리하고...

structopt: Argument를 편리하게 받자

일단 난 CLI를 더 선호한다. 그래서 왠만하면 CLI로 툴을 만드는 편이다. 그런데, bash scripting을 하는 경우가 많아서, argument를 가져올 때 손이 알아서 아래와 같이 입력한다.

if [ $# -ne 2 ]; then
    echo "Usage: $0 <hello> <world>"
    exit -1
fi
HELLO=$1
WORLD=$2

그리고 이 습관은 rust까지 따라왔다.

fn main() {
    let args = std::env::args().collect::<Vec<String>>();
    if args.len() != 3 {
        eprintln!("Usage: {} <hello> <world>", args[0]);
    }
    let hello = &args[1];
    let world = &args[2];
}

그리고 난 CTO가 물려준 코드에서 structopt를 발견했다. 아 물론, 다른 마이크로서비스에도 있었는데, 내 담당은 아니라 대충 넘겼었긴 했다. structopt를 이용하면 아래와 같이 이용할 수 있다.

use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(name = "opt", about = "hello world")]
struct Opt {
    #[structopt(short, long)]
    hello: String,
    #[structopt(short, long)]
    world: String,
}

fn main() {
    let Opt { hello, world } = Opt::from_args();
}

코드 줄 수는 별다른 차이가 없어 보일 수 있지만, eprintln이 사라진 것을 볼 수 있다. argument를 입력받기 위한 안내를 굳이 내가 입력하지 않아도 되는 것이다. 게다가 커맨드라인 상에서 더 깔끔하게 나온다. 추가적으로, Opt struct에서 타입을 정의했다. 자료형에 대해 걱정할 필요가 없이 가져다 쓰면 된다.

serde: 데이터 파싱? 직렬화? 그냥 add하자

이 라이브러리는 내부 프로토콜로서 프로토버프를 이용하면서 예전부터 이용하고 있었다. 꽤 깔끔하게 구조체를 표현할 수 있어서 좋다 정도였고, api 클라이언트를 만들 때, 사용이 아주 권장되지만, 개인적으로 작업을 진행할 때는 귀찮다고 대충 손으로 써내려가면서 만들어 왔다. 하지만, API 클라이언트를 만드는 일이 생각보다 많다. 당장, 개인적으로 작업중인 한국투자증권OpenAPI, open-banking-api만 해도 API 클라이언트다. 또한 회사에서 메시지큐의 공식 라이브러리에서 지원하지 않는 Admin API를 날리는 라이브러리도 개발했는데, 이 또한 API 클라이언트이다. 그리고 이 클라이언트가 날린 리퀘스트에 대한 리스폰스를 파싱하기 위해서는... 그냥 serde 쓰자. 나처럼 손으로 다 빚어내지 않았음 한다 ㅋㅋㅋㅋㅋㅋ. 체대 아니랄까봐 신체의 스피드로 개발속도를 내고 앉아있다. 개인적으로 불편함이 어느정도 쌓여야 해소를 위해 움직이기 때문에, open-banking-api를 작업하면서 serde를 도입하게 되었다. 물론 한국투자증권API에도 serde 라이브러리를 add해놓긴 했지만, 사용해야 할 모든 곳에 제대로 사용하지는 않고 있다. 조만간 바꿔야지.

serde는 데이터의 serialize, deserialize를 지원하는 라이브러리다. derive를 통해 쉽게 serialize/deserialize 매서드를 가져올 수 있다. 만약 이게 없으면 아래와 같이 작성해야 한다.

use json::json;

fn main() {
    // deserialize
    let raw = b"{\\"hello\\":1,\\"world\\":\\"universe\\"}";
    let parsed_json = json::parse(&raw).unwrap();
    let mut hello = 0;
    let mut world = String::new();
    match parsed_json {
        json::JsonValue::Object(o) => {
            match o.get("hello") {
                Some(hello) => {
                    match hello {
                        json::JsonValue::Short(n) => {
                            let (positive, mantissa, exponent) = n.as_parts();
                            hello = positive as i64 * mantissa as i64 * 10i64.pow(exponent as u32);
                        },
                    }
                }
                None => todo!(),
            };
            match o.get("world") {
                Some(world) => {
                    match world {
                        json::JsonValue::String(s) => {
                            world = s.to_owned();
                        },
                    }
                }
                None => todo!(),
            }
        },
        _ => {
            todo!();
        },
    }

    // serialize
    let hello = 1;
    let world = "universe".to_string();
    {% raw %}
    let serialized_message = format!("{{\\"hello\\":{},\\"world\\":\\"{}\\"}}", hello, world);
    {% endraw %}
}

json::parse가 모든 것을 꼬아버렸다. 아주 귀찮다. 이걸 serde와 serde_json을 이용하면 아래와 같이 간단하게 해결된다.

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct ParsedJson {
    pub hello: u8,
    pub world: String,
}

fn main() {
    // deserialize
    let raw = b"{\\"hello\\":1,\\"world\\":\\"universe\\"}";
    let parsed_json: ParsedJson = serde_json::from_slice(raw).unwrap();

    // serialize
    let message = ParsedJson {
        hello: 1,
        world: "universe".to_string(),
    };
    let serialized_message = serde_json::to_string(&message).unwrap();
}

serde 만세

PC의 OS로써 Arch Linux를 사용하는 이유

난 아치리눅스(Arch Linux)를 메인 OS로 이용하고 있다. PC는 물론, 노트북, 회사 업무용 PC까지 모두 아치리눅스이다.

아치리눅스를 쓰게 된 계기는, 회사의 CTO가 아치리눅스를 사용하셨는데, 꽤 재미있어 보였기 때문이었다. 뭔가 저걸 하면, 그냥 자연스럽게 따라오는 것들이 있을 것 같았다.

백문이 불여일견. 바로 트라이했다.

관문들

관문 1. OS 설치

당시까지 써봤던 설치 USB는 설치를 위한 GUI가 뜨는게 대부분이었다. 최소한 TUI더라도 설치를 진행하는게 바로 진행되는, 설치만을 위한 절차가 진행되었다.

그런데 아치리눅스 설치 USB를 만들어서 USB로 부팅했더니, 그저 검은 리눅스 커맨드라인이 하나 나왔다. 띠용? 하고 찾아보니, 설치를 위한 리눅스가 실행된 것이다. 아치리눅스를 PC에 설치하기 위해서는 커맨드라인을 이용하여 파티셔닝과 마운트를 진행하고, 이걸 부트로더에 등록하는 절차를 거치고, 마운트한 디렉터리 중, / 디렉터리가 되는 곳에서 아치리눅스 환경을 설치해야 했다. 이 때 필요한 것을 설치하지 않으면 리눅스 부팅에 성공한다고 해도 반쪽짜리가 된다. 특히 노트북에 설치하는데, 와이파이를 이용해야 하는 경우... 그냥 집 가서 랜선 이용하는걸 추천한다. 정신건강에 좋지 않다.

관문 1로 얻은 것: 만능 해킹USB

아니 이거 지금보니, USB로 부팅하면, 루트잖아? 어딜 가든 이 USB 하나 있으면 이 USB로 부팅해서 자료를 뜯어낼 수 있다. 아 물론 암호화되었다면 할 수 없겠지만. 근데 암호화 파티션 구성하는게 꽤 귀찮아서 거의 안할 것이다. 물리적 보안이 중요한 이유다.

뭐 그렇더라도 내가 이걸 진짜 해킹에 이용하진 않는다. 굳이 밥벌어먹는데 문제 없는데 할 이유가 없다. 아 밥 벌어먹는데 문제 있어도 굳이 앞으로 더 힘들어지게 그럴 이유가 없다. 가끔 퇴사자가 남겨둔 PC에 로그인이 불가한데 OS를 재설치해야 하는 경우 자료 백업을 위해 이용한다.

관문 2. GUI 설치

사용자친화적인 리눅스들은 처음에 gui 설치 여부를 선택하면 알아서 설치해 준다. 그래서 왠만하면 건들지 않고, 최적화된 윈도우 매니저를 이용하게 된다. 아치리눅스는? 그런거 없다. 그래서 CTO가 자신이 아치리눅스에 bspwm 올리고 뭐시기 뭐시기로 개발한다 했던 것을 떠올려서 bspwm을 검색해서 겨우 하나 찾아서 따라했음. 그리고 쓸만한 환경을 구성하기 위해서는 bspwm 뿐만 아니라 설치할 것들이 더 많았다.

관문 2로 얻은 것: OS 설치를 다시 할 때 편하게 하기 위한 꾀를 부리기 시작함

사실 OS 설치 자체는 그리 어렵지 않았다. 유선 환경이면 몇 번 해보면 익숙해지고, 까먹으면 살짝 검색해 보면 됨. 문제는 GUI 구성은 자잘자잘한게 많아서 다 기억하기 어려움.
그래서 GUI 구성을 위해 이용했던 ~/.config 디렉터리를 백업해 두게 되었다. 사실 설치 스크립트도 만들까 하다가 안했는데, 정말 한 번만 더 재설치할 일 있으면 정말 만들 것이다. 그리고, 외장 SSD를 구매해서 거기에 아치리눅스와 GUI를 설치했다. 그리고 intel, amd cpu 모두 호환되도록 설치해서 intel cpu인 PC와 amd cpu인 노트북 모두 이 SSD로 부팅해서 동일한 환경을 이용하고 있다. 짐이 좀 늘고, 부팅하기 위해 외장SSD를 꽂는게 조금 불편하긴 한데, 아무데서나 동일한 환경으로 부팅할 수 있으니 좋다. 아 그리고 이것도, 따지고 보면 만능 해킹 외장 SSD다. 그리고 가끔 수틀리면, 주인의 동의를 구하고 이 SSD를 이용해서 다른 사람의 PC를 빌릴 수 있다. 그리고 내 환경 그대로 이용할 수 있음.

관문 3. 각종 프로그램 설치

아치리눅스의 패키지 매니저는 pacman이다. 그리고 AUR이라는걸 이용할 수 있는데, 난 AUR Helper로 yay를 이용한다. 그런데 아치리눅스가 마이너하다 보니, pacman은 물론 yay에서도 조회되지 않는 프로그램이 가끔 있다. 그럼 공식 홈에서 받게 될텐데, 데비안 계열이나 페도라 계열은 쉽게 설치할 수 있는 패키지 파일이 제공되지만, 다른 리눅스는 그런거 없다. tar.xz를 대부분 이용한다. 받아서 makepkg 등의 절차를 거쳐야 한다.

관문 3으로 얻은 것

tar.xz만 있으면 어디든 설치 가능한거네? 를 깨우침

아치리눅스를 사용한다면?

Vim

vim 써줘야 한다. 이게 완전체라고 본다.

vim으로 개발하면 좋은 점?

일단, vim 세팅을 제대로 하면, 꽤 편하다. 게다가 ssh 접속만 하면 굳이 다른 프로그램 필요 없이 코딩이 가능하다. 추가적으로, 마우스 사용 빈도가 줄어든다. 과거 손목에 문제가 생긴 경험이 있는데 그 때 문제의 원인은 과도한 마우스 사용이었다. 당시 고객사의 클라우드에 제품을 설치하기 위해, 회사의 클라우드에서 이것저것 테스트해보고 실습해보면서 고객사에서 발생한 문제 재현해서 해결하기 위해 밤낮없이 일했던 때였다. 그 때, 하다하다 안돼서 결국 버티컬마우스를 구매했다. 지금은 12시간 코딩만 해도 손목에 아무 문제가 없다.

아 그리고, tui에 익숙해지게 된다. 보통 리눅스를 사용하더라도 vs-code같은걸 깔아두게 되면 터미널은 code .을 입력하기 위해 cd를 반복하는데 사용한다. vs-code를 켠 이후, 커맨드라인을 사용할 일은 빌드/컴파일 할 때 정도이다. 하지만 vim으로 개발하는 경우, 왠만한건 다 명령으로 해결하기 때문에 편해지기 위해 명령을 잘 하는 법을 찾게 되고, 실력이 는다. 게다가 language server를 설치하지 않았더라도, 대충 라이브러리 위치 찾아가는 센스가 생김. 언어가 추가될 때마다 vim 세팅을 진행해야 하는데, 보통 처음엔 그냥 불편한 대로 사용하기 때문이다. 그러다가 사용 빈도가 올라가서 불편함이 가중되면 세팅을 진행한다. 그 때는 이미 해당 언어에 대해 어느정도 익숙해진 후이다.

그냥 불편한게 다인 것 같은데?

맞다. 불편하기 때문에 편해지기 위해 발악하는 과정에서 이해도가 높아진다. 그런데, 주니어일 때 아치리눅스를 사용한건 신의 한 수였던 것 같다. 왠만한 문제는 당황하지 않는다. ㅋㅋㅋㅋㅋㅋ

주석의 중요성

모델이 할 수 있는 주문의 상/하한을 결정하는 공식을 고객사가 수정해달라고 하는 경우가 종종 있다. 문제는, 모델은 해당 공식에 대해 학습되어 있지 않은 채 프로덕션 단에서 수정해야 했다는 것이다. 빨리 고쳐야 하니 말이다. 물론 성능이 떨어질 것임은 숙지시켰지만, 이럴거면 왜 AI를 쓰는가 하는 의문이 생긴다. 여튼 우리는 개쩌는 AI를 만들어 낼 것이므로 성능 향상을 계속 지향하고 있다.

하지만 걸림돌이 몇 가지 있었다. 해당 공식에 대한 설명은, 전-전 팀장님에게 들은, 고객사에서 수정요청해서 급하게 반영한 공식에 대한 설명 뿐이었다. 심지어 내 머리 속에 유일하게 남아있었다. 대충, "합성함수를 사용한다 + 그래서 이런저런 요건을 만족하는 방정식을 만들려고 하는데 + 빡세서 수치 몇 개 대입해서 하드코딩 했다". 딱 이 내용이었다. 그리고 이 내용에 대한 주석은 전혀 없었다.

이렇게 되면 코드만 보면 절대로 의도를 알아차릴 수 없다. 공식을 자세히 밝힐 수는 없지만, 파라미터의 값에 따른 case문 형식의 하드코딩이 들어간 시점에서, 이미 그 방정식의 성질은 유추할 수 없게 된다. 여튼 그래서 기억을 더듬어 다시 해당 공식의 의미는 정리해 놨다. 팀원들에게도 설명해 두긴 했는데, 문서화 했었나, 안했었나... 여튼 내 노트에 있는데 조만간 업데이트해야겠다. 주석도...

또, 고객사에서 수정해달라고 하기 전부터 이용되고 있던, 모델이 학습된 환경과 동일한 공식의 의도 또한, 주석이 없다. 다만 다행인 것은, 이건 하드코딩은 아니다. 1차함수, 지수함수, 로그함수, 합성함수가 이용되었는데, 몇 가지 상수는 있지만, 괜찮은 수준이다. 하지만 처음에 코드에서 이 공식을 뽑아낸 직후엔 의도를 파악하지 못했다가, 어제 학습 데이터 프로세싱 돌리면서 시간이 떠서 이걸 보다보니, 그제서야 파악할 수 있었다.

이 공식은 완벽하지는 않지만 생각보다 현재 고객사가 요청했었던 요건들을 어느정도 반영하고 있었다. 이걸 모르고 있었기 때문에, 현재 고객사가 요청한 것들을 만족시키기 위해, 쓸데없이 프로토콜에 새로운 필드를 심고, 두 개의 파라미터로 공식을 만들게 되었다. 그냥 하나의 파라미터로 이용하는 공식을 좀 더 가다듬으면 되었는데 말이다.

이렇게 또 소중한 경험을 쌓게 되었다(리버스 엔지니어링). 나도 평소에 주석은 좀 장황한 절차가 있는 경우 스텝에 대한 설명 정도를 적는 정도인데, 앞으로는 해당 함수의 의도도 잘 적어놔야겠다. 특히 1차함수 혹은 사칙연산의 범위를 벗어난 경우는 그 식의 의도는 물론, 함수의 성질까지 무조건 적어야겠다.

Simple is the best

simple-is-the-best.md

이전까지는 회사에서 제품 설치 난이도를 줄이기 위해 쿠버네티스 설치를 간편하게 하는데 집중하고 있었다. 그러다가 문득, 쿠버네티스를 사용하는 이유에 대해 고민해보게 되었다. 고민해보게 된 이유는 간단하다. 매번 장애가 나면 대부분 네트워크인데, 이 네트워크 문제를 더 복잡하게만 만들고, 스케일아웃을 하지 않는 온프레미스 서버이기 때문에 클라우드처럼 비용 최적화를 위해 오토스케일을 할 필요가 없기 때문이다.

결론은 금방 나왔다.

쿠버네티스를 사용하는 이유

쉽게 말해서 한 명의 인프라 관리자가 커버할 수 있는 서버를 늘리는 것이다(일자리 냠냠). 이전엔 각 서버를 따로따로 관리하면서 진행했겠지만, 쿠버네티스를 서버에 설치하고 노드를 엮는 순간 한 관리자가 API 호출을 통해 프로세스를 원하는 노드에 쉽게 올릴 수 있다. 심지어 인프라를 코드로서 관리할 수 있게 된다. 인프라 구성을 yaml파일로 만들어 두면, 그냥 kubectl apply -f filename.yaml 한 방에 구성된다. 코드로서 관리한다는 것은 라이브러리화가 가능하다는 것도 시사한다. 마치 npm처럼 사용할 수 있는 helm이 등장한다. 클라우드 세팅까지 함께 진행 가능한 Terraform도 등장한다. 꽤 큰 변화가 아닌가 싶다.

문제점

소프트웨어를 제품을 타사에 설치해주는 경우, 쿠버네티스가 여기에 포함된다면, 그리고 상주인력을 파견하지 않는 형태라면, 대참사가 벌어진다. 일단 겪어본 것만 나열해 보겠다.

  1. 서비스에 장애가 발생했는데, 다수의 Restart 후 etcd의 리소스 사용량이 치솟더니 호스트가 죽어버린 케이스가 발생했다. 문제를 전달받고 방문했을 땐 이미 디버깅조차 할 기회가 없었다. 디버깅을 위해 루트 권한이 필요함은 물론 기본이다.
  2. Calico CNI를 오랫 동안 켜두면 어느 순간 멈춘다. → 매일 서비스 가동과 함께 재시작한다.
  3. 로그 용량을 제한할 정책을 제대로 만들지 않고 서비스를 방치하면 거래량이 많거나 다른 문제가 있는 경우 터진다.
  4. 리눅스의 자동 업데이트 기능으로 인해 도커 데몬이 영향을 받으면 다 터진다. → 자동 업데이트를 해제한다.
  5. Kubeadm으로 설치할 때 발급된 API call 시 사용할 인증서의 유효기간은 1년이다. → 1년 마다 모든 고객사를 방문해서 루트 권한을 받아 인증서를 갱신해야 한다.
  6. 고객사의 쿠버네티스 버전을 업데이트하기 위해서는 루트 권한을 받아서, 현재 클러스터를 내리고, kubelet도 내리고, kubelet, kubeadm, kubectl 바이너리를 새 것으로 교체하고, 쿠버네티스의 새 버전 이미지들을 로드하여 kubeadm init만 하는 과정이면 정말 쉬울텐데... 1.18버전에서 1.21버전 올라갈 땐 몇몇 피쳐가 정식 피쳐로 바뀌면서 서비스의 yaml 파일들을 싹 업데이트해야 했고, 1.26버전을 올라갈 땐 도커 지원을 중단하는 큰 변화가 발생해서 containerd를 추가로 세팅해야 했다. 솔직히 또 1년 안에 무슨 큰 변화가 발생할 지 겁이 난다.

보다시피, 쿠버네티스는 인프라를 직접 관리하는 운영자가 사용하기 위한 것이지, 타사에 납품할 제품에 심는 그런 것이 아니다.

그럼 어떻게?

이미 내 눈 밖에 났다. 쿠버네티스를 날려버렸다. 내가 관리하는 마이크로서비스가 쿠버네티스에 요청을 날려서 모델을 로드할 워커의 개수와 모델에 등록할 작업의 개수를 관리하는 역할을 하는데, 여기서 쿠버네티스 환경인지 아닌지를 탐지해서 쿠버네티스가 아닌 경우 해당 피쳐를 off시키도록 바꿨다. 애초에 제품이 스케일아웃을 고려하여 stateless하게 개발되었기 때문에 다른 마이크로서비스들엔 딱히 이슈가 없었다. 그리고, 도커 이미지가 아닌, 바이너리로 그대로 가져다 쓰는 것도 문제 없도록 했다. 물론, 새 고객사엔 podman으로 서비스를 운영한다. 도커 이 살찐고래는 너무 많은 권한을 가지고 있다. 단지 포트 열고 통신하고 로직을 돌릴 프로그램을 적재하는데 루트권한은 투머치다. podman은 루트가 필요없다. 만만세. 아, 그리고 이후 시간이 날 땐 rpm, deb 패키징도 해볼 생각이다.

결과

편해졌다.

그런데, 뜬금없이 이 과정에서 엄청난 일이 발생했다. 사용하고 있는 메시지큐의 리소스 요구량이 확 줄어든 것이다. 기존엔 2000개 동시작업을 처리하기 위해 broker와 bookie를 3개씩 올리고 거기다 각각 3cpu를 할당하고, 워커에 4개를 할당하고 zookeeper, proxy까지 합하면 최소 25cpu를 할당해야 했는데, 그냥 standalone 이미지 하나로 올리니, 12-thread cpu 서버에서 2000개 잡을 비슷한 수준의 레이턴시를 보이며 돌려버렸다.

결국, 2.0의 흔적은 신규 학습에서 제외된 몇몇 모델을 제외하고, 대부분 사라졌다. 물론 사내에서 실장 레코드를 쌓기 위한 서버는 여전히 쿠버네티스를 이용 중이다. 실시간으로 관리하고 있으니까 말이다.

존버록

난 현 회사의 제품 1.0 버전이 성공하여 2.0 버전 개발을 완료한 후 설치를 앞두고 있던 시기에 입사했다. 2.0 버전은 B2B2C까지도 가능한 시스템을 목표로 하여, 고객사의 클라우드에 설치를 진행하는 IaaS 형태로 설계, 개발되었다.

그래서인지, 구조가 매우 복잡하였다.

먼저, 6개의 마이크로서비스로 서비스가 분리되었다. 그리고 각 서비스는 stateless한 구조로 개발되어, 쿠버네티스 클러스터에 디플로이되었다. 그리고, stateless한 서비스의 상태 복구를 위해 DB를 이용했는데, 복구만을 위해 이용하니, 그냥 팟으로 같이 올렸다. 마이크로서비스로서 동작하기 위해, 또한 작업 등의 상태 복구를 위해 persistence한 메시지큐도 필요했다. 그리고 이 메시지큐로 채택된 것은 Apache Pulsar. IaC도 이용했다. helm chart와 terraform을 구성한다. 로깅도 빠질 수 없다. Elasticsearch + Fluentbit + Kibana 스택을 이용한다. 장애대응도 해야 한다. Kibana에서 Cloudwatch 메트릭을 쏴서 고객사에 문제 알림이 가능하도록 세팅해 줬다.

아닛? 보안 컴플라이언스? 코드를 고객사 서버에서 빌드하는데 CI/CD로 해달라고? 고객사 jenkins에 세팅해 줬다. 파일 반출이 간단하지 않다. 그냥 남겨둠. 보안? 그러고보니...? 네, 방화벽 타이트하게 쪼아주세요. 정신없이 VPC와 subnet, 그리고 EKS, ES 등의 매니지드서비스의 엔드포인트들을 이어가면서 방화벽 작업도 진행했다. 보안은 끝이 없다. 서비스의 IP를 고정해주세요. 네? 쿠버네티스 클러스터의 IP를 고정하라고? nginx로 로드밸런서 켜서 어떻게든 고정해줌. 아니 또 이 로드밸런서 키니까 any allowed 방화벽 룰이 추가되네? 다시 쪼아줌.

...(후략)

눈치챘겠지만, 드러나는 한계 feat. 소규모 팀

하지만 갈수록 한계가 드러났다. 6개의 마이크로서비스, 메시지큐, 디플로이를 위한 IaC들, 고객사의 요청에 따른 자잘한 커스터마이징들... 그와중에 terraform은 신나게 만들어 놓고, 고객사에서 사용을 거부하여 결국 손으로 세팅해야 했다.

가장 문제는 인원이었다. 상기한 것들을 감당하는 사람의 수는 초기엔 6명, 퇴사와 충원을 거처 4명이 되었다. 보통 한 팀이 하나의 마이크로서비스를 맡는다고 알고 있는데, 이 팀은 한 명이 여러 개의 마이크로서비스를 관리해야 했다.

존버는 승리한다 feat. 3.0

관리포인트 줄이기

분산된 마이크로서비스 중 기능이 겹치는 서비스들을 합쳤다. 그 결과, 6개의 마이크로서비스는 3개로 줄었다. 또한, 필요없는 레이어를 날려버렸다. SI처럼 타사에 설치를 해주는 상태에서 IaC는 사치였다. 일단 나 말고 아무도 못알아봄. helm chart를 날리고 모두 kubectl로 바로 deploy 가능하게 yaml파일을 구성했다. terraform은 애초에 2.0 설치하면서 고객사가 거부하여 못쓰게 되어 구경도 안해봤으므로 패스. 그냥 갖다버렸다. 추가로, 모 증권사만 이용하는 클라우드는 해당 증권사 전용이므로, 온프레미스 환경을 표준으로 삼고 bare-metal 설치를 중심으로 관리하면서, 혹시 클라우드를 이용하는 경우 온프레미스 환경에서 필요한 부분만 바꿔서 이용하는 방향으로 변경하였다. 아 그리고, 클라우드를 이용하던 그 증권사도 결국 엄청난 비용에 경악하며 온프레미스로 전환하였다.

코드베이스 리뉴얼

마이크로서비스를 통합하면서 구조를 변경하는 김에, 담당하던 마이크로서비스를 완전 리뉴얼하였다. 당시 난 레이어드패턴에 대해 막 배워가던 시절이었다. 근데, 난 개념을 배웠을 때 아무렇게나 응용하는게 특기라서, 액터 구조랑 혼합했다. type, interface, actor, loop, util 이렇게 5가지 요소로 나누었고, actor는 데이터 계층과 연결되는 interface를 이용하는 역할과, 동기화 이슈가 있을 수 있는 리소스를 관리하는 역할을, loop에는 비즈니스 로직을 몰아넣고, util엔 길고 가독성 떨어지거나, 반복적인 로직을 함수로 빼다가 넣었다. type은 말그대로 type.

그 결과, 내가 짠 코드라서 그런건지, 아니면 비즈니스로직이 한 군데에 몰려있어서 그런지는 모르겠지만, 이전엔 1~2주 걸리던 피쳐들을 하루이틀에 쳐낼 수 있게 되었다.

설치 난이도 줄이기

고객사에 설치 작업을 할 때 진행되는 과정 중 가장 어려운 것은 쿠버네티스 설치이다. 인터넷이 안되는 환경으로 필요한 바이너리와 이미지를 한 번에 들고가서 진행해야 하기 때문이다. 그런데, 그동안은 이 준비 과정을 매뉴얼하게 진행하고 있었고, 무슨 비급같이 생긴 문서를 참고하며 진행하였다.

네 잘하고 있어요. 하지만 쿠버네티스는 버전업 주기가 빠르답니다? 하하하하ㅏ핳....

설치할 때마다 대작업이었다. 그래서 설치 준비과정을 자동화했다. 그 김에 그냥 인터넷 될 때 이용하는 설치 스크립트도 같이 만들어서, 사내에서 이용하는 테스트용 서버 구축도 쉽게 되도록 했다.

문제는 1.26버전부터 dockershim 지원 중단... 그래서 싹 다시 짰는데 내 개발PC와 CI 서버에만 세팅 성공하고 고객사 설치는 아직 실패해서 1.22버전에 머물러 있다... 하지만 이 버전은 공식지원 종료라고 알고 있어서, 조만간 업그레이드해야함.

존버 승리?

승리한 듯 하다. 난 한동안 편해졌다. 그리고 새 역할이 추가되었다. 어...?

아 싫진 않다. 원래 인프라쪽 담당이라 리서치와는 좀 멀었는데, 추가된 새 역할은 리서치의 학습과 연관된 일이라서, 뇌가 덜심심하다. 인프라는 이건 이런데 저건 저렇고 그래서 이걸 바꾸면 또 저게 어쩌고 하는 정신없는 와중에 정신줄 붙잡는 느낌인데, 이쪽은 문제푸는 느낌이다. 인프라 하다가 현타오면 리서치쪽 업무 건들다가 진빠지면 인프라 건드리고 하면 됨.

또한 서비스 안정성이 미친듯이 높아졌다. 원래 우리 서비스는 성능은 좋지만 그와 동시에 장애의 아이콘이었는데, 내심 앞으로가 좀 기대된다.

얻은 것

  • 서비스 안정성
  • 직무능력
  • 처우개선

잃은 것

  • 2.0을 유지하다가 번아웃되어 사라진 팀원들
  • 눈알의 수분
  • 건강

배운 점

  • Simple is the best
  • 유지보수를 신경써서 설계하자
  • 힙해보이면 일단 다시 한 번 생각해보자
  • 이력서 쓰기 좋은 테크스택은 이런거구나

시스템 트레이딩 도전

핀테크 분야에 있다보니, 개발을 진행할 수록 금융에 대해 알아야 할 것들이 많아져서 내친김에 기본 지식도 갖출 겸 트레이딩 서적을 구매했다. 하지만 책만 읽으면 재미없을까봐 내친 김에 시스템 트레이딩에 도전하기로 했다. 그리고, Python 쓰면 재미없을까봐 내친 김에 Rust로 개발하기로 했다. 그리고, 트레이딩 서적을 그냥 읽기만 하면 기억이 안날 수 있으니, 계산식들을 직접 구현하고 있다. 그리고, Rust 개발자로서... 왠만하면 라이브러리가 없다는 고충을 잘 알기에, 계산식들은 물론 사용할 증권사의 OpenAPI 호출 로직까지 따로 빼내어 클라이언트 라이브러리로 만드는 중이다.

겸사겸사 끝판왕인 듯 하다.

아 물론, 메인 전략은 private이다. 안알랴줌. 물론 아직 존재하지도 않는다.

나름의 계획

  1. 일단 주식 현금주문, 정정/취소주문, 시세 OpenAPI 정상 작동하도록 완성(korea-investment-api)
  2. OpenAPI의 시세 스트림으로부터 trading-toolkit의 각종 수치들을 계산해서 HTS의 수치랑 비교해서 맞는지 확인, 틀리면 버그픽스
  3. 라이브러리 문서화
  4. 트레이딩 책에 나온 대로 아주 기본적인 전략 하나 구현 -> 평가 시작
  5. 고유한 전략 제작 -> 평가 반복

알리지 않고서는 못베기는 삽질

주식 현금주문 response의 status가 500으로 뜨는데 body조차 출력되지 않는 초유의 사태가 발생했다. 설상가상으로, 시니어인 팀장님이, OpenAPI 관리가 생각보다 개떡이라, 문서와 다른 경우가 있어 하나하나 찾아야 한다는 정보를 주셨다. 그래서 각종 auth 관련 리퀘스트도 싹 다 확인하고, 파라미터 대소문자, 언더바 바꿔보기 등 별의 별 짓을 다해보고 있었다.

윈도우 가상머신을 띄워서 과거 API 신청한 내역까지 다시 살펴봐도 별다른 문제는 없어 보였다.(그나저나 고작 API 신청한 계좌가 뭔지 보는데 윈도우 켜게 만드네. 화가 난다. 개발자센터는 왜 있는거임? 쓸 기능도 없는데 로그인은 왜 함?) 그러던 중, 그냥 curl로 호출해 보기로 했다. 왜 진작 안해봤을까. curl로 리퀘스트를 날리니, 사실 body가 있었다. 그리고 계좌번호가 틀렸다는 꿀정보를 담고 있었다.

띠용? 하고 다시 고생스럽게 켠 윈도우에서 계좌번호를 확인해보니, 뒷자리 3개가 달랐다. 그리고 그제서야 전에 모의투자 계좌를 재발급받았던 것이 떠올랐다............

그럼 이 문제의 원흉을 다시 색출하면 어느 놈일까.

답은 내가 짠 소스에 있다.

println!("{:?}", response);

잡았다 요놈!

response의 자료형에서 derive했을 Debug trait 탓이다. Debug trait을 impl하면서 fmt를 구현할텐데, 여기다 body를 안넣어놓은 것으로 보임. 그래서 header 까지만 딱 출력되고 body는 저기 어디 숨어서 코빼기도 보이지 않았던 것이었다.

결론: 사실 이 문제의 원흉은 진작에 curl 안 때려본 본인이다.

Rust를 업무에 사용하면서 느끼는 점들

현재 다니고 있는 회사의 소속팀에서는 Rust를 주 언어로 채택했다.
도입하신 분이 말씀하시길, 속도를 포기하지 않을 때 쓸 수 있는 언어는 C, C++, Rust 정도인데, C, C++은 개발자 마다 스타일이 천차만별이라서 Rust를 채택했다고 한다. 물론, 그 이외에 보안성 등은 말할 것도 없을 것이다.

여튼, 이 언어를 근 2년 가까이 사용하다 보니, 거의 적응이 된 듯 한데, 뭔가 불편하면서 편하다. 역설적인데, 딱 이렇게 느끼는 중이다. 애증의 관계이기도 하고. 근데 내 성격엔 이게 맞는 듯 하다.

1. 컴파일러가 일거수일투족 감시하면서 (딴지를 건다 / 가르쳐 준다[v])

이 컴파일러는 단순히 이걸 바이너리로 빌드했을 때 프로그램으로서 잘 돌 것인가만 중요한게 아니다.
다른 언어였으면 런타임에서 오류가 발생할 것들도, rust는 일부 잡아줄 수 있을 정도로 빡세다. 그리고 이건 rust의 소유권과 라이프타임 개념에서 오는데, 쭉 써오면서 느낀 점을 단순히 표현해 보자면, 아나바다 운동을 철폐하라는것이다. 아껴쓰고 나눠쓰고 바꿔쓰고 다시쓰다가 취약점 발생해서 쉘 뜯기지 말라는거.

그래서 가끔 정말 귀찮으면 클론 범벅의 코드가 된다. 이것도 신경 좀 쓰면 최소화 할 수 있는데, 당장 급해서 막 짜다 보면 뭔 문장 끝마다 clone을 남발하고 있다. 만약 C/C++이랑 퍼포먼스 비교했을 때 Rust가 더 떨어진다면, 아마 이 클론들 때문일 듯 하다. clone을 하지 않는 바이너리는 서로 비교했을 때 거의 똑같지 않을까 싶다.

그래서, copy를 잘못하거나, 포인터를 잘못 이용해서 뜻밖의 곳에서 수정이 일어나는 등의 사소하고 찾기 힘든 것들은 왠만하면 거의 일어나지 않는다. 덕분에 지금까지 발생한 버그들은 대부분 비즈니스 로직이나, Network 문제, 비동기 이슈 이 세 가지 안에서만 일어났다.

반대로 불편한 점도 있는데, 라이브러리를 만들 때이다. 최근 회사에서 actor 구조를 라이브러리로 만들었다가 재밌어서 왠만한 돌려쓸 수 있을 것 같은 것들은 다 라이브러리로 빼서 만들고 있는데, 제네릭, 트레잇, 소유권, 라이프타임 이 네 가지가 콜라보되니까 난이도가 급상승한다. 심지어 컴파일러도 여기까지 오면 자기도 헷깔려서 핵심 원인을 안짚어주는 경우가 많다. 그래서 컴파일러에서 뱉는 오류 메시지들의 패턴을 익히는 중이다.

개인적으로는 '가르쳐 준다'에 한 표 던진다. 경력이 2년밖에 안되는 쩌리 개발자가 여따 대고 딴지 건다고 하면 이건 오만이다. 지금 회사가 첫 개발 커리어를 시작한 곳인데, 사수 시스템이 따로 없다. 그런데 업무 지시/지도를 해주시는 팀장님과 함께 사수 역할을 도와준 것이 바로 rust 컴파일러다.

2. 라이브러리가 많지 않다

이제는 개발을 시작할 때, 라이브러리 찾는데 시간을 별로 할애하지 않는다. 실무에서 rust를 사용하는 케이스가 아직 많지 않다 보니, 알아서 구현해야 하는 경우가 꽤 있다. 한국투자증권 API도 마찬가지 이유로 시작된 프로젝트다. "한투 분들이 python으로 예제코드까지 방대하게 잘 구현해 놓으셨지만, rust 사용자는 python은 죽어도 쓸 수 없다며 알 수 없는 오기에 사로잡혀 스스로 API 클라이언트를 개발하게 되었다." 식의 스토리가 꽤 자주 있다. 그래서 시스템 트레이딩 전략을 만들기는 커녕 아직도 라이브러리단 개발만 이어지고 있다. 근데 뭐 이거 당장 안끝낸다고 밥 못벌어먹는 것도 아니고, 일단 재밌으니까 쭉 이어서 하고 있긴 하다.

문제는 이렇게 개발이 늘어지는걸 실무에서는 용납하지 않는다. 그래서 그냥 본인이 미친듯이 빨라져야 함. 근데 개인적으로, 갈수록 빨라져서 지금은 딱히 불편하지 않다. 다만 내가 짠 라이브러리를 돌려쓰는데 문제가 없을지 걱정되긴 한다. 아무리 라이브러리로써 개발한다고 해도 내가 담당하는 마이크로서비스에 알게모르게 맞춰지기 마련이기 때문이다. 게다가, 나중에 만약 이직하거나 퇴사하게 된다면, 인수인계를 했을 때 계속 쓸 지도 의문이다. 만약 퇴사 타이밍에 남아있을 rust 개발자들의 실력이 올라오지 않으면 제네릭, 트레잇, 매크로를 이해해서 라이브러리를 유지보수하는 것보다 각 마이크로서비스에서 따로 개발하는게 빠를 수도 있다. 물론 지금 팀원들이 그때도 계속 남으면 인수인계 쌉가능일 듯 하다.
근데, 라이브러리를 직접 만드는게 재밌긴 하다. 뭔가를 만들려고 할 때 제약이 사라진다. 일단 라이브러리 없다고 포기하는 개발자는 아니게 되었다. 컴퓨터 뺨을 쎄리며 개발하는 느낌이다. 안되면 되게 하라.

3. C/C++과는 다른 개념으로 높은 적응 난이도

적응하기가 쉽지 않다. C/C++은 스타일이 너무 다양하다는 것, 그리고 메모리 누수와 취약점이 쉽게 발생하는게 어려운 요소라면, rust는 컴파일 조건이 너무 까다로워서 실행조차 해볼 수 없다는 것이 어려운 요소이다. 소유권, 라이프사이클은 그 다음의 문제이다. 비컴파일 언어를 좋아하는 개발자는 가장 극혐하는 언어가 될 가능성이 높아 보인다. 로그 찍어서 보는 것조차 허용되지 않으니, 구조를 잘 짜고, 뇌내에서 잘 기억하면서 짜야 한다(잘 메모해 두던가). 물론 그걸 해결해주는 것이 테스트코드이기 때문에, 어떤 경우엔 TDD에 아주 적합한 언어가 될 지도 모르겠다. 하지만 컴파일이 되지 않는 상태에서는 테스트코드도 실행이 안되므로, 작게 작게 완결된 코드를 짜야 한다. 안그럼 지옥을 맛볼 것이다. 덕분에 개발 습관은 잘 잡히는 것 같다고 생각한다. 아님 말고.

대충 요---런 특징들이 있는데, 이 세 가지 모두 나는 좋아한다. 일단 1번은 이미 이유를 설명했고, 2번의 경우, 원래 내가 라이브러리 대충 익혀서 가져다 쓰는걸 좋아하지 않는다. 라이브러리를 써서 빠르게 결과물을 내는 것은 회사 입장에서 아주 중요하겠지만, 개발자로서는 '라이브러리 사용법 빨리 익히기', '라이브러리 빨리 찾기'와 같이 나이가 먹으면서 밀려날 수밖에 없는 능력만 기른다는 생각을 떨칠 수가 없다. 게다가, 이런 능력을 자신의 무기라 할 수 있을까? 토익과 같을 것이라 생각한다. 이건 당연히 어느정도 잘 해야 하는 것이고, 그 다음 무언가가 있어야 그 이상으로 올라갈 수 있을 것이라 생각한다. 아 그리고, 라이브러리 써서 빠르게 결과물을 내는게 중요한 단계의 회사라면, 십중팔구 초기 프로덕트를 만들거나 이것저것 MVP 양산하면서 되는거 하나를 찾기 위한 회사일 가능성이 높은데, 확률상 제대로된 회사는 많지 않을 것이다. 그 회사에 인생을 걸어보겠다는 각오가 없다면, 이런 능력을 요구하는 회사는 더 철저한 검증을 해봐야 할 것이다. 토익점수만 요구하는 회사는 수상할 수밖에 없다.
3번의 경우, 마찬가지로 내 무기가 될 수단으로서 손색이 없기 때문에 선호한다. 어려운 만큼 따라오기도 힘들다. 물론 너무 어려우면 시장에서 사장될 수 있겠지만, 그럴 수준은 아니다. 메모리 취약점 없는 성능좋은 프로그램을 개발하는 수준에 도달하는데 1-2년 걸린다고 생각해보면, 오히려 rust는 쉬운 언어라고 해야 한다고 생각한다. 단지 러닝커브가 지수함수라서 처음에 느릴 뿐이다.

결론: X같은 rust 만만세