docs(TechLog): 주제 7~10 을 다시 쓴다
주소가 게시 시점에 굳어 저장되는 구조, 축 링크를 두 번 옮긴 순서, 한글 slug 가 간헐적으로 보인 두 가지 어긋남을 표로 갈랐다. 화면이 실패를 없음으로 그릴 때 작성 도구에서 왜 더 오래 숨는지, Promise.all 이 거절과 던짐에서 다른 경로를 타는 이유를 채웠다. CSS module 이 왜 전역 규칙에 닿지 않는지, 403 과 404 가 원인을 어떻게 좁혔는지도 적었다. link-audit.py 를 감사 Case 의 evidence 로 걸어 배정한 증거 하나를 메웠다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
193da20d09
commit
b1653dbba8
+10
-4
@@ -61,23 +61,29 @@ tech-log-backend : 911e8ba — 없던 두 컨트롤러를 구현
|
||||
|
||||
편집기는 질문 목록을 받아 고를 수 있게 그린다. 목록이 비면 「이 프로젝트에 열린 질문이 없습니다」를 적는다.
|
||||
|
||||
요청이 실패했을 때도 빈 배열이 되고 있었다.
|
||||
요청이 실패했을 때도 빈 배열이 되고 있었다. 그래서 「없다」와 「못 읽었다」가 같은 화면이 됐다.
|
||||
|
||||
서버는 404 를 주고 있었다. 그 두 목록 조회에 컨트롤러가 없었고, 계약에는 선언돼 있어 프론트가 그것을 믿고 불렀다.
|
||||
|
||||
## 작성자가 무엇으로 읽었나
|
||||
|
||||
작성자는 자기가 쓴 것과 화면을 대조한다. 화면이 「없습니다」라고 하면 아직 안 썼거나 게시하지 않았다고 읽는다.
|
||||
|
||||
이 경우에는 넷이 있었고 공개 사이트에도 나오고 있었다. 편집기만 못 읽고 있었다.
|
||||
이 경우에는 넷이 있었고 공개 사이트에도 나오고 있었다. 두 화면이 같은 데이터베이스를 보는데 한쪽만 비어 있었으므로, 공개 사이트를 함께 보지 않으면 알아챌 방법이 없었다.
|
||||
|
||||
작성 도구에서 이 부류가 특히 오래 숨는다. 읽기 전용 화면이면 방문자가 「데이터가 없나 보다」로 넘어가지만, 작성 도구에서는 그 오독이 곧바로 작업 판단이 된다 — 없다고 읽으면 다시 쓰게 된다.
|
||||
|
||||
## 못 읽었다고 적는다
|
||||
|
||||
> 거짓말을 하느니 못 읽었다고 말한다.
|
||||
|
||||
요청이 실패하면 실패했다고 적는다. 0건은 0건이라고 적는다.
|
||||
요청이 실패하면 실패했다고 적고 0건은 0건이라고 적는다. 이 둘을 구분할 수 있어야 작성자가 다음에 무엇을 할지 정한다 — 실패면 다시 부르거나 서버를 보고, 0건이면 쓰면 된다.
|
||||
|
||||
## 같은 판단을 다른 화면에
|
||||
|
||||
주제 탭에도 같은 판단을 적용했다. 탭 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그려지고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
주제 탭에도 같은 판단을 적용했다. 탭 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
|
||||
탭 줄이 남는 것이 중요하다. 탭 줄까지 사라지면 그 주제가 없는 것처럼 보이고, 그러면 못 읽은 범위가 화면에서 더 넓어진다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
|
||||
+13
-5
@@ -58,19 +58,27 @@ tech-log-frontend : 6e784ed · fd73bc8 · 3bb724b
|
||||
|
||||
## 묶어 읽으면 한쪽이 전체를 끌고 내려간다
|
||||
|
||||
편집기가 질문 목록과 결정 목록을 하나로 묶어 기다리고 있었다. 결정 쪽 연산에 컨트롤러가 없어 404 가 났고, 화면은 두 목록을 다 못 받은 것으로 그렸다.
|
||||
홈 편집기가 질문 목록과 결정 목록을 하나로 묶어 기다리고 있었다. 결정 쪽 연산에 컨트롤러가 없어 404 가 났고, 화면은 두 목록을 다 못 받은 것으로 그렸다.
|
||||
|
||||
질문 목록은 정상적으로 오고 있었다. 둘을 따로 읽도록 갈랐다.
|
||||
질문 목록은 정상적으로 오고 있었다. 묶어 기다리면 하나라도 거절되는 순간 전체가 거절되므로, 성공한 응답이 있어도 쓸 수 없다.
|
||||
|
||||
## 동기적으로 던지면 거절 처리를 지나지 않는다
|
||||
둘을 따로 읽도록 갈랐다. 실패한 목록에만 못 받았다고 적고 나머지는 그대로 그린다.
|
||||
|
||||
## 거절과 던짐이 다른 경로를 탄다
|
||||
|
||||
같은 코드에서 더 미묘한 변종이 났다.
|
||||
|
||||
> `Promise.all([gateway.foo()])` 은 foo 가 **거절하는 것만** 잡는다. 호출이 **동기적으로 던지면** 배열을 만드는 중에 터져 rejection handler 를 지나지 못하고, 그러면 홈 focus 한 칸 때문에 대시보드 전체가 빈 화면이 된다.
|
||||
|
||||
배열을 만드는 표현식 안에서 던지면 그 표현식이 완성되지 않으므로 거절 처리기가 붙을 대상이 없다.
|
||||
배열 리터럴 안에서 함수를 부르는 시점은 `Promise.all` 에 배열이 넘어가기 전이다. 그 호출이 동기적으로 던지면 배열이 완성되지 않으므로 `Promise.all` 이 시작조차 하지 않고, 거기에 붙인 거절 처리기도 붙을 대상이 없다.
|
||||
|
||||
거절만 잡는 처리로는 부족하다. 던지는 경로도 함께 잡아야 한 칸의 실패가 화면 전체로 번지지 않는다.
|
||||
|
||||
## 탭에도 같은 판단을
|
||||
|
||||
탭 줄은 목록 하나로 그리고 상세는 고른 탭만 받는다. 상세 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
탭 줄은 목록 호출 하나가 주는 전부이고 상세는 고른 탭만 그때 받는다. 상세 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
|
||||
이 구조에서는 실패가 번질 수 있는 범위가 처음부터 한 탭으로 좁다. 상세를 미리 다 받아 두는 구조였다면 하나가 실패할 때 어디까지 그릴지를 다시 정해야 했다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
|
||||
+12
-2
@@ -62,20 +62,30 @@ tech-log-design-package : 76a7ccb
|
||||
|
||||
## null 을 돌려주고 걸러 내면 흔적이 없다
|
||||
|
||||
매퍼가 아는 종류가 아니면 `null` 을 돌려준다. 호출부는 그 목록에서 `null` 을 걸러 낸다.
|
||||
매퍼가 아는 종류가 아니면 `null` 을 돌려주고, 호출부는 그 목록에서 `null` 을 걸러 낸다.
|
||||
|
||||
이 조합에서는 오류가 나지 않고 빈 줄도 생기지 않는다. 목록의 길이만 줄어든다.
|
||||
|
||||
| 무엇이 남나 | 있음 |
|
||||
|---|---|
|
||||
| 오류 로그 | x |
|
||||
| 화면의 빈 줄 | x |
|
||||
| 목록 길이의 변화 | o |
|
||||
|
||||
목록에 몇 개가 있어야 하는지 아는 사람만 알아챌 수 있고, 공개 화면에서는 그것을 아는 사람이 작성자뿐이다.
|
||||
|
||||
## 응답 모양이 다른 목록에 다른 매퍼를 썼다
|
||||
|
||||
프로젝트 기록 목록과 탐색의 지식 목록은 응답 모양이 다르다. 프로젝트 쪽은 관계 항목을 그대로 실어 요약도 주제도 게시일도 없었고, 지식 목록은 처음부터 그 칸들을 갖고 있었다.
|
||||
|
||||
모양이 다른데 매퍼를 공유하면서 종류 판정까지 그쪽 것을 따랐다.
|
||||
모양이 다른데 매퍼를 공유하면서 종류 판정까지 그쪽 것을 따랐다. 지식 목록의 매퍼는 CASE 와 REFERENCE 만 다루면 되는 화면을 위해 만들어졌으므로, 질문과 개념을 받으면 `null` 을 돌려준다.
|
||||
|
||||
## 고친 것
|
||||
|
||||
응답 모양에 맞는 매퍼를 쓰고 모든 종류를 싣게 했다. 목록 항목에 요약과 주제와 게시일을 더해 「제목만 있고 가운뎃점만 남은」 줄을 없앴다.
|
||||
|
||||
이 목록은 계약도 함께 고쳐야 했다. 관계 항목을 그대로 싣던 구조라 요약·주제·게시일을 담을 칸이 응답에 없었다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
`null` 을 돌려주고 호출부가 거르는 매퍼가 다른 목록에도 남아 있는지는 세지 않았다.
|
||||
|
||||
+12
-9
@@ -29,23 +29,27 @@ source:
|
||||
|
||||
매번 우는 검사가 읽히지 않게 되는 것을 막는다.
|
||||
|
||||
> 매번 늑대를 외치는 검사는 읽히지 않게 되고, 진짜 실패가 그 옆에 눈에 띄지 않은 채 앉아 있게 된다.
|
||||
|
||||
## 규칙
|
||||
|
||||
### 1. 기대된 실패는 조건을 적어 뺀다
|
||||
|
||||
미리보기가 아직 없는 문서는 현재 미리보기를 물으면 404 를 답하고, 화면은 그것을 「미리보기를 만드세요」로 바꾼다. 이런 응답은 실패가 아니다.
|
||||
미리보기가 아직 없는 문서는 현재 미리보기를 물으면 404 를 답하고, 화면은 그것을 「미리보기를 만드세요」로 바꾼다. 이 404 는 정상 동작이 오류 상태 코드로 나타난 것이지 실패가 아니다.
|
||||
|
||||
로그인 전 세션 탐침의 401 도 같은 부류다. 어느 쪽도 사람이 고칠 것이 없다.
|
||||
|
||||
### 2. 뺀 나머지는 전부 실패시킨다
|
||||
|
||||
조건에 걸리지 않는 4xx 와 5xx 는 모두 스윕을 실패시킨다.
|
||||
조건에 걸리지 않는 4xx 와 5xx 는 모두 스윕을 실패시킨다. 「이건 아마 괜찮을 것」이라는 판단을 스윕 안에 두지 않는다.
|
||||
|
||||
### 3. 조건을 적을 수 없으면 빼지 않는다
|
||||
|
||||
조건 없이 빼면 진짜 실패도 같이 빠진다.
|
||||
조건 없이 빼면 진짜 실패도 같이 빠진다. 어떤 요청이 왜 그 응답을 받는지 한 줄로 적을 수 없으면 그것은 아직 기대된 실패가 아니다.
|
||||
|
||||
### 4. 뺀 조건을 사람이 읽을 수 있는 곳에 남긴다
|
||||
|
||||
왜 그 응답이 기대된 것인지 적혀 있지 않으면 다음 사람이 조건을 넓힌다.
|
||||
왜 그 응답이 기대된 것인지 적혀 있지 않으면 다음 사람이 조건을 넓힌다. 비슷한 404 가 하나 더 나왔을 때 같은 조건에 넣을지 판단할 근거가 없기 때문이다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
@@ -56,11 +60,10 @@ source:
|
||||
## 예외
|
||||
|
||||
- 기계가 판정하고 사람이 결과를 읽지 않는 검사라면 빨간 줄이 쌓여도 무뎌지지 않는다. 그래도 통과 기준은 정해야 한다.
|
||||
- 그 응답이 정말 고쳐야 하는 것이면 조건으로 빼지 말고 고친다. 뺄지 고칠지는 사람이 고칠 것이 있는가로 가른다.
|
||||
|
||||
## 예시
|
||||
|
||||
- 미리보기가 없는 문서의 404 를 스윕이 실패로 셌다. 건강한 배포 아래에 매번 같은 빨간 줄이 남았다.
|
||||
|
||||
> 매번 늑대를 외치는 검사는 읽히지 않게 되고, 진짜 실패가 그 옆에 눈에 띄지 않은 채 앉아 있게 된다.
|
||||
|
||||
- 로그인 전 세션 탐침의 401 도 같은 부류라 같은 조건으로 제외하고, 나머지 4xx·5xx 는 전부 스윕을 실패시킨다.
|
||||
- 미리보기가 없는 문서의 404 를 스윕이 실패로 셌다. 건강한 배포 아래에 매번 같은 빨간 줄이 남았다
|
||||
- 로그인 전 세션 탐침의 401 도 같은 부류라 같은 조건으로 제외했다
|
||||
- 나머지 4xx·5xx 는 전부 스윕을 실패시킨다
|
||||
|
||||
+19
-11
@@ -28,7 +28,9 @@ source:
|
||||
|
||||
## 목적
|
||||
|
||||
작성자가 「아직 안 썼다」와 「못 읽었다」를 구분할 수 있게 한다. 이 둘이 같은 화면이면 작성자는 다음에 무엇을 할지 정할 수 없다.
|
||||
작성자가 「아직 안 썼다」와 「못 읽었다」를 구분할 수 있게 한다.
|
||||
|
||||
이 둘이 같은 화면이면 작성자는 다음에 무엇을 할지 정할 수 없다. 실패면 다시 부르거나 서버를 봐야 하고 0건이면 쓰면 되는데, 화면이 「없습니다」 하나로 답하면 뒤쪽으로 읽고 다시 쓰게 된다.
|
||||
|
||||
## 규칙
|
||||
|
||||
@@ -36,17 +38,25 @@ source:
|
||||
|
||||
빈 배열로 삼키지 않는다. 0건과 실패는 다른 문구를 쓴다.
|
||||
|
||||
목록 응답을 받아 그리는 코드에서 실패 경로가 빈 배열을 만들면, 그 아래의 「비어 있으면 이 문구」 분기가 두 경우를 같은 화면으로 만든다. 실패를 빈 값으로 접는 지점을 없애야 한다.
|
||||
|
||||
### 2. 한 칸의 실패가 옆 칸을 끌고 내려가지 않게 한다
|
||||
|
||||
여러 목록을 하나로 묶어 기다리면 한쪽의 실패가 전체를 실패로 만든다. 따로 읽고 실패한 목록에만 적는다.
|
||||
여러 목록을 하나로 묶어 기다리면 하나라도 거절되는 순간 전체가 거절된다. 성공한 응답이 있어도 쓸 수 없다.
|
||||
|
||||
따로 읽고 실패한 목록에만 적는다. 화면에 여러 묶음이 있으면 실패가 번질 수 있는 범위를 그 묶음 하나로 좁힌다.
|
||||
|
||||
### 3. 거절만 잡는 처리로는 부족하다
|
||||
|
||||
호출이 동기적으로 던지면 그 처리기를 지나지 않는다. 던지는 경로도 잡는다.
|
||||
호출이 동기적으로 던지면 그 처리기를 지나지 않는다. 배열 리터럴 안에서 부르는 함수가 던지면 배열이 완성되지 않으므로, 거기에 붙인 거절 처리기도 붙을 대상이 없다.
|
||||
|
||||
던지는 경로도 함께 잡아야 한 칸의 실패가 화면 전체로 번지지 않는다.
|
||||
|
||||
### 4. 항목을 걸러 낼 때 걸러 낸 것을 세어 둔다
|
||||
|
||||
매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 거르면, 목록이 한 줄 짧아지는 것 말고는 흔적이 없다.
|
||||
매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 그것을 거르면, 오류도 빈 줄도 남지 않고 목록 길이만 줄어든다.
|
||||
|
||||
목록에 몇 개가 있어야 하는지 아는 사람만 알아챌 수 있다. 공개 화면에서는 그것을 아는 사람이 작성자뿐이다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
@@ -58,13 +68,11 @@ source:
|
||||
## 예외
|
||||
|
||||
- 정말로 0건인 것과 못 읽은 것을 구분할 수 없는 화면이라면 그 구분을 먼저 만든다. 구분 없이 문구만 바꾸면 0건이 실패로 읽힌다.
|
||||
|
||||
- 읽는 사람이 그 데이터를 만들지 않는 화면 — 공개 조회 — 에서는 실패를 화면 전체의 오류로 다뤄도 된다.
|
||||
- 읽는 사람이 그 데이터를 만들지 않는 화면에서는 실패를 화면 전체의 오류로 다뤄도 된다. 방문자에게는 어느 목록이 실패했는지가 할 일을 바꾸지 않는다.
|
||||
|
||||
## 예시
|
||||
|
||||
- 「이 프로젝트에 열린 질문이 없습니다」가 적혀 있는 동안 그 프로젝트에는 질문이 넷 있었고 공개 사이트에도 나오고 있었다.
|
||||
|
||||
- 탭 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
|
||||
- 매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 걸러 내, 질문과 개념이 목록에서 사라졌다.
|
||||
- 「이 프로젝트에 열린 질문이 없습니다」가 적혀 있는 동안 그 프로젝트에는 질문이 넷 있었고 공개 사이트에도 나오고 있었다
|
||||
- 결정 목록만 404 인데 함께 묶어 읽은 질문 목록까지 「불러오지 못했습니다」가 됐다
|
||||
- 탭 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다
|
||||
- 매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 걸러 내, 질문과 개념이 목록에서 사라졌다
|
||||
|
||||
Reference in New Issue
Block a user