From 81fced11a83d2c56ff1a974c47b2d56b187048c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9D=80=EC=9A=B0?= Date: Sat, 18 Jul 2026 23:47:27 +0900 Subject: [PATCH 01/10] =?UTF-8?q?feat(content):=20=EC=97=90=EC=84=B8?= =?UTF-8?q?=EC=9D=B4=EC=99=80=20=EC=9D=B4=EB=A0=A5=EC=84=9C=20=EA=B3=B5?= =?UTF-8?q?=EA=B0=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/skills/blog-title-review/SKILL.md | 95 +++ .../blog-title-review/agents/openai.yaml | 4 + docs/README.md | 6 +- .../0026-use-repo-local-title-review-skill.md | 39 + ...0027-use-resume-specific-editorial-grid.md | 53 ++ docs/adr/README.md | 4 +- .../index.mdx" | 348 +++------ .../meta.json" | 22 +- .../index.mdx" | 138 ++-- .../meta.json" | 26 +- resume/ui/pages/ResumePage.test.tsx | 23 + resume/ui/pages/ResumePage.tsx | 680 +++++++++--------- 12 files changed, 759 insertions(+), 679 deletions(-) create mode 100644 .agents/skills/blog-title-review/SKILL.md create mode 100644 .agents/skills/blog-title-review/agents/openai.yaml create mode 100644 docs/adr/0026-use-repo-local-title-review-skill.md create mode 100644 docs/adr/0027-use-resume-specific-editorial-grid.md create mode 100644 resume/ui/pages/ResumePage.test.tsx diff --git a/.agents/skills/blog-title-review/SKILL.md b/.agents/skills/blog-title-review/SKILL.md new file mode 100644 index 00000000..d37cad4b --- /dev/null +++ b/.agents/skills/blog-title-review/SKILL.md @@ -0,0 +1,95 @@ +--- +name: blog-title-review +description: Review, generate, and choose Ark blog post titles. Use when evaluating title candidates for posts/**/index.mdx and sibling meta.json, when the user is stuck choosing a title, or when a draft needs a click-worthy but accurate title that fits the first three paragraphs. +--- + +# Blog Title Review + +## Workflow + +1. Read `docs/blog-quality-guide.md`, the target `index.mdx`, and the sibling + `meta.json` before judging a repository post. If the post is not in the + workspace, use the text the user provided. +2. Preserve `category`, `contentType`, `slug`, and publication state unless the + user explicitly asks for edits. +3. Extract a title brief before proposing titles: + - target reader and reading situation + - the post's concrete object, event, or tension + - the emotional stake or practical promise + - the strongest first-three-paragraph hook + - the current title and why it works or fails +4. Score existing user candidates first when they exist, then add better + alternatives only when useful. +5. Evaluate the title and opening as one unit. If a candidate depends on a hook + that the first three paragraphs do not pay off, flag the required opening + change instead of pretending the title is ready. +6. Do not edit files unless the user explicitly asks for implementation. + +## Title Principles + +- Prefer a specific unanswered question over a complete summary. +- Use concrete nouns from the post before abstract virtues. +- Create tension through contrast, self-recognition, reversal, or specificity. +- Let the title be click-worthy, but keep the promise payable by the intro. +- Check word texture. Reject words whose military, corporate, clinical, or + overly visible metaphorical register clashes with the essay's emotional tone. +- Avoid titles that sound like generic self-help, corporate slogans, product + reviews, or manipulative bait. +- Avoid over-weighting SEO when the post is an essay; the title still needs a + human reason to click. + +## Candidate Patterns + +Generate candidates across multiple patterns when the user needs options: + +- Collision: combine two unlike elements that the post genuinely connects. +- Confession: expose the private pressure, mistake, or need behind the post. +- Reversal: turn an expected belief into the post's real conclusion. +- Object-led: let a concrete object carry the emotional promise. +- Direct problem: name the reader's problem in plain language. +- Quiet essay: use a restrained line when click pressure would cheapen the tone. + +## Scorecard + +Use 1-5 scores in 0.5 increments. + +- `click`: likelihood that the title earns a click from the intended reader. +- `fit`: accuracy to the full post, not only one vivid sentence. +- `introFit`: whether the first three paragraphs pay off the title. +- `specificity`: concrete nouns, situations, or stakes. +- `emotion`: felt tension without melodrama. +- `novelty`: freshness compared with generic essay titles. +- `texture`: whether the key words feel natural in the post's emotional register. +- `arkTone`: fit with Ark's direct, reflective, engineering-adjacent voice. +- `baitRisk`: risk of overpromising or misframing the post; lower is better. + +When ranking titles, prioritize high `click`, `fit`, and `introFit`, then use +`baitRisk` as a veto. A high-click title with high bait risk should be marked as +usable only after an intro rewrite. + +## Output Format + +Return: + +```markdown +## Title Brief +- reader: +- promise: +- tension: +- current title: + +## Recommendation +1. `...` - ... +2. `...` - ... +3. `...` - ... + +## Scorecard +| Title | Click | Fit | Intro Fit | Specificity | Emotion | Novelty | Texture | Ark Tone | Bait Risk | Note | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | + +## Opening Adjustment +... +``` + +Keep the output shorter when the user asks for a quick choice. Omit +`Opening Adjustment` when every recommended title already matches the opening. diff --git a/.agents/skills/blog-title-review/agents/openai.yaml b/.agents/skills/blog-title-review/agents/openai.yaml new file mode 100644 index 00000000..af68f377 --- /dev/null +++ b/.agents/skills/blog-title-review/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Blog Title Review" + short_description: "블로그 제목 후보를 점수화해 더 쉽게 선택합니다" + default_prompt: "Use $blog-title-review to evaluate title candidates for a draft blog post." diff --git a/docs/README.md b/docs/README.md index f00cc8dd..b11609fb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # 문서 인덱스 -Last updated: 2026-07-13 +Last updated: 2026-07-18 이 인덱스는 현재 코드베이스와 함께 유지해야 하는 문서만 추적한다. 계속 업데이트할 문서가 아니라면 삭제하거나, 오래 남겨야 하는 결정만 ADR로 옮긴다. @@ -16,7 +16,7 @@ Last updated: 2026-07-13 ## 유지 대상 문서 - `docs/adr/README.md` -- `docs/adr/*.md` +- `docs/adr/*.md` (도메인별 UI 경계와 같이 오래 유지될 결정 포함) - `docs/adr/0019-use-content-first-typography-scale.md` - `docs/adr/0020-use-runtime-daily-views-for-popular-feed.md` - `docs/adr/0021-load-heavy-mdx-visualizations-on-demand.md` @@ -24,6 +24,8 @@ Last updated: 2026-07-13 - `docs/adr/0023-run-the-release-quality-gate-in-ci.md` - `docs/adr/0024-use-latest-only-home-feed.md` - `docs/adr/0025-use-node-runtime-for-og-image-route.md` +- `docs/adr/0026-use-repo-local-title-review-skill.md` +- `docs/adr/0027-use-resume-specific-editorial-grid.md` - `docs/blog-quality-guide.md` - `docs/database/db-schema.md` - `docs/database/supabase-view-count.sql` diff --git a/docs/adr/0026-use-repo-local-title-review-skill.md b/docs/adr/0026-use-repo-local-title-review-skill.md new file mode 100644 index 00000000..4fced7d5 --- /dev/null +++ b/docs/adr/0026-use-repo-local-title-review-skill.md @@ -0,0 +1,39 @@ +# 0026. 제목 선택은 repo-local skill로 보조한다 + +Date: 2026-07-03 +Status: Accepted + +## 배경 + +블로그 글을 작성할 때 제목 선택은 매번 오래 걸리는 반복 작업이다. 제목은 본문 +요약만으로 충분하지 않고, 클릭할 이유와 첫 세 문단에서 지켜야 할 독자 약속을 +함께 평가해야 한다. + +기존 `blog-growth-review` skill은 글 형식, 공개 가능성, 품질 점수를 다루지만 +제목 후보의 클릭 유도력, 낚시 위험, 도입부 연결성을 독립적으로 비교하지는 +않는다. + +## 결정 + +- repo-local skill `.agents/skills/blog-title-review`를 추가한다. +- 제목 후보는 `click`, `fit`, `introFit`, `specificity`, `emotion`, + `novelty`, `arkTone`, `baitRisk` 축으로 비교한다. +- 제목은 본문 전체뿐 아니라 첫 세 문단과 한 세트로 평가한다. +- 첫 버전은 Codex skill로 운영하고, 안정된 뒤 필요할 때 `tooling/` CLI나 + 메타데이터 보조 필드로 확장한다. + +## 결과 + +- 제목 고민을 감으로만 하지 않고 후보별 장단점을 반복 가능한 형식으로 비교할 + 수 있다. +- 클릭 유도력이 높은 제목을 쓰더라도 도입부가 그 약속을 받는지 함께 점검한다. +- 공개 UI나 콘텐츠 schema에는 아직 새 필드를 추가하지 않는다. + +## 검토한 대안 + +- `blog-growth-review`에 제목 평가를 합치기: 글 전체 품질 리뷰와 제목 선택은 + 초점과 출력 형식이 달라 skill이 비대해진다. +- 바로 CLI를 만들기: 제목 평가는 LLM 판단과 문맥 해석 비중이 높아, 점수 축이 + 안정되기 전에는 스크립트보다 skill이 빠르게 개선하기 쉽다. +- `meta.json`에 제목 점수를 저장하기: 제목은 발행 전 의사결정 성격이 강해, + 현재는 영속 메타데이터보다 리뷰 출력으로 충분하다. diff --git a/docs/adr/0027-use-resume-specific-editorial-grid.md b/docs/adr/0027-use-resume-specific-editorial-grid.md new file mode 100644 index 00000000..e52380d4 --- /dev/null +++ b/docs/adr/0027-use-resume-specific-editorial-grid.md @@ -0,0 +1,53 @@ +# 0027. 이력서에는 콘텐츠 밀도에 맞춘 에디토리얼 그리드를 사용한다 + +Date: 2026-07-15 +Status: Accepted + +## 배경 + +이력서 페이지는 기존에 넓은 소개 영역, 3열 본문, 카드에 가까운 목록 표현을 함께 +사용했다. 경력과 프로젝트의 정보량은 충분했지만, 채용 담당자가 이름, 전문 분야, +연락처, 최근 경력을 빠르게 훑을 때 시선이 여러 블록으로 나뉘었다. + +zero.log의 이력서 레이아웃은 얇은 개인 인덱스에서 정체성, 소개, 링크를 1:3:2 +그리드로 나누고, 이후의 경력 내용을 텍스트 중심으로 정리한다. Ark 이력서는 +프로젝트별 문제·결정·구현·결과처럼 더 높은 정보 밀도를 다뤄야 하므로 이 구조를 +그대로 복제할 수는 없다. + +## 결정 + +- `resume/ui/pages/ResumePage.tsx` 안에서만 이력서 전용 에디토리얼 그리드를 + 적용한다. +- 상단은 이름 1열, 전문성과 소개 3열, 연락처 2열의 1:3:2 그리드로 구성한다. +- 본문은 보조 정보 2열과 경력·프로젝트 4열을 사용한다. 모바일에서는 경력 내용이 + 보조 정보보다 먼저 읽히도록 유지한다. +- 기존 `canvas`, `ink`, `home-accent` token과 Pretendard·JetBrains Mono의 역할을 + 재사용한다. 새 전역 token, 컴포넌트 라이브러리, 자동 모션은 추가하지 않는다. +- route, metadata, 이력서 데이터 모델, 연락처 링크, 프로젝트·경력의 정보 순서는 + 변경하지 않는다. + +## 결과 + +- 데스크톱에서는 빠른 스캔을 위한 비대칭 헤더와 경력 중심 열을 제공한다. +- 모바일과 보조기술에서는 경력 내용을 먼저 읽고, 뒤이어 프로필과 기술 정보를 + 확인할 수 있다. +- 카드를 늘리지 않고 여백, 명확한 텍스트 위계, 필요한 구분선으로 긴 이력서의 + 밀도를 관리한다. +- 홈의 에디토리얼 표현이 다른 도메인 화면으로 무분별하게 번지는 것을 막고, + 이력서 UI 책임은 `resume/` 도메인 안에 유지한다. + +## 검토한 대안 + +- zero.log의 전체 화면 최소 인덱스를 그대로 복제하기: 시각적 밀도는 낮아지지만, + Ark의 상세 프로젝트와 경력 근거를 충분히 전달하기 어렵다. +- 기존 3열 카드형 구조를 유지하고 여백만 조정하기: 변경 위험은 낮지만, 상단의 + 스캔 순서와 경력 중심 위계를 개선하지 못한다. +- AppShell과 모든 콘텐츠 페이지에 같은 그리드를 적용하기: 전체 사이트의 + 일관성은 생기지만, 블로그 독서와 이력서 검증은 다른 정보 구조를 필요로 한다. + +## 검증 + +- `ResumePage` 컴포넌트 테스트로 이름, 전문 분야, 핵심 연락처, 경력·프로젝트 + 섹션과 데스크톱 6열 그리드를 검증한다. +- `npm run test:components`로 관련 도메인과 UI 회귀를 확인한다. +- `npm run build`로 타입 검사와 `/resume` 정적 페이지 생성을 확인한다. diff --git a/docs/adr/README.md b/docs/adr/README.md index be8a2d2b..e0e6d83b 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -1,6 +1,6 @@ # Architecture Decision Records -Last updated: 2026-07-13 +Last updated: 2026-07-18 이 디렉터리는 커밋 히스토리에서 복원한 아키텍처 의사결정을 기록한다. ADR은 AI 협업 가이드와 별개의 문서다. 사람이 결정했든 AI가 초안을 @@ -43,6 +43,8 @@ ADR은 AI 협업 가이드와 별개의 문서다. 사람이 결정했든 AI가 | [0023](0023-run-the-release-quality-gate-in-ci.md) | Accepted | 배포 품질 gate를 CI에서 실행한다 | | [0024](0024-use-latest-only-home-feed.md) | Accepted | 홈 피드를 최신순 단일 경로로 유지한다 | | [0025](0025-use-node-runtime-for-og-image-route.md) | Accepted | OG 이미지 route에 Node.js runtime을 사용한다 | +| [0026](0026-use-repo-local-title-review-skill.md) | Accepted | 제목 선택은 repo-local skill로 보조한다 | +| [0027](0027-use-resume-specific-editorial-grid.md) | Accepted | 이력서에는 콘텐츠 밀도에 맞춘 에디토리얼 그리드를 사용한다 | ## 작성 조건 diff --git "a/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/index.mdx" "b/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/index.mdx" index 473952b3..6f36af1a 100644 --- "a/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/index.mdx" +++ "b/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/index.mdx" @@ -1,298 +1,168 @@ -> "기초를 다 닦은 뒤에 시작하라"는 말보다 -> "일단 만들고, 왜 돌아가는지 끝까지 파고들라"는 말이 더 크게 와닿을 때가 있어요. +> AI가 답을 빨리 준다고 학습이 끝나는 것은 아니다. 오히려 무엇을 먼저 +> 만들고, 어떤 기준으로 흔들고, 어디서 직접 검증할지가 더 중요해졌다. -AI 시대에는 답을 빨리 찾는 것보다 질문을 만들고 검증하는 순서가 더 중요해졌어요. +AI 도구를 쓰면 모르는 개념을 설명받고, 예제 코드를 만들고, 에러 원인을 +추정하는 속도가 빨라진다. 문제는 속도가 빨라진 만큼 잘못 이해한 채로 넘어갈 +위험도 같이 커진다는 점이다. -최근에 읽은 글 하나가 오래 남았어요. -고졸 출신으로 OpenAI 연구원이 된 가브리엘 피터슨의 이야기였어요. +그래서 나는 AI 시대의 학습을 "답을 빨리 얻는 능력"보다 "검증 가능한 질문을 +만드는 능력"으로 본다. 먼저 결과물을 만들고, 공식 문서와 리뷰로 감각을 +흔들고, 다시 구현하거나 글로 설명하면서 이해를 확인하는 루프가 필요하다. -제가 더 크게 본 건 화려한 커리어보다 학습 순서였어요. -기초를 완벽하게 쌓은 뒤에 움직이기보다, 먼저 프로젝트를 만들고, 막히는 개념을 끝까지 파고든 뒤 다시 구현으로 돌아와 이해를 확인하는 방식이었어요. +이 글은 내가 기술 블로그, 문서 번역, Redis와 Flink 학습을 거치며 반복하게 된 +학습 순서를 정리한 것이다. 핵심은 세 단계다. -돌아보면 저도 꽤 오래 비슷하게 배워왔어요. -그런데 이 흐름을 설명하지 못하면 반복은 남아도 기준은 남지 않아요. - -- 먼저 실습해요. -- 그다음 이론으로 기준을 붙잡아요. -- 다시 실습으로 돌아가 이해를 검증해요. - -이 글에서는 이 세 단계가 왜 제 학습의 중심이 됐는지, 왜 AI 시대에 더 강해졌는지, 실제로 어떤 장면에서 돌아가는지 정리해보려고 해요. -이 순서를 따라가면 질문 설계가 왜 중요한지, 그리고 실무에서는 어떤 기준으로 검증해야 하는지까지 한 번에 볼 수 있어요. +1. 먼저 만들어서 모르는 지점을 드러낸다. +2. 공식 문서와 반문으로 기준을 붙잡는다. +3. 다시 구현하거나 설명하면서 이해를 검증한다. --- -## AI 시대에는 학습 순서가 더 중요해졌어요 +## 먼저 만들면 질문이 생긴다 -예전에는 모르는 걸 찾는 일 자체가 큰 비용이었어요. -지금은 AI가 초안도 주고, 개념도 설명하고, 구현 방향도 제안해줘요. +학습을 시작할 때 가장 막연한 상태는 "무엇을 모르는지 모르는 상태"다. 이때 +책이나 강의를 처음부터 끝까지 따라가면 지식은 늘지만 질문은 늦게 생긴다. -문제는 여기서부터예요. -답이 빨라질수록 무엇을 먼저 묻고, 어디까지 믿고, 어떤 방식으로 다시 확인할지가 더 중요해져요. +나는 반대로 먼저 작은 결과물을 만든다. 완성도가 낮아도 괜찮다. 화면이 +깨지고, 빌드가 실패하고, 구조가 지저분해지는 과정에서 배워야 할 지점이 +드러나기 때문이다. -같은 도구를 써도 누군가는 훨씬 빠르게 자기 것으로 만들고, 누군가는 그저 소비하고 끝나요. -저는 그 차이가 답변의 속도보다 질문의 순서에서 나온다고 생각해요. +[`기술 블로그를 일주일 만에 만들 수 있었던 것`](/blog/blog-system-building)도 +그런 흐름에서 시작했다. 처음부터 Next.js App Router, MDX 파이프라인, 목차 +생성, 읽기 진행도, 콘텐츠 메타데이터 구조를 모두 이해한 상태는 아니었다. +먼저 원하는 읽기 경험을 정하고, 그 경험을 실제로 만들면서 질문을 뽑아냈다. -저한테 학습은 단순히 모르는 걸 채우는 일이 아니에요. -이미 가진 감각으로 먼저 부딪혀보고, 문서와 질문으로 흔들어보고, 다시 더 단단한 방식으로 묶어내는 과정에 가까워요. +- MDX 콘텐츠를 어디에서 읽어야 빌드와 런타임 책임이 분리되는가? +- `meta.json`을 분리하면 글 관리와 검증이 어떻게 달라지는가? +- 목차와 heading anchor는 콘텐츠 책임인가, UI 책임인가? +- 글이 늘어났을 때 공개/비공개 정책은 어디에서 강제해야 하는가? -그래서 중요한 건 더 많이 아는지가 아니에요. -제가 이미 알고 있는 것을 어디까지 의심해보고, 어떻게 다시 제 것으로 묶어내느냐가 더 중요해요. - -**정리: AI 시대에는 답을 빨리 받는 능력보다 질문과 검증의 순서를 설계하는 능력이 더 중요해요.** +이 질문들은 문서를 읽기 전에는 잘 생기지 않는다. 직접 만든 결과물이 있어야 +"왜 이 구조가 필요한가"를 구체적으로 물을 수 있다. --- -## 먼저 만들면서 질문을 드러내요 - -저는 배울 때 준비가 다 끝날 때까지 기다리지 않아요. -대신 결과물부터 만들어요. +## 공식 문서는 감각을 흔드는 기준이다 -그래야 제가 뭘 모르는지 바로 드러나요. -어디서 막히는지, 무엇이 애매한지, 어떤 판단이 비어 있는지가 손에 잡혀요. +먼저 만든 결과물은 출발점일 뿐이다. 여기서 멈추면 "돌아가는 코드"는 남지만 +"설명 가능한 판단"은 남지 않는다. -[`기술 블로그를 일주일 만에 만들 수 있었던 것`](/blog/blog-system-building)도 같은 흐름이었어요. -처음부터 설계 원칙과 렌더링 전략을 완벽하게 이해한 상태로 시작한 건 아니었어요. 먼저 원하는 화면과 흐름을 정했고, 그다음 Next.js, MDX, 렌더링 구조, 스타일 시스템을 만들면서 하나씩 붙잡아 갔어요. +AI는 이 간격을 줄이는 데 유용하다. 다만 AI 답변을 기준으로 삼으면 위험하다. +나는 AI를 정답지보다 해설가에 가깝게 쓴다. 기준은 공식 문서, 원문, 실제 +동작, 테스트 결과에 둔다. -중요했던 건 속도 자체가 아니었어요. -"실제로 움직이는 걸 먼저 만든 뒤, 그 구조를 이해한다"는 순서가 저한테 더 잘 맞았어요. +문서를 읽을 때는 단순 요약보다 아래 질문을 반복한다. -결과물이 생기면 질문도 선명해져요. +1. 이 기능은 어떤 문제를 풀기 위해 생겼는가? +2. 이 선택지 말고 어떤 대안이 있는가? +3. 공식 문서가 강조하는 제약은 무엇인가? +4. 내 코드나 운영 환경에서는 그 제약이 어디에서 드러나는가? +5. 다르게 바꾸면 어떤 비용이 생기는가? -- 왜 이 구조에서는 빌드 타임이 안정적일까요? -- 왜 이 컴포넌트는 서버에서 처리하고, 저건 클라이언트에서 처리할까요? -- 왜 같은 UI라도 구현 방식에 따라 유지보수 난이도가 달라질까요? +Redis나 Flink처럼 실무에서 자주 마주치지만 원리를 끝까지 설명하기 어려운 +기술은 특히 이 방식이 필요했다. 이미 사용해본 기술이라도 persistence, +replication, state, checkpoint 같은 개념을 문서 기준으로 다시 읽으면 기존 +감각이 흔들린다. -이런 질문은 책 한 권 읽는다고 바로 생기지 않아요. -직접 만들다가 막히고, 고치고, 설계를 다시 만져볼 때 비로소 생겨요. - -그래서 저한테 실습은 단순한 출력 단계가 아니에요. -좋은 질문을 만드는 장치에 더 가까워요. - -**정리: 먼저 만들면 배워야 할 범위가 막연한 관심사에서 구체적인 질문으로 바뀌어요.** +그 흔들림이 중요하다. 감각만으로 알고 있던 내용을 문서와 대안 비교 앞에 +세워보면, 어디까지가 경험이고 어디부터가 검증된 판단인지 나뉜다. --- -## 공식 문서로 기준을 붙잡아요 - -질문이 생긴 뒤에야 이론이 오래 남아요. -그때부터는 "왜 이게 이렇게 돌아가지?"를 설명할 수 있어야 해요. - -저는 그 지점에서 강의보다 공식 문서로 들어가요. -읽기 어렵더라도 결국 기준이 되는 문장은 공식 문서 안에 있다고 믿기 때문이에요. +## 다시 만들거나 설명해야 내 것이 된다 -물론 처음부터 술술 읽히진 않아요. -그래서 그냥 읽고 지나가지 않아요. 번역하고, 다시 풀어쓰고, 제 언어로 재구성해요. +문서를 읽고 AI에게 설명을 들으면 이해한 것처럼 느껴진다. 하지만 그 상태가 +오래가지는 않는다. 실제 이해는 다시 만들어보거나, 다른 사람에게 설명 가능한 +형태로 정리할 때 드러난다. -문서를 읽다가 막히면 거기서 멈추지 않아요. -모르는 단어를 다시 찾고, 관련 개념을 옆으로 넓히고, 예제를 복기하면서 문장을 제 것으로 바꿔요. +나는 이 단계를 두 가지 방식으로 확인한다. -Redis나 Flink처럼 실무에서 자주 마주치거나 앞으로 더 깊게 써야 할 기술은 특히 이런 방식으로 붙잡아요. -작동은 시킬 수 있어도, 왜 그렇게 동작하는지 설명하려고 하면 말이 막히는 순간이 와요. +1. 코드를 다시 만진다. +2. 글로 다시 설명한다. -그 간격을 메울 때 AI도 큰 도움이 돼요. -다만 저는 AI를 정답지보다 해설가에 가깝게 써요. 문서에서 읽은 추상 개념을 더 잘 이해하도록 질문을 던지는 도구로 써요. +코드를 다시 만질 때는 처음 구현과 다른 기준을 적용한다. 예전에는 "일단 +동작한다"가 목표였다면, 다시 들어갈 때는 책임 경계, 실패 조건, 테스트 방법을 +확인한다. 같은 기능을 더 단순하게 만들 수 있는지, 설정값을 바꾸면 어떤 +문제가 생기는지도 같이 본다. -> 이해가 흐릿한 채로 넘어가고 싶지 않아요. -> 읽고 끝내지 않고, 번역하고 정리하면서 제 언어로 다시 만들어요. +글로 설명할 때는 더 엄격해진다. 문장을 쓰다 보면 이해가 흐릿한 지점이 바로 +드러난다. 용어를 바꿔 말하지 못하거나, 대안을 설명하지 못하거나, 실패 조건을 +적지 못하면 아직 내 것이 아니다. -> **Tip. AI에게 끝까지 묻는 방식** -> -> - "왜 이 코드가 작동하지? 원리가 뭐지?" -> - "어떤 선택지가 있었고, 왜 이 방법을 선택한거지?" -> - "중간 과정은 어떻게 변하는거지?" -> - "하드웨어 수준까지 연결해서 설명해" -> - "내가 12살이라고 생각하고 현실 세계의 사물 기준으로 설명해" - -저는 이 질문을 반복하면서 문서에서 읽은 추상 개념을 실제 이해로 바꿔가요. - -누가 잘 정리한 강의를 듣는 것도 분명 도움이 돼요. -그런데 저한테는 직접 문서를 번역하고 구조화하는 과정이 훨씬 오래 남아요. - -**정리: 공식 문서는 정보를 많이 읽는 곳이 아니라, 판단 기준을 붙잡는 곳이에요.** +그래서 이 블로그의 Redis와 Flink 시리즈도 단순 요약 노트가 아니라 검증 +장치에 가깝다. 글로 남기려면 "이 기능이 무엇인가"보다 "언제 이 선택을 해야 +하는가"까지 답해야 한다. --- -## 다시 만들어 보면서 이해를 검증해요 - -문서를 읽고 나면 끝난 것처럼 느껴질 때가 있어요. -그런데 읽었다와 이해했다 사이에는 늘 간격이 남아요. - -그래서 다시 결과물로 돌아가요. -정말 제 것이 됐는지는 다시 만들어보면 바로 드러나요. - -이론을 읽은 뒤에 구현으로 다시 들어가면 처음에는 보이지 않던 구조가 보여요. -예전에는 "일단 돌아가니까 됐다"에서 멈춘 적이 많았는데, 지금은 그 상태를 오래 두지 않으려고 해요. - -왜 이렇게 설정해야 하는지, 다르게 바꾸면 어떤 문제가 생기는지, 어디까지가 도구의 책임이고 어디부터가 제 책임인지까지 확인하려고 해요. +## AI에게 맡기지 않는 부분 -이 단계에서는 질문이 꼬리를 물어요. +AI를 많이 쓸수록 더 명확히 나눠야 하는 책임이 있다. -- 이 선택이 왜 맞는지 다시 물어요. -- 대안은 무엇인지 확인해요. -- 데이터나 상태가 중간에서 어떻게 바뀌는지 봐요. -- 같은 목적을 더 단순하게 달성할 수 있는지도 따져봐요. +AI에게 맡겨도 좋은 것은 초안, 비교 후보, 설명 방식, 빠른 예제다. 반대로 내가 +끝까지 책임져야 하는 것은 문제 정의, 근거 선택, 최종 판단, 공개 가능한 +표현이다. -이렇게 해야 비로소 제 코드가 돼요. -그냥 붙여 넣은 코드는 제 경험으로 남지 않아요. +실제로 질문도 이렇게 바뀌었다. -> **주의. AI가 답해도 검증은 제가 해요** -> -> AI는 이해 속도를 크게 올려줘요. -> 하지만 정확성, 책임, 최종 판단까지 대신해주진 않아요. -> 그래서 저는 AI를 지름길보다 해설가에 가깝게 써요. +- "이 코드 고쳐줘"보다 "이 코드가 실패하는 조건을 나눠서 설명해줘" +- "정리해줘"보다 "공식 문서 기준으로 빠진 제약을 찾아줘" +- "뭐가 좋아?"보다 "두 대안의 운영 비용을 비교해줘" +- "예제 만들어줘"보다 "이 예제가 실제 환경에서 깨질 조건을 알려줘" -**정리: 이해는 읽을 때 끝나지 않고, 다시 만들 때 비로소 검증돼요.** +질문이 바뀌면 결과도 달라진다. AI 답변을 그대로 가져오는 대신, 내 판단을 +흔드는 재료로 쓸 수 있다. 이 차이가 학습 속도보다 더 중요하다. --- -## 넓게 밟아본 시간도 지금은 강점이 돼요 +## 실제로 쓰는 학습 루프 -돌아보면 저는 오랫동안 실무를 먼저 배웠어요. -UIUX, 디자인, 프론트엔드, 백엔드, 데이터, 인프라를 두루 건드렸지만 어느 하나를 학교 커리큘럼처럼 체계적으로 깊게 밟아온 건 아니었어요. +지금은 새로운 기술이나 도구를 배울 때 아래 순서를 기본값으로 둔다. -그 시기에는 이게 종종 약점처럼 느껴졌어요. -넓게는 아는데, 왜 그런지 설명하려고 하면 허전한 구간이 보였어요. +1. 작은 결과물을 먼저 만든다. +2. 막힌 지점을 질문 목록으로 적는다. +3. 공식 문서에서 질문과 직접 연결되는 구간을 읽는다. +4. AI에게 대안, 제약, 실패 조건을 묻는다. +5. 다시 구현하거나 설정을 바꿔본다. +6. 이해한 내용을 글이나 체크리스트로 설명한다. +7. 설명하지 못한 부분만 다시 문서로 돌아간다. -그런데 AI가 생긴 뒤 이 경험의 의미가 달라졌어요. -여러 영역을 조금이라도 밟아본 사람은 문제의 좌표를 더 빨리 잡아요. -디자인 문제인지, 구조 문제인지, 데이터 흐름 문제인지, 운영 방식 문제인지 먼저 구분할 수 있기 때문이에요. +이 루프의 장점은 학습 범위를 줄여준다는 점이다. "Redis를 공부해야지"처럼 +넓게 시작하면 끝이 없다. 반면 "이 상황에서 RDB와 AOF 중 무엇을 선택해야 +하는가"처럼 질문이 좁아지면 읽어야 할 문서와 검증해야 할 조건이 선명해진다. -AI는 바로 그다음 단계에서 큰 힘을 발휘해요. -이미 밟아본 지형 위에서 빠진 이론과 세부 개념을 훨씬 빠르게 메워주기 때문이에요. - -그래서 지금의 경쟁력은 단순히 많이 아는 데서만 나오지 않는다고 생각해요. -여러 영역의 조각을 연결하고, 부족한 이론을 빠르게 보강하는 능력에서도 나와요. - -이건 "제너럴리스트가 무조건 좋다"는 얘기를 하려는 건 아니에요. -넓게 경험한 시간이 더 이상 애매한 이력으로만 남지 않는다는 이야기예요. - -**정리: 넓게 밟아본 시간은 약점으로 끝나지 않아요. AI 시대에는 연결 감각과 탐색 속도로 다시 힘을 얻어요.** +완벽한 기초를 쌓은 뒤에 움직이는 방식도 필요할 때가 있다. 하지만 실무에서는 +대부분 이미 움직이는 시스템, 이미 만든 코드, 이미 겪은 장애에서 학습이 +시작된다. 그때는 먼저 만든 결과물에서 질문을 뽑아내는 편이 더 빠르다. --- -## 글쓰기도 같은 방식으로 익혀요 - -요즘은 글쓰기 자체도 이 루프로 다시 배우고 있어요. -글맛이 좋다고 느껴지는 글을 만나면 그냥 "잘 쓴다"에서 멈추지 않아요. - -어디서 독자의 질문을 붙잡는지, 어디서 글의 범위를 먼저 잡아주는지, 왜 중간 요약과 비유가 끝까지 읽게 만드는지 구조를 살펴봐요. -최근에는 테오의 연재 글을 읽으면서 그 패턴이 더 선명하게 보였어요. - -독자 질문으로 문을 열고, 프롤로그로 범위를 잡고, 초반에 로드맵을 깔고, 예시와 비유로 설명한 뒤, 중간 요약과 마지막 질문으로 글을 회수하는 구조였어요. - -그걸 보면서 글맛이 좋다는 건 결국 문장이 예쁜 것만은 아니라는 생각도 했어요. -독자가 길을 잃지 않게 계속 안내하는 힘, 그래서 끝까지 읽게 만드는 구조가 함께 필요하다는 걸 배웠어요. +## 공개 글로 남길 때의 기준 -저도 이걸 그대로 흉내 내기보다, 제 글에 맞는 방식으로 배우고 적용해보려고 해요. -소제목은 목차 역할을 하게 두고, 질문은 본문 안에서 독자의 사고를 붙잡는 데 쓰는 방식이 저한테 더 잘 맞았어요. +학습한 내용을 모두 공개 글로 만들 필요는 없다. 공개 글은 단순 기록이 아니라 +다음에 같은 문제를 만났을 때 다시 꺼내 쓸 수 있는 판단 기준이어야 한다. -> **Tip. 글맛이 좋은 글을 읽을 때 제가 보는 기준** -> -> - 첫 화면에서 독자의 질문을 바로 붙잡는지 -> - 초반에 이 글의 범위와 흐름을 먼저 알려주는지 -> - 추상적인 개념을 비유나 사례로 내려주는지 -> - 중간마다 `정리:` 같은 표지판으로 길을 다시 보여주는지 -> - 마지막에 독자에게 다시 말을 걸며 생각을 남기는지 +그래서 글로 옮길 때는 아래 질문을 확인한다. -좋은 글을 읽고 구조를 분해하고, 제 글에 다시 적용해보면서 이해를 검증하는 일도 결국 같은 학습이라고 생각해요. +1. 이 글을 읽을 사람이 처한 상황이 분명한가? +2. 문제를 해결하지 않으면 생기는 비용이 드러나는가? +3. 내가 실제로 검토한 대안이나 실패 조건이 있는가? +4. 독자가 가져갈 한 문장짜리 기준이 남는가? +5. AI 답변이 아니라 내 경험과 검증 결과가 중심인가? -**정리: 글쓰기도 결과물을 읽고, 구조를 이해하고, 다시 제 방식으로 적용해보는 학습이에요.** - ---- - -## 실제로는 이렇게 돌아가요 - -추상적으로만 말하면 그럴듯하게 들릴 수 있어요. -그래서 이번에는 실제로 제 학습 루프가 어떻게 돌았는지, 두 장면으로 나눠서 적어보려고 해요. - -### 사례 1. 기술 블로그를 만들 때 - -기술 블로그를 만들기 전부터 머릿속에는 원하는 화면이 있었어요. -신문처럼 차분한 분위기, 오래 읽어도 피곤하지 않은 레이아웃, 코드와 글이 자연스럽게 섞이는 구조 같은 것들이었어요. - -그런데 그걸 구현하는 방법을 처음부터 다 알고 있진 않았어요. -Next.js App Router를 어떤 경계로 나눌지, MDX 콘텐츠를 어떻게 읽어올지, 목차와 읽기 진행도를 어떤 식으로 붙일지, 전부 손으로 부딪히며 알아갔어요. - -이 지점에서 먼저 꺼내 쓴 건 프론트엔드 감각이었어요. -어떤 화면이 읽기 편한지, 어떤 인터랙션이 과한지, 어떤 디자인이 글의 집중을 깨는지는 경험적으로 어느 정도 알고 있었어요. - -하지만 감각만으로는 오래 못 가요. -그래서 공식 문서와 레퍼런스를 다시 읽고, AI에게 계속 반문했어요. - -- MDX 기반 블로그 시스템을 SSG로 구현하려고 하는데 구조를 어떻게 잡아야 하지? -- `meta.json`을 굳이 분리한 이유는 뭐지? -- TOC를 자동 생성하려면 어떤 방식이 가장 낫지? -- 이 코드는 지금 동작은 하는데, 성능까지 괜찮다고 볼 수 있나? - -이렇게 질문을 던지다 보면 처음에 막연했던 감각이 설명 가능한 판단으로 바뀌어요. -예쁜 블로그를 만들고 싶다는 욕심이, 유지보수 가능한 시스템을 설계하자는 목표로 바뀌는 순간이 와요. - -그래서 이 블로그는 단순히 빨리 만든 결과물이 아니에요. -이미 알고 있던 것과 새롭게 검증한 판단을 다시 묶어서 만든 학습 결과물에 더 가까워요. - -### 사례 2. 공식 문서를 번역하고 시리즈로 이어갈 때 - -Redis나 Flink처럼 실무에서 계속 마주치는 기술은 이상하게도 "쓴다"와 "안다" 사이에 큰 간격이 있어요. -작동은 시킬 수 있는데, 왜 그렇게 동작하는지 설명하려고 하면 갑자기 말이 막히는 순간이 와요. - -예전에는 그 간격을 적당히 넘기고 지나간 적도 많았어요. -하지만 지금은 그 구간을 그냥 두면 결국 다시 돌아오게 된다는 걸 알아요. - -그래서 공식 문서로 내려가요. -개념을 읽고, 번역하고, 제 언어로 다시 정리하고, 필요하면 시리즈 글로 이어가요. - -여기서 중요한 건 읽고 끝내지 않는 거예요. -왜 이런 제약이 생기는지, 다른 선택지는 왜 덜 적합한지, 운영 환경에서는 어떤 기준으로 판단해야 하는지를 끝까지 물어요. - -이 과정을 거치면 문서 내용이 지식으로만 남지 않아요. -실무에서 겪었던 장면과 문서 속 설명이 서로 연결되기 시작해요. - -완전 정복 시리즈를 쓰는 이유도 결국 여기에 있어요. -배운 걸 정리하려는 목적도 있지만, 제가 정말 이해했는지를 끝까지 확인하는 검증 단계이기도 해요. - -**정리: 실제 사례를 넣으면 학습법이 주장으로만 남지 않아요. 어떤 장면에서 어떻게 작동했는지가 함께 보여요.** - ---- - -## 돌아보면 이건 정반합의 리듬이었어요 - -한동안은 이걸 그냥 제 성향이라고 생각했어요. -일단 만들어보고, 막히면 끝까지 파고들고, 다시 손으로 확인하는 습관 말이에요. - -그런데 블로그를 만들고, 공식 문서를 번역하고, 완전 정복 시리즈로 이어가다 보니 그 흐름이 조금 더 또렷하게 보였어요. -늘 같은 순서가 반복되고 있었어요. - -먼저 제가 이미 알고 있는 감각과 경험이 나와요. -어떤 화면이 읽기 편한지, 어떤 구조가 오래 버틸지, 어디가 위험한지 먼저 짐작해보는 단계예요. 이게 제 학습의 `정`이에요. - -그다음에는 그 감각을 그냥 믿고 밀어붙이지 않아요. -문서를 읽고, AI에게 반문하고, 리뷰를 받고, 다른 선택지를 늘려봐요. 제가 맞다고 생각한 걸 일부러 흔들어보는 단계예요. 이게 `반`이에요. - -마지막으로는 둘 중 하나를 버리지 않아요. -몸으로 익힌 감각과 검증된 기준을 다시 묶어서 더 나은 구현과 더 단단한 설명으로 가져가요. 이때 비로소 결과물이 제 것이 돼요. 이게 `합`이에요. - -생각해보면 저는 새로운 걸 배울 때마다 이 리듬을 반복해왔어요. -먼저 만들고, 질문하고, 다시 만들고, 그 과정을 글로 남기면서요. - -정반합은 거창한 철학이라기보다, 제가 배울 때 늘 손으로 밟아온 순서에 더 가까워요. - -**정리: 정반합은 따로 붙인 개념이 아니라, 제가 배우는 순서를 뒤에서 설명해주는 이름에 가까워요.** +이 기준을 통과하지 못하면 private로 둔다. 나에게는 유용한 학습 노트라도, +독자에게 재사용 가능한 판단 기준이 없다면 공개 글로는 아직 부족하다. --- ## 마무리 -AI 시대의 경쟁력은 더 많이 아는 사람보다, 끝까지 연결하는 사람에게 간다고 생각해요. - -결과물을 만들며 질문을 만들고, 공식 문서와 반문으로 자기 감각을 흔들어보고, 다시 손으로 구현하며 더 나은 합으로 가는 사람 말이에요. - -지금 붙잡고 있는 기술 하나를, 당신만의 정반합으로 끝까지 밀어본 적이 있나요? - -돌아보면 이 반복은 결국 제가 아는 것에서 출발해, 그걸 흔들어보고, 더 나은 형태로 다시 묶어내는 과정이기도 해요. - -앞으로도 저는 이 순서를 반복할 거예요. -실습, 이론, 다시 실습. +AI 시대에 학습이 쉬워진 것은 맞다. 하지만 쉬워진 부분은 답을 찾는 과정이지, +이해를 검증하는 책임이 아니다. -이 단순한 루프가 지금까지 저를 가장 멀리 데려갔어요. +나는 앞으로도 먼저 만들고, 문서로 흔들고, 다시 구현하거나 글로 설명하는 +순서를 반복할 것이다. 이 루프가 느려 보일 때도 있지만, 결과적으로는 더 오래 +남는다. -요즘 여러분은 어떤 질문을 끝까지 붙잡고 있나요? +좋은 학습은 많은 답을 모으는 일이 아니다. 내가 만든 결과물을 기준으로 더 좋은 +질문을 만들고, 그 질문을 끝까지 검증 가능한 형태로 바꾸는 일이다. diff --git "a/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/meta.json" "b/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/meta.json" index 1a6ae287..1d3e247f 100644 --- "a/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/meta.json" +++ "b/posts/ai-\354\213\234\353\214\200-\355\225\231\354\212\265\353\262\225/meta.json" @@ -1,7 +1,7 @@ { - "title": "AI 시대, 탑다운 방식으로 익히는 야생형 학습", + "title": "AI 시대의 학습 루프: 먼저 만들고 다시 검증하기", "slug": "ai-wild-learning-style", - "description": "공식 문서 번역과 결과물 해체를 오가며 실무 감각과 이론을 연결한 학습 방식을 정리해요.", + "description": "AI 답변을 그대로 소비하지 않고 결과물, 공식 문서, 재구현을 오가며 이해를 검증하는 학습 루프를 정리합니다.", "date": "2026-03-11", "category": "Tech", "contentType": "essay", @@ -12,19 +12,19 @@ ], "image": "/images/posts/ai-시대-학습법/thumbnail.png", "featured": false, - "visibility": "private", + "visibility": "public", "qualityReview": { - "philosophy": 3.5, - "design": 2.5, - "implementation": 2, - "brandFit": 2, - "clarity": 4, + "philosophy": 4, + "design": 4, + "implementation": 3.5, + "brandFit": 3.5, + "clarity": 4.5, "structure": 4, - "evidence": 3.5, + "evidence": 4, "usefulness": 4, "originality": 4, - "polish": 3.5, + "polish": 4, "reviewedAt": "2026-06-17", - "notes": "비공개" + "notes": "AI 시대 학습법을 결과물-문서-재검증 루프 중심으로 재작성하고 공개 전환" } } diff --git "a/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/index.mdx" "b/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/index.mdx" index 6ba7e573..5e3cfd2d 100644 --- "a/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/index.mdx" +++ "b/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/index.mdx" @@ -1,101 +1,111 @@ -## 들어가기 +## README 번역은 작은 UX 개선이었다 -Wave Terminal의 한국어 README를 번역해서 PR을 올렸고, maintainer 리뷰를 거쳐 `main`에 머지됐어요. -코드를 바꾸지는 않았지만, 한국어 사용자라면 매번 겪던 "번역 → 검증" 반복을 줄이는 구조적 개선이었어요. -이 글에서는 그 불편을 어떻게 구조 문제로 정의했는지, 왜 문서 개선만으로도 읽기 리드타임을 줄일 수 있었는지 정리해요. +영어 README만 제공되는 도구를 쓸 때 불편한 지점은 번역 자체가 +아니었다. 기능을 확인할 때마다 원문을 읽고, 번역하고, 번역 결과가 맞는지 +다시 검증하는 과정이 반복됐다. + +Wave Terminal을 사용할 때도 같은 흐름이 있었다. 한 번만 겪으면 개인의 +불편이지만, 한국어 사용자가 매번 같은 절차를 반복한다면 문서 접근 경로의 +문제가 된다. 그래서 이 작업은 "README를 한국어로 옮긴 일"보다 "읽기 +리드타임을 줄인 일"에 가까웠다. + +이 글은 첫 OSS 기여를 어떻게 고른 것인지, 왜 코드 변경이 아닌 문서 변경을 +선택했는지, 작은 변경을 머지 가능한 범위로 만들기 위해 무엇을 제한했는지 +정리한 기록이다. --- -## 1. 불편했던 점 +## 문제를 반복 비용으로 다시 정의했다 -Wave Terminal은 제가 자주 쓰는 터미널이에요. -당시 공식 README는 영어로만 제공되고 있었어요. +처음에는 영어 문서를 읽는 데 시간이 더 걸리는 개인 문제처럼 보였다. 하지만 +실제로 반복되던 비용은 조금 달랐다. -기능을 파악할 때마다 같은 흐름을 반복해야 했어요. +1. README에서 필요한 기능을 찾는다. +2. AI 번역으로 한국어 설명을 만든다. +3. 번역된 문장이 원문 의미를 잘 보존했는지 다시 확인한다. +4. 그제야 실제 설정이나 기능을 판단한다. -1. 영어 README를 읽어요 -2. AI로 번역해요 -3. 번역 결과를 다시 검증해요 -4. 그제야 실제 내용을 이해해요 +이 흐름에서 가장 아까운 지점은 2번보다 3번이었다. 번역 결과를 다시 검증하는 +시간은 문서를 읽을 때마다 새로 발생했고, 같은 비용을 다른 한국어 사용자도 +반복할 가능성이 컸다. -진짜 비용은 번역 자체가 아니었어요. -번역 결과를 "이게 맞나?" 하고 다시 확인하는 반복 리드타임이 문제였어요. +그래서 문제를 "내가 영어 README를 읽기 불편하다"가 아니라 "한국어 사용자가 +도구를 이해하기 전까지 거치는 중간 단계가 많다"로 바꿔 잡았다. 이 정의가 +바뀌자 해결책도 개인 노트가 아니라 공식 문서 기여로 좁혀졌다. --- -## 2. 문제 +## 변경 범위를 작게 만들었다 -이건 영어 실력의 문제가 아니었어요. -문서 접근 구조 자체가 비효율적이라는 게 핵심이었어요. +첫 기여에서 가장 경계한 것은 좋은 의도를 크게 펼치는 일이었다. 문서 번역에 +기능 개선, 표현 리팩터링, 구조 변경까지 섞이면 리뷰어가 확인해야 할 범위가 +커진다. 그래서 변경 범위를 문서 접근성 개선 하나로 제한했다. -문제를 세 가지로 정리했어요. +실제 PR에는 세 가지만 담았다. -1. 읽기 리드타임이 길어져요 -2. 번역 오차로 의미가 왜곡될 수 있어요 -3. 같은 작업을 한국어 사용자 모두가 반복해요 +1. `README.ko.md`를 추가한다. +2. 기존 README에 언어 전환 링크를 추가한다. +3. 코드, 빌드, 런타임 동작은 바꾸지 않는다. -결국 개인의 불편이 아니라, 한국어 사용자 전체에 누적되는 구조 비용이에요. +번역 기준도 PR을 올리기 전에 정했다. 원문 구조를 유지하고, 과도한 의역을 +피하고, 판단이 필요한 표현은 원문 의미를 먼저 보존했다. 좋은 한국어 문장을 +만드는 것보다 리뷰 가능한 변경으로 남기는 것이 더 중요했다. ---- +이 제한 덕분에 리뷰 포인트가 명확해졌다. maintainer는 코드 영향도를 볼 필요 +없이 문서 파일과 언어 전환 흐름만 확인하면 됐다. -## 3. 해결 +--- -가설은 단순했어요. -공식 한국어 README를 추가하면, 번역하고 검증하는 중간 단계를 줄일 수 있다고 판단했어요. +## 절차도 기여의 일부였다 -실행은 기여 가이드에 맞춰 범위를 최소화했어요. +PR을 올린 뒤에는 예상보다 많은 자동화가 먼저 반응했다. AI 리뷰봇이 변경 +범위를 확인했고, CLA 서명 안내도 붙었다. 처음에는 문서 하나를 고쳤을 뿐인데 +절차가 과하게 느껴졌다. -1. `README.ko.md` 신규 추가 -2. 기존 README에 언어 전환 블록 추가 -3. 코드/런타임 변경 없음 -4. 하나의 논리적 변경만 포함 +하지만 이 과정까지 겪고 나니 OSS 기여에서 중요한 것은 변경 내용만이 아니라 +프로젝트가 신뢰할 수 있는 형태로 변경을 받아들이는 절차라는 점이 보였다. +라이선스, 기여 가이드, 리뷰 단위가 명확해야 작은 변경도 안전하게 합쳐질 수 +있다. -리뷰 리스크를 낮추기 위해 번역 기준도 미리 정해뒀어요. +결과적으로 PR은 maintainer 리뷰를 거쳐 `main`에 머지됐다. -1. 원문 구조를 1:1로 유지해요 -2. 과도한 의역을 배제해요 -3. PR 설명에서 변경 범위를 문서로 제한해요 +[Wave Terminal README 한국어 번역 PR](https://github.com/wavetermdev/waveterm/pull/2943) -저장소는 Apache-2.0, CONTRIBUTING, CLA 절차가 명확했어요. -그래서 README 번역은 정식 기여 범주에 해당한다고 판단했어요. +정량 지표를 직접 측정한 것은 아니다. 다만 한국어 사용자가 "원문 읽기, 번역, +검증"을 매번 반복하던 경로를 공식 README 안의 언어 선택으로 줄였다는 점에서 +문서 구조의 마찰은 분명히 낮아졌다. --- -## 4. 결과 +## 문서 기여의 적용 기준 -PR을 올리자마자 3개의 AI 리뷰봇이 달라붙었어요. -제 작업을 면밀히 분석하더니, CLA 서명을 하라는 안내까지 띄워줬어요. -CLA 서명은 코드의 저작권을 프로젝트에 양도한다는 내용의 서명이에요. +이번 경험에서 남은 기준은 단순하다. 문서 기여는 코드보다 쉬운 대체재가 +아니라, 사용자가 도구를 이해하기까지의 경로를 줄일 때 의미가 있다. -결과적으로 maintainer 리뷰를 거쳐 `main`에 머지됐어요. -https://github.com/wavetermdev/waveterm/pull/2943 +다음 조건을 만족하면 작은 문서 변경도 충분히 좋은 첫 기여가 될 수 있다. -1. 공식 한국어 README가 추가됐어요 -2. 언어 선택 UI가 README에 반영됐어요 -3. OSS 기여 이력이 생겼어요 +1. 같은 불편이 여러 사용자에게 반복될 가능성이 있다. +2. 변경 전후의 읽기 경로가 분명히 짧아진다. +3. 코드 동작을 바꾸지 않아도 사용자의 판단 비용이 줄어든다. +4. 리뷰어가 확인할 범위를 한눈에 이해할 수 있다. -정량 지표를 따로 측정하지는 않았지만, 기존의 "영문 읽기 → 번역 → 검증" 반복 단계를 문서 구조 차원에서 줄였어요. +반대로 내 사용법을 길게 적는 문서나, 원문을 크게 재해석하는 번역은 첫 기여로 +적합하지 않을 수 있다. 의도는 좋아도 프로젝트가 유지해야 할 문서의 책임을 +갑자기 키우기 때문이다. --- -## 5. 배운 점 +## 다음 기여를 고르는 방식 -1. OSS 기여가 꼭 코드 변경일 필요는 없어요 -문서 개선만으로도 사용자 경험과 진입 장벽에 직접 영향을 줄 수 있어요. - -2. 리드타임도 비용이에요 -반복 번역은 혼자만의 작업 같지만, 커뮤니티 전체로 보면 계속 쌓이는 비용이에요. - -3. 범위를 좁히면 머지 가능성이 올라가요 -작고 명확한 변경은 리뷰 비용과 리스크를 함께 낮춰줘요. - ---- +이후로는 OSS 기여 거리를 볼 때 "내가 할 수 있는가"보다 "반복 비용을 줄일 수 +있는가"를 먼저 본다. -## 6. 오픈소스 기여는 이렇게 시작하면 좋아요 +작은 오타 수정도 좋지만, 더 좋은 출발점은 사용자가 매번 같은 확인을 반복하는 +지점이다. 설치 과정에서 빠지는 전제, 문서와 실제 UI가 어긋나는 부분, 비영어 +사용자가 계속 번역해야 하는 핵심 경로가 여기에 해당한다. -1. 반복되는 불편은 개인 문제보다 구조 문제로 먼저 정의하면 좋아요 -2. 첫 OSS 기여는 문서 개선처럼 작고 명확한 범위에서 시작하면 좋아요 -3. 의사결정 기준을 PR 설명에 명시해서 리뷰어의 판단 비용을 줄이면 좋아요 +첫 기여는 거창할 필요가 없다. 대신 문제 정의는 작고 정확해야 한다. 이번 +README 번역 PR에서 배운 기준도 여기에 있다. -이번 경험에서 바뀐 건 기술 스택이 아니라 역할이었어요. -"사용자"에서 "기여자"로 전환되는 기준은 큰 기능 추가가 아니라, 작은 구조 비용을 실제로 줄였는지에 있었어요. +> 좋은 첫 OSS 기여는 큰 기능을 추가하는 일이 아니라, 반복되는 이해 비용을 +> 프로젝트가 받아들일 수 있는 작은 변경으로 줄이는 일이다. diff --git "a/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/meta.json" "b/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/meta.json" index 73352b78..84deb930 100644 --- "a/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/meta.json" +++ "b/posts/waveterm-\353\262\210\354\227\255-oss-\352\270\260\354\227\254/meta.json" @@ -1,7 +1,7 @@ { - "title": "단순 사용자에서 OSS 기여자가 되기까지: README 번역으로 읽기 리드타임 줄이기", + "title": "README 번역으로 첫 OSS 기여를 만든 기준", "slug": "oss-readme-translation-lead-time", - "description": "README 번역 기여로 반복 번역 비용을 줄이기까지 문제를 정의하고 실행한 과정을 정리해요.", + "description": "Wave Terminal README 번역 PR을 통해 반복되는 읽기 리드타임을 문서 구조 문제로 줄인 과정을 정리합니다.", "date": "2026-02-27", "category": "Tech", "contentType": "retrospective", @@ -12,19 +12,19 @@ "Developer Experience" ], "featured": false, - "visibility": "private", + "visibility": "public", "qualityReview": { - "philosophy": 2.5, - "design": 2.5, - "implementation": 2, - "brandFit": 2, - "clarity": 3.5, - "structure": 3.5, - "evidence": 3.5, - "usefulness": 3.5, + "philosophy": 3.5, + "design": 3.5, + "implementation": 3.5, + "brandFit": 3.5, + "clarity": 4, + "structure": 4, + "evidence": 4, + "usefulness": 4, "originality": 3.5, - "polish": 3, + "polish": 4, "reviewedAt": "2026-06-17", - "notes": "비공개" + "notes": "README 번역 PR을 읽기 리드타임 절감 관점으로 재구성하고 공개 전환" } } diff --git a/resume/ui/pages/ResumePage.test.tsx b/resume/ui/pages/ResumePage.test.tsx new file mode 100644 index 00000000..ccbcfa32 --- /dev/null +++ b/resume/ui/pages/ResumePage.test.tsx @@ -0,0 +1,23 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import ResumePage from './ResumePage'; + +describe('ResumePage', () => { + it('renders the resume as a three-column editorial header with core contact links', () => { + const { container } = render(); + + expect( + screen.getByRole('heading', { level: 1, name: '박은우' }) + ).toBeInTheDocument(); + expect(screen.getByText('Backend / Data Platform Engineer')).toBeVisible(); + expect(screen.getByRole('link', { name: 'une@kakao.com' })).toHaveAttribute( + 'href', + 'mailto:une@kakao.com' + ); + expect(screen.getByRole('heading', { name: 'Experience' })).toBeVisible(); + expect( + screen.getByRole('heading', { name: 'Selected Work' }) + ).toBeVisible(); + expect(container.querySelector('header')).toHaveClass('md:grid-cols-6'); + }); +}); diff --git a/resume/ui/pages/ResumePage.tsx b/resume/ui/pages/ResumePage.tsx index 7926bd63..95b0e47f 100644 --- a/resume/ui/pages/ResumePage.tsx +++ b/resume/ui/pages/ResumePage.tsx @@ -115,7 +115,7 @@ function renderTextWithCode(text: string): ReactNode[] { return (
             {code}
           
@@ -126,7 +126,7 @@ function renderTextWithCode(text: string): ReactNode[] { return ( {segment.slice(1, -1)} @@ -139,7 +139,7 @@ function renderTextWithCode(text: string): ReactNode[] { function renderDetailList(detailLines: string[]): ReactNode { return ( -