From 6917ce24208f2eae8881b5c70692e53818884800 Mon Sep 17 00:00:00 2001 From: DongHyeonka Date: Mon, 7 Sep 2026 19:12:37 +0900 Subject: [PATCH] =?UTF-8?q?docs(TechLog):=20=EB=82=A8=EC=9D=80=20=EC=A3=BC?= =?UTF-8?q?=EC=A0=9C=EB=A5=BC=20=EB=8B=A4=EC=8B=9C=20=EC=93=B0=EA=B3=A0=20?= =?UTF-8?q?SSOT=20=EB=A5=BC=20=EC=A0=80=EC=9E=A5=EC=86=8C=20=EC=8B=A4?= =?UTF-8?q?=EB=AC=BC=EB=A1=9C=20=EB=8D=94=20=EB=B3=B4=EA=B0=95=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 주제 11~13 을 다시 쓰고, Case 가 얇은 것들을 저장소에서 실물을 확인해 채웠다. §13.4 ManagementClientSafeMessages — 삭제 관련 코드 여섯의 고정 문구와 원문 메시지를 내보내지 않는 이유(javadoc) §16.1 다섯 참조가 전부 DOCUMENT_IN_USE 하나로 나가고, SSOT 가 인용한 영어 문장은 DeleteDocumentDraftUseCase 안에 남는 진단 메시지라 밖으로 나가지 않는다 §13.6 romanizeSyllable 실물과 음운 변동을 뺀 이유, 문서 slug 와 같은 정규식을 쓰는 이유 §15.4 check:types 가 도는 tsconfig 여섯 — app·node·test·recipes·web-worker·service-worker SSOT 62,643 → 67,526 자. 인용한 코드는 전부 저장소에서 찾아 대조했다. Co-Authored-By: Claude Opus 5 --- docs/TechLog/final/document.md | 57 +++++++++++++++++-- ...case-a-slug-rule-that-threw-korean-away.md | 29 ++++++++-- ...the-comparison-band-changed-three-times.md | 42 +++++++++++--- ...oncept-topic-variant-and-record-variant.md | 18 ++++-- ...-an-axis-inside-a-topic-not-four-topics.md | 16 +++--- .../case-an-error-message-that-guessed.md | 41 +++++++++++-- .../case/case-nine-names-for-five-kinds.md | 16 ++++-- .../case/case-renaming-the-kinds-twice.md | 12 +++- .../reference-ask-which-words-to-use.md | 29 +++++----- .../tech-log-studio/tech-log-tree.json | 21 +++++-- ...-the-typecheck-command-checked-no-files.md | 21 ++++++- ...e-the-guard-worked-and-i-did-not-run-it.md | 17 ++++-- ...ert-the-defect-and-watch-the-guard-fail.md | 26 ++++----- ...what-a-person-must-run-before-deploying.md | 33 ++++++----- 14 files changed, 279 insertions(+), 99 deletions(-) diff --git a/docs/TechLog/final/document.md b/docs/TechLog/final/document.md index 84592a0..a854507 100644 --- a/docs/TechLog/final/document.md +++ b/docs/TechLog/final/document.md @@ -1082,7 +1082,27 @@ QUESTION → 열린 질문 게이트웨이가 서버의 클라이언트 안전 메시지를 실어 나르고 화면이 그것을 보이게 했습니다. -**이 문제는 아직 완전히 안 끝났습니다** — §14.2 를 보세요. +서버는 오류 코드마다 고정 문구를 갖고 있습니다(`ManagementClientSafeMessages`). 예외의 원문 +메시지를 그대로 내보내지 않는 이유가 클래스 javadoc 에 적혀 있습니다: + +> code 별 고정 문구. 예외의 원문 메시지는 진단용이라 그대로 내보내지 않는다 — 저장소 제약 +> 이름이나 SQL 조각이 새어 나갈 수 있고, 그건 클라이언트가 분기할 값도 아니다. + +삭제와 관련된 코드만 여섯입니다. 화면이 추측하던 세 가지는 이 중 셋에 해당합니다: + +```java +case VERSION_CONFLICT -> "다른 곳에서 먼저 수정되었습니다. 새로 불러온 뒤 다시 시도해 주세요"; +case DOCUMENT_PUBLISHED -> "공개된 기록은 삭제할 수 없습니다. 먼저 공개를 취소해 주세요"; +case DOCUMENT_IN_USE -> "이 기록을 참조하는 곳이 있어 삭제할 수 없습니다"; +case QUESTION_IN_USE -> "이 질문을 참조하는 곳이 있어 삭제할 수 없습니다"; +case DECISION_IN_USE -> "이 결정을 참조하는 곳이 있어 삭제할 수 없습니다"; +case TOPIC_IN_USE -> "이 주제를 쓰는 기록이 있어 삭제할 수 없습니다"; +``` + +코드는 카테고리와 재시도 가능 여부도 함께 답합니다 — `DOCUMENT_IN_USE(Category.CONFLICT, 409, +false)`. 그래서 화면이 셋을 나열하지 않아도 어느 것인지 코드로 갈립니다. + +**이 문제는 아직 완전히 안 끝났습니다** — §16.1 을 보세요. ### 13.5 편집기 칸 이름을 공개 화면과 맞췄다 (`82e992d`) @@ -1108,9 +1128,30 @@ QUESTION → 열린 질문 - `Redis 캐시` 와 `Redis 클러스터` → **둘 다 `redis`** → 두 번째가 충돌 **한글을 버리지 않고 로마자로 옮깁니다.** 음절을 초성·중성·종성으로 산술 분해하므로 표가 -필요 없고 결정적입니다: `백엔드 아키텍처` → `baekendeu-akitekcheo`. 국어의 로마자 표기법의 -**자모 대응만** 적용하고 음운 변화 규칙은 일부러 뺐습니다 — slug 는 읽는 것이지 발음하는 것이 -아니고, 그 규칙을 넣으면 같은 이름이 문맥에 따라 다른 slug 가 됩니다. +필요 없고 결정적입니다: `백엔드 아키텍처` → `baekendeu-akitekcheo`. + +```ts +function romanizeSyllable(codePoint: number): string { + if (codePoint < SYLLABLE_BASE || codePoint > SYLLABLE_LAST) { + return String.fromCodePoint(codePoint); + } + const offset = codePoint - SYLLABLE_BASE; + const initial = Math.floor(offset / (MEDIAL_COUNT * FINAL_COUNT)); + const medial = Math.floor((offset % (MEDIAL_COUNT * FINAL_COUNT)) / FINAL_COUNT); + const final = offset % FINAL_COUNT; + return `${INITIALS[initial]}${MEDIALS[medial]}${FINALS[final]}`; +} +``` + +국어의 로마자 표기법의 **자모 대응만** 적용하고 음운 변화 규칙은 일부러 뺐습니다. 함수의 +javadoc 이 그 이유와 결과 모양까지 적어 두었습니다: + +> 표기법은 국어의 로마자 표기법의 자모 대응만 쓴다 — 음운 변동(자음동화 같은 것)은 반영하지 +> 않는다. slug 는 읽히기 위한 것이지 발음을 옮기기 위한 것이 아니고, 변동 규칙을 넣으면 같은 +> 이름이 문맥에 따라 다른 slug 가 될 수 있다. +> +> 결과는 문서 slug 와 같은 모양이다 (`^[a-z0-9]+(?:-[a-z0-9]+)*$`) — 한 저장소가 두 가지 slug +> 규칙을 갖지 않도록. --- @@ -1267,6 +1308,9 @@ jpa-feed-query-performance 축 이름 「조회 전략」 축 3개 ### 15.4 배포 전 검증 (사람이 돌려야 하는 것) +`check:types` 는 tsconfig 여섯 개를 차례로 돌립니다 — app · node · test · recipes · +web-worker · service-worker. 루트 tsconfig 를 직접 부르는 명령은 그중 어느 것도 지나지 않습니다. + ```bash # 프론트 — 다섯 개를 다 돌린다. npx tsc --noEmit 은 아무것도 검사하지 않는다 npm run check:types @@ -1299,6 +1343,11 @@ python3 scripts/check-openapi.py && python3 scripts/check-consistency.py \ another record still links to this one; unlink it first ``` +막는 것은 다섯 참조 중 하나인데, 다섯이 전부 같은 오류 코드(`DOCUMENT_IN_USE`)로 나갑니다. +클라이언트에 나가는 문구는 코드마다 하나로 고정돼 있으므로(§13.4), 참조 종류를 문구로 가르려면 +코드를 먼저 갈라야 합니다. 위 영어 문장은 서버 안에 남는 진단 메시지이고 밖으로 나가지 +않습니다(`DeleteDocumentDraftUseCase`). + 실제로 막는 것은 이 중 하나입니다: ```sql diff --git a/docs/TechLog/tech-log-studio/addresses-frozen-at-publish-time/case/case-a-slug-rule-that-threw-korean-away.md b/docs/TechLog/tech-log-studio/addresses-frozen-at-publish-time/case/case-a-slug-rule-that-threw-korean-away.md index 5c12638..28dbfb3 100644 --- a/docs/TechLog/tech-log-studio/addresses-frozen-at-publish-time/case/case-a-slug-rule-that-threw-korean-away.md +++ b/docs/TechLog/tech-log-studio/addresses-frozen-at-publish-time/case/case-a-slug-rule-that-threw-korean-away.md @@ -64,7 +64,7 @@ tech-log-frontend : 5cffe30 · 7093d84 ## 간헐적으로 보인 이유 -slug 생성이 영문 소문자와 숫자만 남기고 나머지를 버렸다. 한글 이름은 통째로 사라지므로, 결과가 이름에 영문이 얼마나 섞였는지에 따라 갈린다. +slug 생성이 영문 소문자와 숫자가 아닌 것을 전부 하이픈으로 바꿨다. 한글은 전부 거기 걸리므로 이름에 섞인 영문과 숫자만 남는다. | 이름 | 옛 규칙이 만든 slug | 무엇이 일어났나 | |---|---|---| @@ -72,13 +72,28 @@ slug 생성이 영문 소문자와 숫자만 남기고 나머지를 버렸다. | `Redis 캐시` | `redis` | 만들어짐 | | `Redis 클러스터` | `redis` | 두 번째가 충돌 | -사용자는 둘 다 만났다. 어느 쪽도 「한글이 버려졌다」로 보이지 않고, 하나는 폼 오류로 하나는 중복 오류로 나타난다. +두 결과가 서로 달라 보인다. 하나는 폼 오류이고 하나는 중복 오류이며, 어느 쪽도 「한글이 버려졌다」로 읽히지 않는다. 작성자에게는 「가끔 안 되다가 이름을 바꾸면 되는」 현상이었다. > 규칙은 간헐적이었던 적이 없다. **보이지 않았을 뿐이다** — slug 생성이 `[a-z0-9]` 만 남기고 나머지를 버려서, 한글 이름은 아무것도 기여하지 못했다. ## 산술 분해로 로마자를 만든다 -한글 음절은 초성·중성·종성이 정해진 순서로 조합된 코드다. 음절 코드에서 세 값을 산술로 분해할 수 있으므로 변환표가 필요 없고, 같은 입력에 늘 같은 결과가 나온다. +한글 음절은 초성·중성·종성이 정해진 순서로 조합된 코드다. 음절 코드에서 시작 코드를 빼고 중성 수와 종성 수로 나누면 세 값이 그대로 나온다. + +```ts +function romanizeSyllable(codePoint: number): string { + if (codePoint < SYLLABLE_BASE || codePoint > SYLLABLE_LAST) { + return String.fromCodePoint(codePoint); + } + const offset = codePoint - SYLLABLE_BASE; + const initial = Math.floor(offset / (MEDIAL_COUNT * FINAL_COUNT)); + const medial = Math.floor((offset % (MEDIAL_COUNT * FINAL_COUNT)) / FINAL_COUNT); + const final = offset % FINAL_COUNT; + return `${INITIALS[initial]}${MEDIALS[medial]}${FINALS[final]}`; +} +``` + +변환표가 필요 없고 같은 입력에 늘 같은 결과가 나온다. 한글이 아닌 문자는 그대로 돌려주고 뒤의 필터가 처리한다. ```text 백엔드 아키텍처 → baekendeu-akitekcheo @@ -86,9 +101,13 @@ slug 생성이 영문 소문자와 숫자만 남기고 나머지를 버렸다. ## 음운 변화 규칙을 뺀 이유 -국어의 로마자 표기법에는 자모 대응 외에 음운 변화 규칙이 있다. 그것을 넣지 않았다. +국어의 로마자 표기법에는 자모 대응 외에 음운 변화 규칙이 있다. 그것을 넣지 않았고, 함수의 javadoc 이 이유를 적는다. -slug 는 읽는 것이지 발음하는 것이 아니다. 음운 변화를 적용하면 같은 글자가 앞뒤에 무엇이 오느냐에 따라 다르게 옮겨지고, 그러면 이름의 일부만 바뀌어도 앞쪽 slug 가 달라진다. 결정적이지 않은 slug 는 주소로 쓸 수 없다. +> 표기법은 국어의 로마자 표기법의 자모 대응만 쓴다 — 음운 변동(자음동화 같은 것)은 반영하지 않는다. slug 는 읽히기 위한 것이지 발음을 옮기기 위한 것이 아니고, 변동 규칙을 넣으면 같은 이름이 문맥에 따라 다른 slug 가 될 수 있다. + +## 문서 slug 와 같은 모양으로 맞췄다 + +결과가 문서 slug 와 같은 정규식을 만족하게 했다. 한 저장소가 두 가지 slug 규칙을 갖지 않도록 한 것이고, 그래서 주제 slug 와 문서 slug 를 같은 검사로 볼 수 있다. ## 확인하지 못한 것 diff --git a/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/case/case-the-comparison-band-changed-three-times.md b/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/case/case-the-comparison-band-changed-three-times.md index 76d45bb..cbf3361 100644 --- a/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/case/case-the-comparison-band-changed-three-times.md +++ b/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/case/case-the-comparison-band-changed-three-times.md @@ -7,9 +7,18 @@ topicName: 주제 안의 축 project: TechLog status: 게시 전 lastVerifiedOn: 2026-09-04 +assets: + - key: home-tabs-keycloak + file: ../../../final/evidence/browser/home-tabs-keycloak.png + - key: home-topic-tabs-2 + file: ../../../final/evidence/browser/home-topic-tabs-2.png + - key: home-tabs-grouped + file: ../../../final/evidence/browser/home-tabs-grouped.png evidence: - - ../../../final/evidence/browser/home-tabs-grouped.png + - ../../../final/evidence/browser/home-tabs-keycloak.png - ../../../final/evidence/browser/home-topic-tabs.png + - ../../../final/evidence/browser/home-topic-tabs-2.png + - ../../../final/evidence/browser/home-tabs-grouped.png - ../../../final/evidence/browser/tab-metrics.txt sourceRevision: tech-log@2026-09-02 source: @@ -62,23 +71,42 @@ tech-log-frontend : 604ded5 → de4cb8b → 3bb724b · 2b2f443 ## 세 단계 -1단계는 주제 하나만 펼치고 아래에 「다른 주제 N개 보기」 한 줄을 뒀다. 그 줄은 목록을 다 읽고 나서야 만나는 곳이라 대개 지나쳤다 — JPA 주제는 홈에 있으면서도 없는 것과 같았다. +1단계는 주제 하나만 펼치고 아래에 「다른 주제 N개 보기」 한 줄을 뒀다. 홈이 「무엇을 만들었나」로 시작하고 있었는데, 30초 안에 알아야 할 것은 무엇을 견줬는가였다. -2단계에서 제목 자리를 주제 이름 탭이 대신하게 했다. 30px 에 굵기 650 으로 세웠다. +그 줄은 목록을 다 읽고 나서야 만나는 곳이라 대개 지나쳤다. JPA 주제는 홈에 있으면서도 없는 것과 같았다. -3단계에서 탭을 칩 크기로 낮추고 개수 상한을 없앴다. 상한은 주제마다 상세를 미리 받느라 둔 것인데, 그러면 상한 밖의 주제가 다시 밀려난다. +2단계에서 제목 자리를 주제 이름 탭이 대신하게 했다. 30px 에 굵기 650 으로 세웠고, 고른 탭에 파란 밑줄을 뒀다. + +3단계에서 탭을 칩 크기로 낮추고 개수 상한을 없앴다. 주제가 열 개, 스무 개가 되면 이름만으로 화면이 덮이기 때문이다. + +:::evidence key="home-tabs-keycloak" alt="탭을 구역 제목 급으로 세운 2단계 화면" caption=" " zoom="true" +::: + +## 상한이 왜 있었나 + +상한은 주제마다 상세를 미리 받느라 둔 것이었다. 상세를 다 받으려면 요청이 주제 수만큼 늘어나므로 그 수를 제한해야 했다. + +그러면 상한 밖의 주제가 다시 밀려난다. 1단계에서 「다른 주제」 줄에 밀려나던 것과 같은 결과가 된다. ## 요청 구조를 바꿨다 탭 줄은 목록 호출 하나가 주는 전부다. 상세는 고른 탭만 그때 받아 캐시한다. -주제가 몇 개가 되든 홈이 처음 보내는 요청은 목록 하나와 주제 하나로 고정된다. +그래서 주제가 몇 개가 되든 홈이 처음 보내는 요청은 목록 하나와 주제 하나로 고정된다. 상한을 없앨 수 있었던 이유가 이것이고, 상한을 먼저 없애고 요청을 그대로 뒀다면 주제가 늘수록 홈이 느려졌을 것이다. ## 시각 언어를 두 번 고쳤다 -고른 탭의 파란 밑줄을 없앴다. 주제가 스무 개면 밑줄 설 곳 스무 개가 나란히 늘어선다. +고른 탭의 파란 밑줄을 없앴다. 주제가 스무 개면 밑줄 설 곳 스무 개가 함께 늘어선다. -칩으로 낮추니 목록 위에 글자만 떠 있는 것처럼 보였다. 고른 탭에 알약 형태를 주고, 묶음의 윗선을 목록이 아니라 패널이 갖게 해서 탭 줄이 그 선에 바로 얹히게 했다. +칩으로 낮추니 목록 위에 글자만 떠 있는 것처럼 보였다. 고른 것이 색으로만 달라 누를 수 있는 것으로 읽히지 않았고, 탭 줄과 목록 사이가 선 없이 30px 비어 두 덩어리로 갈렸다. + +:::evidence key="home-topic-tabs-2" alt="칩으로 낮춘 직후의 비교 구역 확대" caption=" " zoom="true" +::: + +고른 탭에 알약 형태를 주고, 묶음의 윗선을 목록이 아니라 패널이 갖게 해서 탭 줄이 그 선에 바로 얹히게 했다. + +:::evidence key="home-tabs-grouped" alt="고른 탭에 형태를 주고 탭 줄을 패널 윗선에 얹은 최종 화면" caption=" " zoom="true" +::: ## 확인하지 못한 것 diff --git a/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/concept/concept-topic-variant-and-record-variant.md b/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/concept/concept-topic-variant-and-record-variant.md index d63d954..1209ec3 100644 --- a/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/concept/concept-topic-variant-and-record-variant.md +++ b/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/concept/concept-topic-variant-and-record-variant.md @@ -50,23 +50,29 @@ topic (주제) ## 축 이름은 주제가 정한다 -내부 이름은 축으로 고정하고, 화면에 보이는 이름은 주제가 자기 칸에 적는다. 인증 경계 주제는 「구조」, 조회 성능 주제는 「조회 전략」이다. +내부 이름은 축으로 고정하고, 화면에 보이는 이름은 주제가 자기 칸에 적는다. + +주제마다 비교하는 것이 다르기 때문이다. 인증 경계 주제는 credential 을 어디에 두느냐로 갈리므로 「구조」이고, 조회 성능 주제는 같은 데이터를 어떻게 읽느냐로 갈리므로 「조회 전략」이다. 이름을 한 값으로 고정하면 둘 중 하나에서 어긋난다. ## 기록은 여러 축에 걸린다 한 기록이 여러 축에 걸릴 수 있다. PKCE 는 SPA 와 BFF 양쪽에 관계된다. -아무 축에도 걸리지 않은 기록은 그 주제의 공통 기록으로 읽는다. 「공통」이라는 축을 따로 만들지 않는다. +아무 축에도 걸리지 않은 기록은 그 주제의 공통 기록으로 읽는다. 「공통」이라는 축을 따로 만들지 않는 이유는, 만들면 그 축이 비교 화면에 한 줄로 서서 다른 축들과 견주는 것처럼 보이기 때문이다. ## 외래키가 없다 -`record_variant` 는 외래키를 갖지 않는다. 기록이 종류마다 다른 테이블에 살기 때문이다 — 문서·열린 질문·프로젝트 결정이 각각 다른 테이블이다. 종류와 아이디의 쌍으로만 가리킨다. +기록이 어느 축에 걸리는지를 담는 표는 외래키를 갖지 않는다. 기록이 종류마다 다른 테이블에 살기 때문이다 — 문서·열린 질문·프로젝트 결정이 각각 다른 테이블이고, 하나의 외래키로 셋을 함께 가리킬 수 없다. -검증 상태와 게시 기록이 이미 같은 방식으로 기록을 가리키고 있었다. +그래서 종류와 아이디의 쌍으로만 가리킨다. 이 방식은 이 저장소에서 처음 쓰는 것이 아니고, 검증 상태와 게시 기록이 이미 같은 방식으로 기록을 가리키고 있었다. + +대가는 데이터베이스가 참조 무결성을 지켜 주지 않는다는 것이다. 기록을 지울 때 그 쌍을 함께 지우는 것은 코드가 한다. ## 사람이 쓰는 칸 -주제의 논지, 축의 요약과 결론은 기록을 합쳐 자동으로 나오는 글이 아니다. 특히 결론은 비교표가 읽는 칸이라 기록의 요약 첫 줄을 잘라 쓰면 안 된다. +주제의 논지, 축의 요약과 결론은 기록을 합쳐 자동으로 나오는 글이 아니다. + +특히 결론은 비교표가 읽는 칸이라 기록의 요약 첫 줄을 잘라 쓰면 안 된다. 요약은 그 축이 무엇인지 말하고 결론은 그 축에서 무엇을 알게 됐는지 말하므로, 둘을 같은 문장으로 채우면 비교표가 아무것도 비교하지 않는다. ## 같은 구조가 다르게 보일 때 @@ -86,6 +92,6 @@ jpa-feed-query-performance 축 이름 「조회 전략」 축 3개 fetch-join-paging ← CASE 1 ``` -축마다 기록이 하나씩이고 축 제목을 그 기록 제목과 비슷하게 적으면 「문서가 그대로 나온다」로 보인다. +축마다 기록이 하나씩이고 축 제목을 그 기록 제목과 비슷하게 적으면 「문서가 그대로 나온다」로 보인다. 구조 차이가 아니라 내용 양의 차이다. diff --git a/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/decision/decision-an-axis-inside-a-topic-not-four-topics.md b/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/decision/decision-an-axis-inside-a-topic-not-four-topics.md index c5b9cbe..48ea786 100644 --- a/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/decision/decision-an-axis-inside-a-topic-not-four-topics.md +++ b/docs/TechLog/tech-log-studio/an-axis-inside-a-topic/decision/decision-an-axis-inside-a-topic-not-four-topics.md @@ -32,24 +32,26 @@ source: ## 결정문 -한 질문에 여러 구조를 만들어 비교하는 경우, 주제를 그 수만큼 쪼개지 않고 주제 안에 축을 하나 둔다. 축의 이름은 주제가 정하고, 기록은 여러 축에 걸릴 수 있으며, 아무 축에도 걸리지 않은 기록은 그 주제의 공통 기록으로 읽는다. +한 질문에 여러 구조를 만들어 비교하는 경우, 주제를 그 수만큼 쪼개지 않고 주제 안에 축을 하나 둔다. + +축의 이름은 주제가 정하고, 기록은 여러 축에 걸릴 수 있으며, 아무 축에도 걸리지 않은 기록은 그 주제의 공통 기록으로 읽는다. ## 판단 이유 -주제를 넷으로 쪼개면 PKCE·CSRF·Authorization Code 처럼 네 구조가 함께 쓰는 기록을 어디에 둘지 애매해진다. 어느 한 주제에 넣으면 나머지 셋에서 그 기록에 닿을 수 없고, 넷에 복사하면 같은 글이 넷이 된다. +주제를 넷으로 쪼개면 네 구조가 함께 쓰는 기록을 어디에 둘지 애매해진다. PKCE·CSRF·Authorization Code 가 그런 기록이다. 어느 한 주제에 넣으면 나머지 셋에서 그 기록에 닿을 수 없고, 넷에 복사하면 같은 글이 넷이 된다. -네 주제가 나란히 서면 그것이 같은 질문의 네 답이라는 것을 화면이 말하지 못해 비교도 어려워진다. +비교도 어려워진다. 네 주제가 나란히 서면 그것이 같은 질문의 네 답이라는 것을 화면이 말하지 못하고, 독자는 목록에서 넷을 각각 열어 봐야 한다. 축을 주제 안에 두면 공통 기록은 축을 고르지 않고 두면 되고, 여러 구조에 걸치는 기록은 여러 축에 건다. 화면은 축을 나란히 세워 비교로 그린다. -축 이름을 주제가 정하게 한 것은 주제마다 비교 축이 다르기 때문이다. 인증 경계 주제의 축은 구조이고 조회 성능 주제의 축은 조회 전략이다. +축 이름을 주제가 정하게 한 것은 주제마다 비교하는 것이 다르기 때문이다. 인증 경계 주제는 credential 을 어디에 두느냐로 갈리고 조회 성능 주제는 같은 데이터를 어떻게 읽느냐로 갈린다. ## 영향 -주제의 논지와 축의 이름·요약·결론은 기록에서 자동으로 나오지 않는다. 사람이 쓰는 칸이라 기록을 스무 개 붙여도 그 문장은 누가 고치기 전까지 바뀌지 않는다. +축의 이름·요약·결론이 기록에서 자동으로 나오지 않는다. 주제의 논지와 축의 요약·결론은 사람이 쓰는 칸이고, 기록을 스무 개 붙여도 그 문장은 누가 고치기 전까지 그대로다. 홈의 비교 구역에서 줄은 문서가 아니라 축이다. 줄을 늘리려면 Studio 에서 축을 추가해야 한다. -기록이 어느 축에 걸리는지를 담는 표에 외래키를 걸 수 없다. 기록이 종류마다 다른 테이블에 살기 때문이다. +기록이 어느 축에 걸리는지를 담는 표에 외래키를 걸 수 없다. 기록이 종류마다 다른 테이블에 살기 때문이고, 그래서 기록을 지울 때 그 쌍을 함께 지우는 것은 코드가 한다. -축에 걸린 기록이 하나뿐이면 축 제목과 그 기록 제목이 비슷해져 「문서가 그대로 나온다」로 보인다. 구조 차이가 아니라 내용 양의 차이다. +축이 붙은 기록 수가 적으면 「문서가 그대로 나온다」로 보인다. 축마다 기록이 하나씩이고 축 제목을 그 기록 제목과 비슷하게 적으면 그렇게 읽힌다. 구조 차이가 아니라 내용 양의 차이다. diff --git a/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-an-error-message-that-guessed.md b/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-an-error-message-that-guessed.md index 64ee4eb..d37db13 100644 --- a/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-an-error-message-that-guessed.md +++ b/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-an-error-message-that-guessed.md @@ -57,22 +57,51 @@ tech-log-backend : 857e6a9 — 삭제 거절 사유를 클라이언트 안전 ## 화면이 세 가지를 추측했다 -화면 문구는 「게시됐거나, 참조하는 곳이 있거나, 누가 먼저 고쳤을 수 있습니다」였다. 세 가지 원인을 나열하고 어느 것인지는 말하지 않는다. +작업본 삭제가 실패하면 화면이 「게시됐거나, 참조하는 곳이 있거나, 누가 먼저 고쳤을 수 있습니다」를 적었다. 세 가지 원인을 나열하고 어느 것인지는 말하지 않는다. 서버는 하나를 답하고 있었다. 게이트웨이가 그 답을 버리고 화면이 자기 목록을 그렸다. +## 서버는 코드로 답한다 + +서버는 오류 코드마다 고정 문구를 갖고 있다. 삭제와 관련된 것만 여섯이다. + +```java +case VERSION_CONFLICT -> "다른 곳에서 먼저 수정되었습니다. 새로 불러온 뒤 다시 시도해 주세요"; +case DOCUMENT_PUBLISHED -> "공개된 기록은 삭제할 수 없습니다. 먼저 공개를 취소해 주세요"; +case DOCUMENT_IN_USE -> "이 기록을 참조하는 곳이 있어 삭제할 수 없습니다"; +case QUESTION_IN_USE -> "이 질문을 참조하는 곳이 있어 삭제할 수 없습니다"; +case DECISION_IN_USE -> "이 결정을 참조하는 곳이 있어 삭제할 수 없습니다"; +case TOPIC_IN_USE -> "이 주제를 쓰는 기록이 있어 삭제할 수 없습니다"; +``` + +화면이 추측하던 셋이 이 중 셋에 그대로 있다. 코드는 카테고리와 재시도 가능 여부도 함께 답한다. + +## 왜 원문 메시지를 안 내보내나 + +고정 문구를 두는 이유가 그 클래스의 javadoc 에 있다. + +> code 별 고정 문구. 예외의 원문 메시지는 진단용이라 그대로 내보내지 않는다 — 저장소 제약 이름이나 SQL 조각이 새어 나갈 수 있고, 그건 클라이언트가 분기할 값도 아니다. + +그래서 화면이 실어 나를 수 있는 것은 이 고정 문구다. 서버 안의 진단 메시지는 서버 로그에만 남는다. + ## 무엇이 구분되지 않았나 -버전 충돌은 「누가 먼저 고쳤다」이고 참조 존재는 「사용 중」이다. 문구가 셋을 한꺼번에 적으므로 작성자는 둘을 구분할 수 없다. +세 원인은 해야 할 일이 다르다. -버전 충돌이면 다시 받아서 지우면 되고, 참조가 있으면 그 참조를 먼저 풀어야 한다. +| 무엇이 막았나 | 작성자가 할 일 | +|---|---| +| 버전 충돌 | 다시 받아서 지운다 | +| 참조가 있음 | 그 참조를 먼저 푼다 | +| 이미 게시됨 | 게시를 취소한다 | -## 서버의 답을 실어 나른다 +문구가 셋을 함께 적으므로 작성자는 어느 것인지 모른 채 세 가지를 다 시도하게 된다. 어떤 삭제는 되고 어떤 삭제는 안 되는 것을 지켜보면서도 둘을 구분할 방법이 없었다. -게이트웨이가 서버의 클라이언트 안전 메시지를 그대로 싣고 화면이 그것을 보인다. +## 고친 것 + +게이트웨이가 서버의 클라이언트 안전 메시지를 그대로 싣고 화면이 그것을 보인다. 서버가 답하지 않은 것을 화면이 만들지 않는다. ## 확인하지 못한 것 -서버가 답하는 그 한 문장이 다섯 이유를 다 같은 말로 덮고 있다. 참조 검사가 다섯 테이블을 하나로 묶어 검사하기 때문이고, 그 문제는 아직 열려 있다. +코드 하나에 문구 하나라는 구조는 참조가 어느 표에서 왔는지까지는 말하지 못한다. 다섯 참조가 전부 같은 코드로 나가므로, 그 안에서 어느 것이 막았는지는 아직 열려 있다. diff --git a/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-nine-names-for-five-kinds.md b/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-nine-names-for-five-kinds.md index 7e729da..41ebff6 100644 --- a/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-nine-names-for-five-kinds.md +++ b/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-nine-names-for-five-kinds.md @@ -67,9 +67,9 @@ tech-log-frontend : dc2fda7 · ca1fc92 · 82e992d 바로 아래 「종류별로 읽기」: 검증 기록 · 동작 원리 · 적용 기준 · 열린 질문 ``` -두 목록이 세로로 붙어 있다. 위는 계약의 enum 이름을, 아래는 사람이 붙인 이름을 쓴다. +두 목록이 세로로 붙어 있다. 위는 계약의 enum 이름을, 아래는 사람이 붙인 이름을 쓴다. 독자는 둘이 같은 것이라는 단서를 어디서도 받지 못했다. -이 화면은 이름을 바꾸기 전보다 나빠졌다. 바꾸기 전에는 양쪽이 다 enum 이름이라 적어도 같아 보였다. +이름을 바꾸기 전에는 양쪽이 다 enum 이름이었으므로 적어도 같아 보였다. 이 화면은 이름을 바꾸면서 나빠졌다. ## 표가 여섯 벌이었다 @@ -77,9 +77,17 @@ tech-log-frontend : dc2fda7 · ca1fc92 · 82e992d > 표가 화면마다 복사되어 **여섯 벌**이었고 그래서 갈라졌다: 같은 QUESTION 이 공개 화면에서 "Open Question", 작업본 목록과 게시 기록에서 "Question", 편집기 상태 줄에서 "QUESTION" 이었다. **쓰는 사람은 같은 문서를 화면마다 다른 이름으로 만난다.** +여섯 벌이 동시에 틀린 것이 아니다. 이름을 바꿀 때 그중 일부만 고쳤고, 어느 것을 고쳤는지가 화면마다 달랐다. + ## 표 하나로 모았다 -종류에서 표시 이름으로 가는 표를 하나 만들고 여섯 곳이 그것을 쓰게 했다. 종류가 늘면 그 표에서 빠진 값을 컴파일러가 잡는다. +종류에서 표시 이름으로 가는 표를 하나 만들고 여섯 곳이 그것을 쓰게 했다. 그 표의 javadoc 이 왜 한 곳에 있는지를 적는다. + +> 한 곳에 두면 다음에 종류가 늘어날 때도 한 번만 고친다. 종류를 더하면 이 표가 비어 있는 것을 타입이 잡는다 — `Record` 이므로 빠진 종류가 있으면 컴파일되지 않는다. + +같은 파일에 표가 하나 더 있다. 다섯 종류를 셋으로 접어 지식의 상태로 만드는 표다. + +> 독자가 실제로 구분해야 하는 것은 지식의 상태다. 다섯 종류를 셋으로 접는다 — 확인한 것, 정리한 것, 아직 모르는 것. 목록에서 미해결만 눈에 띄게 하는 것이 이 표의 쓰임이다. 미해결이 이 기록의 가장 정직한 신호인데 다섯 종류가 같은 회색 11px 로 나오면 그것이 가장 안 보인다. ## 편집기 칸 이름도 맞췄다 @@ -96,6 +104,6 @@ tech-log-frontend : dc2fda7 · ca1fc92 · 82e992d ## 확인하지 못한 것 -이름을 바꾸기 전보다 나빠진 화면이 홈 하나였다는 것은 화면으로 확인했다. 다른 화면에서 두 이름이 같이 뜨는 곳을 전수로 세지는 않았다. +이름을 바꾸기 전보다 나빠진 화면이 홈이라는 것은 화면으로 확인했다. 다른 화면에서 두 이름이 같이 뜨는 곳을 전수로 세지는 않았다. diff --git a/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-renaming-the-kinds-twice.md b/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-renaming-the-kinds-twice.md index 9191e6c..e05996a 100644 --- a/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-renaming-the-kinds-twice.md +++ b/docs/TechLog/tech-log-studio/one-thing-many-names/case/case-renaming-the-kinds-twice.md @@ -62,7 +62,7 @@ tech-log-frontend : a6413d0 → af5a6bb Case, Reference, Open Question 은 그 글을 어떤 형식에 담았는지를 말한다. 그 글이 독자에게 무엇을 주는지는 말하지 않는다. -독자는 그 말을 먼저 배워야 목록을 읽을 수 있었다. 뜻풀이는 홈 바닥 2,000px 아래에 있었다. +독자는 그 말을 먼저 배워야 목록을 읽을 수 있었고, 뜻풀이는 홈 바닥 2,000px 아래에 있었다. 목록을 훑는 사람이 거기까지 내려가지 않는다. ## 1차 — 하는 일을 말하게 했다 @@ -72,9 +72,11 @@ Question → 아직 모르는 것 Concept → 어떻게 동작하나 Decision → 이렇게 하기로 ``` +이름만 읽어도 그 글이 무엇을 주는지 알 수 있다. 뜻풀이를 찾아 내려갈 이유가 없어진다. + ## 2차 — 문어체로 다시 세웠다 -1차 안이 기술 기록의 톤에 비해 가벼웠다. 역할은 그대로 말하되 문어체로 바꿨다. +**그런데 이게 기술 기록의 톤에 비해 가벼웠다.** 역할은 그대로 말하되 문어체로 바꿨다. ```text CASE → 검증 기록 CONCEPT → 동작 원리 @@ -82,9 +84,13 @@ REFERENCE → 적용 기준 DECISION → 설계 결정 QUESTION → 열린 질문 ``` +두 안이 말하는 것은 같다. 「직접 해보니」와 「검증 기록」은 둘 다 그 글이 재현한 결과라고 말한다. 갈린 것은 이 사이트의 다른 글들이 쓰는 어조와 맞느냐다. + ## 계약의 kind 는 그대로 뒀다 -바꾼 것은 화면에 보이는 이름이다. 계약의 `RecordKind` 는 다섯 값 그대로이고 주소도 바뀌지 않았다. +바꾼 것은 화면에 보이는 이름이다. 계약의 `RecordKind` 는 다섯 값 그대로이고 주소도 그대로다. + +표시 이름과 계약 값을 갈라 두었기 때문에 두 번 바꾸면서 계약을 한 번도 건드리지 않았다. 계약을 바꿨다면 반입한 두 저장소가 함께 움직여야 했고, 이미 게시된 주소도 함께 흔들렸을 것이다. ## 확인하지 못한 것 diff --git a/docs/TechLog/tech-log-studio/one-thing-many-names/reference/reference-ask-which-words-to-use.md b/docs/TechLog/tech-log-studio/one-thing-many-names/reference/reference-ask-which-words-to-use.md index 55b8e8e..1dcc2ad 100644 --- a/docs/TechLog/tech-log-studio/one-thing-many-names/reference/reference-ask-which-words-to-use.md +++ b/docs/TechLog/tech-log-studio/one-thing-many-names/reference/reference-ask-which-words-to-use.md @@ -29,19 +29,25 @@ source: 작성자의 목소리로 쓰인 글을 고쳐 쓰다 두 번 거절당하는 것을 막는다. +톤을 지적할 때 사용자가 가리키는 것은 문장의 품질이 아니라 그 말을 누가 쓰는가다. 「더 나은 문장」을 제안할 때와 그 사람의 말투로 쓸 때 필요한 것이 다르고, 후자는 제안하는 쪽이 잘하지 못한다. + ## 규칙 ### 1. 톤을 지적받으면 고쳐 쓰기 전에 어떤 말을 쓸지 묻는다 -「더 나은 문장」을 제안하는 것과 그 사람의 말투로 쓰는 것은 다른 일이고, 후자는 제안하는 쪽이 잘하지 못한다. +고쳐 쓴 안을 내면 그것도 같은 이유로 거절될 수 있다. 실제로 첫 번째 안이 거절당했고, 결국 사용자가 직접 쓴 텍스트를 그대로 실었다. ### 2. 무엇이 AI 스러운지 구체적으로 받아 적는다 -무엇을 하는지 말하지 않는 동사로 끝나는 것과 번역투가 실제로 지적된 두 가지였다. +지적이 「AI 스럽다」로 끝나면 무엇을 고칠지 알 수 없다. 이 저장소에서 받은 지적은 두 갈래였다 — 무엇을 하는지 말하지 않는 동사로 끝나는 것(「섞는다」·「함께 기록한다」·「흩어지지 않게」)과 번역투(「결론이 서는 조건」·「프로젝트를 답니다」·「접근을 나눠 견주고」). ### 3. 작성자가 이미 쓰는 말투를 따른다 -Case 소제목에 쓰는 말이 「~한 것」 명사형이면 새 제목도 그 형태로 맞춘다. 의문형 꼬리와 이 기록에서 쓰지 않는 낱말은 쓰지 않는다. +새 문구를 만들 때 기존 글에 없던 어미나 낱말을 들이지 않는다. 이 저장소의 Case 소제목은 「이 구조에서 감수한 것」처럼 「~한 것」 명사형이라, 의문형 꼬리를 단 「무엇을 견줬나」는 그 소제목들과 나란히 서지 못했다. + +### 4. 고친 결과를 전후로 함께 적는다 + +무엇이 무엇으로 바뀌었는지 남겨 두면 다음에 같은 문구를 고칠 때 방향이 정해진다. ## 적용 조건 @@ -52,17 +58,12 @@ Case 소제목에 쓰는 말이 「~한 것」 명사형이면 새 제목도 그 ## 예외 - 오류 문구처럼 서버가 답한 사실을 그대로 실어야 하는 곳에서는 말투를 묻지 않는다. 무엇을 실을지를 먼저 정한다. - -- 계약이나 코드가 정한 이름은 이 규칙에서 뺀다. 표시 이름만 바꾸고 계약 값은 건드리지 않는다. +- 계약이나 코드가 정한 이름은 이 규칙에서 뺀다. 표시 이름만 바꾸고 계약 값은 그대로 둔다. ## 예시 -- 「섞는다」·「함께 기록한다」·「흩어지지 않게」가 무엇을 하는지 말하지 않는 동사로 끝난다고 지적받았다. - -- 「결론이 서는 조건」·「프로젝트를 답니다」·「접근을 나눠 견주고」가 번역투로 지적받았다. - -- 「무엇을 견줬나」는 의문형 꼬리에 이 기록에서 쓰지 않는 낱말이었다. 작성자가 Case 소제목에 쓰는 말은 「이 구조에서 감수한 것」처럼 「~한 것」 명사형이라 그쪽에 맞췄다. - -- 「이 프로젝트가 밝힌 것」은 「프로젝트를 통해 확인한 결과」로, 「운영 가능한 설계로 연결합니다」는 「실제 운영에 적용할 수 있는 형태로 정리합니다」로 바꿨다. - -- 고쳐 쓴 첫 번째 안이 거절당한 뒤 사용자가 직접 쓴 텍스트를 실었다. \ No newline at end of file +- 「섞는다」·「함께 기록한다」·「흩어지지 않게」가 무엇을 하는지 말하지 않는 동사로 끝난다고 지적받았다 +- 「결론이 서는 조건」·「프로젝트를 답니다」·「접근을 나눠 견주고」가 번역투로 지적받았다 +- 「무엇을 견줬나」는 의문형 꼬리에 이 기록에서 쓰지 않는 낱말이었다. 작성자가 Case 소제목에 쓰는 말은 「~한 것」 명사형이라 그쪽에 맞췄다 +- 「이 프로젝트가 밝힌 것」을 「프로젝트를 통해 확인한 결과」로 바꿨다 +- 「운영 가능한 설계로 연결합니다」를 「실제 운영에 적용할 수 있는 형태로 정리합니다」로 바꿨다 diff --git a/docs/TechLog/tech-log-studio/tech-log-tree.json b/docs/TechLog/tech-log-studio/tech-log-tree.json index 3155b3f..0987dbe 100644 --- a/docs/TechLog/tech-log-studio/tech-log-tree.json +++ b/docs/TechLog/tech-log-studio/tech-log-tree.json @@ -976,7 +976,8 @@ "evidenceFiles": [ "../../../final/evidence/raw/db/decision-path-after-v15.txt", "../../../final/evidence/raw/api/decision-anchor-fixed.txt", - "../../../final/evidence/raw/audit/dead-link-sweep.txt" + "../../../final/evidence/raw/audit/dead-link-sweep.txt", + "../../../final/evidence/raw/audit/link-audit.py" ] }, { @@ -1682,11 +1683,21 @@ "file": "an-axis-inside-a-topic/case/case-the-comparison-band-changed-three-times.md", "status": "게시 전", "studioId": "", - "assets": [], - "assetFiles": [], + "assets": [ + "home-tabs-keycloak", + "home-topic-tabs-2", + "home-tabs-grouped" + ], + "assetFiles": [ + "home-tabs-keycloak.png", + "home-topic-tabs-2.png", + "home-tabs-grouped.png" + ], "evidenceFiles": [ - "../../../final/evidence/browser/home-tabs-grouped.png", + "../../../final/evidence/browser/home-tabs-keycloak.png", "../../../final/evidence/browser/home-topic-tabs.png", + "../../../final/evidence/browser/home-topic-tabs-2.png", + "../../../final/evidence/browser/home-tabs-grouped.png", "../../../final/evidence/browser/tab-metrics.txt" ] } @@ -3018,5 +3029,5 @@ "unlisted": 0, "candidates": 91 }, - "ssotSha256": "4f2c6b31f152a7d786e76d8efda5fe27c056ff685a031ba8b772c9595e7d03ad" + "ssotSha256": "6fbb5ffd943df5a6ce53624997f9ebc5b3c80de9c0adf17f62af951f8e55488d" } diff --git a/docs/TechLog/tech-log-studio/what-the-compiler-lets-through/case/case-the-typecheck-command-checked-no-files.md b/docs/TechLog/tech-log-studio/what-the-compiler-lets-through/case/case-the-typecheck-command-checked-no-files.md index 15ba96a..ae28297 100644 --- a/docs/TechLog/tech-log-studio/what-the-compiler-lets-through/case/case-the-typecheck-command-checked-no-files.md +++ b/docs/TechLog/tech-log-studio/what-the-compiler-lets-through/case/case-the-typecheck-command-checked-no-files.md @@ -64,17 +64,32 @@ tsconfig : 루트가 project references 만 나열 이 저장소의 루트 tsconfig 는 컴파일 대상을 갖지 않는다. `"files": []` 에 project references 만 나열하고, 각 프로젝트는 자기 tsconfig 를 갖는다. -`npx tsc --noEmit` 은 references 를 따라가지 않는다. 루트가 지목한 파일 집합만 보고, 그 집합이 비어 있으므로 아무것도 검사하지 않은 채 0 으로 끝난다. references 를 따라가려면 그 모드로 부르는 별도 명령이 필요하다. +`npx tsc --noEmit` 은 references 를 따라가지 않는다. 루트가 지목한 파일 집합만 보고, 그 집합이 비어 있으므로 아무것도 검사하지 않은 채 0 으로 끝난다. + +## 실제 검사는 여섯 번 돈다 + +`check:types` 는 tsconfig 여섯 개를 차례로 돌린다. + +| tsconfig | 무엇을 검사하나 | +|---|---| +| app | 애플리케이션 소스 | +| node | 빌드·스크립트 | +| test | 테스트 | +| recipes | 선택 레시피 | +| web-worker | 웹 워커 | +| service-worker | 서비스 워커 | + +여섯을 따로 두는 이유는 각각 다른 런타임 타입 정의를 쓰기 때문이다. 워커는 DOM 을 갖지 않고 node 는 브라우저 전역을 갖지 않는다. ## 통과가 무엇을 뜻했나 -이 명령이 성공했을 때 확인된 것은 「루트 tsconfig 가 유효하다」까지다. 코드가 컴파일되는지는 묻지 않았다. +짧은 명령이 성공했을 때 확인된 것은 「루트 tsconfig 가 유효하다」까지다. 코드가 컴파일되는지는 묻지 않았다. 운영에서 릴리즈 목록 화면이 비었고 콘솔에 `ReferenceError` 가 났다. 링크 컴포넌트 import 가 빠졌고, 이동 함수는 정의된 적이 없었다. 둘 다 컴파일이 잡는 종류의 오류인데 컴파일이 돌지 않았다. ## 올바른 명령으로 돌렸을 때 -여섯 프로젝트를 각각 돌리는 명령으로 바꾸자 릴리즈 목록의 두 오류에 더해 네 가지가 함께 나왔다. +여섯을 다 돌리자 릴리즈 목록의 두 오류에 더해 네 가지가 함께 나왔다. | 무엇이 나왔나 | 어떤 종류인가 | |---|---| diff --git a/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/case/case-the-guard-worked-and-i-did-not-run-it.md b/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/case/case-the-guard-worked-and-i-did-not-run-it.md index e2ad597..d153cf9 100644 --- a/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/case/case-the-guard-worked-and-i-did-not-run-it.md +++ b/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/case/case-the-guard-worked-and-i-did-not-run-it.md @@ -64,22 +64,29 @@ tech-log-frontend : fd73bc8 · fe6b56a > 화면 테스트는 `test:unit` 이 아니라 `test:tech-log` 가 돌린다. 그것을 돌리지 않아 위 두 결함과, 의도한 변경에 고정돼 있던 단언들이 **23건 빨간 채로 여러 커밋을 지나갔다.** -23건 중에는 실제 결함을 잡은 것도 있고 의도한 변경에 고정된 단언도 있었다. 둘을 구분하려면 그 명령을 돌려야 하는데, 돌리지 않으니 둘 다 그대로 남았다. +23건이 한 종류가 아니었다는 것이 문제를 키웠다. 일부는 실제 결함을 잡은 것이고 일부는 의도한 변경에 단언이 고정돼 있던 것이다. 둘을 구분하려면 그 명령을 돌려 하나씩 봐야 하는데, 돌리지 않으니 둘 다 그대로 남았다. ## 게이트 기준값을 빠뜨렸다 -주제 화면 셋을 더하면서 CI 게이트가 요구하는 기준값 셋을 올리지 않았다. 게이트는 정확히 그것을 거절한다. +주제 화면 셋을 더할 때 CI 게이트가 요구하는 기준값 셋을 함께 올리지 않았다. 게이트는 라우트 집합과 증거 집합이 정확히 일치하기를 요구하므로 그 상태를 정확히 거절한다. -게이트가 빨간 채로 여러 커밋을 지나갔고, 결정 링크 404 를 고치던 커밋에서야 맞췄다. +게이트가 빨간 채로 여러 커밋을 지나갔고, 결정 링크 404 를 고치던 커밋에서야 함께 맞췄다. ## 가드가 아니라 실행이 빠졌다 -두 번 다 가드는 정확했다. 화면 테스트는 실제 결함을 잡았고 게이트는 기준값이 어긋난 것을 정확히 거절했다. +두 번 다 가드는 정확했다. + +| | 가드가 있었나 | 가드가 잡았나 | 무엇이 빠졌나 | +|---|---|---|---| +| 화면 테스트 23건 | o | o | 그 명령을 돌리지 않음 | +| CI 게이트 기준값 | o | o | 결과를 보지 않음 | + +가드가 없어서 샌 것이 아니라 결과를 아무도 읽지 않아서 샜다. 그래서 가드를 하나 더 넣는 것으로는 같은 일이 다시 난다. > **가드는 CI 에 묶여야 의미가 있습니다.** 사람이 기억해서 돌리는 가드는 절반만 존재합니다. ## 확인하지 못한 것 -다섯 명령을 CI 에 묶는 작업은 하지 않았다. 메모리와 배포 전 검증 목록으로만 남겨 뒀다. +다섯 명령을 CI 에 묶는 작업은 하지 않았다. 지금 남은 것은 메모리와 배포 전 검증 목록이고, 그 목록을 읽는 것도 사람이다. diff --git a/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-revert-the-defect-and-watch-the-guard-fail.md b/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-revert-the-defect-and-watch-the-guard-fail.md index 1357411..c7da1f9 100644 --- a/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-revert-the-defect-and-watch-the-guard-fail.md +++ b/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-revert-the-defect-and-watch-the-guard-fail.md @@ -31,17 +31,21 @@ source: ## 목적 -무엇도 잡지 못하는 가드가 초록불로 남는 것을 막는다. 이 상태는 가드가 있는 것과 화면에서 구분되지 않는다. +무엇도 잡지 못하는 가드가 초록불로 남는 것을 막는다. + +가드를 넣었다는 것과 그 가드가 무엇을 잡는다는 것은 다르다. 둘은 화면에서 구분되지 않는다 — 검사가 통과했을 때 그 결함이 원래 없었는지 검사가 그것을 안 보는지 알 방법이 없다. ## 규칙 ### 1. 결함을 되돌려 그 가드가 실제로 멈추는 것을 확인한 뒤 커밋한다 -계약에서 값을 빼고 대조 검사가 빨개지는지 본다. 매핑을 떼어 보고 그 연산 하나를 짚는지 본다. +계약에서 값을 빼고 대조 검사가 빨개지는지 본다. 매핑을 떼어 보고 그 연산을 짚는지 본다. 굵기 선언을 빼고 제목 급 검사가 멈추는지 본다. + +되돌리는 것이 어려우면 그 가드가 무엇을 전제하는지 다시 본다. 되돌릴 수 없는 상태를 잡는 가드는 그 상태가 어떻게 생기는지를 아무도 모른다는 뜻이다. ### 2. 가드가 짚는 대상이 하나인지 본다 -전부를 짚으면 어디가 문제인지 알 수 없고, 결과가 곧 읽히지 않는다. +전부를 짚으면 어디가 문제인지 알 수 없고, 결과가 곧 읽히지 않는다. 매핑 하나를 떼었을 때 그 연산 하나만 나와야 한다. ### 3. 되돌릴 수 없는 것은 현재 상태를 대신 증거로 남긴다 @@ -49,7 +53,7 @@ source: ### 4. 가드를 CI 에 묶는다 -사람이 기억해서 돌리는 가드는 절반만 존재한다. +사람이 기억해서 돌리는 가드는 절반만 존재한다. 가드가 정확해도 결과를 아무도 읽지 않으면 빨간 채로 여러 커밋을 지나간다. ## 적용 조건 @@ -59,16 +63,12 @@ source: ## 예외 -- 결함을 되돌릴 수 없는 것 — 이미 마이그레이션으로 고친 데이터, 지난 배포에서만 나던 상태 — 은 현재 상태가 고쳐져 있음을 증거로 남긴다. - +- 결함을 되돌릴 수 없는 것 — 이미 마이그레이션으로 고친 데이터, 지난 배포에서만 나던 상태 — 은 현재 상태가 고쳐져 있음을 대신 증거로 남긴다. - 기존 가드를 옮기거나 이름만 바꾸는 변경은 되돌려 확인하지 않아도 된다. 다만 옮긴 뒤에 한 번은 돌린다. ## 예시 -- 가드 셋을 각각 결함으로 되돌려 실제로 빨개지는 것을 확인한 기록을 남겼다. - -- 계약에서 CONCEPT 을 빼자 백엔드의 계약 대조 테스트가 빨개졌다. - -- 매핑을 떼어 보고 계약 대조 테스트가 그 연산 하나를 정확히 짚는 것을 확인했다. - -- 굵기 선언을 빼 보고 제목 급 검사가 실제로 멈추는 것을 확인했다. \ No newline at end of file +- 가드 셋을 각각 결함으로 되돌려 실제로 빨개지는 것을 확인한 기록을 남겼다 +- 계약에서 CONCEPT 을 빼자 백엔드의 계약 대조 테스트가 빨개졌다 +- 매핑을 떼어 보고 계약 대조 테스트가 그 연산 하나를 정확히 짚는 것을 확인했다 +- 굵기 선언을 빼 보고 제목 급 검사가 실제로 멈추는 것을 확인했다 diff --git a/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-what-a-person-must-run-before-deploying.md b/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-what-a-person-must-run-before-deploying.md index 0915b61..68b915e 100644 --- a/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-what-a-person-must-run-before-deploying.md +++ b/docs/TechLog/tech-log-studio/when-a-guard-can-be-trusted/reference/reference-what-a-person-must-run-before-deploying.md @@ -31,26 +31,32 @@ CI 에 묶이지 않은 검증이 남아 있으면 그것을 돌리는 것은 ## 목적 -배포 전에 돌려야 하는 것을 사람이 기억에 의존해 고르는 것을 막는다. 두 번 빠뜨려 결함이 배포까지 갔다. +배포 전에 돌려야 하는 것을 사람이 기억에 의존해 고르는 것을 막는다. + +이 저장소에서 두 번 빠뜨려 결함이 배포까지 갔다. 명령이 여럿이고 그중 일부만 도는 것이 가능한 구조에서는 「돌렸다」가 무엇을 돌렸다는 뜻인지 정해 두어야 한다. ## 규칙 ### 1. 프론트는 다섯 개를 다 돌린다 -타입 검사 · lint · 단위 테스트 · 컴포넌트 테스트 · 화면 테스트다. 화면 테스트는 단위 테스트 명령이 돌리지 않는다. +타입 검사·lint·단위 테스트·컴포넌트 테스트·화면 테스트다. 화면 테스트는 단위 테스트 명령이 돌리지 않으므로, 넷을 돌리고 「전부 통과」라고 읽으면 화면 테스트가 빠진다. ### 2. 타입 검사는 프로젝트를 순회하는 명령으로 돌린다 -루트 tsconfig 를 직접 부르는 명령은 한 파일도 검사하지 않고 성공한다. +루트 tsconfig 를 직접 부르는 명령은 한 파일도 검사하지 않고 성공한다. 루트가 `"files": []` 에 project references 만 나열하기 때문이다. ### 3. 백엔드는 커밋한 뒤에 빌드한다 -빌드 산출물 이름에 커밋 해시가 들어간다. 작업 트리가 더러우면 해시가 달라져 stale 산출물 검사가 멈춘다. +빌드 산출물 이름에 커밋 해시가 들어간다. 작업 트리가 더러우면 해시가 달라져 stale 산출물 검사가 멈춘다. 이 순서를 몰라 두 번 헤맸다. ### 4. 테스트를 npm 이나 npx 로 감싸 돌리지 않는다 `npm_config_*` 환경 변수가 설정되어 CI 워크플로 생성 테스트가 실패한다. 그 변수를 지우고 실행기를 직접 부른다. +### 5. 환경 때문에 실패하는 것은 실패로 세지 않되 목록에 적는다 + +하위 프로세스를 띄우는 세 케이스는 이 환경에서 실패하고 같은 리비전의 다른 실행에서도 똑같이 재현된다. 코드 변경과 무관하다는 것을 적어 두지 않으면 다음 사람이 그것을 고치려 든다. + ## 적용 조건 - CI 에 묶이지 않은 검증이 남아 있는 저장소에서 배포 직전에 하는 일 @@ -59,19 +65,12 @@ CI 에 묶이지 않은 검증이 남아 있으면 그것을 돌리는 것은 ## 예외 -- CI 가 그 명령을 돌리면 이 목록에서 뺀다. - -- 환경 때문에 실패하는 것은 실패로 세지 않는다. 하위 프로세스를 띄우는 세 케이스는 이 환경에서 실패하고 같은 리비전의 다른 실행에서도 똑같이 재현되므로 코드 변경과 무관하다. +- CI 가 그 명령을 돌리면 이 목록에서 뺀다. 사람이 기억해서 돌리는 가드는 절반만 존재한다. +- 테스트 실행기가 메모리를 더 필요로 하는 조합이면 힙을 올린다. 증상이 테스트 실패가 아니라 실행기를 완료할 수 없다는 메시지로 나와 원인을 가린다. ## 예시 -- 프론트 다섯 명령 : -`npm run check:types` -`npm run lint` -단위 · 컴포넌트 · 화면 테스트 - -- 백엔드 : 커밋한 뒤 stale 산출물을 지우고 빌드한다. 이 순서를 몰라 두 번 헤맸다. - -- 설계 패키지 : 계약 자체의 유효성 · 세 계약 사이의 정합 · 프론트와 백엔드가 아는 종류와 오류 코드가 같은지, 셋을 돌린다. - -- 테스트 JVM 힙이 기본값이면 컨텍스트 캐시와 아키텍처 검사와 컨테이너가 겹치면서 메모리가 모자란다. 증상이 테스트 실패가 아니라 실행기를 완료할 수 없다는 메시지라 원인을 가린다. \ No newline at end of file +- 화면 테스트를 돌리지 않아 23건이 빨간 채로 여러 커밋을 지나갔다 +- 루트 tsconfig 를 직접 부르는 명령이 통과해서 운영의 ReferenceError 를 못 봤다 +- 커밋 전에 빌드해 stale 산출물 검사가 멈춘 것을 두 번 겪었다 +- 설계 패키지는 계약 자체의 유효성·세 계약 사이의 정합·양쪽이 아는 종류와 오류 코드가 같은지 셋을 돌린다