# 글의 뼈대 — 관찰 기록 > **이 문서는 채워 넣을 틀이 아니다.** 아래 다섯 편이 실제로 어떤 순서를 썼는지 적어 둔 것이다. > 여기 있는 칸을 전부 채우려 들면 문서마다 같은 목차가 나오고, 문장은 한국어인데 글은 > 보고서 생성기 출력처럼 읽힌다. 실제로 그렇게 됐고, 그래서 이 경고를 맨 앞에 둔다. > > 쓰는 법: 어떤 수가 있는지 보고, **이 문서에 필요한 것만 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 기록은 서로 링크로 이어지고, 우아한형제들 글보다 짧다. 그래도 위 뼈대에서 **빼면 안 되는 자리**가 있다. | 자리 | 필수 여부 | |---|---| | 이 기록이 무엇을 다루는지 한 문장 | 필수 | | 독자와 선수 지식의 바 | 필수 | | 처음 쓰는 말의 정의 (본문 안, 첫 사용 앞) | 필수 | | 무슨 일이 있었나 · 왜 그랬나 | 필수 | | 어떻게 했나 · 결과 | 자료에 있으면 필수 | | 단계마다 남은 문제 | 자료에 있으면 필수 | | 차례 예고 | 절이 셋 이상이면 | | 글쓴이의 생각 | 자료에 있을 때만 | 없는 자리를 지어내지 않는다. **자료에 없으면 그 칸은 비운다.** 이 문서는 무엇을 채울 수 있는지를 말할 뿐, 채울 내용을 만들어도 된다는 뜻이 아니다.