De-slop: 생성된 코드를 신중한 인간의 코드와 구분할 수 없게 만들기
슬롭은 스타일 문제가 아니라 신뢰 문제입니다. 슬롭 하나를 발견한 리뷰어는 코드 읽기를 멈추고 더 많은 슬롭을 찾기 시작합니다. 수정은 절대 외형적으로만 이루어져서는 안 됩니다. 아래의 각 패스는 외형뿐만 아니라 필요성을 검증합니다.
실제 diff를 기준으로 작업하고, 작성한 내용을 기억에 의존하지 마십시오. 작업이 여러 브랜치에 걸쳐 있다면 각 브랜치의 diff를 병합 기준(merge base)과 비교하여 감사하십시오.
Pass 0 — 작게 작성하고, 모든 줄을 정당화하라 (예방이 정리보다 낫다)
슬롭은 존재하기 전에 제거하는 것이 가장 저렴합니다. 빌드할 때:
- 조각조각 빌드하라. 한 가지 일을 하는 가장 작은 변경부터 시작하십시오. 올바르고 관용적인 코드가 될 때까지 다음 조각을 추가하지 마십시오. 한 번에 작성된 큰 diff는 항상 슬롭을 축적합니다. 반면, 각각 이 스킬에 따라 검토된 작은 증분 N개는 그렇지 않습니다. 이는 또한 작은 PR을 만들어 내며, 리뷰어는 큰 PR 하나보다 작은 PR을 일관되게 신뢰하고 더 빨리 승인합니다.
- 생성 시점에 모든 줄을 질문하라: 이 줄은 왜 존재하는가? 왜 기존 함수를 호출하는 대신 새 함수인가? 왜 새 파일인가? 답이 "생성 흐름이 그렇게 흘러갔다"라면 삭제하거나 접으십시오. 모든 추가에는 리뷰에서 말로 설명할 수 있는 이유가 있어야 합니다.
- 과도하게 복잡하게 만들지 마라. 두 번째 호출자가 생기기 전까지는 명확한 5줄 버전이 추상화된 25줄 버전보다 낫습니다. 추측성 매개변수, "미래 유연성"을 위한 코드, 하나의 값을 감싸는 래퍼 타입은 금지입니다.
- 바퀴를 다시 발명하지 마라 — 정리할 때뿐만 아니라 작성 시점에도: 유틸리티를 작성하기 전에 저장소에서 기존 헬퍼를 grep하고, 해당 문제를 소유한 패키지가 있는지 의존성 트리를 확인하십시오(Pass 2 참조).
- 작성하기 전에 이웃 코드를 읽어라. 인접한 파일을 먼저 읽고, 그들의 네이밍, 오류 처리, 테스트 하네스를 채택하여 새 코드가 항상 거기에 있었던 것처럼 읽히게 하십시오.
작업을 조각조각 빌드할 수 없는 경우(대규모 포팅, 벤더 계약), 그렇게 말하고 다른 사람이 보기 전에 더 엄격한 Pass 1~5 감사로 보완하십시오.
Pass 1 — 주석
가장 큰 신호입니다. 하나의 규칙을 적용하십시오: 주석은 코드가 보여줄 수 없는 제약 조건을 명시해야 합니다. 나머지는 모두 삭제합니다.
발견 즉시 삭제:
- 설명:
// 항목을 순회,// 헬퍼 호출,// 결과 반환 - 코드나 자신의 문서 헤더를 본문에서 두 번 반복하는 경우
- 리뷰어 말투:
// 위에서 확인했으므로 안전,// 참고:...— 이는 diff를 변호하는 것이지 다음 독자에게 정보를 주는 것이 아님 - PR, 리뷰, 대화 또는 "최근에 변경됨"에 대한 참조
- 변경이 올바른 이유를 설명하는 주석(PR 본문에 속함)
- ~300줄 미만 파일의 섹션 배너(
// ---- 헬퍼 ----)
유지 (이것들은 중요함):
- 와이어 포맷 또는 프로토콜 제약 조건, 특히 공개 사양 없이 리버스 엔지니어링된 것: 필드 X는 null일 때도 반드시 존재해야 함; 클라이언트 Y는 Z가 없으면 전체 페이로드를 거부함; 상류 소스 파일 인용
- 왜 아닌지에 대한 주석: 명백한 접근 방식이 왜 기각되었는지, 무엇이 깨지는지
- 독자가 넘어질 플랫폼 사실: 이 환경 변수는 유닉스 관례임; 이 API는 윈도우에서 조용히 아무 일도 하지 않음
- 보안/데이터 안전 불변 조건: 원시 레코드를 절대 캐시하지 마라, 비밀이 포함되어 있음
- 업스트림 기본값과 상충되는 의도적인 정책 고정, 리프트 조건 포함
밀도 휴리스틱(규칙 아님): 접착제/CRUD 코드의 경우 추가된 줄 15줄당 주석 줄이 1줄을 넘으면 재검토할 가치가 있습니다. 문서화되지 않은 프로토콜 코드의 경우 높은 밀도가 올바를 수 있습니다 — 주석이 바로 사양이기 때문입니다. 각 주석을 개수만이 아니라 유지/삭제 목록으로 판단하십시오.
문서 헤더: 순수 제약 조건만 4~8줄. 헤더가 모듈이 하는 일을 단계별로 설명하는 문단이라면, 파일 이름과 내보내기가 이미 말할 수 없는 것으로 줄이십시오.
Pass 2 — 의존성 또는 표준 라이브러리가 이미 제공하는 코드를 직접 구현한 경우
두 번째로 큰 신호: uuid, 해싱, semver 파싱, glob 매칭, 날짜 계산, 깊은 병합을 재구현하는 경우.
절차:
- 패키지가 이미 의존하는 것을 확인하십시오(package.json을 읽고 기억에 의존하지 마십시오). 새 의존성을 추가하는 것보다 기존 의존성이나 런타임 표준 라이브러리를 선호하십시오.
- 새 의존성이 필요하다면, 지루할 정도로 검증된(battle-tested) 것을 선택하십시오.
- 기존 수제 구현을 교체하기 전에 경험적으로 동등함을 증명하십시오 — 동일한 입력에 대해 둘 다 실행하고 출력을 비교하십시오. 특히 결정론적 ID 및 해싱 코드: 출력을 변경하는 교체는 기존 사용자에게 멱등성을 조용히 깨뜨립니다.
- 수제 버전을 유지하는 것이 진정으로 옳다면(10줄짜리 의존성을 피하는 경우), 리뷰어의 질문을 예상하고 그 논쟁이 의존성보다 더 가치 있는지 결정하십시오. 보통은 그렇지 않습니다: 지루한 것이 리뷰에서 이깁니다.
- 예외: 이미 표준 라이브러리 조합(createHash + pipeline)인 코드는 수제가 아닙니다. 질문받으면 그렇게 말하고; 더 감싸지 마십시오.
Pass 3 — 결집도와 필요성
슬롭은 축적됩니다: 각 편집이 추가만 하고 통합하지 않습니다. 다음을 찾으십시오:
- 반복되는 조건 표현식 → 한 번 추출하고 의미로 이름을 지으십시오(
check1이 아니라noConfigChanges) - N개의 파일에서 동일한 리터럴 → 개념을 소유한 모듈에 하나의 공유 상수; 사용자는 이를 가져옵니다
- 저장소 헬퍼의 지역 재구현 → 개인 복사본을 유지하기 전에 기존 헬퍼를 grep하십시오(
pathExists, 출력/포맷 유틸리티, 오류 헬퍼). 지역 복사본을 삭제하고 공유된 것을 가져오십시오. - 죽은 코드: diff에 있는 모든 헬퍼/타입/내보내기에 대해 소비자를 찾으십시오. 소비자가 없으면 "나중에"가 아니라 지금 삭제하십시오.
- 헬퍼가 소유한 것을 직접 구현하는 호출 지점(간격, 인용, ID 생성) → 동작을 헬퍼로 옮기고 호출 지점을 얇게 만드십시오
- 동일한 사실을 두 번 명시(문서 헤더 + 인라인 주석) → 하나를 유지하십시오
- 느슨하게 관련된 값의 튜플을 반환하는 함수 → 종종 두 책임이 융합되었음을 나타냄; 분할하거나 계약을 문서화하십시오
그런 다음 저장소 적합성을 확인하십시오: 이웃 파일을 읽고 그들의 관용구, 네이밍, 오류 스타일, 테스트 패턴을 일치시키십시오. 하우스 스타일을 무시하는 코드는 올바르더라도 생성된 것처럼 읽힙니다.
Pass 4 — 테스트
- 테스트는 동작을 고정(pin)해야 하며, 버그를 고정해서는 안 됩니다. 단언문이 "코드가 그렇게 하기 때문에" 잘못된 값을 인코딩한다면 둘 다 수정하십시오.
- 스위트의 기존 하네스와 헬퍼를 반영하십시오; 같은 파일에서 병렬 모의 스타일을 발명하지 마십시오.
- 모든 플랫폼 특정 건너뜀에는 한 줄의 이유가 있습니다.
- 테스트 이름은 시나리오를 설명하고 구현을 설명하지 않습니다.
- 출력 형태를 변경할 때는 제거된 형태에 대한 부정 단언문을 추가하십시오.
Pass 5 — 도구 일치, 그다음 검증
- 저장소에 고정된 포맷터/린터 버전을 사용하십시오(package.json을 읽으십시오 — 로컬에서 다른 메이저 버전을 실행하면 CI에서만 실패가 발생합니다).
- 중첩된 변경의 모든 레이어에서 diff가 건드리는 테스트를 실행하고, 최상위에서만 실행하지 마십시오.
- 모든 편집 후 최종 diff를 다시 한 번 재감사하십시오:
git diff를 실행하고 남아 있는 모든 주석 줄을 Pass 1에 비추어 소리 내어 읽으십시오. 밀도 확인:git diff | grep -cE '^\+\s*(//|\*)'대 추가된 총 줄 수. - 커밋 메시지: 사람처럼 산문으로 이유를 설명하십시오. 3줄 커밋에 글머리 기표 체인지로그 없음, "향상/개선/견고함" 없음.
보고
"이 코드가 de-slop 되었나요?"라는 질문을 받으면: 실제 diff를 감사하고 증거(밀도 수치, 삭제된 내용, 의도적으로 유지된 내용과 그 이유)로 대답하고, 절대 기억으로 "예"라고 말하지 마십시오. 리뷰어가 지적할 만한 것을 유지했다면(예: 고밀도 프로토콜 파일), 사전에 이름을 밝히고 한 문장으로 변호를 주십시오.
리뷰어가 무언가를 슬롭이라고 부를 때: 어떤 사례를 변호하기 전에 패턴을 인정하십시오. 그들이 지적하지 않은 파일(그리고 칭찬한 파일)을 포함하여 모든 곳에서 해당 범주를 수정하십시오. 표준을 지적된 줄에 대한 손해 제어가 아니라 규율로 적용하는 것이 신뢰를 재건하는 방법입니다.