(534)

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 ..

나아가면서 되돌아보자.

정말 간단하게 남기는 회고라 좀 러프하게 작성. 새로운 조직에서 처음 접하는 스택들과 더불어 스쿼드의 스프린트와 AX를 동시에 수행하고개인적으로 사이드 프로젝트, 오픈소스 기여와 불편한 부분들을 자동화하는 플로우를 만들면서 정신없이 지내는 요즘문득 한 통의 카톡이 날아왔다. 3일 전에 받았던, 예전에 도입했던 소나큐브를 제거하는 방법을 알려달라던 이전 회사 부장님의 카톡.홀로 개발하는 환경에서, 외로움에(?) 페어 프로그래밍 느낌을 내보고자 여러 rules를 추가해서 소나큐브를 사용했었다.하지만, 여러 AI들이 발전하면서 사용에 의의를 잃었고, 결국 사용하지 않은 채로 관리하지 않았다. 홀로 개발하는 환경이라는 것은, 기본 동작 위에 개발자만이 고려 할 수 있는 부분들은 물론현재 기술 부채를 적절..

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

서론2023년 2024년 회고를 되돌아보니 현실의 벽을 넘기 위한 노력, 의지들이 많이 보였습니다. 하지만 그 벽이 얼마나 높은지 가늠조차 되지 않았었던 것 같아요. 하지만 2025년 한 해는 어느 정도 노력이 헛되지 않았구나 생각이 들었습니다. 요약하자면, 성격의 한계를 극복했고 첫 이직을 했습니다. 그 과정에서 매번 서류 탈락하던 국내 빅테크들의 면접까지 경험할 수 있었습니다.이전과 크게 달라진건 제가 사용하는 기술들에서 다양한 개발자들과 소통하며 기여했고, 과정에서 기술적인 깊이를 기르고자 노력했습니다. AI 때문에 급변했고, 앞으로도 급변할 이 시장에서 어떤 개발자가 되고 싶은지 끊임없이 고민했던 2025년을 되돌아보려고 합니다. 러너스하이 1기올 초에, 토스에서 진행하는 멘토링 세션인 러너스..

Python의 WSGI(Web Server Gateway Interface) - Node와 비교하며 이해하기

서론 Python의 GIL(Global Interpreter Lock) - Node와 비교하며 이해하기서론Node를 처음 접할 때, 가장 먼저 이해해야하는 것들 중에는 아래와 같은 개념들이 있습니다.JS 실행은 기본적으로 싱글 스레드다.대신 이벤트 루프와 비동기 I/O로 동시성을 만든다.CPU를 갈아mag1c.tistory.com 이전글에서 Python의 GIL에 대해 정리했습니다. Node에서 Python으로 전환하면서 동시성 처리의 차이점을 이해하는 것이 중요하다고 생각했기 때문입니다. 이번에는 제가 Python의 레거시 스택을 사용하면서 또 다른 혼동의 원인이었던 WSGI(Web Server Gateway Interface)에 대해 정리해보려 합니다. Node로 웹 서버를 만들 때는 아래처럼 만들..

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년차 주니어 개발자.

나아가면서 되돌아보자.

회고 2026. 1. 12. 23:44
728x90
728x90

 

정말 간단하게 남기는 회고라 좀 러프하게 작성.

 

 


 

 

새로운 조직에서 처음 접하는 스택들과 더불어 스쿼드의 스프린트와 AX를 동시에 수행하고

개인적으로 사이드 프로젝트, 오픈소스 기여와 불편한 부분들을 자동화하는 플로우를 만들면서 정신없이 지내는 요즘

문득 한 통의 카톡이 날아왔다.

 

 

3일 전에 받았던, 예전에 도입했던 소나큐브를 제거하는 방법을 알려달라던 이전 회사 부장님의 카톡.

홀로 개발하는 환경에서, 외로움에(?) 페어 프로그래밍 느낌을 내보고자 여러 rules를 추가해서 소나큐브를 사용했었다.

하지만, 여러 AI들이 발전하면서 사용에 의의를 잃었고, 결국 사용하지 않은 채로 관리하지 않았다.

 

홀로 개발하는 환경이라는 것은,

 

기본 동작 위에 개발자만이 고려 할 수 있는 부분들은 물론

현재 기술 부채를 적절하게 해결하면서 더 나아갈 수 있는 방향은 무엇일까?

 

에 대한 생각을 주로 해왔던 것 같다.

 

저 카톡을 오늘 곰곰이 곱씹어보니,

홀로 개발하고 나발이고 개발자란

 

신기술에 매몰되어 이것저것 싸지르기만 하면 안되는 것은 당연하고,

현실에 안주해서 레거시 위에 또 다른 레거시를 쌓는 것도 아닌 것 같고,

 

당연히 현재 상황에 맞게 적절한 기술을 선택하며,

다양하게 레퍼런스를 보고 깊게 학습하면 자연스레 새로운 신기술도 도입할 수 있는 역량이 생기리라 생각하고 있지만,

 

레거시 관리 측면에서 많이 소홀하지 않았나 생각이 드는 카톡이였다.

 

주저리주저리 싸지른 글이라 나조차도 뭐라는지 모르겠고 읽으시는 분들도 이해하기 힘들 수 있지만 이번 글에선,

 

항상 되돌아보자. 항상 이라는게 추상적이면 매 주, 매 월 단위로 내가 싸지른 것들을 회고할 수 있는 형태로

컨텍스트를 남기고 주기적으로 회고하는 습관을 가져야겠다.

 

는 생각이 들어 회고 글을 급히 싸지르고 퇴장하겠습니다.

 

 

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

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

회고 2025. 12. 26. 18:52
728x90
728x90

 

 

서론

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

 

요약하자면, 성격의 한계를 극복했고 첫 이직을 했습니다. 그 과정에서 매번 서류 탈락하던 국내 빅테크들의 면접까지 경험할 수 있었습니다.

이전과 크게 달라진건 제가 사용하는 기술들에서 다양한 개발자들과 소통하며 기여했고, 과정에서 기술적인 깊이를 기르고자 노력했습니다.

 

AI 때문에 급변했고, 앞으로도 급변할 이 시장에서 어떤 개발자가 되고 싶은지 끊임없이 고민했던 2025년을 되돌아보려고 합니다.

 

 

 

러너스하이 1기

올 초에, 토스에서 진행하는 멘토링 세션인 러너스하이 1기에 참여하게 되었습니다.

신청할 때 기대했던 것과는 달리 멘토링보다는 토스의 인재상에 대한 소개와, 과제를 내려주는 채용 연계형 세션이었어요.

러너스하이는 짧은 기간 동안 스스로 문제를 정의하고, 해결하고, 결과를 돌아보는 집중 성장 프로그램 처럼 느껴졌습니다.

 

토스 Next가 코테 > 과제를 통해 문제 해결 능력을 본다면 러너스하이는 폭발적인 성장 가능성을 보는 것 같았어요.

 

저는 이 세션을 통해 ROI가 높은 과제를 선정하기 위해 끊임없이 관심 갖고 고민하는 관점을 하나 얻게 되었습니다.

추가로, 처음으로 러너스하이 1기에 참여했던 일부 멤버들과 함께 개발자 커뮤니티를 작게나마 형성했습니다.

 

이 두 가지는 개발자로서 끊임 없이 성장하고, 제가 추구하는 공유의 가치를 위해 작은 씨앗이 될 것이라고 생각합니다.

 

 

오픈소스 기여와 발표

오픈소스와 함께 한 2025년이라고 해도 될 만큼 오픈소스 덕분에 얻은게 참 많습니다.

기여 과정에서 얻는 지식은 물론, 내향적인 성격의 한계를 극복하고 이직까지 할 수 있게 된 계기가 되었습니다.

 

 

기여 요약

작년에는 오픈소스 기여의 막막함에 대한 진입 장벽을 허물고 기여하는 방법에 대해 어느정도 익혔다면, 올해는 본격적으로 기여 활동을 늘려나갔습니다. 제 커리어에서 가장 오래 사용했던 Node, Nest 프레임워크와 TS 진영의 ORM들, 모니터링 인프라를 구축하면서 사용했던 Loki와 무료여서 더 끌렸던 Gemini-CLI 등 다양하게 기여를 시도했습니다.

 

총 34개의 PR 중 23개가 Merge 되었어요.

날짜 저장소 PR 제목 상태
25-02-19 nestjs/docs.nestjs.com #3204 docs(swc): add vitest alias resolution Merged
25-02-19 nestjs/docs.nestjs.com #3206 docs(swagger): add ui/raws description Merged
25-02-19 nestjs/swagger #3307 fix(swagger): added options in createEnumSchemaType Merged
25-04-22 nestjs/nest #14995 feat(common): Add fallbackToMimetype support in FileTypeValidator Merged
25-04-22 nestjs/nest #15003 chore(common): Backport FileTypeValidator fallback support Open
25-04-30 nestjs/swagger #3423 feat(swagger-plugin): add skipDefaultValues option Merged
25-05-05 nestjs/swagger #3248 feat(swagger): add extension in SecuritySchemeObject Merged
25-05-21 nestjs/nest #15172 fix(microservices): support custom strategy in async usefactory config Merged
25-07-08 nodejs/node #58988 doc: enhance glob pattern documentation Open
25-07-14 nodejs/node #59061 path: add exclude option to matchesGlob method Open
25-07-16 nestjs/nest #15385 fix(testing): auto-init fastify adapter for middleware registration Merged
25-08-06 grafana/loki #18732 feat: default loki-mixin dashboards to TSDB Open
25-08-07 nestjs/terminus #2671 feat(graceful-shutdown): add enhanced production-ready shutdown sequence Open
25-08-09 nestjs/terminus #2673 fix(deps): update amqplib to 0.10.6 for rmq 4.1+ compatibility Open
25-08-14 nestjs/nest #15539 fix(sample): update gql federation samples to use production-ready Open
25-08-20 prisma/prisma #27897 fix(client): add default generic parameters to PrismaClient constructor Merged
25-08-21 google-gemini/gemini-cli #5751 perf(core): parallelize memory discovery file operations (60% 성능 향상) Merged
25-09-15 nestjs/terminus #2670 feat(terminus): add forRootAsync method Merged
25-09-16 nestjs/nest #15503 feat(common): add force-console option to console logger Merged
25-09-16 nestjs/nest #15571 fix(core): skip lifecycle hooks for non-instantiated transient services Merged
25-10-01 nestjs/graphql #3678 feat(graphql): add type-name-option for custom type naming Merged
25-10-12 nodejs/node #60220 test_runner: add classname hierarchy for JUnit reporter Open
25-10-18 nestjs/swagger #3596 feat(decorator): add type definition for format option Open
25-10-21 nestjs/nest #15705 fix(core): resolve extras in configurable module builder async methods Merged
25-10-27 nestjs/nest #15815 fix(core): ensure nested transient provider isolation Merged
25-11-08 nodejs/node #58205 doc: improve agent.createConnection docs for http/https agents Merged
25-11-14 typeorm/typeorm #11769 refactor: replace uuid with native Crypto API Open
25-11-28 nestjs/nest #15984 sample(sample/22): fix Prisma 7 compatibility Merged
25-11-29 daangn/ventyd #46 fix: improve validation error messages Merged
25-12-05 nestjs/nest #15986 feat(core): add option for async logger compatibility Merged
25-12-05 nodejs/node #60376 esm: improve error messages for ambiguous module syntax Merged
25-12-12 typeorm/typeorm #11669 fix: include joined entity primary keys in pagination subquery Merged
25-12-18 encode/django-rest-framework #9853 Fix viewset actions dict being mutated after first request Open
25-12-19 nestjs/nest #16098 fix(core): instantiate nested transient providers in static context Merged

 

 

최근에는 Python을 사용하는 회사로 이직했기 떄문에, DRF부터 점진적으로 Django > Python에 기여를 해볼 계획을 가지고 있어요.

 

 

 

발표

특히 올 해 오픈소스 기여 덕분에 저는, 저의 내향적인 성격의 한계를 깨고 오프라인 세션에서 발표를 진행하게 되었습니다.

 

 

 

개발자로서 첫 발표를 마치고

첫 발표를 마치고개발자로서 첫 발표를 무사히(?) 끝마쳤습니다. 포스팅을 작성하면서도 가슴이 벌렁벌렁하네요.. 저는 현업에서 혼자 개발하는 환경에 있다 보니,'내가 잘하고 있는 게 맞을까?'

mag1c.tistory.com

 

Prisma와 Gemini-CLI 기여 경험을 바탕으로 발표를 진행했습니다. 단순히 기여 내용을 공유하는 것이 아니라, 이슈를 효율적으로 분석하는 방법과 그 과정에서 어떻게 성장했는지에 초점을 맞췄습니다. 청심환을 먹었음에도 너무 떨려서 제대로 전달이 안되었을 수도 있지만요.. 

 

 

 

이직

기존 조직에서 많은 것을 배웠지만, BM의 한계를 많이 느꼈습니다.

더불어 제가 관심 있던 AI 활용이나 Agentic Workflow 구축을 시도하기엔 환경적 제약이 있었습니다.

 

더 자극을 느끼고 성장하며 다양한 경험을 쌓기 위해 이직을 해야겠다 라는 생각을 했고, 개발자로서 첫 이직을 할 수 있게 되었습니다.

 

그 유명한 당근 면접비 ㅋㅋ

 

작년에 이직 시도를 할 때와는 다르게 서류 합격률이 많이 높아졌습니다.

감사하게도 기술 면접을 열 곳 넘게 볼 수 있는 기회가 주어져서, 다양한 분야의 기업들에서 면접들을 볼 수 있었습니다.

특히 이번 이직 과정에서는 당근을 비롯한 네카라쿠배당토야 중 세 곳에서 과제와 면접 등의 질 좋은 경험들을 할 수 있었습니다.

이전까지는 서류 광탈에 빅테크는 제 길이 아니구나 생각했는데, 올 해는 어느 정도 제 노력들이 시장에서도 먹히고 있는 것 같아서 정말 기분이 좋았습니다.

 

 

저는 완전 새로운 도메인의 스타트업에서 커리어를 이어나가게 되었습니다. 제가 이직 시 고려했던 성장, 처우, 공유 라는 세 키워드가 모두 만족스러운 환경에서 더 많은 기여를 적극적으로 시도하는 중입니다.

 

 

 

 

 

개발자로서의 목표

올해 가장 많이 한 생각은 내가 어떤 개발자가 되고 싶을까? 입니다.

처음에는 시장에서 원하는 개발자가 되어야겠다고 생각했었는데요. 메타인지를 하는 과정에서, 저는 흥미를 잃으면 빠르게 이탈하는 성격이라는 것을 다시 한 번 인지하고 내가 왜 개발자가 되고 싶었었지? 앞으로 무엇을 하고 싶지? 를 중점으로 생각해봤던 것 같습니다.

 

오픈소스 기여를 통해 수 억명의 DX들을 개선하는 경험들을 접하고 기여 사이클에서 얻는 성장과 공유의 도파민이 가장 달콤했습니다.

그러다보니 Product Engineer 보다는 DX를 개선하는 영역 혹은 더 기술적인 깊이를 추구할 수 있는 사람이 되고자 방향을 잡았습니다.

 

최근 AI가 일상 생활에 너무 깊이 침투해있지만 아직은 할루시네이션 등의 이슈로 이런 깊이를 추구하는 방향이 나쁘지 않다고 생각했습니다. AI를 더 잘 활용하는 필수 역량 중 AI의 결과물을 빠르고 정확하게 검토할 수 있는 역량이 이런 깊이감이라고 생각해요. AI가 딸깍으로 모든 것을 해결해주는 세상이 온다면 목표가 달라져야하겠지만, 이떄는 목표를 수정하는 것이 아니라 직종 자체를 변경해야할 수도 있겠습니다.

 

 

 

 

 

장기 목표는 세우지 않아야겠다.

우선, 작년 회고에서 이루고자 했던 목표를 얼마나 달성했을까? 를 되돌아봤어요.

CS 지식을 다듬고 체력 관리를 위해 운동하자!!! 라고 목표를 세웠더라구요.

 

CS 지식을 집중적으로 채워 넣기 보단 현업에서 마주한 문제에 관련된 지식들 위주로 습득했고, 운동은 습관화 시키지 못했어요.

 

저는 강한 동기부여가 있거나 진심으로 좋아하는 일을 할 때 몰입하는 사람이라는 것을 다시 깨달았습니다.

텍스트 형태의 장기 목표는 세우지 않고, 단기적으로 지금 무엇에 관심있는지를 브레인스토밍하고 거기에 집중하는 것이 좋겠다는 생각이 들어요.

 

 

 

 

마무리

2025년은 정말 감사한 한 해였습니다. 이전까지는 비전공 국비, 고졸이라는 자격지심이 있었던 것 같은데 이직 과정에서 이 부분이 100% 해소되었습니다. 앞으로 더 개발을 좋아하고 자연스레 성장해나간다면, 현재 조직에서 많은 임팩트를 주고 제 경험을 다양하게 공유하고 나눌 수 있으면 얼마나 행복할까? 라는 생각을 하고 있습니다.

 

2026년에는, 현재 조직에서 엄청 큰 임팩트를 하나 이상 만들어 보는 것을 최우선 과제로 두고, 현재 조직의 프로덕트 개선과 DX 개선 두 가지에 힘쓸 것 같아요. 개인적인 목표로는 300+ 스타 이상의 오픈소스 운영과, 개인 서비스의 사용자를 1k 이상 만들어보는 경험을 해보고 싶습니다.

 

2026년에는 보다 더 밀도 높은 성장을 통해 보다 더 인정받는 개발자가 위해 열심히 달려나가겠습니다!! 다들 2026년에도 화이팅입니다

 

 

 

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

Python의 WSGI(Web Server Gateway Interface) - Node와 비교하며 이해하기

Tech/Python 2025. 12. 24. 21:43
728x90
728x90

 

 

서론

 

 

Python의 GIL(Global Interpreter Lock) - Node와 비교하며 이해하기

서론Node를 처음 접할 때, 가장 먼저 이해해야하는 것들 중에는 아래와 같은 개념들이 있습니다.JS 실행은 기본적으로 싱글 스레드다.대신 이벤트 루프와 비동기 I/O로 동시성을 만든다.CPU를 갈아

mag1c.tistory.com

 

이전글에서 Python의 GIL에 대해 정리했습니다. Node에서 Python으로 전환하면서 동시성 처리의 차이점을 이해하는 것이 중요하다고 생각했기 때문입니다.

 

이번에는 제가 Python의 레거시 스택을 사용하면서 또 다른 혼동의 원인이었던 WSGI(Web Server Gateway Interface)에 대해 정리해보려 합니다.

 

Node로 웹 서버를 만들 때는 아래처럼 만들죠.

 

const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Hello World');
});

app.listen(3000);

 

express의 app.listen()은 내부적으로  Node의 http.createServer()을 호출합니다.

런타임에 HTTP 서버가 내장되어 있어서, 별도 서버 없이 바로 띄울 수 있죠.

 

// express/lib/application.js
app.listen = function listen() {
    var server = http.createServer(this)  // Node.js 내장 http 모듈 사용
    return server.listen.apply(server, arguments)
}

 

 

그런데 Django는...

 

python manage.py runserver
# "WARNING: This is a development server. Do not use it in production."
# django 소스코드 일부
# django/core/management/commands/runserver.py
self.stdout.write(
  self.style.WARNING(
      "WARNING: This is a development server. Do not use it in a "
      "production setting. Use a production WSGI or ASGI server "
      "instead.\nFor more information on production servers see: "
      f"https://docs.djangoproject.com/en/{docs_version}/howto/"
      "deployment/"
  )
)

 

 

소스코드를 확인해보니 무슨 SGI를 사용하라고하네요. 서울보증보험인가.. 별도의 서버가 필요하다는 것은 확실해 보였습니다.

 

Java기반의 Spring을 짧게 사용했을 때도 당연히 Tomcat을 별도로 사용했기 때문에 그런가보다 했습니다.

그런데 공부하다보니 2025년을 살아가는 저에게는 꽤나 독특한 녀석이라고 생각했습니다.

 

왜 Python 웹 생태계는 GIL 뿐 아니라 WSGI 같은 녀석도 표준이 되어 지금까지도 사용되고 있을까요?

 

 

 

 

애플리케이션과 서버의 분리

 

 

 

다시 말하지만 Node는 개발자가 웹 서버를 별도 구성할 필요가 없습니다.

런타임에 HTTP 서버가 내장되어 있어 별도 서버를 구성하지 않고도 바로 웹 서버를 띄울 수 있죠.

 

 

 

 

왜 이렇게 분리되었을까요?

 

2000년대 초반에는 Python 웹 생태계에는 Zope, Quixote, Webware 등의 다양한 프레임워크가 있었다고 합니다.

문제는 프레임워크 선택이 서버 선택이 되어, Zope를 쓰려면 Zope 서버를, Quixote를 쓰려면 또 다른 서버를 써야 했다고 해요.

 

Java에서는 Servlet API가 이 문제를 해결했어요.

어떤 서블릿 컨테이너(Tomcat, Jetty 등)에서든 서블릿 스펙을 따르는 웹 앱을 실행할 수 있습니다.

 

Python도 비슷한 표준이 필요했고, 그렇게 WSGI가 탄생했다고 합니다.

(이와 관련된 자세한 내용은 PEP-333에 나와있습니다.)

 

 

 

 

WSGI

WSGI(Web Server Gateway Interface)는 웹 서버 게이트웨이의 표준 인터페이스입니다.

웹 서버와 Python Application 사이의 표준 인터페이스 인 셈이죠.

 

Python이 그러한 것 처럼, WSGI 또한 단순하고 간결한 것이 원칙이었다고 합니다.

 

Thus, simplicity of implementation on both the server and framework sides of the interface is absolutely critical to the utility of the WSGI interface, and is therefore the principal criterion for any design decisions.

the goal of WSGI is to facilitate easy interconnection of existing servers and applications or frameworks, not to create a new web framework

Phillip J. Eby (PEP 333 - https://peps.python.org/pep-0333)

 

 

 

WSGI Application 구조

단순하고 간결한 원칙 때문이었을까요? WSGI 애플리케이션은 단순합니다.

 

def application(environ, start_response):
    """단순한 WSGI Application"""
    status = '200 OK'
    response_headers = [('Content-Type', 'text/plain')]
    start_response(status, response_headers)
    return [b'Hello World']

 

두 개의 파라미터를 받는 callable* 객체면 충분합니다. 이게 전부에요.

callable은 말 그대로 호출할 수 있는 객체를 뜻해요. application() 처럼요.

 

참고로 응답이 리스트(iterable)인 이유가 있어요.
대용량 파일을 한 번에 메모리에 올리지 않고 chunk 단위로 스트리밍할 수 있게 하려는 설계입니다.

 

environ

이름만 봐도 감이 오죠? .env를 생각하면 될 것 같아요.

environ은 CGI 스타일의 환경 변수 딕셔너리에요. CGI(Common Gateway Interface)는 1990년대 웹 서버가 외부 프로그램을 실행하던 방식이에요. WSGI가 이 변수 컨벤션을 그대로 사용한 이유는, 당시 Python 프레임워크들이 이미 CGI 방식을 구현해뒀기 때문입니다.

아래의 값들을 통해 웹 서버를 설정해야해요.

 

 

 

 

start_response

start_response는 응답 상태와 헤더를 설정하는 callable 이에요.

 

start_response(status, response_headers, exc_info=None)
status = '200 OK'  # HTTP 상태코드 + 메시지 (문자열)
response_headers = [
  ('Content-Type', 'text/plain'),
  ('Content-Length', '12')
]
start_response(status, response_headers)  # 서버에게 알림
return [b'Hello World!']  # 그 다음 본문 반환

 

 

 

WSGI 실제 구현 예시

제가 사용하는 Django를 예로 들어볼게요. 개발자는, Response안에 응답 데이터와 상태를 넣어줘요.

 

return Response(data=serializer.data, status=status.HTTP_200_OK)

 

 

위에서 언급한 WSGI Application에 들어가는 환경 변수나 응답 헤더 등의 설정은 하지 않았는데요.

Django 내부에서는 이 저수준의 WSGI를 래핑한 고수준의 API를 제공합니다. 아래는 간략화한 예시입니다.

 

class WSGIHandler:
  def __call__(self, environ, start_response):
      # 1. environ을 Django Request로 변환
      request = self.request_class(environ)

      # 2. View 실행 → Response 객체 반환
      response = self.get_response(request)

      # 3. Response를 WSGI 형식으로 변환
      status = '%d %s' % (response.status_code, response.reason_phrase)

      start_response(status, response_headers)
      return response

 

 

 

 

 

 

WSGI를 사용한 HTTP Request LifeCycle

 

 

위 시퀀스 다이어그램은 WSGI를 사용한 HTTP 요청이 처리되기 까지를 요약한 다이어그램입니다.

 

실제 프로덕션 환경에서는

  • 리버스 프록시: HTTPS, static serving, LB, Buffering 등의 역할
  • WSGI 서버: HTTP 요청을 WSGI 프로토콜(environ, start_response)로 변환하여 애플리케이션에 전달, 응답을 클라이언트에 반환, 동시 요청 처리
  • WSGI 애플리케이션: WSGI 스펙을 따르는 callable(wsgi.py)을 통해 요청을 받아 비즈니스 로직 수행

 

위와 같은 플로우로 동작하게 됩니다.

 

 

 

 

WSGI의 한계

WSGI는 2003년에 만들어졌다고 해요. 틀딱인거죠

GIL이 멀티스레드 CPU 연산을 제한하는 것처럼, WSGI도 요청-응답 모델에서 제약이 있습니다. 다만 문제의 성격은 달라요. GIL은 스레드 병렬성의 문제이고, WSGI는 연결 유지와 양방향 통신이 불가능한 설계의 문제입니다

 

def application(environ, start_response):
    result = do_something_slow()  # 블로킹!
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [result.encode()]

 

요청이 들어오면 워커 하나가 요청을 받고, 처리가 끝날 때까지 해당 워커는 점유되며 응답을 반환하고 나서야 다음 요청 처리가 가능해요. (sync worker 기준)

물론 Gunicorn도 gevent나 eventlet 같은 async worker를 사용하면 Green thread 기반으로 수백 개의 동시 연결을 처리할 수 있어요. 하지만 이건 WSGI 표준 위에서의 우회 방식이고, WebSocket 같은 양방향 통신은 여전히 구조적으로 불가능합니다.

 

물론 Django를 사용하더라도 멀티프로세싱이나 스케일 아웃으로 많은 워커를 구성하거나
적절한 캐싱과 인프라 구조의 최적화를 통해 개선할 수도 있겠죠...?

실제로 인스타그램은 2012년 Django + Gunicorn 스택으로 1400만 유저까지 스케일했고,
현재도 Django를 핵심 스택으로 사용하며 수십억 사용자를 처리하고 있어요. 대단하죠.. (인스타 기술 블로그)

 

 

 

 

 

ASGI

ASGI(Asynchronous Server Gateway Interface)는 비동기 기능을 갖춘 파이썬 웹 서버 인터페이스입니다.

(ASGI 스펙 문서에서는 WSGI의 정신적 후계자(spiritual successor)라고 소개되어 있어요)

 

async를 통해 비동기 처리를 지원하는 ASGI는 Django 기준 3.0부터 공식 지원한다고해요.

 

# WSGI
def application(environ, start_response):
    start_response('200 OK', headers)
    return [b'Hello World']

# ASGI
async def application(scope, receive, send):
    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [(b'content-type', b'text/plain')],
    })

 

 

ASGI의 세 파라미터를 간단히 설명하자면

  • scope: 연결의 메타데이터 (HTTP인지 WebSocket인지, 경로, 헤더 등)
  • receive: 클라이언트로부터 메시지를 비동기로 수신
  • send: 클라이언트로 메시지를 비동기로 전송

WSGI가 요청을 받아 응답을 반환하는 단방향이었다면, ASGI는 receive/send로 언제든 양방향 통신이 가능한 구조입니다.

 

# asgi.py
import os
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()



Django에서는 ASGI를 지원한다고 해서 모든 코드가 비동기로 동작을 지원하지는 않습니다.

대표적으로 Django ORM은 기본적으로 동기 드라이버(psycopg2 등)를 사용하기 때문에, DB 쿼리 시 해당 스레드가 블로킹됩니다.

 

def my_view(request):
    result = SomeModel.objects.all()  # 동기 ORM
    return HttpResponse(result)

 

하지만, Django 4.1 버전 이후부터는 async ORM을 점진적으로 지원하기 시작했고, ORM 뿐 아니라 Django와 Python에서 비동기를 점진적으로 지원하기 위한 노력은 지금도 꾸준히 진행되고 있는 것으로 보여요. (이전 글에서 다룬 GIL Free-threading도 그 일환이죠)

 

 

 

 

정리

Node에서는 런타임에 내장되어있었기 떄문에, 그리고 기본적으로 비동기를 지원했기 떄문에 다소 많은 차이가 느껴졌습니다.

 

이전 GIL 포스팅과는 다르게 마냥 부정적으로만 보이지는 않았는데요, 이는 GIL이라는 언어 자체의 레거시와는 느낌이 달랐기 떄문입니다.

GIL은 언어(CPython) 레벨의 문제이고, WSGI는 프레임워크와 웹 서버 생태계의 문제입니다. 흥미롭게도 생태계 전환이 오히려 더 빠르게 진행 중이에요. GIL 제거는 수십 년간 시도 끝에 Python 3.13에서야 실험적으로 도입된 반면, ASGI로의 전환은 FastAPI의 부상, Django 3.0+의 공식 지원 등 이미 활발히 이루어지고 있죠.

 

특히 Django는 ORM, Admin, Auth 등 많은 기능이 내장되어 있고, 이 모든 것들이 동기 기반으로 설계되어 있잖아요. 이걸 비동기로 전환하려면 프레임워크 전체가 바뀌어야 하는 거니까요. 그래도 Django 4.1부터 async ORM이 점진적으로 지원되고 있고, Python 생태계 전체가 비동기를 향해 나아가고 있으니 긍정적으로 보고 있어요. 

 

그리고..... 개발자의 역량에 따라 동기적인 웹 서버로도 충분히 10M+의 트래픽이 제어 가능하고 인스타라는 선진 사례도 있기 떄문에, 이 모든게 저의 역량에 달린 일이 아닐까..(?????????) 하는 생각도 들었습니다.

 

다음 Python 관련 스터디는 딱히 정해지진 않았지만, 무언가 정리할 만한 주제를 찾아 돌아오도록 하겠습니다.

 

 

 

 

 

 

 

 

 

References

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

https://instagram-engineering.com/what-powers-instagram-hundreds-of-instances-dozens-of-technologies-adf2e22da2ad

https://read.engineerscodex.com/p/how-instagram-scaled-to-14-million

https://asgi.readthedocs.io/en/latest/

https://gunicorn.org/

https://www.uvicorn.org/

728x90
300x250
mag1c

mag1c

2년차 주니어 개발자.

방명록