Files
document-haness/.agents/skills/rewriting-technical-prose-naturally/references/document-skeleton.md
T

183 lines
11 KiB
Markdown

# 글의 뼈대 — 관찰 기록
> **이 문서는 채워 넣을 틀이 아니다.** 아래 다섯 편이 실제로 어떤 순서를 썼는지 적어 둔 것이다.
> 여기 있는 칸을 전부 채우려 들면 문서마다 같은 목차가 나오고, 문장은 한국어인데 글은
> 보고서 생성기 출력처럼 읽힌다. 실제로 그렇게 됐고, 그래서 이 경고를 맨 앞에 둔다.
>
> 쓰는 법: 어떤 수가 있는지 보고, **이 문서에 필요한 것만 source가 정하게 한다.**
> 자료가 말하지 않는 칸은 비우고, 자료가 채울 수 있어도 이 글에 필요 없으면 역시 비운다.
# 글의 뼈대
우아한형제들 기술블로그 5편의 목차와 도입·마무리를 그대로 읽고 정리한 것이다. 낱낱의 문장이 아니라
**글 전체가 어떤 순서로 서는지**를 담는다. 인용은 아래 글에서 가져왔고, 브라우저로 페이지를 직접 열어
옮겼다.
- [사람도 AI도 놓친 번역 누락, ESLint 플러그인을 만들어 해결하기](https://techblog.woowahan.com/26388/) — 이하 `26388`
- [WMS 재고 이관을 위한 분산 락 사용기](https://techblog.woowahan.com/17416/) — `17416`
- [로그 및 SQL 진입점 정보 추가 여정](https://techblog.woowahan.com/13429/) — `13429`
- [검색 성능 개선을 위한 Elasticsearch 인덱스 구조와 쿼리 최적화](https://techblog.woowahan.com/20161/) — `20161`
- [나 4년 차 서버개발자, 배달의민족의 지리 체계를 뒤흔들다](https://techblog.woowahan.com/11238/) — `11238`
이 다섯 편은 `scripts/style_profile.mjs`가 쓰는 기준선이기도 하다. 원문을 다시 받으려면
`node scripts/fetch_reference.mjs <디렉터리>`를 쓴다. 사이트가 curl과 리더 프록시를 403으로 막으므로
실제 브라우저가 필요하고, `playwright-core`가 있어야 한다. 받은 뒤
`node scripts/style_profile.mjs --baseline <디렉터리>/*.md`로 값을 다시 잰다.
---
## 1. 다섯 편이 공유하는 순서
| 자리 | 26388 | 17416 | 13429 | 20161 | 11238 |
|---|---|---|---|---|---|
| 왜 이 글인가 | 여는 글 | (첫 문단) | (첫 문단) | (첫 문단) | 포스팅 목적 |
| **말 뜻 정하기** | @lib/i18n과 세 가지 컨벤션 | **WMS란?** | **진입점이 뭐죠?** · **MDC를 아시나요?** | 성능개선을 돕는 도구 | **공간 (Spatial) 데이터 타입이란?** |
| 무슨 일이 있었나 | 험난한 컨벤션 준수의 길 | 할당과 취소를 동시에 요청한다면? | 근데 왜 진입점 정보가 남아야 해요? | 현상 | 프로젝트 배경 |
| 왜 그랬나 | 사람과 AI 검수의 한계 | 동시성 이슈 원인 | — | 문제 원인 분석 및 해결 | 방향성 검토 |
| 어떻게 했나 | 린트로 위반 탐지하고 AI로 교정하기 | 1 단계: 분산 락 추가하기 | 기본 작업 · 추가 작업 | 해결 방안 | 개발 |
| 결과 | 린트 플러그인의 성과 | (단계마다 문제점) | — | 개선 결과 | 결과 · 검증 |
| 닫기 | 맺는 글 | 마무리 | 마무리 | 맺으며 | 회고 |
**용어를 정하는 자리가 항상 문제보다 앞에 있다.** 다섯 편 예외가 없다. 독자가 모르는 말을 안고
문제 설명을 따라가게 두지 않는다.
---
## 2. 첫 문단은 세 가지를 한다
`17416`의 도입은 세 문장이고, 셋이 각각 다른 일을 한다.
> "WMS 재고 이관 과정에서 발생한 동시성 이슈를 분산 락(Distributed Lock)을 사용해 해결한 경험을 공유하는 글입니다. 본 글은 분산 락에 대해 알고 있는 분들을 대상으로 작성되었습니다. 제가 경험한 내용들이 여러분들의 비즈니스에 도움이 되는 글이 되길 바랍니다."
1. **이 글이 무엇인가**`<무엇>에서 <무슨 일>을 <어떻게> 한 <경험/과정>을 공유하는 글입니다`
2. **누가 읽는 글이고, 무엇을 알고 있어야 하는가**
3. 바람 한 줄
`26388`도 같은 자리에 같은 문장을 둔다.
> "이 글은 다국어 라이브러리를 사용하거나, 팀의 까다로운 컨벤션 유지를 위해 AI 및 린트를 활용하는 개발자를 대상으로 합니다. 린트 플러그인을 구현한 경험이 없어도 쉽게 읽을 수 있게 정리했습니다."
`11238`은 독자를 둘로 나눠서 각각에게 읽는 법을 준다.
> "취업 준비 중인 분들이라면 프로젝트 과정을 간접적으로 경험해 보시면 좋겠고, 현업에 계신 분들이라면 속한 부서에서 진행하는 방법과 차이를 비교해 보면서 읽으시면 좋겠습니다."
**독자와 선수 지식의 바를 도입에서 못 박는다.** 이 문장이 있으면 본문에서 어디까지 풀어 써야 하는지가
정해진다. 없으면 글 전체가 흔들린다.
---
## 3. 도입 끝에 차례를 알린다
> `17416` — "본 글에서는 WMS 재고를 이관하는 과정에서 마주친 동시성 문제에 대해 살펴보고, 어떤 방법으로 동시성 이슈를 해결해 나갔는지에 대해 공유합니다."
> `11238` — "프로젝트는 다음 순서대로 소개해 보겠습니다. — 프로젝트 배경 / 방향성 검토 / 개발 / 검증 / 회고"
> `26388` — "먼저 문제의 출발점이 된 @lib/i18n 라이브러리와 컨벤션부터 살펴보겠습니다."
한 줄이든 목록이든, **읽는 사람이 지금 어디쯤인지 알 수 있게 한다.**
---
## 4. 용어 절의 생김새
제목부터 묻는 형태다.
| 제목 | 글 |
|---|---|
| `WMS란?` | 17416 |
| `진입점이 뭐죠?` | 13429 |
| `MDC를 아시나요?` | 13429 |
| `공간 (Spatial) 데이터 타입이란?` | 11238 |
| `근데 왜 진입점 정보가 남아야 해요?` | 13429 |
안에서 하는 일은 셋이다.
1. **한 문장 정의**`WMS(Warehouse Management System, 창고 관리 시스템)는 물류센터에서 반복되는 수기 작업을 시스템화하여 안정적으로 운영될 수 있도록 합니다.`
2. **이 글에서 쓸 말을 직접 정함**`편의상 "화면에 렌더링되어 사용자에게 노출되는 문자열"을 "문구"라고 하겠습니다.` · `이들을 모두 묶어서 "번역 API"라고 표현하겠습니다.`
3. **주변 관계를 한 문단으로**`WMS 재고들은 중앙물류기지라고 불리는 DC(Distribution Center)로 입고되며, DC에 입고된 상품들은 지역 거점 센터인 PPC(Picking Packing Center)로 재고가 이관됩니다.`
약어는 나오는 자리에서 전부 편다. `WMS(Warehouse Management System, 창고 관리 시스템)`,
`DC(Distribution Center)`, `PPC(Picking Packing Center)`, `MDC(Mapped Diagnostic Context)`,
`AST(Abstract Syntax Tree)`, `분산 락(Distributed Lock)`, `보간(Interpolation)`.
---
## 5. 사례 하나를 다루는 작은 틀
`20161`은 같은 세 칸을 다섯 번 반복한다.
```
현상 → 문제 원인 분석 및 해결 → 개선 결과
```
`17416`은 단계마다 자기 문제를 달고 간다.
```
1 단계: 분산 락 추가하기 → 해결방법 → 문제점
2 단계: 분산 락 대기하기 → 해결방법 → 문제점
3 단계: 분산 락과 상태 키 함께 사용하기 → 해결방법
```
**고친 방법마다 남은 문제를 같이 적는다.** 마지막 단계에 와서야 `문제점`이 없다. 처음부터 정답을
내놓지 않고, 왜 다음 단계가 필요했는지를 앞 단계의 `문제점`이 만든다.
---
## 6. 독자를 데리고 다니는 문장
이 글들은 독자가 무엇을 궁금해할지 알고 미리 처리한다. 내 스킬이 가장 크게 놓쳤던 부분이다.
| 하는 일 | 문장 |
|---|---|
| 곁길 막기 | "여기서 번역 API의 내부 동작이 궁금할 수 있겠지만 딴 길로 새지 맙시다." |
| 나중으로 미루기 | "그리고 유형별로는 문구의 포맷 차이가 있는데, 나중에 살펴보겠습니다." |
| 초점 잡기 | "중요한 것은 아래 세 가지 컨벤션을 반드시 지켜야 한다는 점입니다." |
| 다음 칸 예고 | "이번에는 그렇게 탄생한 규칙들을 깊게 파보겠습니다." |
| 수치로 넘어가기 | "숫자 없이 복잡한 글만으로는 효능이 마음에 와닿지 않는 듯하니, 제작한 플러그인의 규칙이 적발한 컨벤션 위반 개수를 확인해봅시다." |
| 범위 좁히기 | "전체적인 내용은 기술적인 내용보다는 ~ 전체 과정을 소개하는 데 집중했습니다." |
**`중요한 것은 ~입니다`는 금지어가 아니다.** 여기서는 앞에 늘어놓은 것 중 무엇을 들고 갈지 고르는
말이고, 자료에 없는 결론을 만드는 말이 아니다. 금지되는 쓰임과 구분해야 한다.
- 쓴다 — 이 글 안에서 독자의 눈을 어디로 보낼지 정할 때
- 안 쓴다 — 측정값 옆에 붙여 자료가 증명하지 않은 해석을 결론처럼 얹을 때
---
## 7. 마무리 절
`26388`의 맺는 글은 네 걸음이다.
> "지금까지 커머스 웹프론트에서 다국어 지원을 위해 도입한 @lib/i18n의 컨벤션 준수 이슈와 그 해결 과정을 살펴봤습니다. 사람은 실수를 하고 AI는 확률론적이다 보니 컨벤션 위반의 미탐과 오탐이 빈번했기 때문에, 결정론적인 린트 규칙을 구현해 탐지하고 교정은 자연어에 능숙한 AI에게 맡기는 하이브리드 접근을 택했습니다. 그 결과 다량의 번역 누락과 오역을 방지하고 코드 복잡도도 낮췄습니다."
>
> "AI는 요술램프가 아닙니다. ... 결정론과 확률론의 경계를 구분하고 적재적소에 일을 맡기는 안목이 더욱 중요해지고 있습니다. 이 글이 비슷한 고민을 하시는 분들에게 도움이 되면 좋겠습니다."
1. `지금까지 ~를 살펴봤습니다` — 다룬 범위를 되짚는다
2. `[원인]이다 보니 [문제]했기 때문에, [해결]을 택했습니다` — 한 문장으로 압축한 줄거리
3. `그 결과 ~` — 성과
4. 글쓴이 자신의 생각 + 독자에게 건네는 인사
**4번은 마무리 절에만 온다.** 본문 문단 끝마다 붙는 교훈과는 다른 것이다. 그리고 이것은 **글쓴이가
실제로 가진 생각**이라 자료에 있을 때만 옮긴다. 없으면 1~3만 쓰고 끝낸다.
---
## 8. 이 저장소에 적용할 때
TechLog 기록은 서로 링크로 이어지고, 우아한형제들 글보다 짧다. 그래도 위 뼈대에서 **빼면 안 되는
자리**가 있다.
| 자리 | 필수 여부 |
|---|---|
| 이 기록이 무엇을 다루는지 한 문장 | 필수 |
| 독자와 선수 지식의 바 | 필수 |
| 처음 쓰는 말의 정의 (본문 안, 첫 사용 앞) | 필수 |
| 무슨 일이 있었나 · 왜 그랬나 | 필수 |
| 어떻게 했나 · 결과 | 자료에 있으면 필수 |
| 단계마다 남은 문제 | 자료에 있으면 필수 |
| 차례 예고 | 절이 셋 이상이면 |
| 글쓴이의 생각 | 자료에 있을 때만 |
없는 자리를 지어내지 않는다. **자료에 없으면 그 칸은 비운다.** 이 문서는 무엇을 채울 수 있는지를
말할 뿐, 채울 내용을 만들어도 된다는 뜻이 아니다.