lukewire129의 등록된 링크

키자드에 등록된 총 178개의 포스트를 확인하실 수 있습니다.

Naver Blog

Claude를 끊고 ChatGPT로 넘어온 지 5일

전 지금까지 ChatGPT로 넘어온 지 4일 정도 지났고, 솔직히 생각보다 많이 썼다. 이틀 만에 주간 한도의 30%를 썼고, 5일 차가 다가올수록 벌써 절반 이상을 써버렸다. Claude에서의 환경과 다르게 OpenCode로 넘어오고 모델도 바꿔가며 테스트했다. Codex CLI도 아직 제대로 정착하지 않았다. 체감으로 Claude를 쓰던 때와 달리 OpenCode는 사용자가 더 적극적으로 관리해야 하는 패턴이 생겼다. Compact 여부, Session 관리, Clear 여부를 직접 결정해야 하며, 오른쪽 상단에 현재 토큰 사용량이 계속 표시된다. “이 세션을 이제 정리해야 하나?” 같은 생각이 자주 들었다. Claude는 세션이 길어도 알아서 정리해주는 편이었으니까.<br><br>가장 큰 차이는 역시 모델 선택의 폭이었다. Claude를 쓸 때는 Sonnet 하나로 대부분 해결됐는데, OpenCode를 열어보니 모델 목록이 너무 많다. 설계 작업은 GPT-5.5 xHigh, 코드 구현은 GPT-5.3 Codex, 폴더 비서는 GPT-5.4 Medium처럼 역할을 나눠 쓰게 되었다. Claude를 한동안 썼던 입장에선 혼란스러운 변화였고, 어떤 모델을 어떤 상황에 써야 하는지 재학습이 필요했다. 하지만 이것도 적응 과정의 일부로 여겼다. GPT는 요청대로만 수행한다는 점이 가장 크게 느껴졌다. 요구사항을 충실히 이행하고 테스트 코드도 꼼꼼히 챙긴다. 작업이 끝나면 다음 단계 제안도 해주지만, 수행 범위를 벗어나진 않는다. 엔지니어다운 성향이랄까.<br><br>반대로 Claude는 종종 내가 시킨 것보다 더 많은 일을 하곤 했다. 때로는 내가 생각하지 못한 기능이나 구조까지 추가로 제안했다. 그것이 Claude의 가장 큰 장점이었지만, 항상 내가 원하는 방향은 아니었다. 그래서 둘을 함께 쓰라는 조언에 어느 정도 공감하게 된다. Claude는 디테일하게 확장하고 GPT는 확장 과정에서 생기는 오해를 잡아준다. GPT가 요구사항 중심으로 움직일 때 Claude가 내가 생각지 못한 방향을 제시해 주기도 한다. 아직 5일도 안 된 시점이라 단정하기 어렵지만, 둘의 차이는 누가 더 낫다기보다 성격이 꽤 다르다는 쪽에 가깝다. 그 차이를 이해하는 과정 자체가 의외로 재미있다.<br><br>지금까지의 비교는 Claude와 Claude Code를 기준으로, 현재는 GPT와 OpenCode를 쓰고 있어서 실제로는 같은 조건이 아닐 때가 많다. Claude Code는 필요하다고 판단하면 관련 파일까지 더 읽고 연관 코드도 살펴보며 예상되는 문제까지 먼저 짚어준다. OpenCode는 사용자가 세션 정리, Compact 여부, 어떤 모델을 사용할지까지 제어하는 영역이 많다. 그래서 내 인상은 Claude 모델 자체보단 Claude Code의 성향이 섞였을 가능성이 크다. Codex를 쓰면 또 다른 이야기가 될 수도 있다. 요즘 가장 궁금한 건 Codex인데, GPT를 Codex 환경에서 쓰면 지금 느끼는 인상이 그대로 유지될지, 아니면 OpenCode가 원래 그러한 성향이었나가 드러날지 아리송하다. 아직은 판단이 이르다. 몇 주 뒤에는 이 글의 절반쯤을 수정하게 될지도 모른다. 그래도 현재는 GPT에 적응하는 과정이자 OpenCode에 적응하는 과정이기도 하다. 어쩌면 나는 Claude와 GPT를 비교하는 게 아니라 Claude Code와 OpenCode를 비교하고 있는 것일 수도 있다.

Naver Blog

요즘 개발자 도구 이야기를 보다 보면, 다들 비슷한 데서 피곤한 것 같다

SNS를 보다 보면 이상하게 비슷한 종류의 글이 계속 눈에 들어온다. 누군가는 Neovim 설정을 또 갈아엎고 있고, 누군가는 jj로 Git 스트레스가 줄었다고 하고, 누군가는 Cursor에서 다시 VSCode로 돌아갔다고 한다. 예전에는 이런 글들을 보면 "새로운 생산성 도구 이야기"처럼 느껴졌는데, 요즘은 약간 다르게 읽힌다. 다들 그냥 덜 피곤해지고 싶은 것 같다는 느낌. 기능 이야기보다 생활 이야기가 많아졌다 예전 개발 툴 이야기는 대체로 비슷했다. 더 빠르다 더 강력하다 더 자동화된다 더 많은 걸 해준다 그런데 요즘은 이상하게 다른 포인트가 자꾸 나온다. 오래 켜놔도 안 거슬린다 흐름이 덜 끊긴다 실수했을 때 복구가 편하다 지금 뭐 하고 있었는지를 덜 잃어버린다 특히 AI 툴 쪽은 더 그렇다. 모델 성능 비교보다도 "이상하게 이건 오래 못 쓰겠다" 같은 이야기가 더 공감될 때가 많다. Git보다 "Git 때문에 생기는 스트레스" 이야기가 나온다 요즘 jujutsu (jj)

Naver Blog

Claude 구독 해지하고 ChatGPT Plus로 옮겼다

11달러의 함정 나는 토스뱅크를 해외 결제용으로만 쓴다. 그래서 평소에는 돈을 많이 채워놓지 않는다. 사실 이 패턴 때문에 예전에도 한 번 당한 적이 있다. 2월에 GitHub Copilot 결제할 때 10달러를 안 넣어놔서 이중 결제 비슷한 일이 생겼고, 그 이야기를 블로그에도 쓴 적이 있다. 물론 그때는 시간이 지나고 잘 해결됐다. 하지만 그렇다고 내가 결제 계좌 운용을 딱히 더 꼼꼼하게 하게 된 건 아니었다. 이번에도 Claude 정기 결제 금액만큼만 대충 계산해서 넣어뒀다. 한 11달러 정도. 왜 11달러였냐면, 지난 3개월 동안 Claude 구독료가 11달러였기 때문이다. 그래서 이번에도 별생각 없이 그 정도만 넣어뒀다. 문제는 이번 달부터 다시 22달러로 바뀌는 결제일이었다는 것. 그걸 깜빡했다. 그렇게 Claude가 끊겼다 결론적으로 결제가 실패했고, Claude 개인 구독이 끊겼다. 원래라면 그냥 다시 결제했을 수도 있다. 그런데 사실 ChatGPT 쪽으로 넘어갈까 하

Naver Blog

Uno MVUX가 좋아서 WPF, Avalonia에 옮겨심었습니다

개발하다 보면 어느 순간 이런 생각이 들 때가 있어요. "이 구조... 내가 제대로 쓰고 있는 게 맞나?" 저한테 그 순간이 왔던 게 꽤 됐는데, 최근에 다시 그 생각이 강하게 들었어요. MVVM, 처음엔 완벽해 보였어요 처음 MVVM을 배웠을 때는 솔직히 "이게 답이구나" 싶었어요. UI랑 로직을 깔끔하게 분리하고, 바인딩으로 연결하고. WPF 시절부터 지금까지 살아남은 데는 이유가 있잖아요. 근데 프로젝트가 커지면서부터 슬슬 이상한 일이 생기기 시작했어요. 문제는 "너무 자유롭다"는 거였어요 MVVM의 가장 큰 문제는 역설적으로 너무 관대하다는 거예요. 뭘 어디에 넣어도 딱히 막는 게 없거든요. 처음엔 괜찮아요. 근데 시간이 지나면서... ViewModel에 비즈니스 로직이 하나둘 들어오기 시작하고 어딘가에선 View가 데이터를 직접 건드리고 "일단 돌아가니까" 하면서 넘어간 코드들이 쌓이고 코드 리뷰해주는 사람이 있거나, 팀 컨벤션이 잘 잡혀 있으면 모르겠는데요. 혼자 또는 느

Naver Blog

개발자인데 요즘 코드보다 문서를 더 많이 쓴다

얼마 전부터 이상한 걸 느꼈다. 하루를 마무리하면서 오늘 뭐 했지? 돌아보면 코드를 거의 안 짰다. 대신 AI랑 대화하면서 컨텍스트를 다듬고, 팀 폴더 구조 잡고, 문서 쓰고 있었다. GitHub 잔디는 안 심어지고, PR도 없고, 커밋 로그엔 내 이름이 별로 없는데 — 뭔가 열심히 한 것 같긴 한데 증명이 안 되는 느낌. 현타가 왔다. 나 개발자 맞나? 2~3개월 전만 해도 나름의 원칙이 있었다. AI는 초안 담당, 실제로 치는 건 내가. IDE를 직접 건드려야 개발자답다고. 틀린 생각은 아니었다. 그때는 그게 맞았다. 근데 그 방식엔 문제가 있었다. 요구사항을 머릿속에 대충 넣고 코드부터 짰으니까, 짜다 보면 "어? 이 케이스는?" 이 계속 나왔다. 버그는 거기서 생겼다. 내가 개발을 못한 게 아니라, 혼자 머릿속에서만 굴리다 보니 놓치는 게 있었던 거다. 문서화도 마찬가지였다 시니어쯤 되면 문서를 써야 한다는 건 알고 있었다. 근데 막상 쓰려면 겁이 났다. 내가 잘못 알고 있는

Naver Blog

Claude Code에 대시보드가 생겼다 — 멀티 에이전트 시대의 시작

2주 만에 세 번 바뀐 Claude Code 5월 들어 Claude Code가 자꾸 바뀐다는 느낌을 받았다면, 실제로 바뀌고 있다. 5월 6일 — 시간당 사용 한도 2배 증가 5월 11일 — Agent View 출시 (리서치 프리뷰) 5월 13일 — 주간 한도 추가 50% 증가 (7월 13일까지 한시적) 5주 동안 세 번. 단순한 업데이트 주기가 아니다. Anthropic이 사용자를 멀티 에이전트 워크플로우 쪽으로 밀고 있다는 신호다. Agent View가 뭐야? 한 줄 요약: CLI에서 여러 Claude Code 세션을 한 화면으로 관리하는 대시보드. claude agents 명령을 치면 지금 돌아가는 세션들이 테이블로 나온다. 특정 행을 클릭하면 전체 화면 전환 없이 마지막 응답을 미리볼 수 있다. agent가 판단이 필요해 멈춰 있으면 거기서 바로 답해주면 세션이 재개된다. 예를 들면 이런 식이다 — 터미널 하나에서 코드 리뷰 에이전트, 테스트 에이전트, 문서화 에이전트를 동시

Naver Blog

팀 공유폴더, AI가 읽을 수 있게 만들어봤다

회사에서 AI 계정을 받았다. 팀 내 몇몇 사람만 부여해줬는데 우리 팀은 나 혼자였다. 막상 쓰려니 애매했다. 관리자가 프롬프트를 볼 수 있다는 얘기를 들어서 개인적인 내용을 치기가 좀 그랬고, 코드를 엄청 짜는 수준도 아니라서 신규 프로젝트에 바로 갖다 붙일 상황도 아니었다. 결국 일주일 넘게 어떻게 쓸지 고민만 하고 있었다. 그때 GitHub Copilot Dev Days에서 들었던 얘기가 생각났다. 어떤 팀이 AI를 사내 업무 지식 공유에 쓰고 있다고 했는데, 그때는 그냥 흘려들었다. 근데 막상 이 상황이 되니까 그게 떠올랐다. 개인적인 내용 칠 필요도 없고, 코드 안 짜도 되고. 우리 팀 공유폴더 자료를 AI가 읽을 수 있게 만들어두면 되겠다 싶어서 한번 해봤다. 나 혼자인데 왜 하냐고? 앞으로 계정이 늘어날지 안 늘어날지도 모르는 상황이긴 하다. 근데 같은 팀, 같은 회사 직원이 나한테 물어봐준다면 나는 그냥 타이핑 쳐서 알려주면 된다. 효율 면에서도 팀을 위한 선택이다.

Naver Blog

GitHub Copilot 없이 2주, 그리고 깨달은 것들

막상 해지하고 IDE를 켰을 때는, 생각보다 아무것도 없었다. 회사 일은 대부분 코드 한두 줄 수정이라 자동완성이 필요한 순간이 거의 없었다. 공백이 작았다. 오히려 그 공백을 채우려고 손을 대기 시작했다. Windows에서 Claude Code 터미널로 제대로 써보고 싶어서 이것저것 찾다가 psmux라는 걸 알게 됐고, 터미널 환경을 하나씩 세팅하는 재미가 생겼다. 그러다가 Claude Code를 쓰면서 CLAUDE.md라는 파일을 보게 됐다. 존재 자체는 알고 있었는데, 알고 보니 이게 끝이 아니었다. 폴더 안에 Skill을 정의할 수 있고, Hook도 있고, settings 구조도 있고 — 정확히 어떻게 돌아가는지는 아직 다 모르지만, 폴더 하나가 그냥 설정 파일 모음이 아니라 에이전트처럼 동작할 수 있다는 느낌이 왔다. 그때부터 이 폴더를 개인비서처럼 키워보고 싶다는 생각이 생겼다. 근데 Claude Code만으로는 좀 아쉬웠다. 안에서 무슨 일이 벌어지는지 알고 싶었달까.

Naver Blog

$1짜리 AI 코딩 에이전트, CommandCode Go 플랜은 미끼일까 진짜일까

요즘 AI 코딩 도구 가격이 만만치 않다. Claude Pro $20, Cursor Pro $20, GitHub Copilot $10... 도구만 몇 개 구독해도 카드 명세서가 무서워진다. 그러던 와중에 CommandCode Go 플랜이 월 $1이라는 걸 보고 눈을 의심했다. 실화인가? 그래서 직접 파봤다. CommandCode가 뭐야? 터미널에서 돌아가는 AI 코딩 에이전트. `npm i -g command-code` 한 줄로 설치되고, Claude Code나 Aider랑 비슷한 포지션이다. 슬로건이 좀 거창하다 — "frontier coding agent with taste". 여기서 taste가 이 도구의 정체성이다. Go 플랜의 가격 구조 — 풀이 두 개다 가격 페이지를 자세히 보면 한 줄짜리로 정리되지 않는다. $1/월 = LLM 크레딧 $10 + taste 사용량 $100 (코딩용) (학습 전용, 별도 풀) 이 두 풀이 완전히 분리 돼 있다는 게 핵심이다. 공식 문서의 결

Naver Blog

GPT, Claude보다 50배 싸다는 AI가 나왔다 — 진짜일까

AI 모델 발표가 워낙 쏟아지다 보니 웬만한 건 그냥 스크롤하게 되는데, 이건 좀 달랐다. 5월 5일, 마이애미 스타트업 Subquadratic이 스텔스에서 나오면서 SubQ라는 모델을 공개했다. 발표 24시간 만에 X 조회수 1,200만, 웨이트리스트 등록 3만 명. 커뮤니티 반응도 "역대급 혁신이거나 AI판 테라노스거나" 딱 두 갈래로 갈렸다. 주장이 맞다면 구조 자체를 바꾼 거다. 그게 왜 의미 있는지부터 얘기해보자. 지금 모든 AI가 가진 공통된 약점 ChatGPT든 Claude든 Gemini든, 우리가 쓰는 LLM은 거의 다 트랜스포머 구조다. 2017년 구글 논문 하나가 업계 표준을 만들어버렸고, 이후 거의 모든 모델이 그 위에서 만들어졌다. 문제는 트랜스포머의 핵심인 Self-Attention이 O(n²) 복잡도라는 것이다. 입력이 2배 길어지면 연산량은 4배가 된다. 4배 길어지면 16배. 그래서 실제로 긴 문서나 대형 코드베이스를 통째로 넘기면 비용이 터진다. 이걸

Naver Blog

OpenCode Go 플랜, 어떤 모델이 담겨있을까?

이전 글에서 OpenCode Go 플랜이 뭔지 소개했는데요, 이번엔 한 단계 더 들어가서 Go 플랜 안에 담긴 모델들의 특성을 살펴보려 합니다. 모델이 여러 개 있는데 그냥 아무거나 쓰면 되는 거 아닌가? 싶을 수 있지만, 모델마다 잘하는 게 확실히 다릅니다. 이걸 알고 쓰는 것과 모르고 쓰는 건 효율에서 꽤 차이가 나요. Go 플랜 모델 한눈에 보기 Go 플랜에서 쓸 수 있는 주요 모델과 월 요청 수입니다. 모델 월 요청 수 한 줄 특징 GLM-5.1 200건 꼼꼼한 검수·리뷰 특화 Kimi K2.6 3,450건 긴 컨텍스트 + 에이전트 최강 Qwen3.6 Plus 3,300건 지식 폭 넓은 글쓰기 강자 MiniMax M2.7 3,400건 문장 다듬기·루틴 작업 전담 DeepSeek V4 Pro 3,450건 추론력 올라운더 DeepSeek V4 Flash 31,650건 잡일 전담, 사실상 무제한 요청 수 차이가 꽤 크죠? 이걸 전략적으로 배분하는 게 핵심입니다. 모델별 성격 — 팀

Naver Blog

GitHub Copilot Pro, 조용히 작별했다

처음 구독을 결심했던 건 단순했다. 코드 자동완성이야 기본이고, PR 300건이 포함된다는 게 결정적이었다. "이거 안 하면 손해다" 싶었다. 월 10달러에 이 정도면 충분히 납득이 가는 조합이었다. 처음엔 꽤 괜찮았다. 코드를 치다 보면 슥 올라오는 제안들, 맥락을 어느 정도 파악하고 다음 줄을 채워주는 느낌. 완벽하진 않아도 손이 한 번씩 쉬어가는 느낌은 분명히 있었다. 없던 시절로 돌아가기엔 약간 아쉬운, 딱 그 정도의 편안함이었다. 그렇게 쓰다 보니 어느새 슬슬 익숙해질 때쯤, Copilot이라는 게 뭔지 좀 알아가려던 찰나에 — Agent가 붙고, SubAgent가 들어오기 시작했다. '이게 진짜 부조종사인가?' 싶기도 했지만, PR 300건이라는 한도로는 Agent를 제대로 써볼 수도 없었다. 이것저것 건드려보다가 금방 한도 걱정이 앞섰다. 결국 그냥 있으면 좋은 거겠거니 하고 냅뒀다. 코드 제안 도구로만 쓰기엔 점점 정체성이 애매해지는 느낌이랄까. 그러던 중 6월 1일부

Naver Blog

코딩 에이전트의 미래: 멀티에이전트 오케스트레이션

코딩 에이전트, 어디서부터 이상해졌나 최근 병렬 Agent에 관심이 가기 시작했다. 어떻게 보면 이게 당연한 수순인 것 같기도 하다. Claude Code, Codex 등, 초기 코딩 에이전트가 나왔을 때만 해도 토큰 대비 결과물이 꽤 좋았던 걸로 기억한다. 그런데 모델이 발전하고, 에이전트가 업데이트될수록 뭔가 이상하다는 느낌이 들기 시작했다. 분명 더 똑똑해졌다는데, 내가 원하는 결과물까지 가는 데 토큰이 이상하리만큼 많이 소비되는 것이다. Threads나 X를 보면 다들 비슷한 경험을 한 것 같다. "Claude 이상해졌네, Codex 가야겠다." "Codex 이상해졌네, Claude 가야겠다." 마치 두 에이전트 사이를 진자처럼 왔다 갔다 하는 사람들. 그러다 보니 자연스럽게 이런 생각이 들었다. 코딩 에이전트에 내 일, 업무의 전부가 의존하게 된다면 어떻게 될까. LLM 회사의 코딩 에이전트에 의존할수록, 무지막지한 토큰 소비를 감내해야 한다. 그 페이스에 내 일정을 맞추거

Naver Blog

그럼 언제 struct가 진짜 빛을 발할까?

앞선 글들에서 struct의 위험성과 DTO에서의 한계를 이야기했다. "그럼 struct는 아예 안 쓰는 게 좋은 걸까?" 물론 아니다. struct는 가장 엄격한 값 모델링 도구다. 그 엄격함을 제대로 활용할 수 있는 자리가 분명히 있다. 의미적으로 ‘값’ 그 자체일 때 데이터의 묶음이 아니라, 그 자체가 하나의 독립된 단위여야 할 때다. 좌표: (X, Y) 범위: (Min, Max) 단위 값: (Amount, Currency / Value, Unit) 이런 것들은 정체성이 "데이터의 집합"이 아니라 그냥 하나의 값이다. 좌표 A와 B의 값이 같으면, 그건 완벽히 같은 것이다. 작고, 불변이고, 확장될 일이 없다면 struct는 가장 자연스러운 표현이 된다. 도메인 값 객체(Value Object) DDD에서 식별자(ID)가 없는 값 객체를 표현할 때 struct는 특히 잘 맞는다. public readonly record struct Money(decimal Amount, str

Naver Blog

AI 코딩 도구 요금 부담? 지금 쓸 만한 대안 4가지

Claude Code의 소스 유출, Pro 플랜 변경 혼란, 토큰 폭증 이슈. GitHub Copilot도 비슷한 시기에 사용 제한을 강화하면서 신규 가입을 일시 중단했어요. 한동안 당연하게 쓰던 AI 코딩 도구들이 갑자기 흔들리기 시작한 느낌이에요. 그러면서 개발자 커뮤니티에서 자연스럽게 대안을 찾는 움직임이 생겼어요. 완벽한 대체는 없지만, 지금 시점에서 눈여겨볼 만한 선택지들을 정리해봤어요. 선택지 1 — Ollama Pro ($20) Ollama는 원래 로컬에서 오픈소스 모델을 돌리는 도구로 알려져 있었어요. 그런데 2025년 9월부터 클라우드 구독 서비스를 출시했어요. Pro 플랜이 월 $20, Max 플랜이 월 $100이에요. 핵심은 이게 단순한 클라우드 API 서비스가 아니라는 거예요. ollama launch 명령어 하나로 Claude Code, Codex, OpenCode, OpenClaw 같은 에이전트를 직접 실행할 수 있어요. 예를 들면 이런 식이에요. ollam

Naver Blog

Skill이 좋다는 건 알겠는데, 어떻게 관리하지?

AI 코딩 도구를 쓰면서 Skill이라는 개념을 알게 됐다. SKILL.md 파일 하나로 AI 에이전트에게 "이 프로젝트에서는 이렇게 행동해줘"라고 지시할 수 있는 것. 좋은 건 알겠는데, 막상 쓰려고 하니 뭔가 이상했다. 뭔가 이상하다 프로젝트가 하나면 문제없다. 스킬 폴더 만들고, 파일 넣고, 끝이다. 근데 현실은 프로젝트가 한 개가 아니다. ~/dev/ project-a/ .claude/skills/ project-b/ .claude/skills/ project-c/ .claude/skills/ 새 프로젝트를 시작할 때마다 스킬을 다시 넣어야 한다. 기존 스킬 파일을 찾아서 복붙하거나, 처음부터 다시 만들거나. 스킬을 조금 개선했다면? 쓰고 있는 프로젝트가 세 개면 세 군데 다 직접 가서 파일을 바꿔야 한다. 이게 맞나 싶었다. 찾아봐도 딱히 이걸 해결해주는 방법이 보이지 않았다. 그런데, 사실 이미 있었다 이 글을 쓰면서 좀 더 찾아보다가 알게 됐는데, 사실 기

Naver Blog

$10으로 AI 코딩? — OpenCode Go 이게 뭔데요

요즘 개발자 커뮤니티에서 조용히 화제가 되고 있는 서비스가 하나 있어요. 바로 OpenCode Go입니다. 한 줄로 설명하면 이렇습니다. "가성비 AI 모델들만 잔뜩 모아서, 월 $10에 쓸 수 있게 해드릴게요." OpenCode가 뭔가요? 오픈소스 터미널 AI 코딩 에이전트예요. Claude Code처럼 터미널에서 AI와 대화하면서 코드를 작성하고, 파일을 고치고, 테스트까지 돌려주는 도구예요. 참고로 OpenCode 자체는 Go 언어로 만들어졌는데, Go 플랜 이름이랑 헷갈리기 딱 좋아요. 특이한 건 75개 이상의 LLM을 지원한다는 점이에요. Claude, GPT, Gemini는 물론이고 로컬 모델(Ollama)까지 붙일 수 있어요. 모델 선택은 내가 하는 거예요. 도구 자체는 완전 무료고, 현재 GitHub 스타 14만 개 이상을 기록하며 2026년 가장 빠르게 성장한 개발자 도구 중 하나가 됐습니다. 그럼 OpenCode Go 플랜은? OpenCode라는 도구 위에서 동작하

Naver Blog

AI가 내 대신지식을 관리한다고?

LLM Wiki — 2026년 4월, Karpathy가 쏘아올린 것 Andrej Karpathy가 짧은 문서 하나를 공개했다. OpenAI 창립멤버, Tesla AI 총괄 출신. 그가 뭔가를 공유하면 커뮤니티가 들썩이는 건 공식인데, 이번 내용은 뜬금없이 단순했다. "LLM한테 내 자료 정리를 맡겼더니, 40만 단어짜리 wiki가 만들어졌다. 내가 직접 쓴 건 한 줄도 없다." 솔직히 처음엔 무슨 말인지 몰랐다. LLM으로 지식 관리? 그게 그냥 ChatGPT한테 요약시키는 거 아닌가? 아니었다. 핵심 차이 우리가 보통 AI를 쓰는 방식부터 생각해보자. 아티클을 읽고, 나중에 AI한테 물어보면, AI가 그때그때 답한다. 매번 물어볼 때마다 AI는 처음부터 다시 분석한다. 기억이 없다. 기존 — 질문할 때마다 원본을 다시 읽는다 LLM Wiki — 받는 시점에 한 번 정리, 이후엔 그 파일만 읽는다 Karpathy가 쓴 비유가 딱 맞았다. 컴파일러. 아티클이 소스 코드고, LLM이 컴

Naver Blog

F5 하나, publish 하나 — .NET Aspire가 바꾼 개발 방식

마이크로서비스 구조로 프로젝트를 짜다 보면 개발 시작 전에 이미 피로해지는 순간이 있다. API 하나 띄우고 Worker 하나 띄우고 DB 컨테이너 올리고 포트 맞추고 디버거 각각 붙이고 Visual Studio 창은 여러 개, 터미널도 몇 개 켜져 있고 “이거부터 다 띄워야 되네…” 하는 순간이 온다. 이게 생각보다 반복 비용이 크다. 그 흐름을 .NET Aspire 가 건드린다. F5 하나 Aspire는 AppHost라는 프로젝트 하나에 전체 구성을 코드로 묶는다. var api = builder.AddProject<Projects.MyApi>("api"); var db = builder.AddPostgres("db"); var cache = builder.AddRedis("cache"); api.WithReference(db) .WithReference(cache); 여기까지가 끝이다. AppHost를 F5로 실행하면 API, DB, Redis가 한 번에 올라온다. 중요한 포인

Naver Blog

GitHub Copilot, 갑자기 요금제 바꾼다고? 무슨 일이 생긴 걸까

갑자기 무슨 일이야? 지난 4월 20일, GitHub이 조용히 공지 하나를 올렸습니다. 제목은 "GitHub Copilot 개인 요금제 변경 사항". 내용을 읽어보면 꽤 충격적인데요. 신규 가입을 잠시 막겠다는 겁니다. Pro, Pro+, Student 요금제 모두 새로 가입하는 건 일단 멈추고, 기존 이용자들 서비스 품질부터 챙기겠다는 거죠. GitHub Copilot이 뭔지 잠깐 설명하자면 GitHub Copilot은 코드를 짤 때 AI가 옆에서 도와주는 서비스예요. 마이크로소프트가 소유한 GitHub에서 만든 건데, 쉽게 말해 "코딩 도우미 AI 구독 서비스"입니다. 개발자들이 많이 쓰고, 요즘엔 AI가 혼자 코드를 짜주는 기능도 생겨서 사용량이 폭발적으로 늘고 있었어요. 이번에 바뀌는 것들 1. 신규 가입 중단 Pro, Pro+, Student 요금제 신규 가입이 일시 중지됩니다. 기존 이용자는 그대로 쓸 수 있어요. 2. 사용량 한도 강화 AI를 너무 많이 쓰면 한도에 걸립

Naver Blog

3년 만에 이해한 MauiReactor

Flutter와 React Native가 MVU로 주목받던 시점에, MAUI는 여전히 MVVM 중심이었다. 그래서 자연스럽게 "MAUI에서도 MVU를 쓸 수 없을까?"라는 생각이 들었고, 그때 찾은 게 MauiReactor였다. 다만, 그때는 깊게 파고들 상황이 아니었다. MAUI 자체도 아직 불안정했고, 업무와 직접적으로 연결된 기술도 아니었다. [Scaffold] 같은 기능도 그저 “다른 UI 라이브러리를 MauiReactor 생태계로 가져오는 정도”로만 이해하고 넘어갔다. 내부가 어떻게 동작하는지는 몰랐고, 굳이 알 필요도 없다고 생각했다. 그렇게 관심만 남겨둔 채 몇 년이 흘렀다. 전환점은 AI였다. MauiReactor 소스 코드를 AI와 함께 하나씩 뜯어보기 시작하면서 비로소 구조가 보이기 시작했다. 가장 크게 느꼈던 건 이거였다. diff가 MAUI 컨트롤 트리(DependencyObject) 위에서 일어나는 게 아니었다는 점. MauiReactor는 자체적인 가상 트리

Naver Blog

AI 개발 도구, 3개월째 쓰고 있습니다

이전 글에서 Claude Code와 GitHub Copilot을 처음 제대로 써봤을 때 이야기를 했습니다. 그때는 2시간 만에 프로젝트 하나가 만들어졌고, 테스트도 거의 안 하고 배포했는데 그냥 돌아갔습니다. 솔직히 그때는 "이게 맞나?" 싶었습니다. 그로부터 시간이 꽤 흘렀습니다. Claude는 2달, Copilot은 3달째입니다. 쓰는 방식이 달라졌습니다 워크플로우 자체는 크게 바뀌지 않았습니다. 여전히 Claude로 설계하고, Copilot으로 보조합니다. 다만 쓰는 방식이 조금씩 달라졌습니다. 예전에는 모르는 게 생기면 검색부터 했습니다. 지금은 Claude를 먼저 켭니다. SNS에서 신기술 링크가 올라오면 그냥 링크를 던지면서 "이거 뭐야?" 하고 묻습니다. 어느 순간부터 검색엔진 자리를 Claude가 차지하고 있었습니다. 프로젝트가 생기면 설계와 초안도 맡깁니다. 예전엔 "여기까지 맡기는 건 좀 아닌데" 싶어서 중간중간 확인했는데, 지금은 그냥 넘깁니다. 생각보다 잘 나옵

Naver Blog

WinUI3 만지작 후기 - NavigationView, x:Bind, 그리고 혼란

WinUI3를 조금 만져봤습니다. 가볍게 NavigationView부터 시작했는데, 생각보다 익숙하지 않은 포인트들이 몇 가지 있었습니다. NavigationView = Frame 조합인 줄 알았는데 처음엔 당연히 이렇게 생각했습니다. NavigationView + Frame = 한 세트 그런데 자료를 찾아보던 중, 닷넷데브에서 활동 중 이신 suwoo 님이 남기신 글을 보고 방향이 조금 바뀌었습니다. WinUI 3의 NavigationView에서의 Navigate 메서드는 WPF의 그것과 달랐군요.. 먼저 저와 비슷한 경험을 찾았어서 공유부터 드립니다.. WinUI3에는 NavigationView라는 녀석이 있습니다. 윈도 앱 좌측 메뉴와 같은 편리하고 예쁜(?) 모양을 제공해서 이걸 사용하기로 했었는데요, 평소 하던 대로 View와 ViewModel을 ServiceProvider에 맡겨서 쓰고 있었던거죠. WPF에서 Navigate는 인스턴스를 인자로 넘기고,(애초에 Naviga

Naver Blog

2달 반 블로그 썼다, 나한테 수고했다고 말하고 싶어서

처음부터 대단한 목표는 없었다. 그냥 생각나면 썼다. 2월엔 주 6개, 3월엔 주 5개, 요즘은 주 4개. 할당량도 아니고, 누가 시킨 것도 아니다. 그냥 내 페이스대로 내 이야기를 적었다. 그렇게 2달 반이 지났다. 일 방문자가 많을 땐 50명을 넘기도 했다. 적을 땐 10~20명. 근데 솔직히 그것보다 내가 꾸준히 기록했다는 것 자체가 더 신기하고 뿌듯했다. 작심삼일로 끝난 것들이 한두 개가 아닌데, 이건 어쩌다 보니 계속되고 있었다. 그래서 애드포스트를 신청했다. 수익 때문이 아니라. 커피 한 잔도 될지 모르지만, 그게 목적이 아니었으니까. 그냥 나한테 "잘했어" 하고 싶었다. 애드포스트 승인이 그 도장 같은 느낌이랄까. 사실 대단한 글을 쓴 것도 아니다. 누군가한테 도움이 됐는지도 모르겠다. 그냥 내가 개발하면서 느낀 것들 관심가지고 싶은 기술을 찾아보고 정리한 글들을 적었을 뿐이다. 근데 그게 쌓이니까 뭔가가 됐다. 앞으로도 거창한 계획은 없다. 생각나면 쓰고, 쓰고 싶지

Naver Blog

WPF도 생각보다 가볍게 만들 수 있습니다

“Hook이 부러운 순간”이라는 글을 쓴 뒤로 한 가지 질문이 계속 머릿속에 남아 있었습니다. WPF는 정말 항상 무겁게 만들어야 할까? 그 다음 글에서는 MVVM이 언제부터인가 선택이 아니라 기본값처럼 사용되고 있다는 이야기를 했습니다. 버튼 하나에도 ViewModel을 만들고 Property를 만들고 Command를 만들고 바인딩을 연결하는 구조. 물론 이 구조는 여전히 좋은 패턴입니다. 특히 규모가 커질수록 더 그렇습니다. 그런데 가끔은 이런 생각이 듭니다. 조금 더 가볍게 시작할 수는 없을까? 사실 방법이 하나 있습니다. 요즘 WPF에서는 CommunityToolkit.Mvvm을 많이 사용합니다. 그리고 이 라이브러리에는 꽤 재미있는 기능이 있습니다. INotifyPropertyChanged를 코드 몇 줄로 만들어주는 Source Generator입니다. 예를 들면 이런 코드입니다. // CounterView.xaml.cs [INotifyPropertyChanged] publ

Naver Blog

ICommand vs onClick, 이벤트를 대하는 태도의 차이

처음엔 버튼은 그냥 "누르면 동작하는 것"이라고 생각했다. 그런데 WPF 에서 ICommand를 제대로 쓰기 시작하면서 이벤트를 바라보는 시선이 조금 달라졌다. 버튼은 그냥 클릭을 받는 객체가 아니라, "의도(Intent)를 전달하는 통로"가 된다. ICommand는 행동을 객체로 만든다 ICommand를 쓰면 실행 로직은 ViewModel에 있고 버튼은 Command를 바인딩하고 CanExecute로 상태까지 제어한다 <Button Command="{Binding SaveCommand}" /> 이 한 줄 안에는 저장이라는 도메인 의미 실행 가능 여부 UI 상태 제어 가 모두 들어 있다. 이건 단순 이벤트 핸들러가 아니다. 행동을 객체로 승격시킨 구조다. 조금 무겁지만, 대신 일관성이 생긴다. onClick은 즉각적이다 반대로 React 의 onClick은 훨씬 직관적이다. <button onClick={handleSave}> 여기에는 계층도, 추상화도 거의 없다. 클릭 → 함수 실

Naver Blog

DTO를 struct로 쓰면 정말 더 빠를까?

"메모리를 아껴야 한다." 개발자의 본능 같은 거다. 힙(Heap) 대신 스택(Stack)을 쓰면 GC가 쉴 수 있으니까 당연히 더 빠를 거라고 믿었다. 그런데 벤치마크를 돌려보고 생각이 바뀌었다. 복사 비용의 역설 참조 타입(class/record)은 데이터가 아무리 커도 8바이트 주소값만 넘기면 끝이다. 하지만 struct DTO는 메서드 인자로 넘길 때마다 그 안에 든 모든 데이터를 복사한다. 필드가 5개, 10개로 늘어날수록 메서드 호출 한 번에 수십 바이트씩 메모리 복사가 일어난다. 가볍게 전달하려고 struct를 썼는데, 정작 전달할 때마다 거대한 짐을 새로 꾸리는 꼴이다. GC는 쉬지만 CPU는 바쁘다 힙 메모리를 쓰지 않으니 GC(Garbage Collector)의 부담은 줄어든다. 하지만 그 대가로 CPU는 쉴 새 없이 메모리를 복사하느라 바빠진다. 메모리 해제 비용을 아끼려다 데이터 전송 비용으로 더 큰 대가를 치르는 셈이다. 심지어 덩치가 커진 struct는 CP

Naver Blog

Result 패턴을 쓰면 예외를 줄일 수 있을까?

예외 처리에 대해 몇 번 고민하다 보면 자연스럽게 이런 질문이 나온다. "그럼 차라리 예외를 덜 쓰면 되는 거 아닌가?" 그 대안으로 자주 등장하는 게 Result 패턴이다. public Result<User> Register(UserCommand command); 성공이면 값이 들어 있고, 실패면 에러 정보가 들어 있는 구조. 겉보기엔 깔끔하고 try-catch도 줄어든다. 근데 이게 정말 정답일까? 1. Result는 예외를 “없애는” 게 아니다 먼저 오해부터 정리해야 한다. Result 패턴은 예외를 제거하는 게 아니라, 예외를 명시적인 흐름으로 바꾸는 거다. 기존 방식: 실패하면 갑자기 throw가 튀어나옴. Result 방식: 실패가 반환 값 안에 포함됨. 차이는 명확하다. 실패를 숨기지 않고 호출자가 반드시 확인하게 만든다. 2. 언제 효과적인가 이 패턴은 "예상 가능한 실패" 가 많을 때 빛난다. 비즈니스 규칙 위반 (잔액 부족 등) 검증 실패나 권한 부족 상태 전이 불

Naver Blog

렌더링이 왜 일어나는가 - 리렌더링 조건 정리

`memo` 를 붙였는데도 리렌더링이 멈추지 않는다. `useCallback` 을 썼는데도 자식이 계속 재렌더된다. 이런 경험이 쌓이면 결국 한 가지 질문으로 돌아온다. "React는 언제 렌더링을 트리거하는가?"" state가 바뀌었을 때 부모가 리렌더됐을 때 구독하는 context가 바뀌었을 때 props가 바뀌었을 때가 아니다. 부모가 리렌더되면, props가 그대로여도 자식은 기본적으로 같이 실행된다. State 변경 const [count, setCount] = useState(0); setCount(1); // 리렌더 O setCount(0); // count가 이미 0이면 리렌더 - X(bail-out) React는 `Object.js`로 이전 state와 비교한다. primitive 값은 문제없지만, 객체·배열은 주의가 필요하다. // 같은 참조 — 리렌더 안 일어남 setState(prev => { prev.name = "kim"; // 기존 객체를 직접 수정 re

Naver Blog

Avalonia는 WPF의 대체제가 아니다

WPF를 오래 다룬 개발자가 처음 Avalonia를 접하면 대개 이런 생각을 합니다. 어? 이거 그냥 WPF잖아? XAML 문법도 비슷하고, 구조도 닮았고, DependencyProperty를 연상시키는 StyledProperty까지. 겉모습만 보면 "Windows 전용 WPF를 크로스 플랫폼으로 옮겨 놓은 것"처럼 보입니다. 하지만 이 지점에서 착각이 시작됩니다. Avalonia는 WPF의 대체제가 아닙니다. 문법만 빌려왔을 뿐, 설계 철학은 전혀 다릅니다. Property 시스템의 차이 — 중심이 다르다 WPF의 DependencyProperty는 Windows UI 인프라 위에서 동작하는 속성 시스템입니다. 플랫폼과 강하게 결합되어 있습니다. 반면 Avalonia의 StyledProperty는 스타일 엔진 중심으로 설계되었습니다. 단순한 속성 저장 구조가 아니라, 스타일 레이어를 통해 상태를 결정하는 시스템입니다. WPF에서는 리소스 사전을 뒤지며 스타일을 바꿨다면, Avalo

Naver Blog

왜 나는 다시 XAML로 돌아왔는가

React로 프로젝트를 하면서 상태 관리 구조를 여러 번 뒤집어본 적이 있다. 날밤을 샌 적은 없다. 대신, 같은 고민을 수도 없이 반복했다. 화면을 띄우는 건 빠르다. 문제는 그 뒤에 따라오는 상태의 흐름이다. 컴포넌트가 늘어나고, 상태가 서로 얽히기 시작하면 문득 이런 생각이 들었다. 나는 지금 화면을 설계하는 걸까, 아니면 상태의 흐름을 붙잡고 있는 걸까? 그 순간이 쌓이면서 나는 다시 XAML을 켰다. React, 렌더링의 세계 React는 정직하다. 상태가 바뀌면 다시 그린다. UI = f(state) 이 명제는 정말 깔끔하다. useState 하나로 세계가 움직이는 그 즉각적인 반응성은 분명 매력적이다. 하지만 규모가 커지면 이야기가 달라진다. 어느 순간부터 렌더링 최적화 고민이 중심이 된다. “어떻게 하면 덜 그릴 수 있을까?” “이 컴포넌트는 왜 다시 렌더링되지?” 그때부터 나는 UI를 설계하는 사람이 아니라 렌더링 사이클을 조정하는 사람이 되어 있었다. XAML, 속

Naver Blog

try-catch를 무작정 감싸면 안 되는 이유 (3)

앞선 글에서 이런 이야기를 했습니다. 예외를 무작정 삼키지 말 것 UI + async 환경에서는 더 위험하다는 것 그런데 실무에서는 이보다 더 자주 발생하는 문제가 있습니다. 모든 예외를 동일하게 취급하는 것입니다. 코드를 보다 보면 이런 형태가 자주 보입니다. catch (Exception ex) { ShowMessage("오류가 발생했습니다."); } 문제 없어 보일 수 있습니다. 하지만 이 코드는 생각보다 많은 문제를 만듭니다. 예외는 크게 두 가지로 나뉩니다. 첫 번째는 도메인 예외 (Business Exception)입니다. 잔액이 부족합니다 이미 존재하는 사용자입니다 승인되지 않은 상태입니다 이건 시스템 오류가 아닙니다. 비즈니스 규칙에 의해 발생한 결과입니다. 실패라기보다는 거절에 가까운 흐름입니다. 두 번째는 기술 예외 (Technical Exception)입니다. DB 연결 실패 네트워크 타임아웃 NullReferenceException JSON 파싱 실패 이건 비즈

Naver Blog

WPF에서 ContentControl이 사실상의 라우터가 되는 이유

WPF를 조금 오래 다루다 보면 재미있는 패턴 하나를 발견하게 됩니다. 처음에는 Page와 NavigationService를 씁니다. 그러다가 점점 구조가 복잡해지고 결국 어느 순간 이렇게 바뀝니다. Window는 하나만 둡니다. 그리고 중앙에 ContentControl 하나를 둡니다. 그리고 ViewModel을 바꿉니다. 그러면 화면이 바뀝니다. 어느 순간 깨닫게 됩니다. “이거… 라우터잖아?” 화면 전환의 본질은 결국 "상태 변경" 웹 프레임워크를 보면 화면 전환은 대부분 라우터가 담당합니다. React도 그렇고 Vue도 그렇고 Angular도 마찬가지입니다. URL이 바뀌면 라우터가 컴포넌트를 바꿉니다. 그런데 WPF는 조금 다릅니다. WPF에서는 URL이 아니라 상태가 바뀝니다. 예를 들어 이런 식입니다. CurrentViewModel = new DashboardViewModel() 이 값이 바뀌면 ContentControl이 다른 View를 보여줍니다. 라우팅처럼 보이지는

Naver Blog

DTO는 왜 struct 대신 record를 쓸까?

모델을 만들다 보면 결국 이 질문으로 다시 돌아온다. 단순히 데이터만 묶는 거면 struct가 더 맞는 거 아닌가? 그런데 실무 코드를 보면 대부분 record를 쓰고 있다. 요즘은 record struct까지 나왔는데도 결국 선택은 record(class)로 모인다. 왜 그럴까? struct: 가볍지만, 오래 들고 가기엔 부담된다 struct는 값 타입이다. 대입할 때마다 복사가 일어난다. 문제는 DTO가 생각보다 꽤 많이 돌아다닌다는 점이다. 메서드 인자로 넘어가고 LINQ에서 변형되고 매핑되고 직렬화된다 이 과정에서 계속 복사가 발생한다. DTO가 작을 때는 괜찮다. 그런데 필드가 조금만 늘어나면 이 복사 비용이 무시하기 어려워진다. 그리고 하나 더. DTO는 단순 데이터 덩어리 같지만 현실에서는 계층 구조가 붙는 순간이 많다. (API 공통 응답, 베이스 모델 등) 이때 struct는 바로 선택지에서 빠진다. 상속이 안 되기 때문이다. record class: 값처럼 쓰는 참

Naver Blog

WPF개발하다 React의 Hook이 부러운 순간

가끔 다른 프레임워크 코드를 보다 보면 묘하게 부러운 순간이 있습니다. 특히 React 코드를 볼 때입니다. 예를 들면 이런 코드입니다. const [count, setCount] = useState(0) <button onClick={() => setCount(count + 1)}> {count} </button> 처음 보면 별 생각이 없습니다. 그냥 버튼을 누르면 숫자가 올라가는 코드입니다. 그런데 어느 순간 이런 생각이 듭니다. "이게 왜 이렇게 가볍지?" WPF에서 같은 걸 하려면 WPF에서는 보통 MVVM 스타일로 작성합니다. 그래서 코드 흐름이 대체로 이렇게 됩니다. ViewModel 생성 Property 구현 INotifyPropertyChanged ICommand 구현 XAML 바인딩 익숙해지면 어렵지는 않습니다. 문제는 어렵냐가 아니라 무게입니다. 버튼 하나를 만들기 위해 생각보다 많은 구조가 따라옵니다. 가끔은 이런 생각이 들기도 합니다. "이 버튼 하나 때문에 우

Naver Blog

MVVM 없이 WPF를 쓰면 안 되는 걸까

얼마 전 "Hook이 부러운 순간"이라는 글을 썼습니다. React의 Hook처럼 문제 크기에 딱 맞는 간결한 구조가 부럽다는 이야기였습니다. 글을 쓰고 나서도 한 가지 생각이 계속 남았습니다. "WPF는 정말 가볍게 만들 방법이 없는 걸까?" 사실 WPF는 마음만 먹으면 꽤 단순하게 만들 수 있습니다. 예를 들면 이런 코드입니다. <Button Click="Button_Click">0</Button> int count = 0; private void Button_Click(object sender, RoutedEventArgs e) { count++; ((Button)sender).Content = count; } 이 정도면 React의 간단한 상태 코드와 크게 다르지 않습니다. 어떤 면에서는 오히려 더 직관적이기도 합니다. 그런데 우리는 보통 이렇게 시작하지 않습니다. WPF 프로젝트를 열면 거의 자동처럼 이런 루틴이 시작됩니다. ViewModel 생성 Property + OnP

Naver Blog

React에게 key는 '메모리 주소'와 같다

React에서 key를 설명할 때 보통 이렇게 말합니다. 리스트 렌더링할 때 필요한 이름표 맞는 말입니다. 그런데 실무에서 React를 오래 쓰다 보면 조금 다른 느낌이 옵니다. key는 단순한 이름표라기보다 컴포넌트의 메모리 위치를 가리키는 좌표에 가깝습니다. React는 state를 어디에 붙일지 기억한다 React는 렌더링할 때 컴포넌트 트리를 만들고 각 컴포넌트에 state를 연결해 둡니다. 그래서 우리가 onChange 같은 걸로 state를 바꾸면 React는 이렇게 판단합니다. 아, 같은 컴포넌트네. 데이터만 바뀌었구나. 그래서 컴포넌트 인스턴스는 유지한 채 내용만 업데이트합니다. 대부분의 렌더링이 이 방식으로 일어납니다. 그런데 key가 바뀌면 이야기가 달라진다 key가 바뀌는 순간 React의 판단은 완전히 달라집니다. React 입장에서는 이렇게 보입니다. 기존 컴포넌트 사라짐 새 컴포넌트 등장 즉, 기존 컴포넌트 unmount 새 컴포넌트 mount 그래서 sta

Naver Blog

처음 만나는 C# - 신입 C# 개발자 기준으로 읽어본 후기

요즘 같은 시대에 굳이 언어 공부를 해야 할까 싶을 때가 있다. AI가 코드를 대신 짜주는데 문법을 처음부터 다 보는 게 의미가 있나 싶기도 하고. 근데 막상 작업하다 보면 막히는 지점은 항상 비슷하다. "이 코드가 왜 이렇게 돌아가는지" 이걸 모르면 AI가 짜준 코드도 결국 내 게 아니다. 그래서 결국 처음에 기본기를 어떻게 잡느냐가 중요해진다. 이 책은 그 시작점으로 괜찮았다. C# 기초부터 실전까지 한 흐름으로 이어진 구성이다. 문법 따로, 실전 따로가 아니라 읽다 보면 자연스럽게 이어진다. "그래서 이걸 쓰는구나"가 바로 이해된다. WinForms 예제도 좋았다. 억지로 넣은 느낌이 아니라 흐름 안에서 자연스럽게 나온다. UI를 실제로 어떻게 쓰는지 감이 온다. ASP.NET Core 파트도 실무 기준에 가깝다. DB 연결부터 API 호출까지 한 번에 흐름으로 이어준다. 읽으면서 들었던 생각은 하나였다. "이거 신입 때 봤으면 덜 헤맸겠다." 추천 대상은 명확하다. 막 시작한

Naver Blog

MVVM vs React Hooks, 나는 어디에 서 있는가

예전에는 MVVM이 당연한 세계라고 생각했다. 특히 WPF 를 오래 만지다 보니 View는 조용히 있고, ViewModel이 상태를 들고, Binding이 알아서 흘러가야 “잘 만든 구조”라고 믿고 있었다. 그 질서가 꽤 마음에 들었다. 그러다 React 를 제대로 보기 시작했다. useState, useEffect, 그리고 함수형 컴포넌트. 처음엔 솔직히 조금 거칠게 느껴졌다. “상태를 이렇게 바로 써도 되나?” “이건 ViewModel이 어디 있는 거지?” 그런데 쓰다 보니 생각이 조금 바뀌었다. MVVM은 ‘구조’를 먼저 세운다 MVVM은 설계가 먼저다. 상태는 ViewModel에 있다 View는 상태를 직접 만지지 않는다 모든 흐름은 Binding을 통해 간다 특히 DependencyProperty, INotifyPropertyChanged, Command 패턴. 이 세계는 무겁다. 하지만 대신, 한 번 구조가 자리 잡으면 어지간해서는 무너지지 않는다. 대규모 화면, 복잡한

Naver Blog

Prism Region은 더 나은 대안일까?

Page 방식의 내비게이션이 묘하게 불편해지는 순간이 있습니다. 그럴 때 우리는 자연스럽게 “다른 방법 없을까?”를 고민하게 됩니다. 그리고 그때 가장 자주 등장하는 선택지가 바로 Prism의 Region 시스템입니다. Region이 해결하려는 본질 Prism의 접근 방식은 꽤 명확합니다. View를 직접 갈아 끼우지 말고, ‘영역(Region)’을 정의한 뒤 그 안에 주입해라 구조를 단순하게 보면 이렇게 나뉩니다. Shell: 전체를 감싸는 큰 틀 (Window) Region: 화면 안의 빈 영역 (Placeholder) RegionManager: 어떤 View를 넣을지 결정하는 관리자 이건 단순한 화면 전환 방식이 아니라, ‘공간’과 ‘내용물’을 분리하는 설계입니다. 왜 Region을 쓰는가? 1. DI(의존성 주입)와의 궁합 ViewModel에서 "이 화면 보여줘"라고 요청하면 컨테이너가 알아서 View를 생성해서 Region에 주입합니다. 직접 new View()를 만들 일이

Naver Blog

try-catch를 무작정 감싸면 안 되는 이유 (2)

UI 스레드와 async/await에서 더 위험해지는 순간 이전 글에서 "try-catch를 무작정 감싸는 건 문제를 숨기는 것에 가깝다"는 이야기를 했습니다. 그런데 이 습관은 UI 애플리케이션, 특히 WPF + async/await 환경에서는 더 위험해집니다. 여기서는 예외가 단순한 오류가 아니라 흐름 제어에 가까운 역할을 하기 때문입니다. 1. async void + try-catch = 조용한 실패 WPF 이벤트 핸들러는 보통 이런 형태입니다. private async void Button_Click(object sender, RoutedEventArgs e) { try { await LoadDataAsync(); } catch (Exception) { // 일단 막자 } } 겉보기에는 안전해 보입니다. 하지만 예외를 그냥 삼켜버리는 순간, 문제는 이렇게 바뀝니다. 데이터는 일부만 로드됨 상태는 갱신되지 않음 사용자에게는 아무 일도 안 일어난 것처럼 보임 즉, 실패가 “조용해

Naver Blog

주소는 바뀌는데 왜 새로고침이 안 될까? : SPA 라우팅

요즘 웹사이트(SPA)는 페이지를 이동해도 화면이 ‘깜빡’이지 않는다. 분명 주소창의 URL은 바뀌는데, 브라우저는 새로고침을 하지 않는다. 이건 단순한 최적화가 아니다. 브라우저의 기본 동작을 가로채고 있기 때문이다. 이 마법의 핵심은 History API에 있다. 브라우저를 속이는 History API 원래 주소창에 새로운 URL을 입력하면 브라우저는 서버에 요청을 보낸다. "이 주소에 해당하는 페이지를 줘." 하지만 SPA는 이 흐름을 끊는다. history.pushState()를 사용하면 서버 요청 없이 주소창의 URL만 변경할 수 있다. 즉, URL은 바뀌었지만 페이지 이동은 일어나지 않는다 사용자 입장에서는 페이지가 이동한 것처럼 보이지만, 실제로는 자바스크립트가 화면의 일부(Component)만 교체하고 있을 뿐이다. "뒤로 가기"는 어떻게 감지할까? 문제는 여기서 시작된다. 우리가 URL을 직접 바꿨기 때문에, 브라우저의 “뒤로 가기”는 더 이상 자연스럽게 동작하지 않

Naver Blog

프레임워크 버그를 만났을 때, 예전이랑 다르게 행동하게 됐다

이전 글에서 AI에게 SKILL을 먼저 세팅하고 그 구조 안에서 작업하는 방식에 대해 이야기했습니다. 그 방식으로 MauiReactor 작업을 계속하다 보니, 생각보다 빨리 흥미로운 상황을 하나 만나게 됐습니다. 프레임워크 내부 버그였습니다. MauiReactor에 대한 기대, 그리고 망설임 MauiReactor는 꽤 매력적인 프레임워크입니다. XAML 없이 순수 C#으로, React처럼 선언적으로 UI를 구성할 수 있습니다. 예전부터 써보고 싶다는 생각은 있었지만 항상 한 가지가 걸렸습니다. - 중간에 내가 손댈 수 없는 문제가 나오면 어떻게 하지? - 기술적인 문제로 도중에 갈아엎게 되면? 회사에서 이걸 쓰겠다고 했다가 지원이 안 되면 그건 누가 감당하지? 개발하다 보면 한 번쯤은 고민하게 되는 지점입니다. 그래도 시작했던 이유 이전 글에서 이야기했듯이, AI에게 SKILL을 정리해서 넣어두면 단순히 코드 생성 이상의 도움을 받을 수 있습니다. 이번에는 그걸 믿고 시작했습니다.

Naver Blog

AI가 쏘아올린 CLI의 재발견 — 그리고 gh extension

요즘 터미널에 계속 남아 있게 됐습니다. 굳이 나갈 이유가 없어서입니다. 처음 계기는 AI 도구들이었습니다. CLI 위주로 돌아가다 보니 자연스럽게 터미널에서 시작했는데, 막상 쓰다 보니 그냥 이쪽이 더 편했습니다. 그러다 이런 생각이 들었습니다. 마크다운 하나 보려고 IDE를 꼭 켜야 하나? gh가 뭔가요? gh는 GitHub의 공식 CLI 도구입니다. 처음 보면 git이랑 헷갈리기 쉬운데, 역할이 다릅니다. git → 로컬 버전 관리 → commit, push, pull 같은 코드 이력 관리 gh → GitHub 자체를 다룹니다 → PR, 이슈, 레포 생성 같은 작업 브라우저를 열지 않고도 GitHub 작업을 터미널 안에서 처리할 수 있게 해주는 도구입니다. gh extension gh에는 extension 시스템이 있습니다. 느낌은 단순합니다. 필요한 기능을 그때그때 붙인다 설치도 별거 없습니다. gh extension install {GitHub계정}/{확장이름} 이걸로 끝입

Naver Blog

WinUI 3는 왜 NavigationService 기반일까?

WPF 개발자가 WinUI 3 프로젝트를 처음 열어보면 대부분 한 번쯤 이런 생각을 합니다. "왜 멀쩡한 Window 놔두고 Frame에 Page를 갈아 끼우지?" "그냥 ContentControl에 ViewModel 바인딩하면 끝 아닌가?" 사실… 됩니다. 그 방식도 충분히 구현은 가능합니다. 다만 그렇게 가면 조금씩 고생길이 열리기 시작합니다. WPF의 사고방식 WPF에서 화면 전환은 보통 이런 느낌입니다. MainContent.Content = new DetailView(); Prism을 쓴다면 이런 식이죠. _regionManager.RequestNavigate("MainRegion", "DetailView"); 핵심 감각은 이겁니다. 창 안의 부품을 교체한다. Navigation은 선택 기능입니다. 안 써도 아무 문제 없습니다. Window가 중심이고 그 안에서 무엇을 보여줄지를 결정하는 구조입니다. WinUI 3 기본 템플릿을 보면 WinUI 3 프로젝트를 만들면 이런 코

Naver Blog

Guid.NewGuid()만 쓰던 나를 반성하며

(UUID v4, v5, v7을 정리해본 기록) 개발자라면 한 번쯤은 써봤을 Guid.NewGuid(). 저도 그랬습니다. 겹치지만 않으면 되는 값. 그 이상으로 생각해본 적은 거의 없었습니다. 그런데 DB를 의식하기 시작하면서 이 값이 조금 다르게 보이기 시작했습니다. 어느 순간 이런 생각이 들었습니다. 왜 PK가 점점 느려지지? 그제야 GUID를 그냥 난수 덩어리가 아니라 설계의 선택지로 보기 시작했습니다. 이번 글은 거창한 구현기라기보다는 UUID 버전들을 직접 뜯어보며 정리한 기록에 가깝습니다. v4 — 편하지만 무심한 선택 Guid.NewGuid()가 만들어내는 건 사실상 UUID v4입니다. 완전 랜덤입니다. var id = Guid.NewGuid(); 애플리케이션 입장에서는 거의 완벽합니다. 충돌 가능성 거의 없음 생성 빠름 어디서든 사용 가능 그래서 저도 아무 생각 없이 사용했습니다. 문제는 DB Primary Key로 사용할 때였습니다. 랜덤 값의 특성 때문에 이런

Naver Blog

Claude 스킬, 파일로 저장하는 방법 (아무도 안 알려주는 꿀팁)

Claude를 쓰다 보면 한 번쯤 이런 생각이 듭니다. “이거… 날아가면 어떡하지?” 열심히 만들어둔 스킬일수록 불안감이 묘하게 따라옵니다. 그런데 의외로 방법은 단순합니다. 스킬을 통째로 파일로 뽑아둘 수 있습니다. 방법 요약 설정 → 스킬 다운로드 → .skill 저장 → .zip으로 변경 → 압축 해제 끝입니다. 진짜 이게 전부입니다. 1. 스킬 파일 다운로드 Claude 설정으로 들어가면 사용자 지정 스킬 목록이 보입니다. 각 스킬 옆에 다운로드 버튼이 있습니다. 누르면 .skill 파일로 떨어집니다. 여기까지는 공식 기능입니다. 2. 확장자를 .zip으로 변경 여기서부터가 핵심입니다. .skill 파일은 사실상 압축 파일입니다. 그래서 이름만 바꿔주면 됩니다. Windows 파일 탐색기 → 보기 → “파일 확장명” 체크 파일 우클릭 → 이름 바꾸기 .skill → .zip 3. 압축 해제 이제 그냥 더블클릭하면 됩니다. 스킬 내부 구조가 그대로 나옵니다. 설정 파일 프롬프트

Naver Blog

C# struct를 잘못 쓰면 생기는 이상한 버그들

struct는 복사됩니다. 이 사실은 대부분 알고 있습니다. 하지만 코드를 짜다 보면 이걸 꼭 한 번씩 잊어버리게 됩니다. 그리고 그 짧은 순간의 망각이 로그에도 잘 남지 않는 이상한 버그를 만들었습니다. 저도 몇 번 당했습니다. 원본은 아프지 않습니다 struct 내부에 상태를 바꾸는 메서드를 만들었습니다. model.ChangeStatus(); 호출도 잘 되었고 에러도 없었습니다. 그런데 값이 바뀌지 않았습니다. 처음에는 로직을 의심했습니다. 하지만 문제는 로직이 아니었습니다. 메서드를 호출하는 과정에서 struct의 복사본이 만들어졌기 때문이었습니다. 저는 원본이 아니라 잠깐 생겼다가 사라지는 복사본의 상태만 바꾸고 있었습니다. 원본은 아무 일도 없다는 듯 그대로 남아 있었습니다. 실제로 있었던 코드 간단한 예입니다. struct Order { public int Status; public void Complete() { Status = 1; } } 그리고 이런 코드가 있었습니

Naver Blog

AI가 삽질하지 않도록 라이브러리 사용 규칙을 SKILL로 먼저 박아넣었다

오픈소스인 github-copilot-usage를 보고 문득 이런 생각이 들었습니다. 이걸 Rust가 아니라 MauiReactor로 옮겨보면 어떨까? 마침 손에 익히고 싶었던 Claude Code CLI + GitHub Copilot 조합을 테스트해 볼 좋은 기회이기도 했습니다. 하지만 단순히 이거 만들어줘 라고 던지는 건 재미없었습니다. 요즘 AI 코딩 이야기를 보면 AI에게 전부 맡기는 흐름이 많은데, 저는 조금 다른 방식으로 접근해 보기로 했습니다. 도구에 휘둘리기보다는 내가 설계한 구조 안에서 AI를 부려먹어 보기로 했습니다. 1. AI에게 먼저 룰을 알려준다 AI는 똑똑합니다. 하지만 특정 라이브러리의 사용 방식까지 정확히 알고 있는 건 아닙니다. 특히 MauiReactor는 체인 메서드 기반이라 선언 순서가 조금만 어긋나도 코드가 쉽게 꼬입니다. 그래서 가장 먼저 한 일이 있습니다. AI가 삽질하지 않도록 라이브러리 사용 규칙을 SKILL로 넣었습니다. MauiReacto

Naver Blog

API 구조를 정리하다가 설정 엔드포인트에서 멈칫한 이유

이번에 API 구조를 정리하다가 설정 관련 엔드포인트를 어디에 둘지 고민하게 되었습니다. 처음에는 단순했습니다. 기존 Controller 안에 Settings 관련 메서드 몇 개만 추가하면 되지 않을까 생각했습니다. 그런데 이상하게 마음이 편하지 않았습니다. 이걸 그냥 기존 API 안에 섞어 넣어도 되는 걸까 하는 생각이 들었습니다. 처음에는 그냥 “기능 중 하나”였습니다 예를 들면 이런 것들입니다. 장비 연결 정보 수정 로그 보관 기간 변경 업로드 주기 설정 라이선스 옵션 변경 처음 보면 전부 그냥 부가 기능처럼 보입니다. 그래서 보통은 기존 도메인 API 안에 슬쩍 넣어버리기 쉽습니다. 그런데 시간이 지나면 설정은 생각보다 빠르게 늘어납니다. 그리고 어느 순간 API 목록을 보다가 이런 생각이 듭니다. 이건 기능일까, 설정일까? 설정은 성격이 조금 다릅니다 일반 API는 대부분 트랜잭션 중심입니다. 데이터를 생성하고 조회하고 수정합니다. 즉 도메인 로직이 실행되는 곳입니다. 하지

Naver Blog

자바스크립트 이벤트 루프, 알고 보면 단순하다

자바스크립트는 '싱글 스레드'다. 말 그대로 한 번에 하나의 일만 처리한다. 그런데 브라우저를 보면 이상하다. API도 호출하고 버튼 클릭도 받고 애니메이션도 돌고 타이머도 작동한다 겉으로 보면 여러 일이 동시에 돌아가는 것처럼 보인다. 그래서 처음엔 이런 생각이 든다. “어? 싱글 스레드라며?” 이 비밀은 자바스크립트 엔진이 아니라 브라우저와 이벤트 루프에 있다. 엔진은 생각보다 단순하다 자바스크립트 엔진(V8 같은 것)은 사실 별거 안 한다. 그냥 명령어 읽고 실행한다. 함수 호출 → Call Stack에 쌓는다 위에서부터 하나씩 실행한다 끝이다. 정말로 그게 전부다. 그래서 여기서 무거운 계산을 돌리면 어떻게 될까? while(true) {} 브라우저가 그냥 멈춘다. 우리가 흔히 말하는 "브라우저 렉"이 바로 이 상황이다. 엔진은 다른 일을 할 능력이 없다. 지금 하는 일 끝날 때까지 계속 그것만 한다. 정말로 한 놈만 팬다. 시간이 걸리는 일은 브라우저에게 넘긴다 그래서 자바

Naver Blog

요즘 나는 이렇게 개발한다 (Claude Code + Github Copilot 사용기)

요즘 AI 이야기가 많습니다. 그래서 저도 한번 제대로 사용해보기로 했습니다. 단순히 코드 한두 줄 생성하는 수준이 아니라 처음부터 끝까지 AI를 끼워 넣어서 개발해보는 실험이었습니다. 사용한 도구는 두 가지입니다. Claude Code Pro (경험 약 2주) GitHub Copilot Pro (경험 약 6주) 제가 사용한 방식 최근에는 이런 방식으로 작업을 해봤습니다. 먼저 마크다운 파일을 하나 만들었습니다. 그리고 생각나는 것들을 그냥 적기 시작했습니다. 필요한 기술 넣고 싶은 기능 Input 데이터 형태 Output 결과 전체 동작 흐름 정말 말 그대로 생각나는 대로 줄줄이 적었습니다. 남들이 보면 “이게 설계서인가?” 싶을 정도로 정리가 안 된 상태였습니다. 그래도 괜찮다고 생각했습니다. Claude Code 계획 모드 그 다음에 Claude Code Desktop을 열고 계획 모드로 전환했습니다. 모델은 Opus를 사용했습니다. 그리고 아까 작성했던 설계서라고 부르기도 애

Naver Blog

빌드 파일을 쌩으로 올리던 시절을 지나 (OpenSilver 배포기)

누구에게나 흑역사는 있다. 나에게는 1년 전 GitHub Pages 배포 사건이 그렇다. 1년 전: 무식하면 용감했다 당시엔 GitHub Actions나 Workflow 같은 건 몰랐다. AvaloniaUI 프로젝트를 만들고, 로컬에서 빌드한 결과물을 그대로 레포지토리에 커밋해서 밀어 넣었다. 처음엔 잘 됐다. 하지만 기능이 추가되고 화면이 복잡해질수록 빌드된 정적 파일들의 용량이 기하급수적으로 커졌다. 결국 GitHub에서 용량 제한으로 인해 더 이상 업데이트 되지 않았다. 그때서야 깨달았다. “아, 이건 뭔가 크게 잘못됐다.” 결국 제대로 된 배포는 마지막으로 만들어둔 Netlify에 올리고 프로젝트는 그대로 접어버렸다. 다시 찾은 XAML, 그리고 OpenSilver 최근 다시 XAML이 그리워져 OpenSilver를 꺼냈다. 이번엔 1년 전과 달랐다. Statiq를 쓰면서 배운 자동화 지식 덕분에 빌드 프로세스를 아예 다시 짰다. 이제는 수동으로 파일을 올리는 방식이 아니라

Naver Blog

속성 중심 UI vs 렌더링 중심 UI

속성으로 설계하던 사람, 렌더링으로 사고하게 되다 처음에 저는 WPF를 오래 썼습니다. 속성을 만들고 DependencyProperty를 등록하고 Metadata를 붙이고 Coerce를 고민하는 게 익숙했습니다. 그게 UI를 설계하는 방식이었으니까요. 속성은 단순한 값이 아니었습니다. 스타일이 덮어쓸 수 있고 애니메이션이 개입할 수 있고 상속으로 내려갈 수도 있었습니다. 값 하나를 만들면서 항상 이런 생각을 했습니다. "이 속성이 어디까지 영향을 줄까?" WPF에서 UI는 속성의 결과였습니다. 그러다 React를 만졌습니다. 처음엔 조금 당황했습니다. Property System이 없습니다. 우선순위도 없습니다. Metadata도 없습니다. const [count, setCount] = useState(0) 이게 끝입니다. 처음엔 너무 가벼워서 오히려 불안했습니다. "이래도 되는 건가?" WPF 계열 프레임워크들은 대부분 비슷합니다. WinUI3 Avalonia .NET MAUI U

Naver Blog

.NET 11 Preview 2에서 달라진 .NET MAUI

.NET 11 Preview 2가 공개되면서 .NET MAUI에도 몇 가지 변화가 포함되었습니다. 이번 업데이트는 거대한 기능 추가라기보다는 지도(Map) 컨트롤 개선과 성능 최적화, 그리고 런타임 변화 쪽에 무게가 실린 업데이트입니다. 최근 MAUI 업데이트들을 보면 새로운 컨트롤이 대거 추가된다기보다는 기존 기능을 다듬고 기반을 정리하는 방향이 계속 보입니다. Map 컨트롤 개선 먼저 눈에 띄는 부분은 Map 컨트롤입니다. 이제 지도 좌표를 XAML에서 좀 더 간결하게 표현할 수 있습니다. 예전에는 Location이나 MapSpan을 사용하려면 x:Arguments 같은 다소 장황한 문법을 써야 했습니다. 하지만 이번 Preview에서는 TypeConverter가 추가되면서 문자열로 바로 좌표를 선언할 수 있게 되었습니다. 또한 지도 위에 그리는 요소들(Polygon, Polyline, Circle)에 IsVisible과 ZIndex가 추가되었습니다. 이를 통해 지도 요소 표시

Naver Blog

WPF에서 Page, NavigationService를 활용하기 애매한 이유

WPF를 처음 잡으면 Page와 NavigationService가 눈에 띕니다. "오, 웹처럼 화면 전환하면 되겠네?" 처음 보면 꽤 그럴듯해 보입니다. 하지만 막상 프로젝트에 태워보면 묘하게 삐걱거립니다. 처음엔 “내가 잘못 쓰고 있나?” 싶기도 합니다. 그런데 조금만 깊게 들어가 보면 왜 실무에서 이 기능이 애매하게 느껴지는지 이유가 보입니다. Window 중심 구조와의 충돌 WPF의 근본은 결국 Window입니다. 하지만 NavigationService는 NavigationWindow나 Frame 안에서만 동작합니다. 그래서 보통 이렇게 됩니다. 메인 Window가 하나 있고 그 안에 Frame을 넣고 그 Frame 안에서 Page를 돌립니다. 화면 하나 띄우기 위해 계층이 한 단계 더 생깁니다. 구조를 먼저 보는 설계자 입장에서는 이 불필요한 레이어가 꽤 거슬립니다. ViewModel과 따로 노는 API MVVM의 핵심은 단순합니다. ViewModel이 상태를 바꾸면 화면이

Naver Blog

리액트가 '바뀐 놈'만 골라내는 법: Diffing 알고리즘

리액트를 쓰다 보면 아무 생각 없이 setState를 던질 때가 있습니다. 그런데 신기하게도 화면 전체를 다시 그리지 않습니다. 딱 바뀐 부분만 조용히 고쳐 놓습니다. 보통은 이걸 두고 "가상 DOM(Virtual DOM) 덕분이다"라고 말합니다. 맞는 말이긴 합니다. 하지만 가상 DOM 자체는 그냥 메모리에 떠 있는 자바스크립트 객체일 뿐입니다. 진짜 핵심은 따로 있습니다. “어디가 달라졌는지 찾아내는 계산” 바로 Diffing 알고리즘입니다. 가상 돔을 쓰는 실질적인 이유 진짜 DOM은 생각보다 예민합니다. DOM을 직접 건드리면 브라우저는 레이아웃을 다시 계산하거나(Reflow) 다시 그려야 할 수도 있습니다(Repaint). 이 작업이 반복되면 성능이 금방 무거워집니다. 그래서 리액트는 진짜 DOM을 바로 건드리지 않습니다. 대신 메모리라는 연습장에 먼저 변경 사항을 시뮬레이션합니다. 그리고 계산이 끝나면 진짜 DOM에는 딱 필요한 만큼만 최소한의 변경만 요청합니다. 리액트의

Naver Blog

기능을 만드는 사람에서, 시스템을 설계하는 사람으로

요즘 코드를 짜다 보면 예전과 다른 질문이 먼저 떠오릅니다. “이 기능 돌아가나?” 예전에는 여기서 끝났습니다. 버튼이 눌리고 데이터가 저장되고 화면에 결과가 나오면 그걸로 충분했습니다. 기능이 동작하면 잘 만든 코드라고 생각했습니다. 그런데 서비스가 조금씩 커지기 시작하면 코드는 생각보다 빠르게 엮입니다. A를 고치면 B가 깨지고, DTO 하나 바꾸면 API 몇 개가 같이 흔들립니다. 한 번은 단순히 필드 하나 추가한 적이 있었습니다. “이 정도는 금방 끝나겠지.” 그렇게 생각했는데 생각보다 많은 곳이 같이 흔들렸습니다. API도 수정해야 했고 프론트도 같이 고쳐야 했고 테스트 코드도 줄줄이 실패했습니다. 그때 처음 이런 생각이 들었습니다. “아… 이거 기능 문제가 아니라 구조 문제구나.” 그 이후로 코드를 보는 기준이 조금 바뀌었습니다. 예전에는 이 기능이 동작하는지만 봤습니다. 요즘은 이 질문이 하나 더 붙습니다. “이 구조가 정말 괜찮은가?” 그래서 요즘은 도구보다 먼저 ‘왜

Naver Blog

try-catch를 무작정 감싸면 안 되는 이유

예전엔 이런 코드 많이 봤다. try { DoSomething(); } catch (Exception ex) { // 일단 잡고 보자 } 에러 나면 앱 죽으니까. 일단 막아두자는 심리. 나도 그랬다. 근데 어느 순간 깨달았다. 이건 예외 처리가 아니라 문제 미루기라는 걸. 예외는 숨기라고 있는 게 아니다 예외는 시스템이 보내는 신호다. 상태가 잘못됐거나 예상하지 못한 입력이 들어왔거나 의존성이 실패했거나 즉, 설계가 가정한 흐름이 깨졌다는 뜻이다. 그걸 catch (Exception)으로 전부 흡수해버리면 문제가 해결되는 게 아니다. 그냥 조용해질 뿐이다. 그리고 나중에 더 이상한 형태로 돌아온다. 책임 경계가 무너진다 예외 처리는 아무 데서나 하면 안 된다. “내가 이걸 책임질 수 있는가?”가 기준이다. 예를 들어, Repository에서 난 DB 예외를 UI에서 그냥 잡아버린다? 그건 예외를 처리한 게 아니라 책임을 흐린 거다. 계층마다 역할이 있다. 인프라 → 기술적 예외 도메

Naver Blog

WPF에서 스타일 상속이 생각보다 어려운 이유

처음 WPF를 접하면 이렇게 생각한다. 스타일도 상속하면 되겠지? OOP처럼 파생 스타일을 만들 수 있겠지? 그래서 자연스럽게 BasedOn을 쓴다. <Style x:Key="BaseButtonStyle" TargetType="Button"> <Setter Property="FontSize" Value="14"/> </Style> <Style x:Key="PrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseButtonStyle}"> <Setter Property="Background" Value="Blue"/> </Style> 겉보기엔 간단하다. 그런데 프로젝트가 커지기 시작하면 이 구조가 점점 버거워진다. 왜일까? 스타일은 “클래스 상속”이 아니다 가장 큰 오해는 여기서 시작된다. WPF 스타일은 OOP의 상속과 다르다. 메서드 오버라이드도 없고 가상 멤버도 없고 동적 디스패치도 없다. 그냥 Setter 묶음이

Naver Blog

struct를 쓸 때 우리가 잊지 말아야 할 것

이번 주에 모델을 하나 만들다가 또 struct를 쓸지 말지 고민했다. 단순한 값 묶음이라 처음엔 가볍게 생각했다. “이 정도면 struct면 되지 않을까?” 그런데 설계를 조금 더 만지다 보니 문득 생각이 멈췄다. 아 맞다, struct는 상속이 안 되지. 익숙함이 주는 착각 class를 쓰다 보면 자연스럽게 이런 식으로 생각하게 된다. 공통 속성은 부모로 빼고 확장 모델은 상속으로 늘리고 공통 로직도 위로 올리고 그런데 struct는 다른 struct나 class를 상속할 수 없다. (인터페이스 구현은 가능하지만) 이게 단순한 문법 제약이 아니라 설계 방식 자체를 제한한다. 왜 상속이 안 될까 struct는 값 타입이다. 복사된다. 상속이 가능해지는 순간, 다형성과 힙 기반 동작이 섞이게 된다. 그럼 “값처럼 동작한다”는 전제가 흔들린다. 결국 struct는 확장 가능한 개체가 아니라, 완결된 값 덩어리 로 보는 게 맞는 것 같다. 그래서 더 조심하게 됐다 처음엔 단순한 Spec

Naver Blog

왜 .NET Core에서 한글이 깨졌을까

이상하게 한글이 전부 깨져 보였습니다. 에러가 난 것도 아니었습니다. 그냥 내용이 이상했습니다. 처음에는 파일이 잘못된 줄 알았습니다. 다시 받아보고, 메모장으로 열어보고, UTF-8로 재저장도 해봤습니다.' 그런데 문제는 파일이 아니라 제가 읽는 방식이었습니다. 내가 당연하게 생각했던 것 저는 그냥 이렇게 쓰고 있었습니다. File.ReadAllText(path); 그리고 속으로 이렇게 생각하고 있었습니다. 요즘은 다 UTF-8 아니야? 하지만 아니었습니다. 그 파일은 CP949 기반이었습니다. .NET Framework와 .NET Core의 차이 과거 .NET Framework 시절에는 이런 파일을 읽어도 크게 문제를 느끼지 못했습니다. 하지만 .NET Core 는 기본이 UTF-8 중심입니다. Code Page 인코딩은 자동으로 열리지 않습니다. 결국 949로 읽어야 할 파일을 UTF-8로 읽어버린 셈이었습니다. 결과는 당연히 깨짐이었습니다. 해결 방법 해결은 단순했습니다. E

Naver Blog

AI 결제를 고민하다가, 갑자기 정신이 번쩍 들었다

어제까지도 고민했다. ChatGPT를 결제할까, Claude로 갈까, Gemini는 또 어떨까. 가격 비교도 해보고 사용량도 따져보고 심지어 “이게 투자일까 낭비일까” 같은 생각까지 했다. 새벽에 한 번 깨서 또 생각했다. 이 정도면 거의 노트북 사기 직전의 심리다. 그러다 문득 이상한 생각이 스쳤다. “이거… 내가 똥을 싸도 박수 쳐주겠네?” 조금 과격하지만 정확한 표현이었다. 내가 가는 길이 논리적으로 허술해도 전제가 잘못되어도 심지어 불구덩이로 가는 선택이어도 그럴듯한 이유를 붙여서 “좋은 시도입니다”라고 말해줄 것 같은 느낌. 그 순간 기분이 싸해졌다. 나는 지금 성장을 위해 쓰려는 건가, 아니면 위로를 받으려고 쓰려는 건가. AI가 무섭다는 생각은 안 든다. 오히려 너무 친절해서 문제다. 반박하지 않고, 날 꺾지 않고, 내 논리를 최대한 존중해준다. 그게 편하다. 너무 편하다. 개발을 오래 하다 보면 이상하게도 ‘편함’이 경고 신호일 때가 있다. 코드가 너무 쉽게 돌아가면

Naver Blog

1.5만 원의 유혹, ChatGPT ‘Go’ 요금제 정리

요즘 이거 때문에 구독 버튼 근처에서 마우스만 왔다 갔다 했습니다. Plus는 솔직히 좀 부담이고 무료는… 쓰다 보면 맥이 끊깁니다. 그 사이에 나온 게 월 8달러. 대략 1.5만 원. 묘하게 현실적인 가격이죠. 메모리는 공짜인데, 왜 자꾸 아쉬울까 무료 버전도 이제 기본적인 기억은 합니다. 내가 어떤 언어 쓰는지, 뭘 자주 묻는지. 근데 그게 문제가 아니더라고요. 파일 여러 개 올리고 구조 설계 얘기하고 에러 로그 몇 번 왔다 갔다 하면 어느 순간 앞에서 했던 얘기를 슬쩍 놓칩니다. 대화가 "깊어질수록" 무료는 체력이 떨어집니다. Go는 확실히 버팁니다. 설계 흐름을 끊지 않고 끝까지 물고 갑니다. 이게 은근히 큽니다. 근데 솔직히, 저는 아직 무료에서 버티고 있습니다. 흐름이 끊기는 게 불편하긴 한데… 끊기면 잠깐 쉬는 거라고 합리화하고 있거든요. 개발자한테 진짜 스트레스는 ‘횟수’가 아니다 한도 초과. 이 말이 제일 싫습니다. 디버깅 한창인데 "내일 다시 오세요" 몰입이 깨지면

Naver Blog

Claude Code를 이틀 써봤다: 반가공이냐, 자동가공이냐

2월 초부터 GitHub Copilot을 본격적으로 쓰고 있습니다. 그리고 이틀 전, Claude Code를 결제했습니다. 아직 많이 써본 건 아닙니다. 그래서 이 글은 리뷰라기보다, 지금 제 머릿속에서 정리된 작업 감각에 가깝습니다. 기능 비교는 하지 않겠습니다. 이제 그건 크게 의미가 없어 보입니다. 기능은 결국 수렴한다 GitHub는 Copilot을 점점 에이전트 방향으로 밀고 있습니다. 파일 단위가 아니라 프로젝트 단위로 이해하고, 테스트를 만들고, 수정까지 수행합니다. Claude Code는 애초에 CLI 기반 에이전트로 시작했습니다. 둘 다 결국 “전체를 보고 수정하는 도구”로 가고 있습니다. 그래서 저는 기능 대신 가공 방식으로 보기로 했습니다. 반가공 vs 자동가공 이틀 써본 감각을 정리하면 이렇습니다. Copilot은 반가공에 가깝습니다. Claude Code는 자동가공에 가깝습니다. Copilot은 스마트 크루즈 같다 Copilot을 켜고 코딩하면 핸들은 여전히 제

Naver Blog

UI 라이브러리 설계 시 가장 먼저 고민한 것

UI 라이브러리를 만들겠다고 마음먹었을 때 제일 먼저 한 일은 코드를 짜는 게 아니었다. 버튼을 어떻게 만들지, 레이아웃을 어떻게 추상화할지, 애니메이션을 어떻게 넣을지. 이건 두 번째 문제였다. 내가 먼저 정해야 했던 건 이것이었다. 이 라이브러리는 어디까지 책임질 것인가. “멋진 컴포넌트 모음집”은 만들고 싶지 않았다 UI 라이브러리라고 하면 보통 이렇게 시작한다. Button Card Dialog Layout Theme 그리고 계속 늘어난다. 편의 기능이 붙고, 도우미가 붙고, 매니저가 붙고, 결국 프레임워크 위에 또 하나의 프레임워크가 된다. 예전에 그런 구조를 만들어본 적이 있다. 결과는 단순했다. 쓰는 사람도 불편했고, 만든 사람도 감당하지 못했다. 그때 깨달았다. UI 라이브러리는 많을수록 좋은 게 아니다. 적을수록 강하다. 두 번째 고민: “상태를 어디까지 가져갈 것인가” UI는 결국 상태를 표현하는 도구다. 그런데 라이브러리가 상태를 소유하기 시작하면 아키텍처와 충돌

Naver Blog

Copilot Pro, PRU 아끼는 실전 운영법

Copilot Pro를 사용하다 보면 어느 순간 PRU가 예상보다 빠르게 줄어드는 걸 체감하게 됩니다. 저도 한 달 정도 사용하면서 “생각보다 빨리 닳는데?”라는 느낌을 받았습니다. 그러다 GitHub에서 진행한 Copilot PRU 운영 관련 웨비나를 하나 들었습니다. 거기서 말한 내용이 거창하진 않았습니다. 모델을 구분해서 쓰고, 요청을 명세화하고, 목표 단위로 던지라는 이야기였습니다. 솔직히 “이게 그렇게 차이가 날까?” 싶었습니다. 그래도 하루만 그대로 적용해봤습니다. 결과는 분명했습니다. 같은 작업량이었는데 PRU 소모 속도가 확실히 줄었습니다. 그때 알게 됐습니다. 이건 사용량의 문제가 아니라 사용 방식의 문제라는 걸. 그래서 지금부터는 제가 실제로 적용하고 효과를 본 기준을 정리해보겠습니다. 1. 모델은 ‘항상 고급’이 아니라 ‘선택적 고급’ 많이 하는 실수는 항상 고성능 모델을 켜두는 것입니다. 이 방식은 비효율적입니다. 기준을 명확히 나눌 필요가 있습니다. 모델 선택

Naver Blog

리소스 탐색 순서를 모르면 결국 꼬인다

XAML을 오래 쓰다 보면 한 번쯤 이런 경험을 한다. 분명히 정의해 둔 색상인데 안 먹는다. 같은 키인데 어떤 화면에서는 다르게 적용된다. MergeDictionary 순서를 바꿨더니 갑자기 UI가 깨진다. 처음에는 “버그인가?” 싶다. 그런데 대부분은 리소스 탐색 순서를 제대로 이해하지 못해서 생기는 문제다. XAML 리소스는 ‘위에서 아래’가 아니다 많이 오해하는 부분이 이거다. 위에 정의하면 먼저 적용될 것 같지만, 실제로는 탐색 체인이 따로 있다. 리소스는 단순한 파일 포함 개념이 아니다. XAML 런타임은 리소스 트리(Resource Tree)를 따라 올라가며 탐색한다. 기본적인 탐색 순서는 이렇다. 현재 컨트롤의 Resources 부모 컨트롤의 Resources 상위 컨테이너를 계속 타고 올라감 Window / Page의 Resources Application의 Resources Theme Dictionary 시스템 리소스 즉, 가장 가까운 곳이 항상 우선이다. CSS와

Naver Blog

UI 라이브러리를 *.Core로 분리한 이유

UI 라이브러리를 만들기 시작했을 때 처음에는 단순히 컨트롤 모음 정도로 생각했다. 그런데 구조가 조금씩 커지면서 이상한 느낌이 들었다. UI 코드 안에 상태 로직이 들어가고 플랫폼 API가 섞이고 테스트가 점점 어려워지고 다른 플랫폼으로 확장하기가 부담스러워졌다. 그때 처음으로 이런 생각을 했다. UI 라이브러리에도 “경계”가 필요하지 않을까? 그래서 *.Core 분리를 고민하게 됐다. 1. 플랫폼 종속성에서 벗어나고 싶었다 WPF, WinUI, Avalonia, MAUI. 모두 XAML 기반이지만 내부 구현은 다르다. UI 계층 안에서 다음과 같은 코드가 섞이기 시작하면 문제가 생긴다. Dispatcher 접근 DependencyProperty FrameworkElement 의존 플랫폼 전용 이벤트 이 순간부터 코드는 해당 프레임워크에 고정된다. 그래서 이렇게 나눴다. MyLibrary.Core MyLibrary.Wpf MyLibrary.Avalonia MyLibrary.Maui

Naver Blog

XAML은 같아 보이는데, 왜 다르게 느껴질까?

요즘 Avalonia를 조금씩 보고 있다. 처음엔 그냥 “WPF랑 거의 똑같다” 라는 말만 듣고 시작했다. XAML도 그대로 쓰고, Binding도 되고, Grid도 있고. 그래서 별 차이 없을 줄 알았다. 그런데 막상 만져보니 이상하게 다르다. 그냥 복붙하면 안 된다 WPF에서 쓰던 코드가 그대로 될 줄 알았는데 은근히 안 되는 게 있다. 문법이 틀린 건 아닌데 뭔가 흐름이 다르다. 특히 스타일 쪽이 좀 헷갈린다. Trigger를 쓰려다가 다른 문법이 나온다. Selector? 이건 또 뭐지 싶었다. 비슷한데, 손에 안 붙는다 이상하게 손에 안 붙는다. XAML은 익숙한데 전체적인 느낌이 다르다. WPF는 뭔가 Windows에 딱 붙어있는 느낌인데 Avalonia는 처음부터 여러 플랫폼을 생각한 구조라서 그런지 약간 결이 다르다. 정확히 뭐가 다른지는 아직 잘 모르겠다. 그냥… 느낌이 다르다. 내가 헷갈리는 건 “비슷하다”는 말을 너무 믿은 것 같다. 비슷하긴 한데 같지는 않다.

Naver Blog

WPF UI 테스트가 어려운 진짜 이유

WPF를 쓰다 보면 한 번쯤 이런 생각을 한다. “UI 테스트만 잘 붙이면 구조가 더 단단해질 텐데…” 그리고 실제로 시도해보면, 생각보다 훨씬 빠르게 포기하게 된다. 이유는 단순히 “툴이 부족해서”도 아니고, “WPF가 구식이라서”도 아니다. 문제는 조금 더 구조적인 데 있다. UI 테스트가 어렵다는 말의 착각 보통 UI 테스트가 어렵다고 하면 다음 같은 이유를 떠올린다. 자동화 도구가 불안정하다 테스트 실행 속도가 느리다 환경 세팅이 번거롭다 이건 전부 사실이긴 하다. 하지만 이건 표면적인 이유다. 진짜 이유는 따로 있다. WPF UI는 “상태”보다 “연결”로 동작한다 WPF UI는 단순히 화면을 그리는 레이어가 아니다. 바인딩 Command Converter Trigger Resource DataContext 전파 이 모든 게 얽혀서 화면이 만들어진다. 즉, UI의 결과는 하나의 상태 값이 아니라 여러 요소의 연결 관계로 결정된다. 테스트 입장에서 보면 이건 굉장히 까다롭다.

Naver Blog

WPF의 한계, 그럼에도 계속 쓰는 이유

새 프로젝트를 시작할 때마다 한 번씩 듣는 질문이 있다. 아직도 WPF를 쓰나요? 이 질문이 틀렸다고 생각하지는 않는다. WinUI도 있고, MAUI도 있고, 다양한 크로스플랫폼 대안도 있다. 선택지는 예전보다 훨씬 많아졌다. 그럼에도 나는 여전히 WPF를 사용한다. 아무 생각 없이가 아니라, 한계를 알고도 선택한다. WPF의 한계는 분명하다 먼저 인정해야 할 부분은 명확하다. Windows 전용이다. 모바일 확장은 어렵다. 최신 디자인 트렌드와는 거리가 있다. 생태계의 중심 기술은 아니다. 특히 멀티 플랫폼이 기본처럼 여겨지는 요즘 분위기에서는 WPF는 보수적인 선택처럼 보일 수 있다. 이건 사실이다. 그런데도 WPF를 쓰는 이유 1. 데스크톱 업무 시스템에는 여전히 강하다 제조, 공정, 장비 제어, 내부 관리 시스템. 이 영역은 여전히 Windows 기반 환경이 많다. PLC 연동, 로컬 네트워크 구성, 산업 장비 연결 같은 맥락에서는 브라우저보다 네이티브 데스크톱이 더 자연스러

Naver Blog

WPF, '1 화면 = 1 뷰모델'이라는 고정관념에 대하여

WPF 처음 배울 때 거의 공식처럼 들었던 말이 있다. 한 화면에는 하나의 ViewModel. 나도 그걸 그대로 믿었다. MainViewModel 하나 만들고 거기에 전부 넣기 시작했다. 처음엔 아무 문제 없었다. 진짜로. 문제가 시작되는 시점 화면에 기능이 조금씩 붙는다. 상단 검색 영역. 가운데 리스트. 우측 상세 패널. 저장 버튼. 엑셀 다운로드. 팝업 다이얼로그. 그러다 ViewModel 파일을 열어보면 뭔가 기묘해진다. 검색 조건 Property 10개 이상. SelectedItem. SelectedItem의 세부 속성. 검색 커맨드. 저장 커맨드. 삭제 커맨드. 팝업 여는 로직. 이벤트 메시지 처리. 파일 길이 800줄. 처음엔 이렇게 생각한다. “이 정도는… 다들 이러지 않나?” 진짜 문제는 그 다음이었다 수정하려고 파일을 열면 어디서부터 봐야 할지 모르겠다. 검색 로직을 고치다가 상세 패널 코드 건드리고, 리스트 바인딩이 깨진다. 이 로직이 왜 여기 있지? 그때 깨닫는

Naver Blog

그 1달러가 진짜로 돌아왔다

예전에 GitHub Copilot Pro 결제가 꼬이면서 1달러가 먼저 빠져나간 적이 있었다. 가결제(Pre-authorization)였고 시간이 지나면 돌아온다던 그 1달러. 그때 나는 이렇게 마무리했었다. 돌아오면 댓글로 남기겠다. 안 돌아오면 수업료로 생각하겠다. 그리고 오늘. 진짜로 들어왔다. 거의 잊고 있었는데 사실 반쯤 포기하고 있었다. 1달러면 큰돈은 아니다. 고객센터에 문의하기도 애매하고 그냥 시스템 테스트 비용이라고 생각하려 했다. 그런데 오늘, 토스 알림에 환불 내역이 찍혀 있었다. 딱 1달러. 묘하게 기분이 좋았다. 시스템은 생각보다 정직했다 그 당시 상황을 다시 정리해 보면 이렇다. 1달러 승인 → 카드 유효성 확인 10달러 실제 결제 → 잔액 부족으로 실패 계정 상태 꼬임 다시 결제 → Pro 전환 성공 그리고 시간차를 두고 10달러 환불, 그리고 마지막으로 1달러 환불. 결국 모든 금액이 정리됐다. GitHub 는 내 1,400원을 가져가지 않았다. 다만,

Naver Blog

Avalonia 12 Preview 1, 그래서 뭐가 달라졌을까?

PR 로그 기준으로 뭐가 달라졌을까? Avalonia 12.0 Preview 1. 공식 블로그 요약 말고, 실제 머지된 PR 기준으로 보면 이번 버전의 성격이 좀 더 명확해집니다. 결론부터 말하면: “기능 추가”보다는 “구조 정리”에 가까운 메이저 업데이트입니다. 1. 렌더링 전략 정리 Direct2D1 제거 Windows 전용 Direct2D1 경로가 제거됐습니다. 이제 렌더링 전략은 더 명확하게 Skia 중심 구조로 정리된 모습입니다. SkiaSharp 3.0 전환 SkiaSharp 2.88 지원 종료 3.0 타겟으로 변경 텍스트, GPU 경로 등 렌더링 내부 동작에 영향이 있는 변화입니다. ※ PR 상에서 Vulkan을 기본 채택했다는 내용은 없습니다. Skia 내부 레벨과 혼동하면 안 됩니다. 2. Composition 시스템 정비 Composition system SP1 렌더링 인터페이스 통합 GeometryContext 계열 병합 외부에서 체감되는 기능보다는 내부 안정화

Naver Blog

깃허브 코파일럿 프로, 일주일 만에 92% 썼다

원래 내 스타일: AI 순회공연 코파일럿 결제 전엔 나름 노련한 전략가였다. 아이디어나 인사이트가 필요할 때마다 ChatGPT, Gemini, Claude를 차례로 도는 '순회공연'이 일상이었다. 이때는 직접 코드를 짜게 하기보다 인사이트를 얻는 용도로만 썼고, 결제 없이도 머리 쓰며 제법 잘 버텼다. 코파일럿 프로면 다 될 줄 알았지 그러다 큰맘 먹고 Github Copilot Pro를 질렀다. "이제 AI 순회공연 끝! 정착이다!" 싶었다. 내 야심 찬 계획은 이거였다. "에이전트 쓸 때 프리미엄 모델을 고르면 한 번에 찰떡같이 알아듣겠지? 그럼 질문 횟수도 줄고, 이거 완전 이득 아냐?" 이게 내 야심 찬 계산이었다. 무제한 에이전트 모드, GPT-5 mini와의 채팅 처음 보면 이렇게 읽힌다. 무제한 에이전트를 쓸 수 있고, GPT-5 mini와도 채팅할 수 있다. 그런데 실제 의미에 더 가깝게 풀면 이렇다. GPT-5 mini 기준에서 무제한 에이전트 및 채팅이 가능하다는

Naver Blog

틀리진 않은데, 선뜻 머지 못하는 코드들

요즘 AI가 짜준 코드를 보면 대부분 이런 감정이 먼저 든다. “음… 돌아가긴 하네?” 문제는 그 다음이다. 왜 이렇게 돌아가는지는 잘 모르겠다는 것. AI가 만든 코드는 이상하게도 정답처럼 보인다. 컴파일 에러 없고, 런타임 에러 없고, 테스트도 대충 통과한다. 딱 여기까지만 보면 "이 정도면 쓰면 되지 않나?" 싶다. 근데 손이 바로 안 간다. 묘하게 찜찜하다. 판단의 흔적이 없다 불안한 이유는 단순하다. 내가 이 코드를 ‘결정’한 적이 없기 때문이다. 이 구조를 선택한 기억이 없고, 이 로직을 여기 두기로 판단한 적도 없고, 예외 처리를 왜 이렇게 했는지도 모르겠다. 코드는 있는데, 판단의 흔적이 없다. 사람이 짠 코드가 안 좋은 경우도 많다. 그래도 최소한 이건 남아 있다. "아, 그때 이래서 이렇게 했지." AI 코드는 그게 없다. 맥락이 통째로 생략돼 있다. 디버깅이 아니라 역추론 그래서 문제가 생기면 디버깅이 아니라 '추적'을 하게 된다. 이 코드가 뭘 가정하고 있는지,

Naver Blog

16바이트의 블랙박스, GUID를 열어보다

나는 GUID를 그냥 Guid.NewGuid()가 만들어주는 랜덤 문자열이라고 생각했다. 그런데 직접 만들어보니 이건 그냥 랜덤이 아니었다. GUID는 16바이트. 그 안에 시간, 버전, 규격 표시(Variant), 랜덤 값이 정해진 자리에 들어간다. 마음대로 섞인 게 아니다. 구조가 있다. 표준은 RFC 4122 에 정의되어 있다. 읽을 땐 단순해 보였는데 직접 구현하니 비트 하나, 방향 하나까지 신경 써야 했다. 특히 .NET의 Guid는 앞부분 바이트를 다르게 해석해서 엔디언 때문에 한참을 헤맸다. 예전엔 그냥 긴 문자열이었다. 지금은 “16바이트 설계도”로 보인다. 직접 열어보니 비로소 이해됐다.

Naver Blog

Gemini AI Plus, 결제 전에 한 번만 더 생각해보세요

AI 구독 버튼은 생각보다 가볍습니다. 하지만 매달 빠져나가는 돈은 꽤 오래 갑니다. 그래서 저는 결제 전에 이 질문부터 던져보는 게 좋다고 봅니다. 나는 이걸 얼마나 자주 쓸 사람인가? 구글로 일하는 사람이라면 메일은 Gmail, 자료는 Drive, 문서는 Docs. 이 환경에서 하루 대부분을 보낸다면 Gemini Advanced는 체감이 있습니다. 메일을 요약해주고, 문서 초안을 잡아주고, 파일 기반으로 질문할 수 있습니다. 구글 생태계 안에서 일하는 사람에게는 도구가 자연스럽게 붙습니다. 반대로, 구글을 단순 계정 정도로만 쓰는 사람이라면 효용은 크게 떨어집니다. 긴 글을 자주 다룬다면 매뉴얼, 보고서, 계약서. 읽기 싫어서 미뤄둔 문서가 쌓여 있다면 도움이 됩니다. 한 번 요약하고 끝나는 게 아니라 계속 질문을 이어갈 수 있다는 점이 다릅니다. 짧은 검색이나 간단한 번역 위주라면 유료까지 갈 이유는 크지 않습니다. 그런데, 이건 알고 써야 합니다 AI가 나를 기억해준다는 건

Naver Blog

LLM을 쓰다 보니 이름들이 쌓여서 적어본 메모

요즘 LLM 관련 도구들을 보다 보니 정리가 좀 필요해졌다. LangChain, Semantic Kernel, LangGraph, LlamaIndex… 처음엔 "다 비슷한 거 아냐?" 싶었는데, 막상 뜯어보니 역할이 미묘하게 다르다. 공통점이라면 전부 'LLM을 한 번 호출하고 끝내는 방식'에서 벗어나려는 시도라는 것. 프롬프트 던지고, 응답 받고 끝. 이 패턴은 생각보다 금방 한계가 온다. 왜 이런 도구들이 필요할까? 이전 맥락을 계속 써야 하고, 외부 데이터랑 섞어야 하고, 여러 단계를 거쳐야 할 때가 많아지면 LLM 호출 자체보다 '그걸 어떻게 엮을지'가 더 큰 문제가 된다. 이 고민을 해결하려고 나온 게 지금의 프레임워크들이다. 내가 느낀 도구별 인상 1. LangChain: 흐름을 엮는 데 집중 프롬프트 → 호출 → 결과 처리 → 다음 단계. 이걸 하나의 '체인'처럼 코드로 정리하려는 쪽에 가깝다. 처음엔 "이걸 꼭 라이브러리로?" 싶다가도, 단계가 복잡해지면 왜 쓰는지 알

Naver Blog

XAML 리소스 구조 정리하다가 깨달은 것

프로젝트가 커질수록 XAML 파일은 늘어난다. 처음에는 MainWindow.xaml 하나였는데, 어느 순간 ResourceDictionary가 10개가 넘어간다. 처음에는 그냥 색상 몇 개 빼놓는 용도였다. 그다음은 버튼 스타일. 그다음은 공통 템플릿. 그러다 보니 “이 리소스는 어디에 둬야 하지?”라는 질문이 계속 생긴다. 리소스가 늘어날수록 관리가 힘들어지는 건, 단순히 내 코드의 문제가 아니었다. 구조를 고민하다 보니 내가 다루는 이 XAML이라는 언어가 가진 근본적인 성격에 집중하게 됐다. XAML은 WPF 전용이 아니다 예전에는 WPF의 일부처럼 생각했다. 그런데 지금은 다르다. WPF WinUI 3 UWP Avalonia Uno Platform OpenSilver 전부 XAML 기반이다. 문법이 조금씩 다르고 지원 기능도 차이가 있지만, “UI를 선언적으로 구성한다”는 철학은 동일하다. 그래서 리소스 구조에 대한 고민은 WPF만의 문제가 아니라 XAML 생태계 전체의 문제

Naver Blog

WPF 이후, XAML 스타일은 조금씩 달라지고 있는 것 같다

WPF를 오래 쓰다 보니까 스타일은 그냥 그런 거라고 생각했다. 컨트롤은 Style 하나 확장하려면 BasedOn 조금 다르면 새 Style 하나 더 만들고 점점 Style 이름은 길어지고 이게 당연한 구조라고 생각했다. 불편하긴 했지만 “원래 XAML은 이런 거지” 하고 넘겼다. 그러다가 Avalonia를 조금 보게 됐는데 Classes라는 게 있더라. <Button Classes="primary rounded shadow" /> 처음엔 그냥 “CSS 흉내 냈네” 정도로 생각했는데 가만히 보니까 이게 좀 다르게 느껴졌다. WPF에서는 PrimaryButtonStyle RoundedPrimaryButtonStyle ShadowRoundedPrimaryButtonStyle 이런 식으로 상속 체인이 늘어나거나, 거의 복붙에 가까운 스타일이 계속 생긴다. 근데 Avalonia는 그냥 필요한 걸 붙이면 된다. 그 순간 약간 묘했다. “아… 그동안 상속으로 억지로 풀던 걸 조합으로 풀면 되는

Naver Blog

디자인과 기능 실험

오늘은 UI 디자인 실험을 진행했다. 그라데이션 효과 적용과 다양한 화면 구성 테스트를 해보면서, 작은 변화가 사용자 경험에 어떤 영향을 주는지 확인할 수 있었다. 한편, 새로운 기능을 구현하려고 했지만 설계상의 몇 가지 고민이 있어, 실제 코딩은 다음 단계로 미뤘다. 짧은 회고: 작은 기능도 설계 단계에서 충분히 고민해야 후속 작업이 수월하다는 것을 다시 느꼈다.

Naver Blog

템플릿 구성과 문제 해결

템플릿 구성 작업을 진행했다. 가로 레이아웃은 문제없이 완료했지만, 세로 레이아웃에서는 균등 분배 문제가 발생했다. 작은 설정 차이가 전체 결과물에 영향을 준다는 걸 다시 한번 깨달았다. 이후 팀과 주간 회의를 진행하며 진행 상황과 문제점을 공유했다. 짧은 회고: 같은 작업이라도 환경에 따라 고려할 요소가 달라, 문제를 사전에 예측하고 테스트하는 습관이 중요하다는 것을 배웠다.

Naver Blog

XAML 리소스 실험

XAML 기반 리소스에서 언어 번역 리소스를 테스트해보려고 했지만, 예상과 달리 제대로 작동하지 않았다. 아직 정식으로 적용하는 단계는 아니므로, 다양한 방법으로 실험하며 테스트 중이다. 짧은 회고: XAML Resource 기반으로 구성된 리소스는 의외의 제약이 있을 수 있다는 걸 배우게 됐다. 작은 실험이라도 직접 시도해보는 경험이, 이후 문제 해결 능력과 이해도를 높이는 데 도움이 된다.

Naver Blog

UI 개선과 언어팩 실험

컨트롤 디테일을 수정하고, 화면 구성과 폰트 적용을 점검했다. 프로그램 진입 화면과 핵심 화면은 작업을 마쳤다. 한편, XAML 기반 언어팩 적용 중 일부 화면에서 변경이 제대로 반영되지 않는 현상이 발생했다. 아직 완전히 적용 단계는 아니므로, 다양한 접근 방법을 테스트하며 문제를 해결할 계획이다. 짧은 회고: UI 개선과 리소스 적용 과정에서 작은 불일치가 예상보다 큰 영향을 줄 수 있음을 배우게 됐다. 이런 경험은 이후 화면 구성과 리소스 관리에 중요한 밑거름이 된다.

Naver Blog

리소스 준비와 UI 작업

리뉴얼 프로그램 관련 임시 작업을 진행했다. 각 화면에 필요한 폰트 리소스 파일을 생성하며, UI 구성과 화면 표현에 필요한 준비를 마쳤다. 짧은 회고: 작업 자체는 반복적이지만, 폰트와 리소스를 일관되게 관리하는 습관이 이후 화면 개발 속도를 크게 향상시킨다는 걸 다시 느꼈다. 작은 준비 단계가 나중의 안정성과 효율성을 결정한다는 점이 인상적이었다.

Naver Blog

요구사항 검토와 장비 테스트

프로그램 리뉴얼 관련 요구사항을 검토하고, 일정 산정을 진행했다. 기획 세부 내용을 확인하며, 앞으로 진행될 작업의 우선순위와 예상 난이도를 점검했다. 이외에도 장비 테스트와 주간 보고를 수행하며, 다음 날 진행될 시연 준비를 위해 환경을 세팅했다. 짧은 회고: 기획 단계에서 요구사항과 일정, 장비 환경을 미리 점검하는 습관이 실제 구현 단계에서 문제를 줄이고 효율을 높이는 데 크게 도움이 된다는 걸 다시 느꼈다.

Naver Blog

2023년 5월 Blazor & WPF 밋업 후기

기술 밋업에 참여했다. 이번 밋업에서는 .NET 8 Preview 4 기준의 Blazor 업데이트와 PWA(Progressive Web Apps), 그리고 WPF 사용자 지정 컨트롤 관련 내용을 다뤘다. Blazor 실시간 스트리밍을 통한 Blazor 컴포넌트 활용 폼 데이터 처리 시 CascadingModelBinder를 활용하는 SSR(Form Post) 방식 URL 내 해시(#)를 활용한 특정 요소 라우팅 방법 웹어셈블리 관련 문제: 일부 환경에서 백신 프로그램이 관련 파일을 삭제해 정상 동작이 어려운 사례 PWA 웹 페이지를 앱 형식으로 설치 가능 Service Worker를 활용한 오프라인/알림 기능 지원 앱센터 없이도 웹 앱처럼 활용 가능 WPF 사용자 지정 컨트롤 실습: ListBox와 ListBoxItem의 독립적 사용 가능성 XAML 기반 언어·테마 리소스 관리 방법 소개 짧은 회고: 밋업을 통해 새로운 프레임워크 기능과 한계, 그리고 최신 실무 기술을 직접 접하니

Naver Blog

스킨 에디터 화면 구현과 효율 판단

스킨 에디터 프로그램의 화면 구현 작업을 진행했다. 기본 스킨을 적용하고 화면 구성과 기능을 점검했다. 작업 중, 공수 산정이 필요하다는 의견이 있었지만, 최근 진행된 방송 스킨을 기반으로 개발하면 생각보다 빠르게 화면 구현을 완료할 수 있다는 판단을 내렸다. 또한, 이 접근 방식을 비디오 프로그램에도 적용하면 효율적인 작업 진행이 가능할 것으로 예상된다. 짧은 회고: 기존 결과물을 참고하고, 최적의 접근 방식을 판단하는 습관이 실제 개발 속도와 품질 향상에 큰 도움이 된다는 것을 다시 느꼈다.

Naver Blog

화면 데이터 테스트와 바인딩 실험

다른 프로그램에서 화면 관련 데이터를 불러와 테스트를 진행했다. 또한 데이터 바인딩 동작을 점검하며, 화면과 데이터 연결이 의도대로 이루어지는지 확인했다. 짧은 회고: 작은 테스트라도 데이터 흐름과 바인딩을 직접 확인하는 경험이 화면 개발의 안정성과 문제 해결 능력을 높이는 데 큰 도움이 됨을 다시 느꼈다.

Naver Blog

현장 테스트와 문제 해결 경험

전날 현장에 다녀와서 발생했던 이슈를 정리했다. 실제 장비 연동 과정에서 일부 기능이 의도대로 동작하지 않는 문제가 있었지만, 원인은 프로그램 자체가 아닌 장비 설정에 있었다. 방송 담당자의 지원을 받아 설정을 조정하니 정상적으로 동작하는 것을 확인했다. 추가로, 다음과 같은 기술 포인트를 검토했다: 크로마키 배경 위에 게임 데이터를 출력하는 기능 여러 화면에서 게임 데이터와 비디오 영상을 동시에 송출하는 기능 스킨 에디터 관련 이미지 배치 방식(고정 위치 조정 필요) 짧은 회고: 현장에서 직접 문제를 확인하고, 장비 설정과 소프트웨어 동작을 동시에 점검하는 경험은 책상 앞에서만 확인할 수 있는 테스트와는 다른 학습과 성장의 기회를 준다는 것을 다시 느꼈다.

Naver Blog

에디터 데이터 연동 테스트

에디터 프로그램에서 생성된 데이터를 다른 프로그램으로 불러오는 기능을 테스트했다. 생각보다 데이터 연동의 품질이 좋았고, 주요 구성 요소(플레이어, 보드, 상태 정보 등)도 정상적으로 동작하는 것을 확인했다. 앞으로 업데이트 기능까지 연동하면 더 효율적인 데이터 관리가 가능할 것으로 예상된다. 짧은 회고: 작은 테스트라도 실제 데이터를 다뤄보는 경험이 연동 과정에서 생길 수 있는 문제를 미리 예측하고 개선하는 데 큰 도움이 된다는 것을 다시 느꼈다.

Naver Blog

스킨 업데이트 개발

6월 23일 테스트한 스킨 데이터를 기반으로 일부 다른 스킨 부분의 업데이트 개발을 진행했다. 앞서 성공적으로 연동 테스트한 데이터 덕분에, 이번 업데이트도 예상보다 원활하게 진행되었고 효율적인 작업 순서를 미리 계획한 것이 도움이 됐다. 짧은 회고: 작은 성공 경험을 바탕으로 다음 단계를 계획하고 진행하면 연속적인 개발 흐름을 유지하면서 안정성을 높일 수 있다는 점을 다시 느꼈다.

Naver Blog

스킨 외형 연동과 폰트 기능 추가

이전에 개발한 스킨 데이터를 기반으로 외형을 가져오고, 텍스트에 적용할 폰트 기능을 추가했다. 이전 작업에서 구축한 스킨 구조 덕분에, 새로운 기능 추가도 비교적 원활하게 진행되었다. 작은 기능이라도 미리 구조를 잡아두면, 연속적인 개발 흐름에서 효율성이 크게 향상됨을 느낄 수 있었다. 짧은 회고: 기존 구조를 활용해 기능을 확장하는 경험이, 새로운 기능 추가와 유지보수 속도를 높이는 데 큰 도움이 된다는 것을 다시 확인했다.

Naver Blog

카드 뒷면 이미지 적용

스킨 업데이트 작업의 연장으로 카드 뒷면 이미지를 적용했다. 이전 스킨 외형 및 폰트 기능 작업 덕분에, 새로운 이미지 적용도 비교적 원활하게 진행되었다. 작은 기능이지만, 세부 요소까지 완성해야 전체 화면의 완성도가 높아진다는 점을 다시 느꼈다. 짧은 회고: 점진적으로 기능을 추가하고 구조를 활용하는 과정이, 연속적인 개발 흐름과 효율적인 유지보수에 얼마나 중요한지 다시 한번 깨닫는 경험이 되었다.

Naver Blog

스킨 에디터: 기초 Import/Export 테스트

스킨 에디터 프로그램의 Import/Export 기능 구현을 완료했다. 기본 데이터를 불러오고 저장하는 과정을 테스트하며, 구조적 안정성을 확인했다. 작은 기능이지만, 제대로 동작하는지 반복적으로 검증하면서 기초를 튼튼히 다지는 경험이 되었다. 짧은 회고: 기초 기능의 안정화가 이후 확장 작업의 기반이 된다는 것을 느꼈다.

Naver Blog

이미지와 폰트 적용 실험

스킨에 폰트와 카드 이미지를 적용하는 테스트를 진행했다. 작은 이미지 요소 하나도 전체 화면 구성과 사용자 경험에 큰 영향을 주는 것을 확인했다. 또한 테스트 프로그램을 활용하여 다양한 조합을 빠르게 확인할 수 있었다. 회고: 테스트 환경을 갖추어 놓으면, 작은 시행착오를 통해 더 큰 학습을 얻을 수 있다.

Naver Blog

스킨 확장: 언어와 국기 설정

스킨 편집 기능을 넘어, 커스텀 언어 확장과 국기 설정 기능을 구현했다. 단순한 UI 요소가 아니라, 확장 가능한 구조를 고민하며 개발했다. 스킨 파일의 Git 기반 관리도 시작해, 버전과 변경사항 추적을 경험했다. 회고: 기능 확장과 버전 관리는 개발 속도와 안정성 모두에 중요하다.

Naver Blog

템플릿 컨트롤 미리보기

템플릿 컨트롤 미리보기 기능을 구현했다. 위치 조정, ZIndex 관리, 저장 기능까지 포함하여, 화면 구성 실험을 반복했다. 단순히 보여주는 것뿐 아니라, 구조적 저장 방식까지 고려하며 개발 경험을 확장했다. 회고: 작은 미리보기 기능도 설계와 구조를 고민하면 큰 학습이 된다.

1 2