Markdown in /src
코드가 생성되는 /src에 Markdown을 함께 두기
LLM이 코드를 생성하는 시대에는 프롬프트 세션에서 사라지는 의도와 설계를 Markdown으로 남겨야 한다고 제안합니다. Markdown을 코드와 함께 /src에 저장하고, 코드와 테스트를 그 문서에서 파생시키자는 구상입니다.
- 주제
AI 요약
Carson Gross는 agentic coding이 확산되면서 Markdown을 단순한 문서가 아니라 소스 코드로 다뤄야 한다고 주장합니다. LLM이 코드를 생성하는 현재의 작업 방식에서는 여러 차례 주고받은 프롬프트와 시행착오가 세션 종료와 함께 사라집니다. 결과적으로 저장소에는 생성된 코드만 남고, 코드가 무엇을 해야 하는지와 왜 그렇게 작성됐는지 설명하는 원래의 의도는 Linear, Slack, wiki, 티켓 등에 흩어집니다.
사라지는 원본 소스
LLM을 고수준 사양을 저수준 구현으로 바꾸는 컴파일러처럼 보는 관점이 있습니다. 하지만 전통적인 컴파일러 작업은 원본 소스 코드를 보존하는 반면, LLM 작업에서는 프롬프트가 일시적인 경우가 많습니다. 생성된 코드가 사실상 해당 기능의 ground truth가 되지만, 그 코드만으로는 설계 의도와 버려진 선택지를 확인하기 어렵습니다. Gross는 LLM이 컴파일러라는 비유에는 동의하지 않으면서도, 전문적인 agentic coding 환경에서 프롬프트 세션의 산출물을 그대로 남기는 방식은 바꿔야 한다고 봅니다.
Markdown을 /src에 저장하기
제안은 기존 소스 코드 옆에 src/md 디렉터리를 두고, 코드에 가까운 수준의 설계와 결정을 Markdown으로 기록하는 방식입니다. 이 문서에는 아키텍처 결정, 소스 수준의 결정, 낮은 수준의 데이터 설계 결정이 들어갑니다. 전통적인 디자인 문서나 프로젝트 관리 문서보다 구현에 가깝고, 정식 사양보다는 유연한 문서입니다.
Markdown은 일반 텍스트라서 diff, grep, pull request 리뷰에 적합합니다. 사람은 별도 도구 없이 읽고 수정할 수 있고, LLM도 기본적으로 읽고 작성합니다. AGENTS.md, 사양서, 계획 문서, TASK.md 같은 파일이 이미 비슷한 역할을 하지만, 이를 저장소의 표준 구조로 다루지는 않았다는 설명입니다.
/src에 문서를 두면 코드 모듈과 그 의도를 가까이 배치할 수 있습니다. 위키나 Notion, Confluence, Jira에 있는 사양을 찾아다니지 않아도 되고, 사람과 에이전트가 같은 위치에서 모듈의 맥락을 읽습니다. Linear나 wiki는 상위 수준의 설계 문서와 처리 절차가 필요한 이슈를 맡고, 현재 시스템이 의도한 정적 동작은 소스 디렉터리의 Markdown에 기록하는 식으로 역할을 나눕니다.
테스트와 코드의 관계
테스트가 새로운 사양이라는 주장에는 일부 진실이 있지만, 테스트는 사람과 에이전트가 시스템을 이해하는 문서로는 적합하지 않다고 봅니다. 테스트에는 보일러플레이트가 많고, 무엇을 검증하는지 가릴 수 있습니다. 사람이 시스템을 파악할 때 원하는 수준보다 낮은 추상화에 머무는 경우도 많으며, Mermaid 다이어그램 같은 설명을 자연스럽게 담기 어렵습니다.
Gross가 제안하는 분업은 /src의 Markdown이 사양에 가까운 역할을 맡고, /test의 테스트가 그 문서를 바탕으로 자동 검증을 수행하는 구조입니다. 개발자는 프롬프트에서 곧바로 코드와 테스트를 만들기보다 Markdown을 먼저 다듬고, 코드와 테스트를 그 문서에서 파생시킵니다. 생성된 코드에 제약을 추가하거나 일부를 삭제하는 작업을 했다면, 그 결정도 다시 Markdown에 반영해야 합니다. 따라서 문서와 파생 코드의 동기화가 새로운 개발 기술이 됩니다.
제안한 디렉터리 구조
Gross는 아직 충분히 사용해 보지 않은 아이디어라고 전제하면서 다음과 같은 구조를 예로 듭니다.
src/md/README.md는 에이전트가 진입할 전체 문서 목록입니다. TODO.md에는 모듈의 일반적인 할 일을 적고, OVERVIEW.md에는 기술 개요를 둡니다. 기능별 문서는 features/FEATURE_1.md, 데이터 모델은 data/DATAMODEL_1.md, API는 api/API_1.md, 인프라 설명은 infrastructure/INFRASTRUCTURE_1.md에 배치합니다. 기능, 데이터, API, 인프라 디렉터리는 선택 사항이며, 모듈의 동작을 가장 잘 설명하는 축으로 나누면 됩니다.
이 Markdown에도 소스 코드처럼 Complexity Budget이 필요합니다. 문서를 깨끗하게 유지하고, 서로 잘 나누며, 적절한 추상화 수준을 지켜야 합니다. 특히 /src/md의 내용은 에이전트가 대량 생성하기보다 사람이 작성하고 관리해야 한다고 강조합니다. 문서가 또 다른 프롬프트 기록이나 검토하기 어려운 계획 모드 산출물로 변하면 제안의 목적을 잃기 때문입니다.
Lobsters 반응
- @facundoolano — 에이전트가 /src/md에 많은 내용을 생성해서는 안 된다고 생각합니다. 이 디렉터리는 주로 사람이 작성하고 관리해야 합니다. 이 제안의 핵심은 여기에 있다고 생각하지만 글 깊숙한 곳에 묻혀 있습니다. 그렇지 않으면 사람들이 제가 검토하기 끔찍하다고 느끼는 plan mode slop이라고 생각할 겁니다.
- @cceckman — LLM이 이런 생각을 촉발했다는 점이 이상합니다. “소스 산출물은 코드와 함께 있어야 한다”는 원칙이 먼저 떠오르기 때문입니다. 소스 산출물에는 여러 종류의 의사결정 기록과 실험을 수행하는 데 사용한 lab notebook도 포함됩니다. 코드를 이해하려는 사람에게 그런 자료가 필요하다면 접근 가능하게 만들어야 합니다.
- @bgs_ — Markdown은 문서가 아니라 소스 코드가 되어가고 있습니다 :c
- @bakkot — 이 방식이 실제로 어떻게 작동해야 하는지 모르겠습니다. 자세한 초기 프롬프트를 작성하고, 보통 커밋 메시지에 남기려고 합니다. 하지만 사소하지 않은 작업이라면 그 뒤에 여러 차례 주고받는 과정이 이어집니다. “Foo를 빼고 Bar를 확장하는 방식으로 다시 해보세요”라고 하거나, “조건 X에 대한 테스트를 추가하고 실패하면 코드를 고치세요”라고 말하는 식입니다. 더 나은 모델이 나와도 이 과정이 사라지지는 않을 것 같습니다. 시도해 보고 결과를 보기 전에는 제가 무엇을 원하는지 모르는 경우가 많기 때문입니다. 나중에 이런 후속 프롬프트까지 기록할 수는 있지만, 앞선 코드 반복을 버린 상태에서는 해석하기가 쉽지 않습니다. 세션 전체를 저장하는 방법도 있고 그런 주장을 본 적도 있지만, 여기서 요구하는 방식과는 조금 다릅니다.
- @facundoolano — 이 모델을 따르면 이런 새로운 사실을 발견할 때마다, 또는 몇 번 발견할 때마다 초기 문서에 그 내용을 수동으로 반영하고 세션을 다시 시작해야 할 수 있다고 생각합니다. 여기에 LLM CI 리뷰를 더해 최종 구현이 문서에 적힌 내용을 지키는지 판단하게 하면 좋겠습니다. 직접 시도해 보지는 않았고 실제로 합리적인지도 확신하지 못하지만, 흥미로운 실험처럼 들립니다.
- @zetashift — 여기서는 정말 반대합니다. 다만 왜 사람들이 이런 방식을 원하는지는 알겠습니다. “티켓과 논의를 코드 옆에 둬야 한다”는 논의와 비슷한 위치에 있습니다. Elixir에는 exdoc, Rust에는 rustdoc, Unison에는 {{ fancy doc comments }}가 있습니다. 노트북 스타일의 프로그래밍 환경도 많습니다. 이런 도구들이 생성 품질이 낮은 코드와 통합될 가능성은 Markdown을 한 디렉터리에 모아 소스 코드로 보는 방식보다 훨씬 크다고 생각합니다. OCaml이나 Elm처럼 사용하기 편한 타입 시스템이 자리 잡는 데도 수년이 걸렸습니다. 그런데 이제 검증되지 않는 Markdown을 작성하고 이를 시스템의 일부로 보자는 건가요? 유지 가능한 시스템을 만드는 방법이 정말 이것인가요?
- @toastal — 저도 잘 이해되지 않습니다. 타입 시스템은 결정적이고, 예측 가능한 방식으로 불변식을 표현하려고 합니다. LLM 출력에는 그 두 가지 특성이 없습니다. 이미 문서와 기술 글을 쓰기에는 형편없는 형식인 Markdown이 여기저기 흩뿌려지는 것만으로도 충분히 답답합니다. Markdown은 JavaScript의 타입 시스템만큼이나 사용하기 편하고 기능이 풍부합니다.
- @slightknack — 일부 프로젝트에서는 루트에
docs/폴더를 만듭니다. 파일 이름은YYYY-MM-DD-title.md로 정하거나, 000부터 시작해 번호를 올리는NNN-title.md형식을 씁니다. 이 폴더에는 사람이 작성한 문서만 엄격하게 보관합니다. 인터페이스와 테스트, 불변식을 직접 사양으로 작성하고, 문서와 인터페이스가 일치하는지 자동으로 확인하는 검사를 만듭니다. 모든 파일에 Provenance frontmatter를 넣는 방식도 좋아합니다. 사람이 작성한 Markdown이나 코드에는+++ created: YYYY-MM-DD author: Name <email> provenance: human +++처럼 적습니다. AI가 생성한 코드나 Markdown에는// created: YYYY-MM-DD // model: glorm-9-promax // driver: Name <email> // provenance: ai처럼 기록합니다. “AI는 사람이 작성한 provenance를 수정하지 않고, 사람은 AI provenance를 수정하지 않는다”는 정책을 엄격하게 지킵니다. 제가 그 규칙을 깨고 직접 수정하면 AI가 그 산출물의 provenance를 오염시키고 낮춘 것으로 처리합니다. 사람이 작성한 trait, interface 정의, module 파일을 먼저 만들고, 그 인터페이스를 기준으로 AI provenance를 가진 테스트 스위트나 구현을 생성하는 방식을 자주 씁니다. 사람 provenance는 항상 source of truth가 됩니다. - @dlisboa — 이 글에서 제안한
/src/md규칙은 글쓴이도 인정했듯 가장 약한 부분입니다. 모든 것을markdown디렉터리에 넣는 건 말이 되지 않습니다. 모든 파일을 한곳에 넣는/src/javascript가 이상한 것과 같습니다. 문서는 설명하는 대상 가까이에 둬야 합니다.- @cceckman — 이 글은 “Markdown은 문서가 아니라 소스 코드가 되어가고 있다”고 주장합니다.
- @dlisboa — 저는 동의하지 않습니다. 어느 쪽이든 소스 코드를 파일 형식으로 분류하지는 않습니다.
- @hyperpape — Maven의
src/main/java가 반대 사례 중 하나입니다. 물론 그 구조가 나쁜 생각이라고 주장해도 됩니다.
- @xyproto — Algernon 웹서버는 로컬 LLM을 사용해
.prompt파일을 직접 제공할 수 있습니다. 결과는 결정적이며 캐시됩니다.
원문: htmx.org / 번역·요약: Trawling