(537)

늦은 3월 회고 - 기존의 업무 방식을 깨보기, AX로 나아가기

들어가며꽃이 만개하든 말든, 여러 다양한 시도들을 하며 재밌게 바쁘게 알차게 보냈던 3월의 회고.3월엔 이전의 회고들에서도 주구장창 얘기했던, 깊게 하는 생각을 다 깨고 빠르게 빠르게 바로 시도해 볼 수 있는 기반을 닦았다고 생각이 든다. 기존의 틀을 깨보기어떻게 보면 AI 과도기인, 산업 혁명(?) 과도 같은 시기에 있는 지금. 아무리 스타트업이라고 하더라도 스프린트에 어느정도 고착화되어 있을 수 있다. 우리 또한 마찬가지라고 생각했다. 기존 업무 방식인 스프린트 단위의 사이클도 물론 빠르지만 PM/디자이너/개발자 등의 업무 체계가 명확하게 나뉘어져있고, 의사 소통에서 오는 병목이 반드시 존재한다. 물론 AI Native하게 바로 가자! 도 아니고, AI를 맹신해서 하는 말도 아니다. 다만 지금 시..

uWSGI buffer-size와 502, 서버가 죽었나?

서론여느 때처럼 평화롭게 개발을 하던 어느날, 프로덕트의 dev 환경에서 502가 계속해서 발생했습니다. 지표도 정상이고 헬스 체크도 정상이고, 도대체 무슨 문제인지 긴가민가 했습니다. 로그를 확인 해 본 결과 처음보는 낯선 에러가 발생하더군요 요약하자면 Python WSGI 애플리케이션 서버인 uWSGI의 buffer-size 설정 값을 초과했기 때문이었습니다. 찾아보니 이 buffer-size는 요청 헤더의 사이즈의 설정 값이라고 하더군요. Express를 사용했을 때를 떠올려보면 발생하지 않았던 문제였습니다. 요청 헤더가 커서 요청이 Drop된 적이 없었기 때문입니다.이에 관련된 CS적인 지식은 기초 수준의 간단한 것입니다만, Django 진영의 웹 서버는 왜 이런 방식을 선택했는지 궁금해서, 기록..

입사 후 개인의 불편함에서 시작해 전사 AI 플랫폼을 만들기까지

서론 AI 시대에 개발자로 살아남으려면 - 백엔드 개발자의 스타트업 수습 회고서론이직 후 딱 3개월이 되는 오늘, 수습 전환 계약서에 사인을 했다.돌아보면 정신없었다. 이전 환경과 달리, 스택도 도메인도 업무 방식도 전부 다른 환경에 던져졌다. 이전 회사에서는 IDC 환mag1c.tistory.com 스타트업으로 이직 후, 수습 회고 통해 입사 후 혼란스러운 환경을 개선하기 위한 노력들을 소개했었습니다. 요약하자면 빠르게 적응하기 위해 개인적으로 가장 필요했던 것이 무엇인지 생각해봤고, 자주 연달아 이어지는 구두 논의나 회의 때문에 이전 맥락을 잊어버리기 일쑤였습니다. 이를 극복하기 위해 미팅 컨텍스트 허브를 만들어서 개인적으로 사용해왔습니다. 미팅 녹음을 올리면 AI가 자동으로 요약하고, 결정사항을 ..

Claude Code 바이브 코딩으로 30분만에 멜론 잔여 좌석 티켓 알림 만들기

현 와이프분께서 엑소에 재입덕하신 관계로, 멜론 잔여 좌석 티켓 알림을 한 번 만들어봤다. 로직은 굉장히 단순하다. 저 수많은 자리들 중 원하는거 선택해서 빈 자리가 있는지 간간히 트래킹하는 방식이다. 그래서 빈자리가 있으면 디스코드나 슬랙 등 웹훅이 있는 곳으로 쏴주는 방식.. 요새 Codex vs Claude Code를 심심할 때 마다 경쟁시키고 퍼포먼스를 대조해보는데, 이번엔 어느정도 요구사항이 명확해서일까 클로드가 작업이 더 빨리 끝났다. 클로드는 30분 정도, Codex는 1시간 20분 정도 걸렸다. (오케스트레이터(내)가 멍청했던걸까?) 옛날에도 필요한 게 있으면 직접 만들었지만, 요새는 더 빨리 만들어지는 것 같다. 제목이 멜론 빈자리 알림 뭐시기여서 그런 것 같지만, 그냥 AI의..

겜스고(GamsGo)로 AI 시대에 비싼 구독료로부터 탈출하기

본 글은 소정의 원고료를 지급 받아 작성한 글입니다.링크를 통한 구독이나 프로모션 코드를 입력하면 더 할인된 가격으로 이용해 볼 수 있다고 합니다. 링크: https://www.gamsgo.com/partner/sVffq프로모션 코드: CEGAD 대 AI 시대인 만큼, 또 개발자이니 만큼 직면할 수 밖에 없는게 AI 구독료입니다. 저는 현재, Claude Code Max를 2개, GPT Pro를 1개를 비롯해 커서와 Claude API, OpenAI API, Gemini API를 별도로 사용중입니다. 이를 환산해보면 한 달에 대략 700$ 정도 지출하고 있는 셈이에요. 저는 이 지출을 최대한 아끼기 위해, Claude Code Max 구독료를 절반 가격에 이용할 수 있는 겜스고(Gams..

AI 시대에 개발자로 살아남으려면 - 백엔드 개발자의 스타트업 수습 회고

서론이직 후 딱 3개월이 되는 오늘, 수습 전환 계약서에 사인을 했다.돌아보면 정신없었다. 이전 환경과 달리, 스택도 도메인도 업무 방식도 전부 다른 환경에 던져졌다. 이전 회사에서는 IDC 환경에서 NodeJS를 사용했다. 현재 조직에서는 Django와 AWS를 사용한다. 모든 게 낯설고 적응하기에 바빴던 것 같다.혼란스러웠고, 지금도 완전히 정리되진 않았다. IDC에서 콘솔을 들여다보는 게 문제여서 PLG로 모니터링 인프라를 구축했던 것처럼, 이번에도 무언가 시도하려고 파닥거렸던 것 같다. 수습 회고기획이 버무려진 디자인을 받으면 스스로 판단해서 구현하는 환경에서 2년가량 근무했다. 소통의 필요가 적었고, 혼자 깊게 고민하는 게 습관이 되었다. 문제는 성장이 정체된 느낌이었다. 주어진 업무를 수..

2026년 1월 회고 - 이직 후 적응하기, 러너스하이 2기, Claude Code Max 200$ 등..

항상 회고글은 러프하게 남기는 것 같은데, 이번에도 역시.. 혼란스럽다.굉장히 혼란스럽다. 여태까지는 항상 요구사항이 담긴 기획서를 보고, 개발자가 정할 것들을 스스로 정해서 판단하고 개발하는 환경에 있었다. 생각해보면 개발자 이전, 내 삶의 전반에 항상 결정 후 통보가 일상이었던 것 같다. 그래도 어느 조직의 개발자이기 때문에, 어느정도 개발 스펙도 검토를 해야한다. 그래서 이전보다는 조금 나아졌다고 생각했다. 여러모로 혼란스러운데, 정리하자면1. 소통이 생각보다 어렵다.2. 목적조직과 파트의 업무. 그리고 개인 업무 사이에서 너무 많은 컨텍스트가 오간다. 소통이 어렵다.항상 혼자 의사결정을 했기 때문에 내면에서 많이 고민을 했다. 그래서 정말 크리티컬한 이슈가 아니면 혼자 생각을 많이 하는 ..

ccusage보다 1000배 빠른 AI 토큰 트래커 오픈소스를 만들기까지

한줄 요약:ccusage보다 최저 40배, 최대 1000배 빠른 오픈소스를 만들다. GitHub - mag123c/toktrack: Ultra-fast token & cost tracker for Claude Code, Codex CLI, and Gemini CLIUltra-fast token & cost tracker for Claude Code, Codex CLI, and Gemini CLI - mag123c/toktrackgithub.com 개발 동기갑자기 느려진 ccusageccusage를 출시 이래로 정말 잘 사용하고 있던 사용자 중 한 명이었습니다. 그런데 최근 체감될 정도로 느려졌어요. Claude Code의 JSONL 파일들을 확인해봤습니다. # 용량du -sh ~/.claude/pro..

GoP(Garden of Practice) 회고 - 주니어 개발자 성장을 위한 커뮤니티!?

작년을 돌아보며 개인적으로 가장 크게 남았던 경험은 오픈소스 기여를 통해 진행했던 발표였다. 3년차 백엔드 개발자의 2025년 회고 (첫 이직)서론2023년 2024년 회고를 되돌아보니 현실의 벽을 넘기 위한 노력, 의지들이 많이 보였습니다. 하지만 그 벽이 얼마나 높은지 가늠조차 되지 않았었던 것 같아요. 하지만 2025년 한 해는 어느 정도mag1c.tistory.com 누군가에게 내 지식과 경험을 전달하려면, 단순히 알고 있는 수준을 넘어 더 깊이 이해하고, 불필요한 것을 덜어내며, 핵심만 남기는 과정이 필요하다는 걸 체감했기 때문이다. 발표를 준비하며 느낀 건 잘 전달한다는 건 말솜씨의 문제가 아니라 이해의 깊이와 사고의 구조가 드러나는 결과라는 점이었다.이런 생각을 하던 시기에 조직의 CPO ..

늦은 3월 회고 - 기존의 업무 방식을 깨보기, AX로 나아가기

회고 2026. 4. 8. 22:01
728x90
728x90

 

들어가며

꽃이 만개하든 말든, 여러 다양한 시도들을 하며 재밌게 바쁘게 알차게 보냈던 3월의 회고.

3월엔 이전의 회고들에서도 주구장창 얘기했던, 깊게 하는 생각을 다 깨고 빠르게 빠르게 바로 시도해 볼 수 있는 기반을 닦았다고 생각이 든다.

 

 

 

기존의 틀을 깨보기

어떻게 보면 AI 과도기인, 산업 혁명(?) 과도 같은 시기에 있는 지금. 아무리 스타트업이라고 하더라도 스프린트에 어느정도 고착화되어 있을 수 있다. 우리 또한 마찬가지라고 생각했다. 기존 업무 방식인 스프린트 단위의 사이클도 물론 빠르지만 PM/디자이너/개발자 등의 업무 체계가 명확하게 나뉘어져있고, 의사 소통에서 오는 병목이 반드시 존재한다.

 

물론 AI Native하게 바로 가자! 도 아니고, AI를 맹신해서 하는 말도 아니다. 다만 지금 시점에는 스프린트 업무를 가져가면서 병렬로 충분히 가져갈 수 있는 부수 업무들이 많아질 수 있다고 생각한다. 또 다른 얘기로는, 본인의 판단이 맞다고 생각이 든다면 어느정도 PoC를 빠르게 내볼 수 있는 환경 정도는 이미 갖추어져 있다고 생각이 든다.

 

그래서 시도했던건, 조직 내에 여러 레거시 제품들 중에서, 꾸준히 수익이 나는데 휴먼 루프가 많은 것들을 선정하여 1인 풀스택으로 AI Native하게 개발을 진행했다. 그들의 리소스를 절감하면서, 자연스레 제품의 뎁스도 간소화도 이루어졌고 그 결과 해당 기능들을 이용하는 고객들이 조금 늘어났다.

 

 

풀스택 개발을 자랑하려고 하는 것도, 컨텍스트 엔지니어링을 좀 잘하는 것 같다. 라고 으스대려고 하는 말도 아니다. 다만 기존의 업무 방식을 냅다 망치들고 갖다 깨버릴 수 있는 사람이 나타났다!!! 정도로 이해해주길 바란다. 충분히 의도한 바가 맞고, 이런 시도들이 모여 결국 조직의 업무 방식이 긍정적으로 변화할 수 있길 바라는 마음이다.

 

 

 

AX, AX, AX!!!!

AI 관련된 글을 많이 쓰긴 하지만, AI 맹신론자는 아니다. 오히려 Claude Blue라고 불리는, AI 우울증 환자 중 한명이다.

그럼에도 분명한건, 더 많은 기여를 할 수 있는 환경이 깔렸다는 것에는 이견이 없다.

 

위에 업무 틀을 깨부수는 시도를 했던 것 처럼, 업무 틀을 깨부술 수 있는 가장 좋은 것이 전사적으로 AI를 활용하여 필요한 것들을 만들어 나갈 수 있으면 어떨까? 하는 것이었다. 그게 AX가 되겠지..

 

그 전까지는, 전사적으로 가져갈만한 조직적인 컨텍스트 관리 도구라던가, 부수적인 봇들을 만드는데 치중했던 것 같다. 뭔가 이런 것들로는 한계가 있을 것이라고 판단해서 - 결국 내가 계속 만들게 되면 업무 틀을 깨는게 아니게 되니 - 3월 초에는, 제품 운영팀 리드분께 Claude Code 사용을 위해 하네스 세팅을 해드리는 것으로 방향을 틀었다.

 

 

 

하루에도 수십 번씩 커밋을 하시면서 나아가시는 모습들을 보면서 괜히 뿌듯하다. 요새는 직접 하네스도 고쳐보시고 스킬도 직접 만들어보시는 등 사내 AX 챔피언으로 자리매김하고 계신다.

 

의도는 명확했던 것 같다. 최초에는 운영 팀 분들이 쓸 수 있는 전용 대시보드가 필요했고 - 구글 시트, 어드민 페이지 등등 여러 관리 도구들을 통합하기 위함 - 이걸 통합하는 PoC를 빠르게 구축해 드리려했다. 하지만 니즈를 듣고 이해하는데도 병목이 생기니, 직접 해보시라고 깔아드린 것이었다.

 

이런 사례들도 하나하나 씨앗이 되어 조직적인 AX의 한 걸음을 걸을 수 있지 않을까? 라는 생각이 든다. 더불어 내가 만든 도구들도 잘 말아서, 조직적인 AX에 여기저기 활용할 수 있도록 시도해 볼 생각이다.

 

 

 

묵묵히 나아갈 걸음

프론티어가 아니면 어떤가 라는 생각이 계속해서 든다. 조직적으로도 개인적으로도 말이다.

며칠 전 Claude Code 유출 사건 때 Sionic AI의 진형님이 몇 시간 만에 Rust로 클로드 코드를 포팅한 레포가 화제가 됐다.

오픈클로를 만든 사람이나, OmC, OmX등을 만든 예찬님, 링크드인에 좋은 사례들을 공유해주시는 프론티어처럼 욕심을 내고 잘 안됐을 때 현타가 오는 경험도 겪었던 것 같다.

 

현재 공유 오피스 건물에 AICX 팀을 별도로 또 운영하고 있는, 미디엄 블로그로 AX 사례를 거의 찍어내다시피 공유하는 마이리얼트립 또한 어떻게 보면 조직적인 AX는 프론티어라는 생각이 들었다.

 

요즘은 그에 비해 속도가 느리다고 도태되었다거나, 조급해하는 생각을 아예 없애버렸다. 생각해보면 Node도 Nightly 스냅샷을 내놓고 여러 실험들을 하지만 결국 LTS가 선택받는다. LLM 사용 사례를 봐도 여러 키워드들이 나왔다 사라졌지만 최근 트렌드는 결국 Nightly를 시도했던 프론티어 분들이 결론낸 하네스나 컨텍스트 엔지니어링이고, 그걸 잘 말아서 쓰는 사람이 결국 퍼포먼스를 내고 있다고 생각한다.

 

그래서, 결국 도구에 불과한 이 녀석을 멀리 하지만 않고 변화에 능동적으로 대응할 수 있으면 되지 않을까? 라는 조금 내려놓는 마음가짐을 요새는 가지려고 하는 중인 것 같다.

 

 

 

 

마치며

다음달 회고에는 단기 목표도 어느정도 이뤘는지 리마인드 하기 위해 이번 달에 세운 목표를 첨부하는 것을 마무리로, 글을 마무리하려고 한다. 어떤 시대건 간에 결국 묵묵히 해내고 해낸 것들을 체화할 수 있는 사람이 결국 성장하고 나아가지 않나. 라는 생각이다

 

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

uWSGI buffer-size와 502, 서버가 죽었나?

삽질/트러블슈팅 2026. 4. 2. 23:05
728x90
728x90

서론

여느 때처럼 평화롭게 개발을 하던 어느날, 프로덕트의 dev 환경에서 502가 계속해서 발생했습니다. 지표도 정상이고 헬스 체크도 정상이고, 도대체 무슨 문제인지 긴가민가 했습니다. 로그를 확인 해 본 결과 처음보는 낯선 에러가 발생하더군요

 

요약하자면 Python WSGI 애플리케이션 서버인 uWSGI의 buffer-size 설정 값을 초과했기 때문이었습니다. 찾아보니 이 buffer-size는 요청 헤더의 사이즈의 설정 값이라고 하더군요.

 

Express를 사용했을 때를 떠올려보면 발생하지 않았던 문제였습니다. 요청 헤더가 커서 요청이 Drop된 적이 없었기 때문입니다.

이에 관련된 CS적인 지식은 기초 수준의 간단한 것입니다만, Django 진영의 웹 서버는 왜 이런 방식을 선택했는지 궁금해서, 기록 겸 포스팅을 남깁니다.

 

 

 

원인

위에서 정리했듯이, 원인은 HTTP 요청 헤더의 사이즈 초과입니다. 

 

 

uWSGI 관련 공식 문서를 보면, 버퍼 사이즈는 매우 작게 설정되어있으며, 로그에서 이상 현상이 감지된다면 더 큰 사이즈로 변경이 필요할 수도 있다고 언급되어 있습니다. 말은 쉽지만 실제 환경에서는 충분히 문제가 발생할 수 있고 저 또한 겪었습니다. 핫픽스로 배포를 나가도 물려있는 CICD 때문에 10여분 넘게 다운타임이 발생할 수 있는 것이죠 (실제로는 서버 다운은 아니고 UX적인 다운타임이겠습니다.)

 

정확한 원인을 추적하기 위해 좀 더 깊게 파악해보겠습니다.

 

일반적인 Python 웹 서비스는 요청이 리버스 프록시(nginx)를 통해 uWSGI를 거쳐 Django로 들어오는 흐름입니다. 리버스 프록시는 클라이언트로부터 요청을 받아 uWSGI로 패킷을 전달 할 때 uwsgi 바이너리 프로토콜로 변환해서 보내게 됩니다.

 

 

# nginx 설정
location / {
  uwsgi_pass unix:///tmp/uwsgi.sock;
  include    uwsgi_params;
}


uwsgi_pass를 쓰면 nginx가 HTTP 헤더들을 uwsgi 프로토콜의 key-value 쌍으로 변환하고, 이걸 하나의 uwsgi 패킷으로 직렬화해서 전송합니다. uwsgi 프로토콜 스펙 자체가 하나의 패킷을 전달 받아야만 하는 스펙으로 설계가 되어있기 때문입니다. uwsgi 프로토콜은 패킷 헤더에 datasize라는 변수를 16비트 정수로 담습니다.

struct uwsgi_packet_header {
  uint8_t modifier1;
  uint16_t datasize;
  uint8_t modifier2;
};

 

 

패킷 헤더의 datasize가 뒤따르는 전체 데이터 크기를 나타내는 구조라서, 요청 메타데이터를 여러 패킷으로 나눠 보내는 개념이 없습니다. 그래서 수신 측인 uWSGI도 이 패킷을 고정 버퍼에 통째로 받는 구조가 됩니다.

 

즉, 버퍼 사이즈를 초과하는 요청이 들어오면 uWSGI는 Django에 요청을 넘기지 않고 Drop하게 됩니다. 서버가 죽은 것이 아니라 요청이 앱에 도달하기 전에 버려지게 되어 헬스 체크는 200인데 UX는 다운된 것처럼 보였던 것입니다.

 

 

 

 

Express

이전에 썻던 Node의 Express는 파싱 방식과 기본값에서 차이가 있었습니다.

Node의 HTTP 파서인 llhttp는 헤더를 고정 버퍼에 담지 않습니다. 들어오는 데이터를 바이트 단위로 스트리밍하면서, 누적 크기만 카운터로 추적합니다.

 

nodejs의 http parser

 

고정 버퍼에 통째로 담는 uWSGI와 달리 파싱하면서 카운터만 올리는 방식입니다. 그리고 결정적으로 기본 제한값이 16KB로 크기 때문에 대부분의 상황에서 발견하지 못했습니다. 더불어 uwsgi처럼 바이너리 프로토콜 변환 없이 raw HTTP를 직접 파싱하기 때문에 프로토콜 크기의 제약도 없습니다.

 

즉, Express를 사용했을 때는 같은 요청이여도 서버가 받아들이는 구조가 다르기 때문에 한 번도 겪어본 적이 없었습니다.

 

 

 

 

해결

원인을 알았으니 해결책은 명확하겠죠..?

 

근본 원인인 헤더가 커진 이유를 조사하기 시작했습니다. 짐작하시겠지만, 프로덕트가 커져가면서 구워지는(?) 쿠키도 많아졌습니다. 구체적으로는 A/B 테스트나 지표 추적을 위해 이벤트를 심는 양이 늘어남에 따라 쿠키가 같이 늘어났습니다. 디버깅 결과 전체 쿠키의 70% 이상이 해당 지표 추적을 위한 쿠키였고, 계속해서 늘어나고 있었습니다. 브라우저가 요청마다 이 쿠키를 전부 실어 보내는 구조였기 때문에 점점 헤더 사이즈가 커지면서 결국 터져버렸던 것입니다.

 

저희는 일단 버퍼 사이즈를 늘리는 것으로 선조치를 했습니다. 하지만 쿠키가 계속 늘어난다면 또 터질테니 근본 해결책은 아니겠죠.

 

 

 

 

CloudFront Origin Request Policy에서 쿠키를 필터링하거나 로컬 스토리지로 쿠키를 마이그레이션, 쿠키 도메인을 분리하는 등의 방안을 고려중에 있습니다. 각각 하나씩 간단히 살펴보면서 마무리하겠습니다.

 

CloudFront가 오리진(nginx/uWSGI)에 요청을 전달할 때 필요한 쿠키만 화이트리스트로 전달하도록 설정이 가능합니다.

브라우저는 쿠키를 다 보내지만 CF가 걸러줄 수 있도록 설정이 가능하다고 합니다. 프론트 코드 변경 없이 인프라 설정만으로 적용이 가능하지만, CF를 통하지 않고 직접 접근할 때는 효과가 없습니다.

 

서버에 보낼 필요가 없는 데이터를 쿠키에서 로컬 스토리지로 마이그레이션하는 방법도 있습니다.

이 방법은 서버가 읽어야 하는 쿠키는 이동이 불가능하고, 프론트 코드 변경이 필요할 수도 있습니다.

 

마지막으로 쿠키 도메인을 분리하는 방법입니다.

.example.com에 쿠키가 설정되면 모든 서브도메인에 전송됩니다. 이걸 api.example.com으로 분리하고 쿠키 도메인을 서브도메인 별로 격리하면, API 요청에는 해당 서브도메인 쿠키만 실리게 되겠죠. 가장 구조적인 해결이 될 것이라 생각하는데, 서드파티 스크립트인 GA나 이벤트 도구 등이 최상위 도메인에 쿠키를 설정해야한다면, 통제가 어려울 수도 있겠습니다. (아직 확인해보진 않았습니다.)

 

 

 

 

마무리

오랜만에, 정말 오랜만에 AI에서 벗어나 실제 문제를 좀 깊게 파볼 수 있는 시간이었습니다. 

 

 

 

 

Ref

https://peps.python.org/pep-3333/

https://uwsgi-docs.readthedocs.io/en/latest/Protocol.html

https://uwsgi-docs.readthedocs.io/en/latest

https://github.com/nodejs/llhttp

https://github.com/nodejs/node/blob/main/src/node_http_parser.cc#L1023-L1030

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html

https://datatracker.ietf.org/doc/html/rfc6265#section-5.4

 

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

입사 후 개인의 불편함에서 시작해 전사 AI 플랫폼을 만들기까지

Tech/기타 2026. 3. 28. 13:53
728x90
728x90

 

서론

 

AI 시대에 개발자로 살아남으려면 - 백엔드 개발자의 스타트업 수습 회고

서론이직 후 딱 3개월이 되는 오늘, 수습 전환 계약서에 사인을 했다.돌아보면 정신없었다. 이전 환경과 달리, 스택도 도메인도 업무 방식도 전부 다른 환경에 던져졌다. 이전 회사에서는 IDC 환

mag1c.tistory.com

 

 

스타트업으로 이직 후, 수습 회고 통해 입사 후 혼란스러운 환경을 개선하기 위한 노력들을 소개했었습니다.

 

요약하자면 빠르게 적응하기 위해 개인적으로 가장 필요했던 것이 무엇인지 생각해봤고, 자주 연달아 이어지는 구두 논의나 회의 때문에 이전 맥락을 잊어버리기 일쑤였습니다. 이를 극복하기 위해 미팅 컨텍스트 허브를 만들어서 개인적으로 사용해왔습니다. 미팅 녹음을 올리면 AI가 자동으로 요약하고, 결정사항을 뽑아주고, 임베딩해서 검색 가능하게 만들어주는 도구였습니다.

 

개인적으로 만들어 사용했던 미팅 컨텍스트 허브

 


개인적으로 MCH(Meeting-Context-Hub)라고 부르는 이 도구의 사용성이 꽤나 좋았어서 전사적으로 공유해야겠다고 생각했던 찰나, 사내에서도 티로라고 불리는 비슷한 제품을 구독해서 사용하기 시작했습니다. 미팅록을 한 곳에 모으고 정리하는 역할은 티로가 해결해버렸습니다. 전사적으로 제 도구를 도입하지는 못했지만, 이 과정을 겪으면서 돌아보게 된 것이 있습니다.

 

구성원들이 더 효율적으로 빠르게 일하기 위해, 현재 워크플로우의 문제들이 무엇일까?


미팅에서 결정된 내용은 티로를 통해 확인할 수 있습니다. 하지만 그 결정이 실행되는 과정은 슬랙 스레드에 흩어집니다. 더불어 큰 의사결정 안에서 작은 논의들이 계속 오가고, 자잘하게 변경되는 내용도 많습니다.

또, 저는 이제 막 수습을 지났습니다. 제가 입사하기 이전의 수 많은 컨텍스트는 무시되어도 되는 걸까요? 이전 조직 구성원들이 슬랙에 나눈 대화와 정리된 노션 문서 또한 조직의 자산입니다. 이건 저희 조직 뿐 아니라 어떤 조직이든 공통적인 부분이라고 생각합니다.

MCH를 만들면서 느낀 건, 개인의 기억력 문제가 아니라 조직의 맥락이 검색 가능한 형태로 존재하지 않는다는 것이었습니다. 미팅록은 그 퍼즐의 한 조각일 뿐이고, 여러 컨텍스트들이 전부 한 곳에 모여야 비로소 재활용 가능한 가장 좋은 형태가 될 것이라고 생각했습니다. 원활하게 꺼내볼 수 있어야 이걸 찾아보는 리소스도 줄어들고, 자연스레 다음 스텝이 있을 수 있다고 판단했습니다. 그래서 이 허브를 전사의 컨텍스트 허브로 확장해보기로 했습니다.

 

 

사내 컨텍스트 허브인 아라

 

 

 

데이터 수집 파이프라인 설계

사람이 작업을 하든, AI가 하든 맥락이 있어야 합니다. 당연하게도 슬랙과 노션에 흩어진 조직의 지식을 한 곳에 모으는 것이 첫 시작이었습니다. 현재 파이프라인을 시각화하면 아래와 같습니다.

 

 

 

 

임베딩

임베딩을 통해 텍스트를 고정 길이의 숫자 벡터로 변환합니다. 예를 들어 연차 규정휴가 정책의 글자는 다르지만, 임베딩 벡터 간의 거리는 가깝다는 논리입니다. 이를 이용하면 키워드가 정확히 일치하지 않아도 의미적으로 유사한 문서를 찾을 수 있게 됩니다.

 

 

 

임베딩에는 OpenAI의 text-embedding-3-small 모델을 사용했습니다. 우선은 빠르게 PoC를 구축하는 것이 목표였기 때문에 API 호출 한 번으로 바로 쓸 수 있고, 비용이 저렴한 것을 우선에 뒀습니다. 블로그를 작성하는 지금 시점에서는 임베딩 벤치마크 리더보드에서 괜찮은 모델로 마이그레이션 할 계획을 가지고 있습니다.

 

변환된 벡터를 SQLite에 AI가 추출한 메타데이터와 함께 저장합니다. AI가 뽑아낸 메타데이터(제목, 요약, 태그)는 키워드 검색과 필터링에 활용하고, 임베딩은 시맨틱 검색에 활용됩니다. 이 때 수집된 원본 텍스트는 반드시 그대로 보존합니다.  조직의 데이터 규모가 수천 건 수준이기 때문에 파일 하나로 단순하게 관리되고, 백업에도 용이하기 때문입니다. 코사인 유사도(임베딩) 계산은 애플리케이션 레벨에서 수행할 수 있는 수준이기 때문에 SQLite를 사용했습니다.

 

 

 

 

메타데이터 추출 파이프라인

메타데이터를 수집 시점에 AI가 한 번 추출하지만, 특히 긴 문서의 경우 중요한 결정사항이나 맥락을 놓치는 경우가 있었습니다. 

그래서 2-pass 구조로 확장하여, 최초 수집 시점은 빠르게 처리하고, 그 뒤에 정교한 분석을 수행하도록 했습니다.

 

// notion-ingester.ts — 2nd pass는 fire-and-forget
const firstPass: FirstPassResult = {
  title: ctx.context.title ?? '',
  summary: ctx.context.summary ?? '',
  decisions: ctx.context.decisions ?? [],
  actionItems: ctx.context.actionItems ?? [],
  tags: mergedTags,
};

runEnhancedExtraction(ctx.context.id, rawInput, firstPass, null, { skipGuard: true })
  .catch(err => console.warn(`Enhanced extraction failed:`, err));

 

2nd pass에서는 1st pass의 결과와 원본 텍스트를 함께 LLM에게 전달하여 최종 검토를 하게 됩니다.

 

 

 

 

데이터 수집

현재 조직의 컨텍스트는 노션과 슬랙으로 관리되고 있습니다. 두 도구의 성격이 당연히 다른데요.

  • 슬랙: 러프한 대화 위주의 내용. 잡담도 포함. 데이터 구조가 단순하며 플랫함(최대 1Depth Thread 구조)
  • 노션: 구조화된 포맷을 기반으로 각 논의된 내용들을 어느정도 정리함. 페이지, DB 등 여러 Depth로 구성되어 복잡함

도구의 성격이 다른 만큼, 수집 방법도 달랐는데요, 슬랙과 노션의 수집 방법은 이렇습니다.

 

 

슬랙

평일 1시간 단위의 스케줄러가 슬랙의 채널 대화를 수집합니다. 채널 중에는 정말 잡담을 위한 채널도 존재하고, 레거시 채널도 존재합니다. 수집할 필요가 없는 채널들을 제외하고 화이트리스트 방식으로 수집 대상 채널만 직접 선택하는 구조로 만들었습니다. 이 채널의 대화는 조직의 지식으로 보존할 가치가 있다고 판단되는 채널만 등록했습니다.

 

굳이 디테일을 언급하자면, 증분 수집을 위해 채널 단위의 독립적인 워터마크를 추가했습니다.

// slack-watermark.service.ts
export interface ChannelWatermark {
  channelId: string;
  channelName: string;
  lastThreadTs: string;    // 마지막 수집 시점의 타임스탬프
  updatedAt: string;
}

 

이를 통해 각 채널의 메세지와 쓰레드를 증분 수집했고, 별도 노이즈 필터링을 통해 봇 메세지나 시스템 메세지, 10자 미만 메세지나 특정 노이즈 키워드(ㅋㅋ, 넵 등등)를 위한 딕셔너리를 별도로 두어 관리하고 있습니다.

 

 

노션

노션은 특정 결정의 중간/최종 산물의 성격을 띱니다. 그렇기에 평일 12시간 단위로 08:00, 20:00에 하루 일과 시작 전/후를 고려하여 배치 시간을 정했습니다.

 

위에서 언급했듯이 노션은 복잡한 뎁스의 트리 구조입니다. 페이지 안에 하위 페이지가 있고, 그 안에 또 하위 페이지가 있을 수 있죠. 데이터베이스 안에 row가 있고, 각 row도 하나의 페이지입니다. 그래서 기존 노션 문서들의 포맷을 보면서, 어느 깊이까지 탐색해야 할 지 정했습니다.

 

 

 

더불어 중복과 업데이트 처리도 같이 신경 써야했습니다. 같은 배치 안에서 상위 하위 페이지가 모두 수집 대상이 될 수 있고, 이미 수집한 페이지가 수정되었을 경우도 충분히 발생할 수 있는 경우이기 때문입니다.

 

// notion-ingester.ts — 중복/업데이트 판별
for (const page of pages) {
  // 제외 대상 페이지 또는 그 하위 트리 전체를 건너뜀
  if (excludeSet.has(page.id) || (page.parentId && excludeSet.has(page.parentId))) {
    result.skippedExcluded++;
    continue;
  }

  // 동일 배치 내 중복 제거
  if (seenPageIds.has(page.id)) {
    result.skippedDuplicate++;
    continue;
  }
  seenPageIds.add(page.id);

  // 마지막 수집 이후 수정되지 않은 페이지는 건너뜀
  const existing = existingByPageId.get(page.id);
  if (existing && existing.lastEditedTime >= page.lastEditedTime) {
    result.skippedUnchanged++;
  } else {
    toProcess.push(page);
  }
}

 

 

결론적으로, 제외 목록을 건너뛰고, 배치 내 중복을 건너뛰며, 마지막으로 변경 여부를 확인하여 건너 뛰는 로직을 통과한 페이지만 5개의 동시 워커로 병렬 처리했습니다.

 

 

 

 

RAG는 실패했다

결론부터 얘기하자면, 저는 RAG 방식으로 대차게 실패했습니다. 첫 시도부터 틀려먹어서 좀 당황했습니다. 이 허브를 구축하면서 RAG에 관련된 레퍼런스를 많이 찾아봤는데, 정말 매력적이고 좋은 패턴이라고 생각합니다. 다만 저는 이 패턴에 대한 이해도가 모자랐기 때문에 실패했다고 생각합니다.

 

 

제 최초 설계는 5단계 RAG 파이프라인이었습니다.

  1. SEARCH -  임베딩 유사도 + 키워드(SQL LIKE) 하이브리드 검색
  2. FILTER - 유사도 0.3(30%) 미만 결과 제거
  3. ENRICH - 슬랙 메타(채널명, 날짜), 미팅록이 있다면 미팅록의 메타로 검색 결과 보강
  4. ASSEMBLE - Token Budget(21000자, 약 6000토큰) 내에서 컨텍스트 조립
  5. SYNTHESIZE - Claude에게 조립된 컨텍스트와 질문을 전달하여 답변 생성

 

 

거창하게 5단계를 나눠서 썻지만, 결론적으로 RAG란 제가 미리 특정 컨텍스트를 단정지어서 LM에게 넘기는 방식입니다.

 

위 실패 케이스를 자세히 살펴보고 비슷한 실험들을 토대로 결론을 내릴 수 있었습니다. 결국 긴 문서에서 제가 설계한 방법은 틀려먹었다는 겁니다. 저희 노션 페이지에 긴 문서들의 특징은 한 페이지 안에 여러 주제의 내용들이 혼재되어 있는 경우에 해당합니다. 위 연차 규정 같은 경우도 신규 입사자 온보딩 가이드라는 큰 문서의 한 섹션에 있었고, 저는 그 가이드 전체를 통째로 임베딩 했었던 것이었습니다.

 

문서 전체를 하나의 벡터로 변환했을 때, 그 벡터는 문서의 평균적인 의미를 담습니다. 과연 이 문서가 연차 규정인지 알까요? 당연히 연차 규정이라는 질문과 코사인 유사도가 0.3 미만으로 나왔고, 2단계 필터에서 잘려나갔습니다.

 

 

 

문제점을 파악했다면 당연히 개발자스럽게 해결하면 되겠습니다. 문서를 작은 단위로 쪼개면 해결하기 쉽겠죠? 바로 청킹(Chunking)을 사용하면 됩니다. 청킹이란 방대한 정보나 개별 요소를 의미 있는 작은 덩어리(Chunk)로 묶어 기억하거나 처리하는 인지 심리학 기법이라고 합니다. 여기서의 청킹이란, 긴 문서를 청크 단위로 쪼개서 각각을 별도로 임베딩한다는 의미로 이해하시면 됩니다. 온보딩 가이드를 섹션별로 나누면 연차 섹션의 임베딩이 질문과 높은 유사도를 보일 것입니다.

 


하지만 청킹은 새로운 튜닝 포인트를 만듭니다. 청크 크기는 얼마로 할 지? 크기에 따라 문맥이 잘릴 수도 있겠죠... 문맥이 잘리면 이전 결정 사항과 분리되어 의미를 잃을 수 있고, 너무 크다면 원래 문제가 재현됩니다. 이를 위해 오버랩을 사용할 수 있습니다. 하지만 오버랩은 노션 페이지가 수정될 때 마다 청크를 다시 나누고 임베딩을 또 해야되는 문제가 있겠죠...

 

또 다른 방법으로, 청킹 과정에서도 별도 LLM 레이어를 두어 문맥 단위로 청킹 시키도록 할 수 있겠습니다. 하지만 저는 이런 방법들로 또 다른 문제를 야기할 수도 있다는 생각에, 검색 파이프라인을 고도화하는 방법에서 LLM의 자율 주행에 몸을 맡겨보기로 했습니다.

 

 

 

Agentic Search

사실 선택의 이유는 두 가지가 더 있습니다. Claude Code의 모델이 발전함에 따라 알아서 잘 찾겠구나 라는 생각과 거기에 기름을 부어준 클로드 코드 창시자인 Boris Cherny의 트윗을 보고 빠르게 전환을 결심했습니다. 트윗의 내용은 Claude Code 자체도 초기에는 RAG + 로컬 벡터 DB 기반이었다가 Agentic Search로 전환했다는 내용입니다.

 

Agentic Search를 통해 검색 파이프라인의 각 단계를 사람이 하드코딩하지 않고, LLM에게 검색 도구를 쥐어주고 스스로 판단하게 했습니다. 사람이 어떤 순서로 검색할지 정하는 게 아니라 LLM이 질문을 보고 건 키워드 검색이 낫겠다, 이 문서의 3번째 섹션을 읽어야겠다 를 자율적으로 결정합니다.

 

 

Agentic Search도 거창해보이지만 간단합니다. 로컬 CLI로 여태까지 Claude Code를 사용했던 경험을 떠올려 보니 자연스레 MCP를 떠올렸습니다. 저는 8가지 MCP를 통해 LLM의 자율 주행을 보장했습니다. 각 MCP는 Claude Agent SDK의 tool()로 정의하고, query()를 통해 질문과 MCP를 포함한 각종 옵션들을 넘겨 사용합니다. 

 

// tools.ts — MCP 도구 정의 예시
const searchByMeaning = tool(
  'search_by_meaning',
  '의미 기반(시맨틱) 검색입니다. 질문과 의미적으로 유사한 문서를 찾습니다.',
  {
    query: z.string().describe('검색할 질문 또는 문장'),
    sourceType: z.enum(['slack', 'notion', 'meeting', 'cs-kb']).optional(),
    channel: z.string().optional().describe('채널명 필터'),
  },
  async ({ query, sourceType, channel }) => {
    const results = await semanticSearch(query, { sourceType, channel, limit: 30 });
    return {
      content: [{ type: 'text' as const, text: JSON.stringify(results, null, 2) }]
    };
  },
);
// agentic-orchestrator.ts
const conversation = query({
  prompt: req.question,
  options: {
    systemPrompt,
    mcpServers: { 'hub-search': mcpServer },
    maxTurns: 12,
    model: 'claude-sonnet-4-6',
  },
});

 

 

 

현재 구성해둔 MCP들은 다음과 같습니다.

MCP 기능 설계 의도
search_by_meaning 임베딩 기반 시멘틱 검색 의미가 유사한 문서를 넓게 탐색
search_by_keyword SQL LIKE로 제목/요약/본문 매칭 고유명사, 정확한 키워드 검색
search_by_tag 태그 AND 조건 필터(ex. doctype:policy) 문서 유형별 필터링
list_channel_contexts 특정 슬랙 채널 벌크 조회 채널 단위 맥락 파악
read_context 문서 1건 전체 읽기 검색 결과의 상세 내용 파악
read_context_section 문서 내 제목, 소제목 기준 특정 섹션만 읽기 긴 문서에서 필요한 부분만 추출
list_sources 수집된 데이터 목록 조회 어떤 데이터가 있는지 빠르게 파악
generate_document 마크다운 > DOCX 변환 후 슬랙 업로드 검색 결과를 문서로 정리

 

 

이렇게 MCP를 분리해서 LLM이 질문의 성격에 따라 전략을 선택할 수 있게 했습니다. 위의 연차 규정처럼 명확한 키워드가 있으면 바로 search_by_keyword를 사용하고, 최근 팀 분위기가 어떠니? 같은 모호한 질문에는 search_by_meaning을 사용합니다. 짧은 스레드는 read_context로 전체를 읽으면 되지만, 긴 맥락은 read_context_section으로 맥락 내 특정 섹션만 읽어야 효율적입니다. 

 

LLM이 완전히 자율적으로 도구를 선택하지만, 효율적인 전략을 가이드했습니다.
예를 들어 검색형 질의에는 search_by_meaning을 우선 사용하고 고유명사가 포함된 질문에는 search_by_keyword을 먼저, 분석형 질의에는 list_channel_contexts로 벌크 조회를 수행하라는 가이드가 있습니다.

 

 

 

 

 

연차 규정 알려줘 라는 동일한 질문에 대해 이제 Agent Search는 다음과 같이 동작합니다.

 

 

 

모든 도구 선택을 LLM이 자율적으로 수행합니다. 임베딩 유사도에 의존하지 않기 때문에 긴 문서 안에 묻힌 정보도 정확히 찾아낼 수 있게 되었습니다. 

 

 

 

운영하면서 겪은 문제들

2~3주 정도 운영해오면서 아래와 같은 이슈들을 발견했고, 다음과 같이 수정했습니다.

 

  1. 유사도가 낮은 문서까지 여러 개 확인하면서 응답 시간이 수 분까지 늘어났다
    • 비동기 + graceful degradation(실패해도 답변을 돌려줌)로 개선
  2. 슬랙 스레드에서 후속 질문을 하면 이전 대화 맥락을 몰라 발생하는 문제
    • 스레드의 이전 메세지를 수집해서 질문에 컨텍스트로 주입

 

 

 

 

맺으며

개인의 미팅록 관리 도구에서, 필요한 것들을 하나씩 추가하며 점진적으로 구조를 정리하고 전사적인 플랫폼으로 발전시키려고 했습니다. 이 허브가 궁극적으로 지향하는 것은 조직의 기억입니다. 누구든지 직군의 구분 없이 조직의 맥락을 쉽게 파악하고, 과거 논의와 결정을 즉시 찾아주고 담당자가 바뀌어도 히스토리가 유실되지 않게 하는 것. 그것을 사람의 손으로 항상 문서를 정리하고 인수인계를 만들어야 했던 것들을 당장에 해결할 수 있겠죠. 또, 이 허브를 바탕으로 CS 자동화도 쉽게 구축할 수 있습니다. 허브에 과거 CS들을 최초 정리만 하고, 정말 필요 시 CX 담당자가 직접 소통 할 때, CX 담당자의 상담 내용을 재학습하는 하네스를 구축한다면 쉽게 도달 할 수 있는 영역입니다.

(이미 CS 봇은 테스트 중에 있습니다.)

 

물론 위에서 언급한 UX가 전부라 생각하지는 않습니다. 저는 이 허브를 바탕으로, 다양한 시도들을 해나갈 생각입니다. 이 허브가 정말 두뇌라면, AX화를 하기 위한 멀티 에이전트의 오케스트레이터가 되기에 가장 적합하다고 생각합니다. 이러한 방향으로 발전시켜 볼 생각입니다.

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

Claude Code 바이브 코딩으로 30분만에 멜론 잔여 좌석 티켓 알림 만들기

2026. 2. 27. 09:15
728x90
728x90

 
 
현 와이프분께서 엑소에 재입덕하신 관계로, 멜론 잔여 좌석 티켓 알림을 한 번 만들어봤다.
 

 
 
로직은 굉장히 단순하다.
 

 
 
저 수많은 자리들 중 원하는거 선택해서 빈 자리가 있는지 간간히 트래킹하는 방식이다. 그래서 빈자리가 있으면 디스코드나 슬랙 등 웹훅이 있는 곳으로 쏴주는 방식..
 

 
 
요새 Codex vs Claude Code를 심심할 때 마다 경쟁시키고 퍼포먼스를 대조해보는데, 이번엔 어느정도 요구사항이 명확해서일까 클로드가 작업이 더 빨리 끝났다.
 
클로드는 30분 정도, Codex는 1시간 20분 정도 걸렸다. (오케스트레이터(내)가 멍청했던걸까?)
 
옛날에도 필요한 게 있으면 직접 만들었지만, 요새는 더 빨리 만들어지는 것 같다.
 
제목이 멜론 빈자리 알림 뭐시기여서 그런 것 같지만, 그냥 AI의 산업 혁명 시대에 살고 있는 지금의 내가 느끼는 이 감정이 이전 산업 혁명을 살아가던 분들이 느끼던 감정일까? 막연히 두렵기도 하고 설레고 재밌기도 하다 ㅋㅋ

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

겜스고(GamsGo)로 AI 시대에 비싼 구독료로부터 탈출하기

2026. 2. 25. 20:20
728x90
728x90

 

본 글은 소정의 원고료를 지급 받아 작성한 글입니다.

링크를 통한 구독이나 프로모션 코드를 입력하면 더 할인된 가격으로 이용해 볼 수 있다고 합니다.

 

링크: https://www.gamsgo.com/partner/sVffq

프로모션 코드: CEGAD

 

 

 

 

 

대 AI 시대인 만큼, 또 개발자이니 만큼 직면할 수 밖에 없는게 AI 구독료입니다.

 

AI Token Cost Tracking 오픈소스 - toktrack

 

 

저는 현재, Claude Code Max를 2개, GPT Pro를 1개를 비롯해 커서와 Claude API, OpenAI API, Gemini API를 별도로 사용중입니다. 이를 환산해보면 한 달에 대략 700$ 정도 지출하고 있는 셈이에요.

 

 

 

 

 

저는 이 지출을 최대한 아끼기 위해, Claude Code Max 구독료를 절반 가격에 이용할 수 있는 겜스고(GamsGo)를 활용하고 있습니다.

 

 

 

 

 

 

겜스고는 OTT, 스트리밍과 더불어 최근 대세가 된 AI의 여러 모델들을 절반 이상의 가격으로 구독하여 사용할 수 있는 구독 공유 플랫폼입니다.

 

옛날에는 단순히 OTT나 스포티파이 등의 스트리밍 플랫폼의 구독료 절감을 위해 사용했었던 기억이 있는데요.

최초에는 저도 유튜브 프리미엄을 사용하기 위해 구독 공유 플랫폼인 겜스고를 이용했었습니다.

 

보시다시피 유튜브 프리미엄, 티빙, 넷플릭스 가격이 절반 혹은 절반 이상 할인된 가격으로 이용할 수 있어요.

 

 

 

 

 

 

 

하지만 최근 AI 시대가 되면서, 비개발자분들도 쉽게 AI를 접하고있고, 긍정적이든 부정적이든 바이브코딩이나 AI로 생산성을 높이는 분들이 많이 늘어났습니다. 이 때문인지 겜스고에서도 다양한 AI 툴들을 반 이상 할인된 가격으로 접해보실 수 있어요.

 

ChatGPT, 클로드 프로, 클로드 맥스, 제미나이 등의 메이저 AI와 다른 AI들도 할인된 가격으로 사용해 볼 수 있어요.

 

 

 

 

 

워낙 AI 툴들의 가격이 비싸기 때문에, 절반 이상의 할인이 더 크게 체감이 되는 것 같습니다.

 

 

클로드 맥스를 구매

 

 

 

 

결제를 하고 나면 겜스고에서 제공해주는 가이드 링크에 자세한 설명이 나와있다.

가이드를 따라 차례차례 진행하면 된다. 설정에 한 2분 걸렸던 것 같다.

 

 

【Claude】Max-20x (Pre-Activated Account) Instructions for use

Claude Max-20x Pre-Activated Account Instructions for use

doc.gamsgo.com

 

 

 

 

 

 

가이드를 따라 세팅해주면 클로드 코드를 할인된, 반 값으로 이용할 수 있다.

 

 

 


 

 

 

 

 

AI를 다양하게 사용해보고 싶지만, 비싼 가격 때문에 망설여지신다면 이 포스팅이 조금 도움이 되셨으면 좋겠습니다.

 

기본 반 이상 할인된 가격과 더불어 조금 더 할인된 혜택을 받아보고 싶으시다면 아래 링크, 프로모션 코드를 활용해보셔도 좋겠습니다.

링크: https://www.gamsgo.com/partner/sVffq
프로모션 코드: CEGAD

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

AI 시대에 개발자로 살아남으려면 - 백엔드 개발자의 스타트업 수습 회고

회고 2026. 2. 23. 22:34
728x90
728x90

서론

이직 후 딱 3개월이 되는 오늘, 수습 전환 계약서에 사인을 했다.

돌아보면 정신없었다. 이전 환경과 달리, 스택도 도메인도 업무 방식도 전부 다른 환경에 던져졌다. 이전 회사에서는 IDC 환경에서 NodeJS를 사용했다. 현재 조직에서는 Django와 AWS를 사용한다. 모든 게 낯설고 적응하기에 바빴던 것 같다.

혼란스러웠고, 지금도 완전히 정리되진 않았다. IDC에서 콘솔을 들여다보는 게 문제여서 PLG로 모니터링 인프라를 구축했던 것처럼, 이번에도 무언가 시도하려고 파닥거렸던 것 같다.

 

 

 


 

수습 회고

기획이 버무려진 디자인을 받으면 스스로 판단해서 구현하는 환경에서 2년가량 근무했다. 소통의 필요가 적었고, 혼자 깊게 고민하는 게 습관이 되었다. 문제는 성장이 정체된 느낌이었다. 주어진 업무를 수행하고, 안정적으로 다니는 분위기였던 것 같다.

물론 극복하기 위해 주도적으로 사내에 여러 레퍼런스를 공유하고, 오픈소스 기여도 활발하게 하는 등 열심히 했다. 하지만 조직 내에서의 성장이 가져다주는 것에 대한 목마름은 여전했다. 나는 성장 욕구가 있는 사람들 사이에서 서로 기여하고 기여받는 선순환 구조를 원했다.

그래서 이직했다. 완전히 새로운 도메인의 스타트업. 5년 이하 주니어 개발자들로 구성되어 있지만, 다들 성장하고자 하는 욕구가 강하고 서로 공유하는 문화. 제품에 깊게 관여하고, 개발 외에도 제품적 사고를 하는 조직. 여기라면 내가 원하는 환경이 될 수 있겠다고 생각했다.

 

 

 


 

 

 

스택이 바뀐 건 예상했지만, 업무 방식의 변화는 예상 밖이었다.

전 직장에서는 대부분 하나의 프로젝트씩 순차적으로 수행했다. 현재 조직은 스프린트 단위의 잦은 회의, 노션이나 슬랙 등 여러 업무 도구들에 분산된 정보들이 쏟아졌다. 단순히 일이 많은 게 아니라, 정보가 파편화되어 있었다. 어제 회의에서 뭐라고 했는지, 그 결정이 노션 어디에 있는지, 슬랙 어느 채널에서 논의가 이어졌는지 이걸 따라가는 것 자체가 일이었다. 나는 잘 잊어먹는 스타일이라 이게 치명적이었다.

 

 

개인의 문제를 해결해서 빠르게 적응을 해야했다. 그래서 MCH라 불리우는 업무를 위한 보조 도구를 만들게 되었다.

 

회의 중 발생하는 컨텍스트(텍스트/음성)를 입력하면 AI가 자동으로 분류하고, 프로젝트별로 체이닝해서 관리하는 TUI 도구를 만들었다. 마이크 녹음 → 자동 청크 분할 → STT → 임베딩을 통한 분류까지 추가했다. 나와 더불어 성장하고 제품에 대한 이해도를 같이 높일 수 있도록, 컴파운드 엔지니어링과 유사한 TIL도 추가했다. 점진적인 교정을 위한 도메인 용어 교정 사전도 넣었다.

 

 

이 데이터를 재활용해서 워크로그 대시보드를 만들었다. 오늘의 미팅, 코드 활동, AI 세션, GitHub 활동을 한 화면에서 볼 수 있는 도구. 하루 만에 MVP를 완성했다. 이 도구를 통해 조직에서의 나의 컨텍스트 관리를 정말 편하게 할 수 있게 되었다.

 

 

 


 

 

MCH를 만들 때는 조직의 문제를 해결하겠다는 거창한 생각이 없었다. 그냥 내가 혼란스러워서, 내 문제를 해결하려고 만들었다.

 

이번엔, 현재 조직에서 ROI가 높은게 무엇이 있을까? 고민해보았다. 하지만 마땅히 보이지는 않았다.

그러던 와중 조직의 슬랙 오류 제보 채널을 보면서 이거 매번 사람이 봐야 하나?라는 의문을 가졌다. 대부분 간단한 수정이기도 하고 이미 Agentic Workflow는 자리잡았기 때문이었다.

 

n8n 워크플로우 엔진 위에 Claude Code를 커스텀 노드로 올리고, Slack에서 앱 멘션으로 트리거하는 핫픽스봇을 만들었다. CS 문의가 들어오면 AI가 코드베이스를 분석하고, 원인과 수정 방안을 Slack으로 보고하고, 버튼 하나로 PR까지 생성하는 시스템이다. 전사적으로 사용할 수 있도록, 비개발자도 사용할 수 있도록 깎아나가는 중이다.

 

 

 


 

 

그런데 돌아보면, 이것들이 결국 AX의 출발점인가? 라는 생각이 들었다. 정보가 파편화되어있다 는 나의 문제, 반복적인 오류 분석에 시간을 쓴다 라는 기존 워크플로우의 문제도 모두 조직의 문제이기 때문이다.

AI로 기존 문제들을 해결하기 위한 시도들을 했던 덕분일까? 테크 조직 내에서도 2026년 목표에 대한 얘기들을 했을 때, 자연스레 AX로 역할을 정하게 되었다.

 

그런데 AX를 어떻게 접근해야할까?

자동화에 너무 초점이 맞춰져 있다는 생각이 들던 와중 일론 머스크의 어떤 인터뷰 내용을 전해 들었다.

 

회사에 있는 모든 사람은 벡터다. 진전은 그 모든 벡터의 합으로 결정된다. 대기업에선 벡터들이 서로 다른 방향을 가리키기 쉬워 합이 0이 된다. xAI는 엔지니어 팀은 작지만 모든 벡터가 같은 방향을 향한다. 그래서 합이 크게 나온다.

 

크기가 아무리 커도 방향이 다르면 의미가 없다. AX도 마찬가지라고 생각했다. 단순 자동화가 목적이 아니라, 조직의 실제 문제를 해결하는 게 목적이어야 한다고 생각했다. AX를 AI 도입이 아니라 MCH를 만들 때처럼 문제 해결로 접근하자. 솔루션이 아니라 문제에서 출발하자. 이 생각을 조직 대표님과의 커피챗에서 나눴다. 

 


AX를 위해 조직원 한 명 한 명 일정을 조율하고 커피챗을 시작했다. 업무의 문제점과 불편함을 묻고, AI를 어디 사용하고 계시는지 등에 대한 인터뷰를 진행하고있다.

 

 

 

3개월동안 스프린트를 통해 제품 중심의 사고와 소통하는 방향에 대해 가닥을 잡고, 조직의 문제를 AI와 연계해서 해결하고자 하는 시도들을 하고 있다. 조금 더 문제를 잘게 쪼개고, 소통도 작게 작게 하는 방향으로 점진적으로 변해가고 있다. 아직도 여전히 혼란스럽지만 더 많고 다양한 시도들을 통해 조직에 다채롭게 기여하고 싶은 바람이다.

 

 

 


 

 

 

AI 시대에 어떻게 살아남아야할지 모르겠다.

나름 여러 시도들을 하면서도 계속 드는 생각이 있다. AI 시대에 어떻게 살아남아야 할지 모르겠다.

수습 기간동안 작업물들을 보면 백엔드 모노레포에 커밋이 835개, 기타 작업물들을 합치면 1500개 가량의 커밋을 올렸다.
Claude의 JSONL 세션 파일이 960개가 넘고, 최근 Codex를 병행해서 사용하니 5GB가량, 1000개 가량의 세션 파일이 있다.

 

숫자가 많은지 적은지는 모르겠고, 이 모든것이 AI로 작성되었다는게 주제의 핵심이다.

문제를 해결하기 위해 A to Z 코딩을 했던 과거에서, 트렌드에 맞게 나 또한 의사 결정만 수행하고, AI 에게 코딩을 시키고 오케스트레이션만 수행하고 있다. 예전에는 내가 직접 코드를 쓰면서 이 로직은 왜 이렇게 돼야 하지? 를 코드 레벨에서 사고했다. 지금은 단순 코드보다는 구조에 대한 생각을 더 많이한다. 관점이 코드에서 시스템으로, 구현에서 설계로 이동했다.

이게 성장인지, 아니면 하드스킬의 도태인지 아직 모르겠다. 그래서 아직까지는 이게 불안하다고 느낀다. 어느 정도 개발력이 되는 개발자분들과 달리, 저연차의 주니어 개발자이기 때문에 여러모로 지식이 많이 달린다고 생각했다.

 

 

 

최근 본 개발바닥의 강바닥에 벽돌 쌓기 영상에서 들은 말이 계속 머리에 맴돈다.

 

AI가 만들어낸 결과물의 좋고 나쁨을 판단할 수 있는 눈을 갖추고, 그 결과물이 실제 요구사항에 적합한지 평가하기 위해 꾸준한 학습이 필요하다.

 


아직 내가 좋은 코드를 알아보는 눈이 많이 부족하다고 느낀다. AI가 아무리 코드를 잘 써줘도, 그 코드가 이 프로젝트의 맥락에서 적절한지 판단하는 건 나의 몫이다. 하지만 현재 업무를 병행하면서 속도를 내기 위해선 이제 AI가 선택이 아니라 필수라고도 느낀다.

AI 때문에 더 조급한 요즘, 더 차분하게 벽돌을 차곡차곡 쌓아보려고한다.

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

2026년 1월 회고 - 이직 후 적응하기, 러너스하이 2기, Claude Code Max 200$ 등..

회고 2026. 2. 2. 22:15
728x90
728x90

 

 

항상 회고글은 러프하게 남기는 것 같은데, 이번에도 역시..

 

 

 

 

혼란스럽다.

굉장히 혼란스럽다. 여태까지는 항상 요구사항이 담긴 기획서를 보고, 개발자가 정할 것들을 스스로 정해서 판단하고 개발하는 환경에 있었다. 생각해보면 개발자 이전, 내 삶의 전반에 항상 결정 후 통보가 일상이었던 것 같다. 그래도 어느 조직의 개발자이기 때문에, 어느정도 개발 스펙도 검토를 해야한다. 그래서 이전보다는 조금 나아졌다고 생각했다.

 

여러모로 혼란스러운데, 정리하자면

1. 소통이 생각보다 어렵다.

2. 목적조직과 파트의 업무. 그리고 개인 업무 사이에서 너무 많은 컨텍스트가 오간다.

 

 

 

소통이 어렵다.

항상 혼자 의사결정을 했기 때문에 내면에서 많이 고민을 했다. 그래서 정말 크리티컬한 이슈가 아니면 혼자 생각을 많이 하는 것 같다.

더 많이 소통하고, 더 많이 물어보면서 조금씩 개선하고 있다. 하지만 부족하다. 더 많이, 귀찮을정도로 물어봐야된다고 생각한다.

단순 개발적인 부분을 넘어 제품을 함께 만드는 한 사람으로서 얼라인이 확실하게 되어야 할 것 같다.

 

 

너무 많은 컨텍스트.

다양한 언어들에서 동시성도 높이면서 병렬 처리를 할 수 있는 다양한 방법들이 많이 나왔었고, 더 좋은 퍼포먼스를 갈수록 보이고 있다.

AI도 마찬가지다. 동시에 여러 작업들을 멀티로 돌리면서, 다양한 일을 동시에 수행할 수 있게 됐다.

 

한 번에 하나의 업무만 하던 환경에서, 동시에 다양한 업무들을 처리하다보니 기록하는 습관으로는 부족하다 생각이 들었다.

노션, 슬랙과 더불어 킥오프, 핸드오프, 타운홀 등 수도 없는 구두 논의 등에서 적느라고 이해하지 못하고 넘어가고, 듣느라고 적지 못해서 기억하지 못하고 있다.

 

 

 

 

혼란을 해결해보자.

그러던 도중 링크드인에 좋은 AX 관련 글을 봤다. (분명 링크를 저장해뒀는데 어디갔는지 없다.)

 

기억하자면 미팅 내용을 PRD로 자동화해서 만들고, 1차 검토 후 Claude Code로 PR까지 생성한다는 내용이었다.

이 레퍼런스에서 아이디어를 얻어, 여러 컨텍스트들을 녹음하거나 텍스트로 붙여넣기하고 Claude Code로 연관성 있는 것들끼리 그룹핑해서 바로 확인할 수 있게 구성해보면 어떨까? 생각했고 바로 실행했다. 녹음은 회의가 길어질 수 있기 때문에, FFMPEG + 청크 단위로 Whisper API를 통해 텍스트로 변환하여 Claude Code에게 던지는 간단한 형태이다.

 

 

최종적으로는 옵시디언, 노션 등의 텍스트 에디터로 export하거나 GUI로 구성하는 것을 목표로 하고 있다.

꽤나 유용하게 사용하고 있는 개인 툴이다. (TUI에서 위 ASCII Text가 왜 깨지는지는 모르겠다)

 

GitHub - mag123c/meeting-context-hub

Contribute to mag123c/meeting-context-hub development by creating an account on GitHub.

github.com

 

기억하기 위한 기록에서 해방되고, 많은 결정사항들을 뒤에 까먹지 않을 수 있게 되었다.

추가로 노션, 슬랙 등에 파편화 되어있는 여러 PRD들, 제품에 대한 여러 내용들을 복사 붙여넣기를 통해 한 번에 관리할 수 있게 되어 매우 편해졌다.

 

 

 

별거아닌 링크 저장소용 Chorme Extension.

 

 

 

 

 

링크 형태의 레퍼런스들을 많이 가지고있는데, 기존에는 카카오톡 나와의 채팅에 보관하다가 Linko라는 개인 앱을 만들었다.

휴대폰으로는 개발 레퍼런스를 유튜브 밖에 보지 않다보니 텍스트 형태의 링크 레퍼런스는 보지 않았다.

언제 내가 기술 블로그같은 레퍼런스를 많이 보나 생각해보니 데스크탑 앞에 앉아있을 때였다. 그래서 이번엔 Chrome Extension으로 만들었다.

언제까지 쓸 지는 모르겠지만, 아직까지 유용하게 잘 쓰고 있다.

 

 

 

난 어디에 시간을 할애하고 있는가?

개인적으로, 조직원으로서 어디에 개인적으로 시간을 할애하고 있는지 갑자기 오늘 고민이 됐다.

현재 같은 스쿼드의 개발자 두 분과 오늘 점심을 먹었는데, 나에게 날아온 질문이었다. 현재 어떤 것들을 하고 계시고 어디에 각 얼마만큼의 시간을 할애하고 계시냐고.

 

그냥 궁금해서 하셨던 질문일지, 나와 같은 2~3년차를 지나오신 개발자분들이 나를 위해 해주신 질문인지는 모르겠다.

나는 개인적으로는 DX 향상이 느껴질 때 가장 보람을 느낀다. 그래서 개인적으로는 AX나 사용하고 있는 기술들 자체에 더 개선할 수 있는 부분, 혹은 우리가 잘못 사용하고 있어서 충분히 개선 가능한 부분들(성능적인 부분, 레거시 청산 등)에 기여하는 것을 좋아한다.

 

하지만, 특정 조직에 속해있는 일원으로서 조직의 제품이 성장할 때 가장 큰 보람을 느낄 것 같다. 프리랜서 생활을 할 때 내가 맡은 팀이 하위권에서 1등을 했던 경험을 잊지 못한다. 그 도파민을 실제 제품이 J커브를 그리면서 성장할 때 똑같이 느낄 수 있지 않을까?

 

그렇다면 정답은 나와있는 것 같기도 하다. 제품 성장을 위한 AX와, 제품을 개발하는 개발자로서 제품을 보는 눈도 성장시켜야 한다는 것을 점차 알아가고 있는 것 같다.

 

 

 

부록 [1] - 러너스하이 2기 회고

러너스하이 2기를 신청했었다.

단언컨데 이직의 의사는 아니었고, 나는 어떤 환경에서도 빠르게 적응하고 성과를 낼 수 있다는 자만이었던 것 같다.

ROI는 무슨 현재의 환경에서 나은 퍼포먼스를 내기 위해 적응하고 적응하느라 2달을 통째로 썻다.

러너스하이 마감일에 제출은 무슨ㅋㅋ.. 마감일까지 한 술도 못 떳다.

 

 

부록 [2] - 오픈소스 기여모임 10기 운영진

오픈소스 기여모임 10기 운영진 활동을 참여했다.

이 또한 부끄럽게도 선택의 실패인 것 같다. 나의 활동이 도움이 되신 분들이 한 분이라도 계신다면 정말 다행이지만, 이직 후 적응을 핑계로 오프라인 행사에도 참여하지 못했고, 내 스택이 아닌 부분들도 오픈소스 기여를 처음 접한 분들에게 도움이 될 수 있는 부분들을 충분히 도움을 드리지 못한 것 같다.

 

다음 기수에도 운영진으로 참여할 수 있다면, 더 나은 오픈소스 기여 경험과, 오픈소스 기여 문화를 위해 조금은 더 활동에 박차를 가해야겠다.

 

 

부록 [3] - Claude Code Max

역대 최대로 Claude Code 사용량이 많은 것 같다.

 

 

주말에는 사용량이 많이 줄어서, 평일만 기준으로 보면 평균 150$씩 사용하고 있는 것 같다. 한 달 정도 사용했는데 2700$를 돌파했다.

굳이 따지고보면 한 달은 아닌데, Claude Code 세션이 자동으로 30일 뒤에 삭제된다. 이걸 최근에 알았다.

 

1. 이것저것 다양하게 시도해보고, 외부 AX 사례들을 시도해본다.

2. AI를 곁들인 무언가를 만들어낸다. 개인적으로도, 조직의 제품 내에 녹여내기도..

3. 코드 자체를 쓰는건 앞으로 더욱 더 안하겠구나.

 

 

 

 

 

마치며

내 삶의 전반에서 맡은 역할에 최선을 다했고, 개발자로서 처음 속했던 조직에서도 맡은 바 최선을 다했고 최선의 결과를 보여왔다고 생각한다. 하지만 직급과 역할이 정해진 뚜렷한 환경에서, 개발자는 개발만 맡았다 라는 전제가 깔려있다.

 

스타트업으로 이직하면서 현재의 그릇에 많은 생각이 든다.

생각하건데 그릇을 키우기 위해 노력하는 것이 아니라 그릇 자체를 꺠부실 필요가 있다.

앞으로의 회고에서는, 이런 부분들에 대한 시도와 실패. 경험들을 주로 회고할 수 있도록 현재의 조직에서 최선의 결과를 만들어봐야겠다.

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

ccusage보다 1000배 빠른 AI 토큰 트래커 오픈소스를 만들기까지

OpenSource 2026. 2. 2. 21:29
728x90
728x90

 

 

한줄 요약

:

ccusage보다 최저 40배, 최대 1000배 빠른 오픈소스를 만들다.

 

 

 

GitHub - mag123c/toktrack: Ultra-fast token & cost tracker for Claude Code, Codex CLI, and Gemini CLI

Ultra-fast token & cost tracker for Claude Code, Codex CLI, and Gemini CLI - mag123c/toktrack

github.com

 

개발 동기

갑자기 느려진 ccusage

ccusage를 출시 이래로 정말 잘 사용하고 있던 사용자 중 한 명이었습니다. 그런데 최근 체감될 정도로 느려졌어요. Claude Code의 JSONL 파일들을 확인해봤습니다.

 

# 용량
du -sh ~/.claude/projects
3.4G

# 파일 수
find ~/.claude/projects -name "*.jsonl" | wc -l
2772

 

Claude Code는 기본적으로 30일 지난 세션 파일을 자동 삭제합니다. 그럼에도 불구하고 최근에 역대급으로 많이 사용해서 그런지, 세션 파일이 생각보다 많이 남아있더라구요. 아마 사용량이 엄청나게 증가해서, ccusage가 수집하는 데 많은 시간을 소요하는 것이라고 생각했습니다. 43초가 걸렸으니까요.

 

 

 

 

해결되지 않는 이슈

국내/해외 할 것 없이 저보다 많은 사용량을 가진 사람이 더 많을 것으로 생각되는데요. 역시나 ccusage의 깃헙에는 여러 관련 이슈들이 이미 발행되어있는 상태였습니다. (#821, #804, #718)

 

성능 관련 이슈들이 열려있고, PR들도 머지되지 않은 채 방치되어 있었습니다.

이참에 직접 만들어보기로 했습니다. 성능 좋기로 소문난 Rust로 만들면서, 관심 있던 Rust 학습도 겸할 수 있으니까요.

 

 

언어는 Rust로, JSON처리는 Rust의 simd-json을 사용했습니다.

 

 

NodeJS의 한계

ccusage는 제 주력 스택인 TS로 작성되어 있습니다.

// ccusage의 파일 처리 방식
import { readFile } from 'node:fs/promises';
import { glob } from 'tinyglobby';

const files = await glob(['**/*.jsonl']);

for (const file of files) {
  const content = await readFile(file, 'utf-8');
  for (const line of content.split('\n')) {
    const parsed = JSON.parse(line);
    // 처리...
  }
}

 

glob으로 파일을 탐색하고, fs로 파일을 읽고 JSON.parse로 파싱하게 되어있어요.

 

 

JSON.parse

V8은 JSON의 처리 성능을 꾸준히 개선해왔던 것으로 알고 있습니다.

v7.6에서는 JSON.parse의 메모리 최적화를, 최근 v13.8에서는 JSON.stringify의 SIMD 최적화가 대표적이죠.

하지만 이와 관계없이 JSON.parse는 여전히 순차 처리입니다.

 

JavaScript의 JSON.parse는 바이트 단위로 순차 처리합니다.

 

반면 simdjson은 CPU의 SIMD 명령어를 활용해 한 번에 32~64바이트를 병렬 처리하죠. simdjson은 초당 기가바이트 단위의 JSON을 처리할 수 있습니다. 문자 하나씩이 아니라 64문자를 한 번의 CPU 명령으로 처리하기 때문입니다.

 

 

 

물론 simdjson은 Node.js 바인딩도 존재하지만 유지 보수가 5년째 되지 않고 있어요.

그리고 JSON 파싱만 빨라져도 아래에서 다룰 싱글스레드, GC 오버헤드 문제는 여전히 남아있습니다.

 

 

fs.readFile

const content = await readFile(filePath, 'utf-8');

 

readFile은 파일 전체를 한 번에 메모리에 로드합니다. 2,772개 파일을 순차적으로 읽으면서 각 파일의 내용이 메모리에 올라가고, UTF-8 디코딩이 수행되고, 이후 split('\n')으로 또다시 새로운 문자열 배열이 생성됩니다.

createReadStream으로 스트리밍 읽기가 가능하지만, 어차피 JSON.parse는 완전한 문자열 단위로 동작하기 때문에 근본적 해결은 아닙니다.

 

 

 

 

libuv

Node.js의 파일 I/O는 이벤트 루프가 아닌 libuv의 스레드풀에서 처리됩니다. 기본값은 4개입니다.

 

 

UV_THREADPOOL_SIZE 환경변수로 늘릴 수 있지만, 실제로 테스트해본 결과 스레드풀을 32배로 늘려도 22% 개선이 한계였습니다.

CPU 사용률이 100%에 도달했는데도 33초. 파일 I/O를 병렬화해도 JSON.parse를 실행하는 메인 스레드가 병목이기 때문입니다.

Worker Threads로 JSON 파싱 자체를 병렬화할 수 있지만, Worker 간 데이터 전달 시 직렬화/역직렬화 오버헤드가 발생합니다. 결국 병렬로 파싱하려면 직렬화가 필요하고, 직렬화 자체가 파싱만큼 비싸다는 딜레마에 빠집니다.

 

 

GC

3GB 분량의 JSONL을 파싱하면 수많은 임시 객체가 생성됩니다. 이 정도 규모의 데이터를 처리하면 stop-the-world가 자주 발생할 것으로 추측됩니다. 실제로 ccusage 실행 중 --trace-gc 옵션으로 GC를 트레이싱해봤습니다.

 

# GC 트레이싱 결과 (3GB / 2,772 파일 처리)
총 GC 이벤트:       504회
힙 메모리 최대:      378MB
Major GC 단일 pause: 최대 135ms

 

# Major GC (Mark-Compact) 로그 일부
605 ms: Mark-Compact 195.3 → 163.4 MB, 135.79ms pause
1051 ms: Mark-Compact 273.0 → 239.9 MB
1378 ms: Mark-Compact 378.9 → 225.5 MB
1650 ms: Mark-Compact 390.2 → 210.9 MB
1886 ms: Mark-Compact 375.3 → 161.7 MB

 

V8은 Orinoco GC를 통해 Incremental Marking, Concurrent Sweeping 등으로 pause를 줄이고 있지만, 대용량 데이터를 처리할 때는 여전히 무시할 수 없는 오버헤드입니다. 50초 실행 중 504번의 GC가 발생했다는 것은, 평균 100ms마다 한 번씩 GC가 개입한다는 뜻이니까요.

 

 


 

 

Rust 선택의 이유

외부 레퍼런스들을 보면 항상 성능 좋다고 언급되는 Rust를 이 기회에 한 번 사용해보고 싶었습니다. 겸사겸사 공부도 하면 좋으니까요.

그 외에 사실 크게 특별한 이유는 없었습니다. (다른 오픈소스 홍보 글에는 사실 적어두었지만, 솔직하게 입장을 밝힙니다 ㅋㅋ)

 

JSON.parse에는 simd-json을, 파일 탐색에는 glob을, 병렬 처리는 rayon을 사용했습니다.

 

 

simd-json

// toktrack의 JSON 파싱 (zero-copy)
let data: ClaudeJsonLine = simd_json::from_slice(&mut line_bytes)?;

 

Rust의 simd-json simdjson의 Rust 포트입니다. from_slice&mut [u8]을 전달하면 in-place로 파싱하여 불필요한 메모리 할당 없이 데이터를 추출합니다. (zero-copy 파싱)

 

 

rayon

// 병렬 파일 처리: .iter() → .par_iter() 한 줄 변경
let entries: Vec<UsageEntry> = files
    .par_iter()
    .flat_map(|f| parse_file(f))
    .collect();

 

rayon 데이터 병렬 처리 라이브러리입니다. .iter().par_iter()로 바꾸는 것만으로 CPU 전체 코어를 활용한 병렬 처리가 가능합니다. work-stealing 알고리즘으로 코어 간 부하를 자동으로 분산합니다.

Node.js에서는 병렬로 파싱하려면 직렬화가 필요하다는 딜레마가 있었지만, Rust에서는 각 스레드가 독립적으로 파일을 읽고 파싱한 뒤 결과만 모으면 됩니다. 직렬화 오버헤드가 없습니다.

 

 


 

 

 

그렇게 완성된 toktrack

Apple Silicon (M-series), 2,772개 JSONL 파일, 3.4GB 기준 측정

# ccusage (Node.js)
$ time ccusage daily --offline
# 43.26s

# toktrack (Rust) - cold start, 캐시 없음
$ time toktrack
# Cold start: ~ 1000ms
# Warm start: ~ 40ms

 

 

toktrack은 Claude Code만이 아니라, 현재는 Gemini-CLI, Codex도 지원합니다. 앞으로 GLM, Opencode등을 빠르게 지원할 예정입니다.

 

 

캐시 아키텍처

성능을 0.04s까지 끌어올렸던 캐싱 전략입니다.

  • Cold Start: 전체 glob 스캔 → 병렬 SIMD 파싱 → 캐시 생성 → 집계 → 1000ms
  • Warm Start (cached): 캐시된 일별 요약 로드 → 오늘 데이터만 재파싱 (과거 날짜는 캐시에서 제공) → 병합 → 집계 → 40ms

 

 

캐싱으로 엄청난 성능 최적화를 했지만, 한 가지 의도가 더 숨어있습니다.

 

CLI에 따라 세션을 디폴트로 삭제할 때가 있습니다. 특히 Claude Code는 기본적으로 cleanupPeriodDays: 30으로 설정되어, 30일이 지나면 JSONL 파일이 사라집니다. 파일이 삭제되면 토큰 사용량과 비용 이력도 함께 사라집니다.

toktrack의 일별 캐시가 이 문제를 해결합니다. 과거 날짜는 불변(immutable)입니다.

한번 집계된 일별 요약은 이후 수정되지 않습니다. Claude Code가 한 달 뒤에 원본 세션 파일을 삭제하더라도, 비용 이력은 ~/.toktrack/cache/에 그대로 남아있습니다.

 

 

 

 

마치며

오픈소스는 메인테이너의 일정에 따라 반영되는데 지연이 될 수 있는 것을 잘 알고 있습니다.

그래서 저 또한 여러 이슈들의 PR을 합치고, 현재 프로젝트의 아이디어인 캐싱 전략까지 포함하여 ccusage에서 해결하려고 시도해봤지만 구조적 한계가 있었습니다.

  • JSON.parse의 순차 처리
  • libuv 스레드풀 확장해도 22% 한계
  • Worker Threads 병렬화의 직렬화 오버헤드
  • 50초 동안 504번의 GC

 

Rust의 SIMD JSON 파싱, 제로 코스트 병렬 처리, GC 없는 메모리 관리.

이 조합이 40배 속도 향상을 가능하게 했습니다. 똑똑한 알고리즘이 아니라, 병목 자체를 제거한 결과입니다.

 

toktrack은 오픈소스로 공개되어 있습니다. 피드백이나 기여는 언제든 환영합니다!

 

 

GitHub - mag123c/toktrack: Ultra-fast token & cost tracker for Claude Code, Codex CLI, and Gemini CLI

Ultra-fast token & cost tracker for Claude Code, Codex CLI, and Gemini CLI - mag123c/toktrack

github.com

 

 

 

 

 

 

 

 

 

 

 

References.

https://v8.dev/blog/v8-release-76

https://v8.dev/blog/json-stringify

https://v8.dev/blog/trash-talk

https://v8.dev/blog/concurrent-marking

https://deepu.tech/memory-management-in-v8/

https://docs.libuv.org/en/v1.x/design.html

https://simdjson.org/
https://deepwiki.com/simdjson/simdjson
https://arxiv.org/abs/1902.08318
https://nodesource.com/blog/State-of-Nodejs-Performance-2024

https://github.com/ryoppippi/ccusage/issues

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

GoP(Garden of Practice) 회고 - 주니어 개발자 성장을 위한 커뮤니티!?

회고 2026. 1. 20. 21:15
728x90
728x90

 

작년을 돌아보며 개인적으로 가장 크게 남았던 경험은 오픈소스 기여를 통해 진행했던 발표였다.

 

 

3년차 백엔드 개발자의 2025년 회고 (첫 이직)

서론2023년 2024년 회고를 되돌아보니 현실의 벽을 넘기 위한 노력, 의지들이 많이 보였습니다. 하지만 그 벽이 얼마나 높은지 가늠조차 되지 않았었던 것 같아요. 하지만 2025년 한 해는 어느 정도

mag1c.tistory.com

 

누군가에게 내 지식과 경험을 전달하려면, 단순히 알고 있는 수준을 넘어 더 깊이 이해하고, 불필요한 것을 덜어내며, 핵심만 남기는 과정이 필요하다는 걸 체감했기 때문이다. 발표를 준비하며 느낀 건 잘 전달한다는 건 말솜씨의 문제가 아니라 이해의 깊이와 사고의 구조가 드러나는 결과라는 점이었다.


이런 생각을 하던 시기에 조직의 CPO 님 추천으로 GoP(Garden of Practice) 오프라인 모임에 참여하게 되었다.

 

 

 

 

 


신기하다.

 

 

처음 든 감정이었다.

각기 다른 조직에 속한 많은 시니어 레벨의 구성원들이 주니어의 성장에 대해 진지하게 고민하고, 그 경험을 나누기 위해 모여 있다는 점이 인상 깊었다. 평소 비슷한 레벨의 주니어들과만 교류해왔던 나에게 이 풍경은 꽤 낯설고 새로운 자극이었다.

실제 모임에는 약 20명 정도가 모였는데, 체감상 시니어 비중이 훨씬 높았다. 또한 국내 애자일 코치 커뮤니티인 AC2에서 활동했던 분들도 많았는데, 그만큼 논의의 깊이와 밀도가 높게 느껴졌다.

 

 

 

삼삼오오 대화를 나누는 방식의 모임에서, 두 그룹에서 대화를 했다. 대화의 주제는 크게 두 가지로 모였다.

어떻게 하면 조직 구성원들의 성장을 구조적으로 도울 수 있을지,
AI를 개인 차원이 아니라 조직 차원에서 어떻게 더 효과적으로 활용할 수 있을지에 대한 고민이었다.

이야기를 들으며 한 가지 생각이 계속 머릿속을 맴돌았다. 나는 이런 생각들을, 이렇게 정리해서 말할 수 있을까?

 

 

 

 

여전히 나는 내 생각을 정리해서, 듣는 사람이 이해하기 쉽게 전달하는 데 부족함을 느낀다.

 

특히 모임 중간중간 너드랩 대표이신 재완님이 복잡하게 흩어진 이야기를 짧고 명확한 문장으로 정리해 줄 때마다 그 전달력에 감탄하게 되었다. 같은 내용을 듣고 있었지만, 누군가는 이야기로 남기고 누군가는 구조로 정리해 전달한다는 차이가 분명히 느껴졌다. 효과적으로 전달하는 능력 역시 의도적으로 훈련해야 하는 하나의 역량이라는 생각이 들었다.

 

 

 

나는 내향적인 편이고, 사람들 앞에서 말을 조리 있게 잘하는 스타일은 아니다. 그래서인지 이런 시니어 중심의 커뮤니티는 편한 공간이라기보다는 나의 한계를 더 선명하게 보여주는 공간처럼 느껴졌다.

 

하지만 동시에 그래서 더 필요한 환경이라는 생각도 들었다. GoP가 지향하는 작은 실천, 정리된 기록, 반복 훈련이라는 같은 방향을 바라보다보면 천천히 생각하고, 구조를 쌓아가면서 점점 조리있게 전달하는 능력도 향상될 것 같다.

2026년에는 GoP와 더불어 여러 커뮤니티에 보다 적극적으로 참여하며 기술 스킬뿐 아니라 생각을 정리하고 전달하는 소프트 스킬을 의도적으로 훈련해보고 싶다. 편하지 않은 환경이지만, 지금의 나에게는 바로 그런 환경이 다음 단계로 가기 위한 조건이라는 생각이 든다.

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

방명록