docs(TechLog): Reference 15편의 규칙 표기를 게시된 기록에 맞추고 주제 6 을 다시 쓴다
게시된 Reference 15편이 전부 규칙을 `### N. 제목` 으로 쓰고 적용 조건·예외·예시를 항목으로 쓴다. 내 15편은 규칙을 `**굵게**` 로, 나머지 셋을 문단으로 쓰고 있었다 — Studio 의 rules[]·applyWhen[]·exceptions[]·examples[] 는 배열이라 문단으로 두면 항목이 하나로 접힌다. 규칙 68개를 `### N. 제목` 으로 바꿨다 (편당 3~7개, 게시된 것은 4~10개) 적용 조건·예외·예시를 항목으로 갈랐다. 한 항목뿐이던 아홉 편은 조건을 나눠 적었다 주제 6 은 본문을 다시 썼다 — location = 이 정확히 일치하는 경로만 잡아 27개가 얼어붙은 구조, 여덟 곳이 우는 시점을 셋으로 가른 표, digest 를 다시 계산할 때 옛 값을 먼저 재현하는 이유. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
53537e37e8
commit
193da20d09
+17
-10
@@ -31,32 +31,39 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**만드는 쪽에서 생성한 경로를 공개 라우트 패턴에 맞춘다**
|
||||
### 1. 만드는 쪽에서 생성한 경로를 공개 라우트 패턴에 맞춘다
|
||||
|
||||
종류마다 만들어 낸 주소가 실제 라우트에 걸리는지 백엔드 테스트가 본다.
|
||||
|
||||
**그리는 쪽에서 서버가 준 주소를 라우트 표에 맞추고, 맞는 라우트가 없으면 링크로 그리지 않는다**
|
||||
### 2. 그리는 쪽에서 서버가 준 주소를 라우트 표에 맞추고, 맞는 라우트가 없으면 링크로 그리지 않는다
|
||||
|
||||
같은 부류가 또 생겨도 방문자가 404 를 만나지는 않는다.
|
||||
|
||||
**주소를 고쳤으면 이미 저장된 행도 함께 고친다**
|
||||
### 3. 주소를 고쳤으면 이미 저장된 행도 함께 고친다
|
||||
|
||||
주소가 게시 시점에 굳어져 저장되면 코드만 고쳐도 기존 링크는 깨진 채 남는다.
|
||||
|
||||
**배포 뒤 서버가 내보내는 주소를 전수로 훑는다**
|
||||
### 4. 배포 뒤 서버가 내보내는 주소를 전수로 훑는다
|
||||
|
||||
저장소를 훑는 감사와 다른 것을 본다. 실제로 나가는 주소는 DB 에 있다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
주소를 서버가 만들어 내보내고 화면은 받은 문자열을 링크로 그리는 구조. 게시 시점에 주소가 굳어져 저장되면 특히 걸린다.
|
||||
- 주소를 서버가 만들어 내보내고 화면은 받은 문자열을 링크로 그릴 때
|
||||
- 게시 시점에 주소가 굳어져 저장되는 구조일 때. 코드만 고치면 이미 저장된 행이 깨진 채 남는다
|
||||
- 공개 라우트를 더하거나 지워 주소의 모양이 바뀔 때
|
||||
- 배포 뒤 서버가 내보내는 주소를 전수로 훑을 때
|
||||
|
||||
## 예외
|
||||
|
||||
외부 주소는 라우트 표에 없으므로 이 대조의 대상이 아니다.
|
||||
- 외부 주소는 라우트 표에 없으므로 이 대조의 대상이 아니다.
|
||||
|
||||
그리는 쪽에만 가드를 두면 링크가 아예 그려지지 않는 것으로 끝나고 원인이 남는다. 만드는 쪽에도 같은 검사를 둔다.
|
||||
- 그리는 쪽에만 가드를 두면 링크가 아예 그려지지 않는 것으로 끝나고 원인이 남는다. 만드는 쪽에도 같은 검사를 둔다.
|
||||
|
||||
## 예시
|
||||
|
||||
결정 링크가 404 였다. 계약은 앵커라고 적었고 만드는 두 곳이 경로를 만들었다.
|
||||
- 결정 링크가 404 였다. 계약은 앵커라고 적었고 만드는 두 곳이 경로를 만들었다.
|
||||
|
||||
배포 후 서버가 내보내는 주소 26개와 주제·축 9개를 더해 35개 전부 200 인 것을 확인했다.
|
||||
- 배포 후 서버가 내보내는 주소 26개와 주제·축 9개를 더해 35개 전부 200 인 것을 확인했다.
|
||||
|
||||
저장소 안의 링크 리터럴을 훑는 감사로는 이 결함이 잡히지 않았다. 그 주소는 코드에 없다.
|
||||
- 저장소 안의 링크 리터럴을 훑는 감사로는 이 결함이 잡히지 않았다. 그 주소는 코드에 없다.
|
||||
+15
-10
@@ -31,31 +31,36 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**우회를 넣는 커밋에 되돌릴 조건을 적는다**
|
||||
### 1. 우회를 넣는 커밋에 되돌릴 조건을 적는다
|
||||
|
||||
무엇이 채워지면 되돌리는지 한 줄로 적는다. 그 조건이 충족됐을 때 실제로 되돌린다.
|
||||
|
||||
**우회할 때 무엇이 비어 있어서 우회하는지 함께 적는다**
|
||||
### 2. 우회할 때 무엇이 비어 있어서 우회하는지 함께 적는다
|
||||
|
||||
채울 것이 없어서 돌린 것과 구조상 그쪽이 맞아서 돌린 것은 다르다.
|
||||
|
||||
**되돌릴 생각이 없으면 우회가 아니라 결정으로 적는다**
|
||||
### 3. 되돌릴 생각이 없으면 우회가 아니라 결정으로 적는다
|
||||
|
||||
그때는 조건이 아니라 근거와 감수한 비용을 적는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
그 화면이 줄 수 있는 것이 아직 비어 있어 링크나 흐름을 다른 곳으로 돌릴 때.
|
||||
- 그 화면이 줄 수 있는 것이 아직 비어 있어 링크나 흐름을 다른 곳으로 돌릴 때
|
||||
- 임시라고 말하면서 코드에 남기는 변경을 커밋할 때
|
||||
- 왜 이 링크가 저기로 가는지 다음 사람이 물을 만한 변경을 넣을 때
|
||||
|
||||
## 예외
|
||||
|
||||
되돌릴 생각이 없는 영구 변경은 우회가 아니다. 조건 대신 근거를 적는다.
|
||||
- 되돌릴 생각이 없는 영구 변경은 우회가 아니다. 조건 대신 근거를 적는다.
|
||||
|
||||
조건을 적을 수 없으면 그것은 우회가 아니라 아직 정하지 않은 것이다. 열린 질문으로 남긴다.
|
||||
- 조건을 적을 수 없으면 그것은 우회가 아니라 아직 정하지 않은 것이다. 열린 질문으로 남긴다.
|
||||
|
||||
## 예시
|
||||
|
||||
주제 화면이 주제 셋을 하드코딩해 두고 있어 실제 주제는 무엇이든 404 였다. 그때 주제 페이지를 채우는 대신 링크를 탐색 필터로 돌렸다.
|
||||
- 주제 화면이 주제 셋을 하드코딩해 두고 있어 실제 주제는 무엇이든 404 였다. 그때 주제 페이지를 채우는 대신 링크를 탐색 필터로 돌렸다.
|
||||
|
||||
돌린 이유는 그 페이지만 줄 수 있는 것 — 설명, 범위, 선별한 대표 기록 — 이 전부 비어 있었고 Studio 에 주제 설명을 쓸 칸조차 없었기 때문이다.
|
||||
- 돌린 이유는 그 페이지만 줄 수 있는 것 — 설명, 범위, 선별한 대표 기록 — 이 전부 비어 있었고 Studio 에 주제 설명을 쓸 칸조차 없었기 때문이다.
|
||||
|
||||
우회를 남겨 두면 「왜 주제 링크가 탐색으로 가지?」라는 질문이 계속 따라온다.
|
||||
- 우회를 남겨 두면 「왜 주제 링크가 탐색으로 가지?」라는 질문이 계속 따라온다.
|
||||
|
||||
그 조건을 커밋 메시지에 적었고, 주제 화면을 계약에 잇고 하드코딩을 없앤 뒤 링크를 곧장 주제 화면으로 되돌렸다.
|
||||
- 그 조건을 커밋 메시지에 적었고, 주제 화면을 계약에 잇고 하드코딩을 없앤 뒤 링크를 곧장 주제 화면으로 되돌렸다.
|
||||
+18
-11
@@ -34,34 +34,41 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**보고된 증상과 같은 축의 값을 잰다**
|
||||
### 1. 보고된 증상과 같은 축의 값을 잰다
|
||||
|
||||
「제목이 작아 보인다」는 글자 크기와 굵기다. 격자와 열은 다른 축이다.
|
||||
|
||||
**촬영을 스크립트로 고정한다**
|
||||
### 2. 촬영을 스크립트로 고정한다
|
||||
|
||||
손으로 찍으면 뷰포트와 축소 배율이 매번 달라진다.
|
||||
|
||||
**폭을 고정해 여러 개를 돌고, 폭마다 측정값도 남긴다**
|
||||
### 3. 폭을 고정해 여러 개를 돌고, 폭마다 측정값도 남긴다
|
||||
|
||||
스크린샷만 남기면 나중에 그 값이 얼마였는지 다시 잴 수 없다.
|
||||
|
||||
**전체 페이지를 한 장으로 찍지 않는다**
|
||||
### 4. 전체 페이지를 한 장으로 찍지 않는다
|
||||
|
||||
축소되어 글자 크기가 실제와 달라진다. 화면 높이만큼 잘라 찍는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
화면이 잘못됐다는 보고를 확인하는 일. 배포본의 실제 렌더 결과를 판단 근거로 삼을 때.
|
||||
- 화면이 잘못됐다는 보고를 확인할 때
|
||||
- 배포본의 실제 렌더 결과를 판단 근거로 삼을 때
|
||||
- 고쳤다고 답하기 전에 무엇을 쟀는지 대야 할 때
|
||||
- 여러 폭에서 배치가 갈리는 사이트를 검토할 때
|
||||
|
||||
## 예외
|
||||
|
||||
측정 대상이 좌표나 간격 자체라면 바운딩 박스는 프록시가 아니라 대상이다.
|
||||
- 측정 대상이 좌표나 간격 자체라면 바운딩 박스는 프록시가 아니라 대상이다.
|
||||
|
||||
CSS 선언이 정본과 같은지를 보는 검사는 렌더 결과를 재지 않는다. 그 검사가 덮는 범위를 알고 쓰면 된다.
|
||||
- CSS 선언이 정본과 같은지를 보는 검사는 렌더 결과를 재지 않는다. 그 검사가 덮는 범위를 알고 쓰면 된다.
|
||||
|
||||
## 예시
|
||||
|
||||
격자와 열만 재고 「정상」이라 답했다. 사용자가 다시 지적한 뒤 전체 페이지 스크린샷을 찍어서야 26px 과 400 을 봤다.
|
||||
- 격자와 열만 재고 「정상」이라 답했다. 사용자가 다시 지적한 뒤 전체 페이지 스크린샷을 찍어서야 26px 과 400 을 봤다.
|
||||
|
||||
목록 간격을 바운딩 박스로만 재서 「판단 기준」을 결함으로 잘못 지목한 적이 있다.
|
||||
- 목록 간격을 바운딩 박스로만 재서 「판단 기준」을 결함으로 잘못 지목한 적이 있다.
|
||||
|
||||
브라우저 세션이 리셋되면 창이 약 877px 로 돌아가는데 이 사이트의 분기는 1179·1050·900·767 이라, 877px 에서 본 배치는 방문자 대부분이 보는 배치가 아니다.
|
||||
- 브라우저 세션이 리셋되면 창이 약 877px 로 돌아가는데 이 사이트의 분기는 1179·1050·900·767 이라, 877px 에서 본 배치는 방문자 대부분이 보는 배치가 아니다.
|
||||
|
||||
전체 페이지를 한 장으로 찍으면 1425x4466 이 638x2000 으로 들어와 17px 글자가 7~8px 이 된다.
|
||||
- 전체 페이지를 한 장으로 찍으면 1425x4466 이 638x2000 으로 들어와 17px 글자가 7~8px 이 된다.
|
||||
+16
-9
@@ -31,32 +31,39 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**배치 속성은 그 배치를 쓰는 요소까지 좁혀 적는다**
|
||||
### 1. 배치 속성은 그 배치를 쓰는 요소까지 좁혀 적는다
|
||||
|
||||
`display: grid|flex`, `grid-template-columns`, `padding` 을 구역 클래스 아래 태그 선택자로 걸지 않는다.
|
||||
|
||||
**CSS 만으로 막지 않고 구조도 본다**
|
||||
### 2. CSS 만으로 막지 않고 구조도 본다
|
||||
|
||||
선택자를 좁히면 같은 구조가 다시 생겼을 때 다시 샌다. 제목 안에 링크를 두지 않는 편이 낫다.
|
||||
|
||||
**이미 좁혀 둔 곳은 검사에서 명시적으로 뺀다**
|
||||
### 3. 이미 좁혀 둔 곳은 검사에서 명시적으로 뺀다
|
||||
|
||||
예외를 적어 두지 않으면 검사 결과가 늘 빨갛고 곧 읽히지 않는다.
|
||||
|
||||
**전역 규칙과 CSS module 이 섞인 화면을 따로 센다**
|
||||
### 4. 전역 규칙과 CSS module 이 섞인 화면을 따로 센다
|
||||
|
||||
전역 규칙을 고쳐도 module 을 쓰는 화면에는 닿지 않는다. 한 화면 안에서 두 언어가 섞이면 더 눈에 띈다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
구역 클래스 아래에 태그 선택자로 배치를 거는 CSS. 같은 구역 안에 제목과 목록이 같이 있으면 특히 걸린다.
|
||||
- 구역 클래스 아래에 태그 선택자로 배치를 거는 CSS 를 쓸 때
|
||||
- 같은 구역 안에 제목과 목록이 함께 있을 때
|
||||
- 전역 규칙과 CSS module 이 한 화면에 섞여 있을 때
|
||||
- 「디자인이 안 된 것처럼 보인다」는 보고를 받았을 때
|
||||
|
||||
## 예외
|
||||
|
||||
색이나 글꼴만 거는 규칙은 새어도 티가 나지 않으므로 대상이 아니다.
|
||||
- 색이나 글꼴만 거는 규칙은 새어도 티가 나지 않으므로 대상이 아니다.
|
||||
|
||||
구역 안의 모든 같은 태그가 실제로 같은 배치를 써야 하는 화면이라면 좁히지 않아도 된다. 그때는 그 의도를 검사의 예외 목록에 적는다.
|
||||
- 구역 안의 모든 같은 태그가 실제로 같은 배치를 써야 하는 화면이라면 좁히지 않아도 된다. 그때는 그 의도를 검사의 예외 목록에 적는다.
|
||||
|
||||
## 예시
|
||||
|
||||
비교 행을 위한 격자가 제목 안의 링크까지 잡아 제목이 200px 칸에 갇혔다.
|
||||
- 비교 행을 위한 격자가 제목 안의 링크까지 잡아 제목이 200px 칸에 갇혔다.
|
||||
|
||||
같은 모양이 다른 구역 아홉 곳에도 있어 선택자 51개를 고쳤다.
|
||||
- 같은 모양이 다른 구역 아홉 곳에도 있어 선택자 51개를 고쳤다.
|
||||
|
||||
`section-selector-scope.test.ts` 가 `.클래스 태그` 모양에 배치 속성이 걸려 있으면 멈춘다.
|
||||
|
||||
+20
-14
@@ -34,42 +34,48 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**서버 쪽은 매핑을 리플렉션으로 모아 계약의 경로와 전수 대조한다**
|
||||
### 1. 서버 쪽은 매핑을 리플렉션으로 모아 계약의 경로와 전수 대조한다
|
||||
|
||||
`@RestController` 들을 훑어 실제 매핑을 모으고 계약이 선언한 경로 전부와 맞춘다. 기대 목록을 손으로 적으면 그 목록이 또 하나의 손 목록이 되므로 계약에서 읽는다.
|
||||
|
||||
**화면 쪽은 계약이 선언한 연산이 기여 목록에 등록됐는지 본다**
|
||||
### 2. 화면 쪽은 계약이 선언한 연산이 기여 목록에 등록됐는지 본다
|
||||
|
||||
타입은 계약에서 생성되므로 등록을 빠뜨려도 에디터에서 그 연산이 보이고 컴파일이 통과한다. 그 상태에서 부르면 게이트웨이가 등록된 것 중에서 고르므로 옆 분기로 떨어지고, 서버는 그 요청에 정상 응답한다.
|
||||
|
||||
**구현하지 않기로 한 연산은 이유와 함께 명시 목록에 넣는다**
|
||||
### 3. 구현하지 않기로 한 연산은 이유와 함께 명시 목록에 넣는다
|
||||
|
||||
「빠뜨린 것」과 구분되지 않으면 대조 결과가 곧 무시된다. 이 저장소는 작업본 API 로 대체된 옛 연산 51개를 그 이름의 상수에 담고, 봉투 없이 바이트를 주는 연산 하나를 별도 상수로 면제한다. 면제가 코드에 이름으로 남아 다음 사람이 세어 볼 수 있다.
|
||||
|
||||
**두 쪽 다 돌린다**
|
||||
### 4. 두 쪽 다 돌린다
|
||||
|
||||
한쪽만 대조하면 다른 쪽을 지웠을 때 잡히지 않는다.
|
||||
|
||||
**생성 모델 검사를 이 대조로 세지 않는다**
|
||||
### 5. 생성 모델 검사를 이 대조로 세지 않는다
|
||||
|
||||
모델 생성은 스키마와 속성만 본다. 구현이 없어도 모델은 멀쩡히 만들어진다.
|
||||
|
||||
**전수 대조가 무거우면 깨지는 모양으로 좁힌다**
|
||||
### 6. 전수 대조가 무거우면 깨지는 모양으로 좁힌다
|
||||
|
||||
관리 계약은 86 operation 이라 전수 대조가 무겁다. 이 저장소는 대신 「한 종류만 빠진 항목」을 보게 했다 — 깨진 것이 늘 그 모양이었기 때문이다. 좁힌 기준은 무엇을 보지 않는지도 함께 적는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
계약이 한 저장소에 있고 두 저장소가 그것을 반입해 각자 구현하는 구조. 연산을 더하거나 지우는 변경에서 이 대조를 돌린다.
|
||||
- 계약이 한 저장소에 있고 두 저장소가 그것을 반입해 각자 구현하는 구조. 연산을 더하거나 지우는 변경에서 이 대조를 돌린다.
|
||||
|
||||
화면이 「데이터가 없습니다」를 그리는데 저장소에는 값이 있을 때 이 대조를 먼저 본다. 구현이 없어서 404 인 것과 정말 0건인 것이 화면에서 같아 보인다.
|
||||
- 화면이 「데이터가 없습니다」를 그리는데 저장소에는 값이 있을 때 이 대조를 먼저 본다. 구현이 없어서 404 인 것과 정말 0건인 것이 화면에서 같아 보인다.
|
||||
|
||||
## 예외
|
||||
|
||||
계약과 구현이 같은 저장소에 있고 같은 빌드를 지나면 컴파일러가 이 대조를 대신한다.
|
||||
- 계약과 구현이 같은 저장소에 있고 같은 빌드를 지나면 컴파일러가 이 대조를 대신한다.
|
||||
|
||||
연산이 봉투 규약을 따르지 않으면 경로 대조에서 뺀다. 다만 뺀 이유를 목록에 적는다.
|
||||
- 연산이 봉투 규약을 따르지 않으면 경로 대조에서 뺀다. 다만 뺀 이유를 목록에 적는다.
|
||||
|
||||
## 예시
|
||||
|
||||
매핑 하나를 떼어 보고 대조 검사가 그 연산 하나를 정확히 짚는 것을 확인한 뒤 커밋했다.
|
||||
- 매핑 하나를 떼어 보고 대조 검사가 그 연산 하나를 정확히 짚는 것을 확인한 뒤 커밋했다.
|
||||
|
||||
두 목록 조회에 컨트롤러가 없어 홈 편집기가 「이 프로젝트에 열린 질문이 없습니다」를 그렸다. 실제로는 넷이 있었고 공개 사이트에도 나오고 있었다.
|
||||
- 두 목록 조회에 컨트롤러가 없어 홈 편집기가 「이 프로젝트에 열린 질문이 없습니다」를 그렸다. 실제로는 넷이 있었고 공개 사이트에도 나오고 있었다.
|
||||
|
||||
옛 연산 51개를 명시하지 않았다면 대조 결과가 51건의 실패로 나와 아무도 읽지 않았을 것이다.
|
||||
- 옛 연산 51개를 명시하지 않았다면 대조 결과가 51건의 실패로 나와 아무도 읽지 않았을 것이다.
|
||||
|
||||
기여 목록에 등록하지 않은 연산 넷을 만났다. 둘은 옆 분기로 떨어져 다른 기록을 다뤘고 둘은 빈 목록이 됐다.
|
||||
- 기여 목록에 등록하지 않은 연산 넷을 만났다. 둘은 옆 분기로 떨어져 다른 기록을 다뤘고 둘은 빈 목록이 됐다.
|
||||
+14
-8
@@ -31,30 +31,36 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**기대된 실패는 조건을 적어 뺀다**
|
||||
### 1. 기대된 실패는 조건을 적어 뺀다
|
||||
|
||||
미리보기가 아직 없는 문서는 현재 미리보기를 물으면 404 를 답하고, 화면은 그것을 「미리보기를 만드세요」로 바꾼다. 이런 응답은 실패가 아니다.
|
||||
|
||||
**뺀 나머지는 전부 실패시킨다**
|
||||
### 2. 뺀 나머지는 전부 실패시킨다
|
||||
|
||||
조건에 걸리지 않는 4xx 와 5xx 는 모두 스윕을 실패시킨다.
|
||||
|
||||
**조건을 적을 수 없으면 빼지 않는다**
|
||||
### 3. 조건을 적을 수 없으면 빼지 않는다
|
||||
|
||||
조건 없이 빼면 진짜 실패도 같이 빠진다.
|
||||
|
||||
**뺀 조건을 사람이 읽을 수 있는 곳에 남긴다**
|
||||
### 4. 뺀 조건을 사람이 읽을 수 있는 곳에 남긴다
|
||||
|
||||
왜 그 응답이 기대된 것인지 적혀 있지 않으면 다음 사람이 조건을 넓힌다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
배포 뒤 전 화면을 훑는 스윕처럼 결과를 사람이 훑어보는 검사. 정상 동작이 오류 상태 코드로 나타나는 화면이 있는 서비스에서 걸린다.
|
||||
- 배포 뒤 전 화면을 훑는 스윕처럼 결과를 사람이 훑어보는 검사를 만들 때
|
||||
- 정상 동작이 오류 상태 코드로 나타나는 화면이 있는 서비스에서
|
||||
- 같은 빨간 줄이 매번 남기 시작했을 때
|
||||
|
||||
## 예외
|
||||
|
||||
기계가 판정하고 사람이 결과를 읽지 않는 검사라면 빨간 줄이 쌓여도 무뎌지지 않는다. 그래도 통과 기준은 정해야 한다.
|
||||
- 기계가 판정하고 사람이 결과를 읽지 않는 검사라면 빨간 줄이 쌓여도 무뎌지지 않는다. 그래도 통과 기준은 정해야 한다.
|
||||
|
||||
## 예시
|
||||
|
||||
미리보기가 없는 문서의 404 를 스윕이 실패로 셌다. 건강한 배포 아래에 매번 같은 빨간 줄이 남았다.
|
||||
- 미리보기가 없는 문서의 404 를 스윕이 실패로 셌다. 건강한 배포 아래에 매번 같은 빨간 줄이 남았다.
|
||||
|
||||
> 매번 늑대를 외치는 검사는 읽히지 않게 되고, 진짜 실패가 그 옆에 눈에 띄지 않은 채 앉아 있게 된다.
|
||||
|
||||
로그인 전 세션 탐침의 401 도 같은 부류라 같은 조건으로 제외하고, 나머지 4xx·5xx 는 전부 스윕을 실패시킨다.
|
||||
- 로그인 전 세션 탐침의 401 도 같은 부류라 같은 조건으로 제외하고, 나머지 4xx·5xx 는 전부 스윕을 실패시킨다.
|
||||
+17
-10
@@ -32,32 +32,39 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**요청이 실패하면 실패했다고 적는다**
|
||||
### 1. 요청이 실패하면 실패했다고 적는다
|
||||
|
||||
빈 배열로 삼키지 않는다. 0건과 실패는 다른 문구를 쓴다.
|
||||
|
||||
**한 칸의 실패가 옆 칸을 끌고 내려가지 않게 한다**
|
||||
### 2. 한 칸의 실패가 옆 칸을 끌고 내려가지 않게 한다
|
||||
|
||||
여러 목록을 하나로 묶어 기다리면 한쪽의 실패가 전체를 실패로 만든다. 따로 읽고 실패한 목록에만 적는다.
|
||||
|
||||
**거절만 잡는 처리로는 부족하다**
|
||||
### 3. 거절만 잡는 처리로는 부족하다
|
||||
|
||||
호출이 동기적으로 던지면 그 처리기를 지나지 않는다. 던지는 경로도 잡는다.
|
||||
|
||||
**항목을 걸러 낼 때 걸러 낸 것을 세어 둔다**
|
||||
### 4. 항목을 걸러 낼 때 걸러 낸 것을 세어 둔다
|
||||
|
||||
매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 거르면, 목록이 한 줄 짧아지는 것 말고는 흔적이 없다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
목록·요약·카운트처럼 「비어 있음」이 정상값이라 실패와 구분되지 않는 화면. 작성 도구에서 특히 걸린다 — 작성자가 자기 작업물과 화면을 대조하기 때문이다.
|
||||
- 목록·요약·카운트처럼 「비어 있음」이 정상값이라 실패와 구분되지 않는 화면을 만들 때
|
||||
- 작성 도구를 만들 때. 작성자가 자기 작업물과 화면을 대조하므로 오독이 곧바로 작업 판단이 된다
|
||||
- 한 화면이 여러 목록을 함께 받아 그릴 때
|
||||
- 매퍼가 모르는 값에 빈 값을 돌려주고 호출부가 그것을 거를 때
|
||||
|
||||
## 예외
|
||||
|
||||
정말로 0건인 것과 못 읽은 것을 구분할 수 없는 화면이라면 그 구분을 먼저 만든다. 구분 없이 문구만 바꾸면 0건이 실패로 읽힌다.
|
||||
- 정말로 0건인 것과 못 읽은 것을 구분할 수 없는 화면이라면 그 구분을 먼저 만든다. 구분 없이 문구만 바꾸면 0건이 실패로 읽힌다.
|
||||
|
||||
읽는 사람이 그 데이터를 만들지 않는 화면 — 공개 조회 — 에서는 실패를 화면 전체의 오류로 다뤄도 된다.
|
||||
- 읽는 사람이 그 데이터를 만들지 않는 화면 — 공개 조회 — 에서는 실패를 화면 전체의 오류로 다뤄도 된다.
|
||||
|
||||
## 예시
|
||||
|
||||
「이 프로젝트에 열린 질문이 없습니다」가 적혀 있는 동안 그 프로젝트에는 질문이 넷 있었고 공개 사이트에도 나오고 있었다.
|
||||
- 「이 프로젝트에 열린 질문이 없습니다」가 적혀 있는 동안 그 프로젝트에는 질문이 넷 있었고 공개 사이트에도 나오고 있었다.
|
||||
|
||||
탭 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
- 탭 하나를 못 받아도 탭 줄과 나머지 탭은 그대로 그리고, 못 받은 탭에는 못 받았다고 적는다.
|
||||
|
||||
매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 걸러 내, 질문과 개념이 목록에서 사라졌다.
|
||||
- 매퍼가 모르는 종류에 빈 값을 돌려주고 호출부가 걸러 내, 질문과 개념이 목록에서 사라졌다.
|
||||
+25
-18
@@ -35,51 +35,58 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**유한한 집합의 분기는 값마다 항목을 요구하는 형태로 쓴다**
|
||||
### 1. 유한한 집합의 분기는 값마다 항목을 요구하는 형태로 쓴다
|
||||
|
||||
`Record<K, V>` 는 키 집합이 `K` 와 정확히 같은 객체 타입이라, 키가 하나 모자라면 그 리터럴이 그 타입이 아니게 된다. `K` 에 값을 더하면 리터럴을 쓴 곳이 전부 타입 오류가 된다. Java 에서는 sealed 타입을 대상으로 switch 를 식으로 쓴다 — 식은 값을 내놓아야 하므로 모든 경우에 무엇을 반환할지 컴파일러가 요구한다. 문으로 쓴 switch 는 요구하지 않는다.
|
||||
|
||||
**키가 그 열거형이 아니면 표로 좁히지 말고 그 이유를 코드 옆에 적는다**
|
||||
### 2. 키가 그 열거형이 아니면 표로 좁히지 말고 그 이유를 코드 옆에 적는다
|
||||
|
||||
주소 앞머리로 종류를 거꾸로 찾는 코드는 키가 종류가 아니라 주소다. 담기는 값이 열거형 밖으로 나가는 칸도 같다. 억지로 표로 바꾸면 실제 값 집합과 타입이 어긋나므로, 배열이나 문자열 분기로 두고 왜 좁힐 수 없는지를 주석으로 남긴다.
|
||||
|
||||
**표에 있는 「그렇게 정했다」를 표 안에서 읽히게 한다**
|
||||
### 3. 표에 있는 「그렇게 정했다」를 표 안에서 읽히게 한다
|
||||
|
||||
표의 어느 칸이 다른 값들과 다른 규칙을 따르면, 그것이 빠뜨린 것인지 정한 것인지 표만 봐서는 갈리지 않는다. 이 저장소의 종류별 목록 표에서 결정만 자기 목록이 아니라 프로젝트 목록으로 가는데, 그 이유가 표 위에 적혀 있어 다음 사람이 구분한다.
|
||||
|
||||
**한 파일을 표로 바꿨다고 그 파일이 다 바뀐 것으로 보지 않는다**
|
||||
### 4. 한 파일을 표로 바꿨다고 그 파일이 다 바뀐 것으로 보지 않는다
|
||||
|
||||
작업본 검증기는 유형별 칸을 표로 갖고 있으면서 문자열 칸 목록은 사슬로 남겨 두었다. 같은 함수 안에서 두 목록의 상태가 갈린다.
|
||||
|
||||
**컴파일러가 못 보는 경계에는 계약을 읽어 대조하는 검사를 둔다**
|
||||
### 5. 컴파일러가 못 보는 경계에는 계약을 읽어 대조하는 검사를 둔다
|
||||
|
||||
계약이 다른 저장소에 있고 생성기를 지나 타입으로 들어오면, 계약 쪽 열거형이 좁아도 그 타입은 유효하다. 계약 문서를 파싱해 코드의 표와 맞춰 본다.
|
||||
|
||||
**가드를 넣었으면 그 가드가 실제로 잡는지 되돌려 확인한 뒤 커밋한다**
|
||||
### 6. 가드를 넣었으면 그 가드가 실제로 잡는지 되돌려 확인한 뒤 커밋한다
|
||||
|
||||
계약에서 값을 하나 빼고 검사가 빨개지는 것을 본다. 확인하지 않은 가드는 그 값이 원래 없었는지 검사가 안 도는지 구별되지 않는다.
|
||||
|
||||
**한 열거형을 여러 계약이 따로 적고 있으면 그 목록을 기계로 뽑는다**
|
||||
### 7. 한 열거형을 여러 계약이 따로 적고 있으면 그 목록을 기계로 뽑는다
|
||||
|
||||
세 계약을 파싱해 「일부 값만 열거한 enum」을 전부 뽑는 편이 눈으로 찾는 것보다 빠르고 빠뜨림이 없다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
값이 유한한 집합인 것을 코드나 계약 여러 곳에서 분기하거나 열거하는 곳. 문서 종류, 상태, 역할, 오류 코드, 라우트 이름이 여기 해당한다.
|
||||
- 값이 유한한 집합인 것을 코드나 계약 여러 곳에서 분기하거나 열거하는 곳. 문서 종류, 상태, 역할, 오류 코드, 라우트 이름이 여기 해당한다.
|
||||
|
||||
새 값을 더하는 변경을 시작할 때 이 규칙을 먼저 건다. 다 더한 뒤에 빠진 곳을 찾는 순서로는 조용히 빠진 곳을 못 찾는다 — 조용히 빠진 곳은 증상이 없으므로 훑어서는 나오지 않는다.
|
||||
- 새 값을 더하는 변경을 시작할 때 이 규칙을 먼저 건다. 다 더한 뒤에 빠진 곳을 찾는 순서로는 조용히 빠진 곳을 못 찾는다 — 조용히 빠진 곳은 증상이 없으므로 훑어서는 나오지 않는다.
|
||||
|
||||
계약을 소유한 저장소가 따로 있으면 계약 쪽 열거형에도 같이 건다. 이 저장소에서 열세 건 중 셋이 계약 안에 있었다.
|
||||
- 계약을 소유한 저장소가 따로 있으면 계약 쪽 열거형에도 같이 건다. 이 저장소에서 열세 건 중 셋이 계약 안에 있었다.
|
||||
|
||||
## 예외
|
||||
|
||||
그 칸이 집합 밖의 값도 담으면 표로 좁힐 수 없다. 공개 투영의 resource_type 이 그런 칸이다 — 문서 종류 다섯에 더해 PROJECT 와 RELEASE 를 담는다. 이때는 대조 검사를 대신 둔다.
|
||||
- 그 칸이 집합 밖의 값도 담으면 표로 좁힐 수 없다. 공개 투영의 resource_type 이 그런 칸이다 — 문서 종류 다섯에 더해 PROJECT 와 RELEASE 를 담는다. 이때는 대조 검사를 대신 둔다.
|
||||
|
||||
키가 그 열거형이 아닌 자료 구조도 대상이 아니다. 주소 앞머리로 종류를 찾는 배열이 그렇다.
|
||||
- 키가 그 열거형이 아닌 자료 구조도 대상이 아니다. 주소 앞머리로 종류를 찾는 배열이 그렇다.
|
||||
|
||||
값이 하나뿐이거나 분기가 한 곳에만 있으면 표로 바꾸는 비용이 이득보다 크다.
|
||||
- 값이 하나뿐이거나 분기가 한 곳에만 있으면 표로 바꾸는 비용이 이득보다 크다.
|
||||
|
||||
## 예시
|
||||
|
||||
종류를 하나 더한 커밋에서 컴파일러가 게시 상태 코드와 활동 유형과 소유자 유형과 slug 중복 검사와 렌더 모델까지 짚었다. 식으로 쓴 switch 였기 때문이다.
|
||||
- 종류를 하나 더한 커밋에서 컴파일러가 게시 상태 코드와 활동 유형과 소유자 유형과 slug 중복 검사와 렌더 모델까지 짚었다. 식으로 쓴 switch 였기 때문이다.
|
||||
|
||||
같은 종류를 더할 때 프론트엔드에서는 열세 곳이 조용히 지나갔다. 삼항 사슬과 배열 리터럴이었다.
|
||||
- 같은 종류를 더할 때 프론트엔드에서는 열세 곳이 조용히 지나갔다. 삼항 사슬과 배열 리터럴이었다.
|
||||
|
||||
계약에서 CONCEPT 을 빼자 백엔드의 계약 대조 테스트가 빨개졌다. 그 확인을 하고 커밋했다.
|
||||
- 계약에서 CONCEPT 을 빼자 백엔드의 계약 대조 테스트가 빨개졌다. 그 확인을 하고 커밋했다.
|
||||
|
||||
라우트에 딸린 청크 이름 표도 같은 부류라 다섯 검사 안에서 대조하게 했다.
|
||||
- 라우트에 딸린 청크 이름 표도 같은 부류라 다섯 검사 안에서 대조하게 했다.
|
||||
|
||||
종류별 목록 주소가 세 화면에 흩어져 있던 동안 셋 다 개념을 빠뜨렸다. 표 하나로 모은 뒤에는 화면들이 목록을 손으로 적지 않고 그 표에서 뽑는다.
|
||||
- 종류별 목록 주소가 세 화면에 흩어져 있던 동안 셋 다 개념을 빠뜨렸다. 표 하나로 모은 뒤에는 화면들이 목록을 손으로 적지 않고 그 표에서 뽑는다.
|
||||
+16
-6
@@ -60,25 +60,35 @@ tech-log-frontend : ab8c6c1 · 6784eb1
|
||||
|
||||
## 내부 이동은 되고 하드 로드는 안 된다
|
||||
|
||||
SPA 안에서 이동할 때는 라우터가 화면을 그리므로 웹 서버가 개입하지 않는다. 주소를 직접 넣거나 새로고침하면 웹 서버가 먼저 그 경로를 받는다.
|
||||
SPA 안에서 이동할 때는 라우터가 화면을 그리므로 웹 서버가 개입하지 않는다. 주소를 직접 넣거나 새로고침하면 웹 서버가 그 경로를 먼저 받는다.
|
||||
|
||||
서빙 계약에 그 경로가 없으면 nginx 는 SPA 로 넘기지 않고 404 를 준다.
|
||||
서빙 계약에 그 경로가 없으면 nginx 는 SPA 로 넘기지 않고 평문 404 를 준다. 그래서 「내부에서는 되는데 새로고침하면 안 된다」로 나타나고, 개발 중에는 대개 내부 이동으로만 화면에 닿으므로 배포 뒤에 드러난다.
|
||||
|
||||
## 손으로 유지하는 절반
|
||||
|
||||
서빙 계약의 절반은 라우트 레지스트리에서 유도하고 있었고 나머지 절반은 배열이었다.
|
||||
|
||||
> 서빙 계약의 공개 절반은 라우트 레지스트리에서 패턴을 유도한다. **Studio 절반은 손으로 유지하는 배열이었고, 손으로 유지하는 배열이 실패하는 방식 그대로 실패했다** — `^/studio/assets$` 위의 주석이 바로 그 버그를 한 번 고친 기록이고, 라우트를 더하니 즉시 반복됐다.
|
||||
|
||||
그 주석이 남아 있었다는 것이 이 건의 성격을 말한다. 같은 배열을 한 번 고치면서 왜 고쳤는지를 적어 두었는데, 다음 사람이 그 배열에 줄을 더할 때 그 주석을 읽지 않았다.
|
||||
|
||||
## 얼어붙은 27개
|
||||
|
||||
공개 절반도 유도가 아니었다. 서빙 계약이 번들된 픽스처에 우연히 들어 있던 공개 경로를 전부 열거하고, 생성된 nginx 가 정확히 그것들을 `location =` 블록으로 게시했다.
|
||||
공개 절반도 유도라고 하기 어려웠다. 서빙 계약이 번들된 픽스처에 우연히 들어 있던 공개 경로를 전부 열거하고, 생성된 nginx 가 정확히 그것들을 `location =` 블록으로 게시했다.
|
||||
|
||||
빌드 이후에 게시된 기록 — 백엔드를 두는 이유 그 자체 — 은 SPA 에 묻기도 전에 엣지에서 404 였다. 경로 27개가 얼어 있었고 28번째는 무엇이든 닿을 수 없었다.
|
||||
`location =` 은 정확히 일치하는 경로만 잡는다. 그래서 빌드 시점에 픽스처에 있던 27개는 열리고, 빌드 이후에 게시된 기록은 SPA 에 묻기도 전에 엣지에서 404 였다 — 백엔드를 두는 이유 그 자체가 그 경계에서 막혔다.
|
||||
|
||||
## 라우트 계약에서 유도한다
|
||||
|
||||
지금은 라우트 계약에서 등록된 Public 라우트마다 정규식 하나를 만든다. 파라미터는 한 세그먼트만 잡고 슬래시는 잡지 않으므로 `/cases/a/b` 는 404 로 남는다.
|
||||
지금은 라우트 계약에서 등록된 Public 라우트마다 정규식 하나를 만든다.
|
||||
|
||||
같은 구조 때문에 `robots.txt` 도 404 였다. 파일은 이미지에 있었지만 nginx 설정이 서빙할 파일을 하나씩 명시하는 구조라 등록되지 않은 것은 SPA 폴백으로 떨어졌고, 크롤러가 index.html 을 규칙으로 읽을 수는 없으므로 규칙이 없는 것과 같았다.
|
||||
파라미터는 한 세그먼트만 잡고 슬래시는 잡지 않는다. 그래서 `/cases/a/b` 는 404 로 남고, 그 주소가 잘못됐다는 것이 방문자에게도 감사에게도 드러난다.
|
||||
|
||||
## 같은 구조가 파일에도 걸렸다
|
||||
|
||||
`robots.txt` 도 404 였다. 파일은 이미지에 있었지만 nginx 설정이 서빙할 파일을 하나씩 명시하는 구조라 등록되지 않은 것은 SPA 폴백으로 떨어진다.
|
||||
|
||||
폴백은 index.html 을 준다. 사람에게는 화면이 뜨는 것처럼 보이지만 크롤러는 그 HTML 을 robots 규칙으로 읽을 수 없다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
|
||||
+19
-5
@@ -60,6 +60,8 @@ CI : FE-GATE-009 — 라우트마다 수동 접근성 증거 1개
|
||||
|
||||
## 여덟 곳
|
||||
|
||||
개념 라우트를 더한 커밋이 그 목록을 남겼다.
|
||||
|
||||
```text
|
||||
라우트 계약 tech-log-route-contract.ts
|
||||
런타임 등록 route-runtime-contract
|
||||
@@ -73,13 +75,21 @@ CI 게이트 형상 digest 게이트 집합의 sha256
|
||||
|
||||
## 우는 시점이 다르다
|
||||
|
||||
주제 편집 화면을 더하고 청크 이름 표를 빠뜨렸더니 번들은 만들어지는데 빌드 매니페스트 단계에서 `Missing built route chunk: TECH_LOG_STUDIO_TOPIC_EDIT` 로 멈췄다. 검사 다섯 개를 다 통과한 뒤 배포 직전에야 드러났다.
|
||||
여덟이 같은 시점에 울면 한 번에 고치면 된다. 시점이 갈리므로 다섯 검사를 다 통과한 뒤에도 남는 것이 있다.
|
||||
|
||||
| 언제 우나 | 무엇이 |
|
||||
|---|---|
|
||||
| 빌드 매니페스트 단계 | vite chunk 이름 표 |
|
||||
| 배포 직전 CI | 아티팩트 개수 상수 · 수동 접근성 증거 개수 · 게이트 집합의 sha256 |
|
||||
| 배포 뒤 | nginx 서빙 패턴 |
|
||||
|
||||
주제 편집 화면을 더하고 청크 이름 표를 빠뜨렸더니 번들은 만들어지는데 매니페스트 단계에서 `Missing built route chunk: TECH_LOG_STUDIO_TOPIC_EDIT` 로 멈췄다. 검사 다섯 개를 다 통과한 뒤 배포 직전에야 드러났다.
|
||||
|
||||
이 표도 손으로 나열한 목록이므로 다섯 검사 안에서 대조하게 했다.
|
||||
|
||||
## 게이트 기준값 셋은 라우트마다 움직인다
|
||||
## 게이트 기준값 셋이 함께 움직인다
|
||||
|
||||
FE-GATE-009 는 설치된 라우트마다 수동 접근성 증거를 하나씩 요구하고, 그 집합이 정확히 일치하지 않으면 거절한다.
|
||||
접근성 게이트는 설치된 라우트마다 수동 증거를 하나씩 요구하고, 그 집합이 정확히 일치하지 않으면 거절한다. 빠뜨림이 통과가 되지 않게 하려고 정확한 일치를 요구하는 것이고, 그래서 라우트를 더할 때마다 상수 셋이 함께 움직인다.
|
||||
|
||||
| 커밋 | 라우트 | 아티팩트 기준선 | 증거 개수 | digest |
|
||||
|---|---|---|---|---|
|
||||
@@ -88,12 +98,16 @@ FE-GATE-009 는 설치된 라우트마다 수동 접근성 증거를 하나씩
|
||||
| `048c1b2` | `/concepts/:slug` | +1 | +1 | fb138e7c… 재계산 |
|
||||
| `fe6b56a` | `/topics`, `/topics/:s/:v`, `/studio/topics/:id` | 135 → 138 | 114 → 117 | 87a22f68… 재계산 |
|
||||
|
||||
표의 마지막 줄인 주제 화면 셋을 더할 때는 이 목록을 또 빠뜨렸다. 게이트가 빨간 채로 여러 커밋을 지나갔고, 결정 404 를 고치던 `fe6b56a` 에서야 함께 맞췄다.
|
||||
## 옛 값을 먼저 재현한다
|
||||
|
||||
digest 를 다시 계산할 때는 매번 이전 gates.json 에서 옛 상수를 먼저 재현해 계산 방법이 맞는지 확인한 뒤 새 파일을 해싱했다. 그렇게 하지 않으면 계산이 달라져서 새 값이 나온 것과 파일이 바뀌어서 새 값이 나온 것을 구분할 수 없다.
|
||||
digest 를 다시 계산할 때는 매번 이전 gates.json 에서 옛 상수를 먼저 재현해 계산 방법이 맞는지 확인한 뒤 새 파일을 해싱했다.
|
||||
|
||||
그렇게 하지 않으면 「계산이 달라졌는데 새 값이 나왔다」와 「파일이 바뀌어서 새 값이 나왔다」를 구분할 수 없다. 둘 다 새 값이 나오고 둘 다 게이트를 통과시킨다.
|
||||
|
||||
## 확인하지 못한 것
|
||||
|
||||
게이트 기준값 셋은 여전히 손으로 움직인다. 옛 값을 먼저 재현하는 절차는 사람이 기억해야 하고 검사가 강제하지 않는다.
|
||||
|
||||
주제 화면 셋을 더할 때 이 목록을 또 빠뜨렸고, 게이트가 빨간 채로 여러 커밋을 지나갔다.
|
||||
|
||||
<!-- body:end -->
|
||||
|
||||
+13
-7
@@ -30,20 +30,26 @@ source:
|
||||
|
||||
## 결정문
|
||||
|
||||
라우트 계약에서 nginx 서빙 패턴을 생성할 때, catch-all 라우트는 패턴으로 번역하지 않고 버린다. 등록된 Public 라우트마다 정규식 하나를 만들고, 파라미터는 한 세그먼트만 잡되 슬래시는 잡지 않는다.
|
||||
라우트 계약에서 nginx 서빙 패턴을 생성할 때, catch-all 라우트는 패턴으로 번역하지 않고 버린다.
|
||||
|
||||
등록된 Public 라우트마다 정규식 하나를 만들고, 파라미터는 한 세그먼트만 잡되 슬래시는 잡지 않는다.
|
||||
|
||||
## 판단 이유
|
||||
|
||||
모든 미매치 URL 에 index.html 을 주면 엣지에서 404 였을 요청이 200 으로 바뀐다. 그러면 깨진 링크를 크롤러도 우리도 볼 수 없다.
|
||||
모든 미매치 URL 에 index.html 을 주면 엣지에서 404 였을 요청이 200 으로 바뀐다. 라우터는 그 주소를 모르므로 「없는 화면」을 그리지만, 상태 코드는 200 이다.
|
||||
|
||||
서버가 내보내는 주소를 전수 감사할 때 그 감사가 상태 코드로 판정한다. soft 200 이 섞이면 감사가 통과하고 방문자만 빈 화면을 만난다.
|
||||
그러면 깨진 링크를 상태 코드로 판정하는 쪽이 전부 못 본다. 크롤러도 못 보고, 서버가 내보내는 주소를 전수로 훑는 감사도 못 본다. 그 감사는 이 저장소에서 실제로 결함을 잡은 방법이고, soft 200 이 섞이면 감사가 통과하면서 방문자만 빈 화면을 만난다.
|
||||
|
||||
파라미터가 슬래시를 잡지 않게 한 것도 같은 이유다. `/cases/a/b` 가 404 로 남아야 그 주소가 잘못됐다는 것이 드러난다.
|
||||
파라미터가 슬래시를 잡지 않게 한 것도 같은 이유다. `/cases/a/b` 가 404 로 남아야 그 주소가 잘못됐다는 것이 드러난다. 슬래시까지 잡으면 세그먼트가 몇 개든 라우트에 걸리고, 라우터가 그것을 「없는 기록」으로 그린다.
|
||||
|
||||
대안은 catch-all 을 번역하고 라우터가 404 화면을 그리게 하는 것이었다. 사람에게 보이는 화면은 같지만 기계가 읽는 상태 코드가 달라지므로 고르지 않았다.
|
||||
|
||||
## 영향
|
||||
|
||||
라우트를 더할 때마다 서빙 패턴도 움직인다. 이 비용은 라우트 계약에서 유도해 없앴다 — 손으로 배열을 고치지 않는다.
|
||||
라우트를 더할 때마다 서빙 패턴이 함께 움직인다. 이 비용은 라우트 계약에서 유도해 없앴다 — 손으로 배열을 고치지 않는다.
|
||||
|
||||
등록되지 않은 주소는 SPA 에 닿지 못한다. 라우트를 더하고 프론트를 배포하기 전까지 그 경로는 엣지에서 404 다. 그래서 새 라우트는 프론트를 먼저 배포한다.
|
||||
등록되지 않은 주소는 SPA 에 닿지 못한다. 라우트를 더하고 프론트를 배포하기 전까지 그 경로는 엣지에서 404 이고, 그래서 새 라우트는 프론트를 먼저 배포한다.
|
||||
|
||||
감사에서 200 을 받은 35개 주소는 실제로 화면이 그려지는 주소다.
|
||||
배포 뒤 감사에서 200 을 받은 35개 주소는 실제로 화면이 그려지는 주소다. catch-all 을 번역했다면 그 수는 아무 주소나 세어도 나왔을 것이다.
|
||||
|
||||
파일도 같은 규칙을 받는다. 서빙 목록에 등록되지 않은 정적 파일은 SPA 폴백으로 떨어지므로, 크롤러가 읽어야 하는 파일은 그 목록에 명시해야 한다.
|
||||
|
||||
+28
-14
@@ -28,36 +28,50 @@ source:
|
||||
|
||||
## 목적
|
||||
|
||||
라우트를 더할 때 같이 고쳐야 하는 목록이 빠지는 것을 막는다. 이 부류는 우는 시점이 제각각이라, 어떤 것은 배포한 뒤 방문자가 먼저 만난다.
|
||||
라우트를 더할 때 함께 움직여야 하는 목록이 빠지는 것을 막는다.
|
||||
|
||||
이 부류는 우는 시점이 제각각이다. 어떤 것은 빌드 매니페스트 단계에서, 어떤 것은 배포 직전 CI 에서, 어떤 것은 배포한 뒤 방문자가 먼저 만난다.
|
||||
|
||||
## 규칙
|
||||
|
||||
**서빙 패턴은 라우트 계약에서 유도한다**
|
||||
등록된 Public 라우트마다 정규식 하나를 만든다. 파라미터는 한 세그먼트만 잡고 슬래시는 잡지 않는다.
|
||||
### 1. 서빙 패턴은 라우트 계약에서 유도한다
|
||||
|
||||
**빌드가 아는 목록을 서빙 계약의 근거로 쓰지 않는다**
|
||||
번들된 픽스처에 우연히 들어 있던 경로를 열거하면 빌드 이후에 게시된 기록이 엣지에서 404 가 된다.
|
||||
등록된 Public 라우트마다 정규식 하나를 만든다. 파라미터는 한 세그먼트만 잡고 슬래시는 잡지 않는다 — 그래야 잘못된 주소가 404 로 남아 감사에 잡힌다.
|
||||
|
||||
**유도할 수 없는 목록에는 대조 검사를 둔다**
|
||||
vite chunk 이름 표가 그렇다. 이 표를 빠뜨리면 다섯 검사를 다 통과한 뒤 빌드 매니페스트 단계에서 멈춘다.
|
||||
### 2. 빌드가 아는 목록을 서빙 계약의 근거로 쓰지 않는다
|
||||
|
||||
**기준값 상수는 옛 값을 먼저 재현한 뒤 갱신한다**
|
||||
그렇게 하지 않으면 계산 방법이 달라져 새 값이 나온 것과 파일이 바뀌어 새 값이 나온 것을 구분할 수 없다.
|
||||
번들된 픽스처에 우연히 들어 있던 경로를 열거하면 그 목록이 빌드 시점에 얼어붙는다. `location =` 은 정확히 일치하는 경로만 잡으므로, 빌드 이후에 게시된 기록은 SPA 에 묻기도 전에 엣지에서 404 가 된다.
|
||||
|
||||
### 3. 유도할 수 없는 목록에는 대조 검사를 둔다
|
||||
|
||||
청크 이름 표가 그렇다. 번들러가 그 표를 읽어 이름을 정하므로 라우트 계약에서 만들어 낼 수 없고, 대신 두 목록이 같은지 보는 검사를 다섯 검사 안에 넣는다.
|
||||
|
||||
### 4. 기준값 상수는 옛 값을 먼저 재현한 뒤 갱신한다
|
||||
|
||||
새 값만 계산해 적으면 계산 방법이 달라져 새 값이 나온 것과 파일이 바뀌어 새 값이 나온 것을 구분할 수 없다. 둘 다 게이트를 통과시킨다.
|
||||
|
||||
### 5. 정확한 일치를 요구하는 게이트는 그 대가를 함께 적는다
|
||||
|
||||
빠뜨림이 통과가 되지 않게 하려면 집합이 정확히 일치해야 한다. 그러면 라우트를 더할 때마다 상수들이 함께 움직이고, 그 갱신을 사람이 한다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
라우트 하나가 서빙 패턴·청크 이름·게이트 기준값 같은 목록을 동시에 움직이는 프론트엔드. 라우트를 더하거나 지우는 변경에서 걸린다.
|
||||
- 라우트 하나가 서빙 패턴·청크 이름·게이트 기준값 같은 목록을 함께 움직이는 프론트엔드. 라우트를 더하거나 지우는 변경에서 걸린다.
|
||||
|
||||
- 새 화면을 여는 작업을 시작할 때 그 목록부터 세고 시작한다. 다 만든 뒤에 세면 배포 직전에 걸린다.
|
||||
|
||||
## 예외
|
||||
|
||||
catch-all 라우트는 서빙 패턴으로 번역하지 않는다. 모든 미매치 URL 에 index.html 을 주면 엣지 404 가 soft 200 이 된다.
|
||||
- catch-all 라우트는 서빙 패턴으로 번역하지 않는다. 모든 미매치 URL 에 index.html 을 주면 엣지 404 가 soft 200 이 된다.
|
||||
|
||||
목록이 하나이고 그 목록을 빌드가 강제하면 유도 규칙을 따로 두지 않아도 된다.
|
||||
- 목록이 하나이고 그 목록을 빌드가 강제하면 유도 규칙을 따로 두지 않아도 된다.
|
||||
|
||||
## 예시
|
||||
|
||||
`/studio/releases` 가 평문 404 였다. 라우트도 청크도 있었고 서빙 계약의 손 배열에만 없었다.
|
||||
|
||||
주제 편집 화면을 더하고 청크 이름 표를 빠뜨렸더니 빌드 매니페스트 단계에서 멈췄다.
|
||||
- 같은 배열을 한 번 고치면서 왜 고쳤는지를 주석으로 남겨 두었는데, 다음 사람이 그 배열에 줄을 더할 때 그 주석을 읽지 않았다.
|
||||
|
||||
라우트 셋을 더하면서 게이트 기준값을 빠뜨렸다. 게이트가 빨간 채로 여러 커밋을 지나갔다.
|
||||
- 주제 편집 화면을 더하고 청크 이름 표를 빠뜨렸더니 검사 다섯 개를 다 통과한 뒤 빌드 매니페스트 단계에서 멈췄다.
|
||||
|
||||
- 라우트 셋을 더하면서 게이트 기준값을 빠뜨렸다. 게이트가 빨간 채로 여러 커밋을 지나갔다.
|
||||
+16
-11
@@ -31,33 +31,38 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**톤을 지적받으면 고쳐 쓰기 전에 어떤 말을 쓸지 묻는다**
|
||||
### 1. 톤을 지적받으면 고쳐 쓰기 전에 어떤 말을 쓸지 묻는다
|
||||
|
||||
「더 나은 문장」을 제안하는 것과 그 사람의 말투로 쓰는 것은 다른 일이고, 후자는 제안하는 쪽이 잘하지 못한다.
|
||||
|
||||
**무엇이 AI 스러운지 구체적으로 받아 적는다**
|
||||
### 2. 무엇이 AI 스러운지 구체적으로 받아 적는다
|
||||
|
||||
무엇을 하는지 말하지 않는 동사로 끝나는 것과 번역투가 실제로 지적된 두 가지였다.
|
||||
|
||||
**작성자가 이미 쓰는 말투를 따른다**
|
||||
### 3. 작성자가 이미 쓰는 말투를 따른다
|
||||
|
||||
Case 소제목에 쓰는 말이 「~한 것」 명사형이면 새 제목도 그 형태로 맞춘다. 의문형 꼬리와 이 기록에서 쓰지 않는 낱말은 쓰지 않는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
공개 화면의 글이 작성자의 목소리인 곳 — 프로필, 프로젝트 소개, 구역 제목, 기록의 소제목.
|
||||
- 공개 화면의 글이 작성자의 목소리인 곳 — 프로필, 프로젝트 소개, 구역 제목, 기록의 소제목
|
||||
- 톤이 어색하다는 지적을 받았을 때
|
||||
- 기존 글에 없던 낱말이나 어미를 새로 넣으려 할 때
|
||||
|
||||
## 예외
|
||||
|
||||
오류 문구처럼 서버가 답한 사실을 그대로 실어야 하는 곳에서는 말투를 묻지 않는다. 무엇을 실을지를 먼저 정한다.
|
||||
- 오류 문구처럼 서버가 답한 사실을 그대로 실어야 하는 곳에서는 말투를 묻지 않는다. 무엇을 실을지를 먼저 정한다.
|
||||
|
||||
계약이나 코드가 정한 이름은 이 규칙에서 뺀다. 표시 이름만 바꾸고 계약 값은 건드리지 않는다.
|
||||
- 계약이나 코드가 정한 이름은 이 규칙에서 뺀다. 표시 이름만 바꾸고 계약 값은 건드리지 않는다.
|
||||
|
||||
## 예시
|
||||
|
||||
「섞는다」·「함께 기록한다」·「흩어지지 않게」가 무엇을 하는지 말하지 않는 동사로 끝난다고 지적받았다.
|
||||
- 「섞는다」·「함께 기록한다」·「흩어지지 않게」가 무엇을 하는지 말하지 않는 동사로 끝난다고 지적받았다.
|
||||
|
||||
「결론이 서는 조건」·「프로젝트를 답니다」·「접근을 나눠 견주고」가 번역투로 지적받았다.
|
||||
- 「결론이 서는 조건」·「프로젝트를 답니다」·「접근을 나눠 견주고」가 번역투로 지적받았다.
|
||||
|
||||
「무엇을 견줬나」는 의문형 꼬리에 이 기록에서 쓰지 않는 낱말이었다. 작성자가 Case 소제목에 쓰는 말은 「이 구조에서 감수한 것」처럼 「~한 것」 명사형이라 그쪽에 맞췄다.
|
||||
- 「무엇을 견줬나」는 의문형 꼬리에 이 기록에서 쓰지 않는 낱말이었다. 작성자가 Case 소제목에 쓰는 말은 「이 구조에서 감수한 것」처럼 「~한 것」 명사형이라 그쪽에 맞췄다.
|
||||
|
||||
「이 프로젝트가 밝힌 것」은 「프로젝트를 통해 확인한 결과」로, 「운영 가능한 설계로 연결합니다」는 「실제 운영에 적용할 수 있는 형태로 정리합니다」로 바꿨다.
|
||||
- 「이 프로젝트가 밝힌 것」은 「프로젝트를 통해 확인한 결과」로, 「운영 가능한 설계로 연결합니다」는 「실제 운영에 적용할 수 있는 형태로 정리합니다」로 바꿨다.
|
||||
|
||||
고쳐 쓴 첫 번째 안이 거절당한 뒤 사용자가 직접 쓴 텍스트를 실었다.
|
||||
- 고쳐 쓴 첫 번째 안이 거절당한 뒤 사용자가 직접 쓴 텍스트를 실었다.
|
||||
+21
-15
@@ -35,44 +35,50 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**스프링 컨텍스트를 띄우는 검사를 하나 둔다**
|
||||
### 1. 스프링 컨텍스트를 띄우는 검사를 하나 둔다
|
||||
|
||||
컴파일도 단위 테스트도, 실제 데이터베이스를 쓰는 통합 테스트도 컨텍스트를 띄우지 않을 수 있다. 컨테이너가 필요해서 통합 테스트인 것과 컨텍스트를 띄우는 것은 다르다. 스캔되는 컴포넌트의 생성자 규칙처럼 정적으로 셀 수 있는 것은 아키텍처 검사로 대신할 수 있고, 그 편이 빌드 시간을 늘리지 않는다.
|
||||
|
||||
**persistence SQL 을 실제 데이터베이스에서 돌리는 태스크를 둔다**
|
||||
### 2. persistence SQL 을 실제 데이터베이스에서 돌리는 태스크를 둔다
|
||||
|
||||
표준 검사가 컨테이너를 띄우지 않으면 어댑터의 SQL 은 한 줄도 실행되지 않는다. 컴파일은 문자열 안을 보지 않고 단위 테스트는 어댑터를 스텁으로 바꾸므로, 컬럼 이름은 실행해야만 검증된다.
|
||||
|
||||
**계약 모양 그대로의 응답을 진짜 게이트웨이에 넣는 검사를 둔다**
|
||||
### 3. 계약 모양 그대로의 응답을 진짜 게이트웨이에 넣는 검사를 둔다
|
||||
|
||||
화면 테스트는 정적 픽스처 어댑터를 쓰므로 계약 모양을 한 번도 통과시키지 않는다. 픽스처를 게이트웨이가 읽는 모양으로 만들면 그 테스트는 늘 통과한다.
|
||||
|
||||
**실제 런타임 어댑터를 실제 응답 본문에 대고 조립하는 검사를 둔다**
|
||||
### 4. 실제 런타임 어댑터를 실제 응답 본문에 대고 조립하는 검사를 둔다
|
||||
|
||||
게이트웨이 테스트는 실행기를 스텁으로 바꾸고 화면 테스트는 게이트웨이를 스텁으로 바꾼다. 합성 루트에서 credential 을 정하는 코드는 둘 다 덮지 않는다.
|
||||
|
||||
**생성기는 모델이 만들어졌는지가 아니라 property 가 계약과 같은지로 본다**
|
||||
### 5. 생성기는 모델이 만들어졌는지가 아니라 property 가 계약과 같은지로 본다
|
||||
|
||||
모델은 필드가 빠져도 만들어진다. 아직 그 필드를 쓰는 코드가 없으면 컴파일도 통과한다.
|
||||
|
||||
**전용 태스크로 뺐으면 그것을 돌리는 것이 사람 몫이라는 것도 적는다**
|
||||
### 6. 전용 태스크로 뺐으면 그것을 돌리는 것이 사람 몫이라는 것도 적는다
|
||||
|
||||
컨테이너를 띄우는 검사를 표준 검사에 넣으면 모든 빌드가 느려진다. 빼는 것은 되지만, 뺀 뒤에 그 태스크가 돌지 않으면 검사가 없는 것과 같다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
스텁으로 층을 나눠 시험하는 구조. 계약이 다른 저장소에 있고 생성기를 지나 들어오거나, 컨테이너가 필요한 검사를 별도 태스크로 뺀 저장소에서 걸린다.
|
||||
- 스텁으로 층을 나눠 시험하는 구조. 계약이 다른 저장소에 있고 생성기를 지나 들어오거나, 컨테이너가 필요한 검사를 별도 태스크로 뺀 저장소에서 걸린다.
|
||||
|
||||
「모든 검사가 통과했는데 운영에서 깨졌다」가 나오면 무엇이 깨졌는지보다 어느 이음매를 아무 검사도 지나지 않았는지를 먼저 센다.
|
||||
- 「모든 검사가 통과했는데 운영에서 깨졌다」가 나오면 무엇이 깨졌는지보다 어느 이음매를 아무 검사도 지나지 않았는지를 먼저 센다.
|
||||
|
||||
## 예외
|
||||
|
||||
그 층을 실제로 지나는 검사가 이미 있으면 더 두지 않는다.
|
||||
- 그 층을 실제로 지나는 검사가 이미 있으면 더 두지 않는다.
|
||||
|
||||
스텁을 쓰는 테스트를 늘리는 것은 이 문제를 덮지 않는다. 스텁의 개수가 아니라 어느 층을 대신했는지가 기준이다.
|
||||
- 스텁을 쓰는 테스트를 늘리는 것은 이 문제를 덮지 않는다. 스텁의 개수가 아니라 어느 층을 대신했는지가 기준이다.
|
||||
|
||||
정적으로 셀 수 있는 규칙은 컨텍스트를 띄우지 않고도 걸린다. 그때는 무거운 검사를 새로 두지 않는다.
|
||||
- 정적으로 셀 수 있는 규칙은 컨텍스트를 띄우지 않고도 걸린다. 그때는 무거운 검사를 새로 두지 않는다.
|
||||
|
||||
## 예시
|
||||
|
||||
컨텍스트를 띄우지 않아 파드가 두 번 CrashLoopBackOff 로 들어갔다. 실제 PostgreSQL 위에서 도는 통합 테스트 26개도 통과한 상태였다.
|
||||
- 컨텍스트를 띄우지 않아 파드가 두 번 CrashLoopBackOff 로 들어갔다. 실제 PostgreSQL 위에서 도는 통합 테스트 26개도 통과한 상태였다.
|
||||
|
||||
삭제 경로의 SQL 이 한 번도 실행된 적이 없어서 전용 통합 테스트 태스크를 만들었다.
|
||||
- 삭제 경로의 SQL 이 한 번도 실행된 적이 없어서 전용 통합 테스트 태스크를 만들었다.
|
||||
|
||||
화면 테스트가 픽스처를 쓰므로 질문 상세의 매핑을 아무도 지나지 않았다. 계약 모양 응답을 진짜 게이트웨이에 넣으니 되돌려 보면 운영과 같은 오류로 실패한다.
|
||||
- 화면 테스트가 픽스처를 쓰므로 질문 상세의 매핑을 아무도 지나지 않았다. 계약 모양 응답을 진짜 게이트웨이에 넣으니 되돌려 보면 운영과 같은 오류로 실패한다.
|
||||
|
||||
생성 모델 대조를 schema 이름에서 property 로 바꿨다. 이름 대조는 필드 넷이 빠진 모델을 통과시켰다.
|
||||
- 생성 모델 대조를 schema 이름에서 property 로 바꿨다. 이름 대조는 필드 넷이 빠진 모델을 통과시켰다.
|
||||
+20
-15
@@ -34,43 +34,48 @@ Studio 편집기에서는 값이 다 보이는데 공개 화면만 비어 있으
|
||||
|
||||
## 규칙
|
||||
|
||||
**Studio 에서는 보이고 공개 쪽만 비면 그 사이의 계약을 먼저 본다**
|
||||
### 1. Studio 에서는 보이고 공개 쪽만 비면 그 사이의 계약을 먼저 본다
|
||||
|
||||
두 화면이 같은 데이터베이스를 보는데 한쪽만 비면, 다른 것은 그 사이에 놓인 계약이다. 작성 쪽은 작성 계약을 지나고 조회 쪽은 조회 계약을 지난다. 이 저장소에서 같은 신호가 여덟 번 같은 원인을 가리켰다.
|
||||
|
||||
**화면이 그리는 칸을 먼저 적고 응답에 있는지 하나씩 맞춘다**
|
||||
### 2. 화면이 그리는 칸을 먼저 적고 응답에 있는지 하나씩 맞춘다
|
||||
|
||||
응답에서 출발하면 없는 칸은 보이지 않는다. 상세 endpoint 가 없는 종류에서 특히 그렇다 — 부를 상세가 없으므로 목록 항목이 문서 전체를 실어야 하고, 그 목록에 없는 칸은 화면이 각자 메운다.
|
||||
|
||||
**한 종류의 저장 구조가 다른 종류와 다르면 조회 쪽이 그것을 알아야 한다**
|
||||
### 3. 한 종류의 저장 구조가 다른 종류와 다르면 조회 쪽이 그것을 알아야 한다
|
||||
|
||||
Reference 의 본문은 문서 본문 칸이 아니라 규칙과 예시를 담는 별도 테이블에 있다. 이름이 맞아도 읽는 곳이 틀리면 빈 문자열이 나온다.
|
||||
|
||||
**칸을 더할 때 required 로 올릴지는 따로 판단한다**
|
||||
### 4. 칸을 더할 때 required 로 올릴지는 따로 판단한다
|
||||
|
||||
이미 나가 있는 응답에는 그 칸이 없다. required 로 올리면 계약을 반입한 쪽이 배포되기 전까지 그 응답이 검증에 걸린다. 배포 순서에 따라 깨지는 것과 값이 안 오는 것 중에서 고른다.
|
||||
|
||||
**값이 아니라 이름을 지키는 검사를 둔다**
|
||||
### 5. 값이 아니라 이름을 지키는 검사를 둔다
|
||||
|
||||
게이트웨이가 읽는 이름이 계약의 타입에 있는지를 묻는다. 값을 비교하는 검사는 픽스처를 게이트웨이가 읽는 이름으로 만들면 그대로 통과한다 — 테스트 작성자와 게이트웨이 작성자가 이름에 대해 합의한 것을 확인할 뿐이다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
같은 데이터를 두 표면이 각자의 계약으로 읽고, 한쪽만 비어 보이는 화면. 작성 계약과 조회 계약이 나뉜 구조에서 걸린다.
|
||||
- 같은 데이터를 두 표면이 각자의 계약으로 읽고, 한쪽만 비어 보이는 화면. 작성 계약과 조회 계약이 나뉜 구조에서 걸린다.
|
||||
|
||||
계약에 칸을 더하거나 화면에 칸을 더하는 변경에서도 건다. 화면이 먼저 늘면 그 칸이 응답에 있는지 확인할 곳이 없다.
|
||||
- 계약에 칸을 더하거나 화면에 칸을 더하는 변경에서도 건다. 화면이 먼저 늘면 그 칸이 응답에 있는지 확인할 곳이 없다.
|
||||
|
||||
## 예외
|
||||
|
||||
두 표면이 같은 계약을 쓰면 이 신호는 성립하지 않는다. 그때는 매퍼나 질의를 먼저 본다.
|
||||
- 두 표면이 같은 계약을 쓰면 이 신호는 성립하지 않는다. 그때는 매퍼나 질의를 먼저 본다.
|
||||
|
||||
저장 구조가 종류마다 다르면 계약이 아니라 조회가 원인일 수 있다. 이름이 계약과 맞는데도 값이 비면 그쪽을 본다.
|
||||
- 저장 구조가 종류마다 다르면 계약이 아니라 조회가 원인일 수 있다. 이름이 계약과 맞는데도 값이 비면 그쪽을 본다.
|
||||
|
||||
값이 있는데 겹쳐 보이는 경우는 이 신호가 아니다. 빈 칸을 다른 값으로 메우면 같은 글이 두 번 나온다.
|
||||
- 값이 있는데 겹쳐 보이는 경우는 이 신호가 아니다. 빈 칸을 다른 값으로 메우면 같은 글이 두 번 나온다.
|
||||
|
||||
## 예시
|
||||
|
||||
공개 Reference 가 통째로 비었을 때 게이트웨이가 읽던 네 이름이 전부 계약에 없었다.
|
||||
- 공개 Reference 가 통째로 비었을 때 게이트웨이가 읽던 네 이름이 전부 계약에 없었다.
|
||||
|
||||
프로젝트의 「주요 주제」는 테이블도 조인도 가능했는데 응답에 실을 칸이 없었다.
|
||||
- 프로젝트의 「주요 주제」는 테이블도 조인도 가능했는데 응답에 실을 칸이 없었다.
|
||||
|
||||
질문 목록만 주제가 빠져 있어서 질문 줄의 맥락이 「· 프로젝트」로 시작했다. 지식 목록은 처음부터 그 칸을 싣고 있었다.
|
||||
- 질문 목록만 주제가 빠져 있어서 질문 줄의 맥락이 「· 프로젝트」로 시작했다. 지식 목록은 처음부터 그 칸을 싣고 있었다.
|
||||
|
||||
프로젝트 목록 행에 slug 가 없었다. 다른 목록이 프로젝트를 가리킬 때 쓰는 것은 id 가 아니라 slug 다.
|
||||
- 프로젝트 목록 행에 slug 가 없었다. 다른 목록이 프로젝트를 가리킬 때 쓰는 것은 id 가 아니라 slug 다.
|
||||
|
||||
문서 요약 자리에 유형별 요약을 대신 넣었더니 머리말이 바로 아래와 같은 글을 두 번 말했다.
|
||||
- 문서 요약 자리에 유형별 요약을 대신 넣었더니 머리말이 바로 아래와 같은 글을 두 번 말했다.
|
||||
+18
-13
@@ -35,39 +35,44 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**고친 값이 실제로 그려지는 곳까지 가서 본다**
|
||||
### 1. 고친 값이 실제로 그려지는 곳까지 가서 본다
|
||||
|
||||
배포본에서 그 화면을 열거나 실제 요청을 보내 응답을 읽는다. 관계 요약은 세 경계에서 연달아 버려졌고, 매번 화면을 보고 나서야 다음 경계가 버리는 것을 알았다.
|
||||
|
||||
**타입 검사 통과를 반영의 증거로 쓰지 않는다**
|
||||
### 2. 타입 검사 통과를 반영의 증거로 쓰지 않는다
|
||||
|
||||
메서드 매개변수의 bivariance, `as` 단언, 검사 대상이 없는 tsconfig 가 각각 통과시킨 사례가 있다. 통과는 「코드가 맞다」가 아니라 「검사가 그 질문을 하지 않았다」를 뜻할 수 있다.
|
||||
|
||||
**게이트웨이를 실제로 불러 어떤 연산이 나가는지 확인한다**
|
||||
### 3. 게이트웨이를 실제로 불러 어떤 연산이 나가는지 확인한다
|
||||
|
||||
등록을 빠뜨린 연산은 옆 분기로 떨어지므로 서버는 정상 응답을 준다. 나가는 경로를 봐야 알 수 있다.
|
||||
|
||||
**여정이 끝나는 곳을 먼저 정하고 시작한다**
|
||||
### 4. 여정이 끝나는 곳을 먼저 정하고 시작한다
|
||||
|
||||
어디까지 가면 확인이 끝나는지 모르면 중간에서 멈추게 된다. 공개 화면의 한 줄이면 그 줄이 그려지는 화면이 끝이다.
|
||||
|
||||
**검사가 덮는 구간을 적어 둔다**
|
||||
### 5. 검사가 덮는 구간을 적어 둔다
|
||||
|
||||
값이 아니라 이름을 지키는 검사를 두면 여정의 한 구간을 그 검사가 대신한다. 그 구간이 어디까지인지 적어 두지 않으면 다음 사람이 검사를 여정 전체로 읽는다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
값이 계약·매퍼·포트를 여러 번 갈아타는 구조에서 「고쳤다」를 판단할 때. 계약을 소유한 저장소가 따로 있고 생성기를 지나 들어오면 특히 걸린다.
|
||||
- 값이 계약·매퍼·포트를 여러 번 갈아타는 구조에서 「고쳤다」를 판단할 때. 계약을 소유한 저장소가 따로 있고 생성기를 지나 들어오면 특히 걸린다.
|
||||
|
||||
앞선 커밋이 같은 값을 고치려다 못 고친 이력이 있으면 반드시 건다. 그 커밋이 무엇을 근거로 고쳤다고 판단했는지가 대개 중간 지점이다.
|
||||
- 앞선 커밋이 같은 값을 고치려다 못 고친 이력이 있으면 반드시 건다. 그 커밋이 무엇을 근거로 고쳤다고 판단했는지가 대개 중간 지점이다.
|
||||
|
||||
## 예외
|
||||
|
||||
경계가 하나뿐이거나 고친 그 곳이 여정의 끝이면 중간 확인으로 충분하다.
|
||||
- 경계가 하나뿐이거나 고친 그 곳이 여정의 끝이면 중간 확인으로 충분하다.
|
||||
|
||||
배포본을 열 수 없는 변경 — 아직 배포되지 않은 경로 — 은 여정의 끝까지 갈 수 없다. 그때는 어디까지 확인했는지를 적는다.
|
||||
- 배포본을 열 수 없는 변경 — 아직 배포되지 않은 경로 — 은 여정의 끝까지 갈 수 없다. 그때는 어디까지 확인했는지를 적는다.
|
||||
|
||||
## 예시
|
||||
|
||||
관계 요약을 세 번 고쳤다. 매번 화면을 보고 나서야 다음 경계가 버리는 것을 알았다.
|
||||
- 관계 요약을 세 번 고쳤다. 매번 화면을 보고 나서야 다음 경계가 버리는 것을 알았다.
|
||||
|
||||
개념 삭제가 계속 질문 삭제 경로로 나갔다. 타입 검사가 통과해서 반영된 줄 알았고, 배포된 번들의 서버 로그에서 404 를 보고 알았다.
|
||||
- 개념 삭제가 계속 질문 삭제 경로로 나갔다. 타입 검사가 통과해서 반영된 줄 알았고, 배포된 번들의 서버 로그에서 404 를 보고 알았다.
|
||||
|
||||
CONCEPT 을 질문 삭제로 되돌려 가드가 깨지는 것을 확인했다.
|
||||
- CONCEPT 을 질문 삭제로 되돌려 가드가 깨지는 것을 확인했다.
|
||||
|
||||
한 경계를 고치고 판단해 세 번 틀렸다. 값이 지나는 경계가 열한 개다.
|
||||
- 한 경계를 고치고 판단해 세 번 틀렸다. 값이 지나는 경계가 열한 개다.
|
||||
+17
-11
@@ -35,34 +35,40 @@ source:
|
||||
|
||||
## 규칙
|
||||
|
||||
**결함을 되돌려 그 가드가 실제로 멈추는 것을 확인한 뒤 커밋한다**
|
||||
### 1. 결함을 되돌려 그 가드가 실제로 멈추는 것을 확인한 뒤 커밋한다
|
||||
|
||||
계약에서 값을 빼고 대조 검사가 빨개지는지 본다. 매핑을 떼어 보고 그 연산 하나를 짚는지 본다.
|
||||
|
||||
**가드가 짚는 대상이 하나인지 본다**
|
||||
### 2. 가드가 짚는 대상이 하나인지 본다
|
||||
|
||||
전부를 짚으면 어디가 문제인지 알 수 없고, 결과가 곧 읽히지 않는다.
|
||||
|
||||
**되돌릴 수 없는 것은 현재 상태를 대신 증거로 남긴다**
|
||||
### 3. 되돌릴 수 없는 것은 현재 상태를 대신 증거로 남긴다
|
||||
|
||||
이미 마이그레이션으로 고친 데이터는 실패 상태를 다시 만들 수 없다. 그럴 때는 지금 고쳐져 있다는 것을 남긴다.
|
||||
|
||||
**가드를 CI 에 묶는다**
|
||||
### 4. 가드를 CI 에 묶는다
|
||||
|
||||
사람이 기억해서 돌리는 가드는 절반만 존재한다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
재발 방지로 넣는 테스트·아키텍처 규칙·CI 게이트. 결함을 고치는 커밋에서 함께 넣을 때 걸린다.
|
||||
- 재발 방지로 테스트·아키텍처 규칙·CI 게이트를 넣을 때
|
||||
- 결함을 고치는 커밋에서 가드를 함께 넣을 때
|
||||
- 이미 있는 가드가 무엇을 잡는지 확인해야 할 때
|
||||
|
||||
## 예외
|
||||
|
||||
결함을 되돌릴 수 없는 것 — 이미 마이그레이션으로 고친 데이터, 지난 배포에서만 나던 상태 — 은 현재 상태가 고쳐져 있음을 증거로 남긴다.
|
||||
- 결함을 되돌릴 수 없는 것 — 이미 마이그레이션으로 고친 데이터, 지난 배포에서만 나던 상태 — 은 현재 상태가 고쳐져 있음을 증거로 남긴다.
|
||||
|
||||
기존 가드를 옮기거나 이름만 바꾸는 변경은 되돌려 확인하지 않아도 된다. 다만 옮긴 뒤에 한 번은 돌린다.
|
||||
- 기존 가드를 옮기거나 이름만 바꾸는 변경은 되돌려 확인하지 않아도 된다. 다만 옮긴 뒤에 한 번은 돌린다.
|
||||
|
||||
## 예시
|
||||
|
||||
가드 셋을 각각 결함으로 되돌려 실제로 빨개지는 것을 확인한 기록을 남겼다.
|
||||
- 가드 셋을 각각 결함으로 되돌려 실제로 빨개지는 것을 확인한 기록을 남겼다.
|
||||
|
||||
계약에서 CONCEPT 을 빼자 백엔드의 계약 대조 테스트가 빨개졌다.
|
||||
- 계약에서 CONCEPT 을 빼자 백엔드의 계약 대조 테스트가 빨개졌다.
|
||||
|
||||
매핑을 떼어 보고 계약 대조 테스트가 그 연산 하나를 정확히 짚는 것을 확인했다.
|
||||
- 매핑을 떼어 보고 계약 대조 테스트가 그 연산 하나를 정확히 짚는 것을 확인했다.
|
||||
|
||||
굵기 선언을 빼 보고 제목 급 검사가 실제로 멈추는 것을 확인했다.
|
||||
- 굵기 선언을 빼 보고 제목 급 검사가 실제로 멈추는 것을 확인했다.
|
||||
+17
-11
@@ -35,37 +35,43 @@ CI 에 묶이지 않은 검증이 남아 있으면 그것을 돌리는 것은
|
||||
|
||||
## 규칙
|
||||
|
||||
**프론트는 다섯 개를 다 돌린다**
|
||||
### 1. 프론트는 다섯 개를 다 돌린다
|
||||
|
||||
타입 검사 · lint · 단위 테스트 · 컴포넌트 테스트 · 화면 테스트다. 화면 테스트는 단위 테스트 명령이 돌리지 않는다.
|
||||
|
||||
**타입 검사는 프로젝트를 순회하는 명령으로 돌린다**
|
||||
### 2. 타입 검사는 프로젝트를 순회하는 명령으로 돌린다
|
||||
|
||||
루트 tsconfig 를 직접 부르는 명령은 한 파일도 검사하지 않고 성공한다.
|
||||
|
||||
**백엔드는 커밋한 뒤에 빌드한다**
|
||||
### 3. 백엔드는 커밋한 뒤에 빌드한다
|
||||
|
||||
빌드 산출물 이름에 커밋 해시가 들어간다. 작업 트리가 더러우면 해시가 달라져 stale 산출물 검사가 멈춘다.
|
||||
|
||||
**테스트를 npm 이나 npx 로 감싸 돌리지 않는다**
|
||||
### 4. 테스트를 npm 이나 npx 로 감싸 돌리지 않는다
|
||||
|
||||
`npm_config_*` 환경 변수가 설정되어 CI 워크플로 생성 테스트가 실패한다. 그 변수를 지우고 실행기를 직접 부른다.
|
||||
|
||||
## 적용 조건
|
||||
|
||||
CI 에 묶이지 않은 검증이 남아 있는 저장소에서 배포 직전에 하는 일.
|
||||
- CI 에 묶이지 않은 검증이 남아 있는 저장소에서 배포 직전에 하는 일
|
||||
- 명령이 여럿이고 그중 일부만 도는 것이 가능할 때
|
||||
- 빌드 산출물이 작업 트리 상태에 따라 달라지는 저장소에서
|
||||
|
||||
## 예외
|
||||
|
||||
CI 가 그 명령을 돌리면 이 목록에서 뺀다.
|
||||
- CI 가 그 명령을 돌리면 이 목록에서 뺀다.
|
||||
|
||||
환경 때문에 실패하는 것은 실패로 세지 않는다. 하위 프로세스를 띄우는 세 케이스는 이 환경에서 실패하고 같은 리비전의 다른 실행에서도 똑같이 재현되므로 코드 변경과 무관하다.
|
||||
- 환경 때문에 실패하는 것은 실패로 세지 않는다. 하위 프로세스를 띄우는 세 케이스는 이 환경에서 실패하고 같은 리비전의 다른 실행에서도 똑같이 재현되므로 코드 변경과 무관하다.
|
||||
|
||||
## 예시
|
||||
|
||||
프론트 다섯 명령 :
|
||||
- 프론트 다섯 명령 :
|
||||
`npm run check:types`
|
||||
`npm run lint`
|
||||
단위 · 컴포넌트 · 화면 테스트
|
||||
|
||||
백엔드 : 커밋한 뒤 stale 산출물을 지우고 빌드한다. 이 순서를 몰라 두 번 헤맸다.
|
||||
- 백엔드 : 커밋한 뒤 stale 산출물을 지우고 빌드한다. 이 순서를 몰라 두 번 헤맸다.
|
||||
|
||||
설계 패키지 : 계약 자체의 유효성 · 세 계약 사이의 정합 · 프론트와 백엔드가 아는 종류와 오류 코드가 같은지, 셋을 돌린다.
|
||||
- 설계 패키지 : 계약 자체의 유효성 · 세 계약 사이의 정합 · 프론트와 백엔드가 아는 종류와 오류 코드가 같은지, 셋을 돌린다.
|
||||
|
||||
테스트 JVM 힙이 기본값이면 컨텍스트 캐시와 아키텍처 검사와 컨테이너가 겹치면서 메모리가 모자란다. 증상이 테스트 실패가 아니라 실행기를 완료할 수 없다는 메시지라 원인을 가린다.
|
||||
- 테스트 JVM 힙이 기본값이면 컨텍스트 캐시와 아키텍처 검사와 컨테이너가 겹치면서 메모리가 모자란다. 증상이 테스트 실패가 아니라 실행기를 완료할 수 없다는 메시지라 원인을 가린다.
|
||||
Reference in New Issue
Block a user