목록전체 글 (31)
MAKE IT SIMPLE
AI로 개발했더니, 오히려 워터폴로 돌아갔다1편("기획서와 코드 사이를 잇고…")·2편("잔존률은 높은데, 절반이 뒤집혔다")·3편("git blame으로는 AI 기여도를 셀 수 없었다")의 후속입니다. 이번 글은 지표가 아니라, 한 분기에 가까운 프로젝트를 AI 워크플로우로 마치고 팀 전체가 남긴 회고에서 출발한다.반년 가까이 결제·정산이 걸린 큰 기능을 AI 워크플로우로 만들었다. PRD 초안도, 스펙도, 테스트 코드도 상당 부분을 AI가 뽑았다. 프로젝트가 끝나고 팀 전체가 모여 회고를 했는데, 각자 관점은 달라도 이상하게 한 곳으로 수렴하는 문장이 있었다."AI로 빠르게 갈 줄 알았는데, 앞을 제대로 안 정하면 뒤가 통째로 흔들린다."그러니까 우리는 더 애자일해진 게 아니었다. 오히려 옛날 워터폴..
git blame으로는 AI 기여도를 셀 수 없었다 — 라인 단위 attribution 파이프라인1편("기획서와 코드 사이를 잇고…")·2편("잔존률은 높은데, 절반이 뒤집혔다")의 후속입니다.2편에서 잔존률이라는 지표를 다시 문제 삼았다. 잔존률이 높다고 기획이 안정적이었던 건 아니라고. 그런데 한 발 물러서면 더 앞선 질문이 있다. 그 잔존률은 애초에 어떻게 측정되는가?1편에서 "1차 MVP는 기록을 안 남겨 측정할 수 없었고, 2차부터 git notes로 기록했다"고 한 문장으로 넘어갔다. 이 글은 그 한 문장의 구현이다. 결론부터 말하면, 이건 분석 문제가 아니라 기록 문제였다.사후에는 복원할 수 없다처음엔 나중에 git blame으로 세면 될 줄 알았다. AI가 쓴 라인이 최종 코드에 얼마나 남..
잔존률은 높은데, 절반이 뒤집혔다 — 스펙 번복률을 재보기까지1편("기획서와 코드 사이를 잇고, AI가 얼마나 썼는지 숫자로 답하기까지")의 후속입니다.1편 마지막에 스스로에게 숙제를 하나 남겼다. 우리 워크플로우는 상위 문서가 바뀐 건 감지하지만, 그 변경이 미정이던 걸 채운 보강인지 이미 합의한 결정을 뒤집은 번복인지는 구분하지 못한다고. 다음 사이클에는 기준선을 남기고 변경을 두 종류로 분류하겠다고 적었다.이번에 그 숙제를 실제로 해봤다. 결과를 먼저 말하면, 예상보다 불편한 숫자가 나왔다.잔존률만 보면 "기획이 안정적이었다"로 읽힌다앞 글에서 신규 결제·계약 도메인의 두 에픽에서 AI 잔존률을 처음 측정했다고 했다. 계약 관리 에픽의 코드 잔존률은 99.7%, 정산 에픽의 PRD·디자인 문서 잔존..
기획서와 코드 사이를 잇고, AI가 얼마나 썼는지 숫자로 답하기까지AI 코딩 도구를 도입하는 건 어렵지 않았다. 어려운 건 기획이 PRD·아키텍처·스펙·테스트 케이스로 번역되는 동안 결정이 유실되지 않게 만드는 일이었다.얼마 전 한 릴리즈의 이슈를 전수 분류했다. 순수 구현 버그와 “무엇을 만들지가 흔들려서 생긴 이슈”가 각각 약 38%로 비슷한 규모였다. 코드 구현만큼이나, 무엇을 만들지 확정하고 변경을 추적하는 과정이 주요 실패 지점이었다.내가 만든 것은 SDD 자체가 아니다. 문서 안에 머물던 결정을 Jira 완료 조건과 Figma 화면, 그리고 구현까지 밀어 넣는 연결 계층이었다. 같은 결정이 도구마다 다르게 남아 있을 때, 사람이 QA에서 뒤늦게 발견하기 전에 Jira·Figma·테스트 케이스 ..
동적 데이터셋 테이블, 어디까지 만들어봤니행/열/값을 사용자가 마음대로 끌어다 놓으면 알아서 피벗되고, 소계·합계·총계까지 끼워 넣는 테이블을 React로 만들면서 정리한 기록.1. 들어가며 — 단순해 보였던 요구사항"엑셀 피벗 같은 거 화면에서 보여주면 돼요."처음 받은 한 줄. 가볍게 시작했는데, 막상 펴 보니 정적 테이블과는 완전히 다른 영역이었다. 사용자는 같은 데이터셋을 가지고 어떨 땐 단순 목록으로 보고 싶고, 어떨 땐 부서×월로 묶어서 보고, 또 어떨 땐 거기에 소계와 총계까지 끼워서 보고 싶어 한다. 그리고 모든 모드가 같은 컴포넌트에서 매끄럽게 전환돼야 한다.이 글은 그 요구사항을 풀면서 만든 컴포넌트와 useCreateTableV2 훅의 설계·구현을 정리한 회고다. 일부 헬퍼는 재귀가..
LLM 이 뭘하고 있는지 사용자는 궁금해한다챗봇 기반 문서편집 AI 서비스를 개발하다 보면 LLM이 문서 및 자료를 분석하고, 사고 과정(thinking)을 거치고, 편집 명령을 생성하고, 최종 메시지를 작성하기까지 평균 10~30초가 걸린다. 그때 사용자가 원하는 건 단순한 로딩바가 아닌 "지금 AI가 뭘 하고 있는지" 아는 것이였다. 문서를 검색하는 중인지, 생각하는 중인지, 편집을 시작했는지. 그 과정이 실시간으로 보여야 했다.폴링 vs WebSocket vs SSE 비교폴링(Polling): 가장 단순하지만, LLM 응답의 특성과 맞지 않았다. 토큰 단위로 생성되는 텍스트를 0.5초마다 긁어오면 불필요한 요청이 대량 발생하고, 실시간 느낌도 살릴 수 없다.WebSocket: 양방향 통신이 가능하다..
AI 코딩의 역설요즘 개발 현장에서 AI 코딩 도구를 안 쓰는 곳을 찾기 어렵다. GitHub Copilot, Claude, ChatGPT 등 AI에게 "이런 기능 만들어줘"라고 말하면 순식간에 코드가 완성된다.그러다보니 예전에는 개발 공수 때문에 신중하게 결정했던 것들이 이제는 "일단 만들어보고 바꾸죠"가 되어버렸다.결과는? 기획 변경이 잦아지고, UI/UX 수정이 늘어나고, 스펙이 수시로 바뀐다.빠른 변경이 가능해진 건 좋다. 하지만 빠른 변경 ≠ 안전한 변경이다. AI가 아무리 빨리 코드를 짜줘도, 그 코드가 기존 기능을 망가뜨리지 않았는지는 인간이 확인해야 한다.여기서 TDD의 새로운 가치가 드러난다.SDD(Spec-Driven Development)란?SDD는 Spec-Driven Develop..
// ProductDetail.jsxconst handleAddToCart = async (product) => { await cartAPI.add(product); eventBus.emit('cart:item-added', { product, timestamp: Date.now() });};// CartIcon.jsxuseEffect(() => { const handleItemAdded = ({ product }) => { showToast(`${product.name} 담김!`); // 또는 refetch cart count }; eventBus.on('cart:item-added', handleItemAdded); return () => eventBus.off('cart:i..