유지보수성
코드는 작성되는 횟수보다 훨씬 더 많이 읽힙니다. 유지보수성이 3년 된 코드베이스를 즐거움으로 만들지, 수렁으로 만들지를 결정합니다. 다음 개발자(6개월 후의 당신일 수도 있습니다)를 위해 최적화하세요.
규칙
- 하나의 기능, 하나의 위치. 기능별로 패키징하세요(backend/core/SKILL.md 참조). 변경 사항이 있을 때 인접한 파일들만 함께 수정되어야 하며, 여러 계층에 흩어져서는 안 됩니다.
- 모듈 경계에서만 인터페이스를 사용하세요. 기능 내부에서는 구체 클래스를 사용해도 괜찮습니다. 인터페이스는 호출자가 경계를 넘어 계약에 의존할 수 있도록 하기 위해 존재하며, 모든 클래스를 장식하기 위해 존재하는 것이 아닙니다.
- 주석 처리 대신 삭제하세요. 죽은 코드와 영원한
// TODO주석은 썩어갑니다. Git이 기억하므로 IDE가 기억할 필요는 없습니다. - 작고 순수한 함수를 선호하세요. 테스트, 추론, 조합이 더 쉽습니다. 부작용은 시스템의 가장자리에서만 발생해야 하며, 시스템 전체에 흩어져서는 안 됩니다.
- 테스트는 행위를 검증하고 구현을 검증하지 않아야 합니다. 내부 구현을 다시 작성해도 테스트가 깨지지 않아야 합니다. 만약 깨진다면 테스트가 잘못된 것에 결합되어 있는 것입니다.
- 공개 API는 버전 관리되어야 합니다. 호환되지 않는 변경은 새 버전이나 기능 플래그 뒤에서 이루어져야 하며, 절대 조용히 이름을 바꾸지 마세요.
- 정적 싱글턴 대신 의존성 주입을 사용하세요. 정적 싱글턴은 테스트 불가능하며 결합을 숨깁니다. 의존성을 주입하고 테스트에서 모의 객체로 대체하세요.
- 의존성을 고정하고 정기적으로 업데이트하세요. 잠금 파일을 커밋하고 Renovate/Dependabot이 자동으로 PR을 만들도록 하세요. 2년 뒤쳐지면 계획에 없던 2주 마이그레이션이 필요합니다.
- '무엇'이 아니라 '왜'를 문서화하세요. 코드는 '무엇'을 보여주고, 주석은 비즈니스 규칙, 과거의 제약, 명확하지 않은 트레이드오프를 설명합니다.
- CI에서 린트, 포맷, 타입 검사를 수행하세요. 권고사항이 아니라 차단 조건입니다. 인간은 디자인에 대해 논쟁해야지, 공백에 대해 논쟁해서는 안 됩니다.
- 빌드를 항상 통과 상태로 유지하고 빠르게 유지하세요. 불안정하거나 느린 테스트는 무시되며, 한 번 무시되면 아무것도 보호하지 못합니다.
적신호
- 약 500줄이 넘는 단일 파일 또는 약 10개 이상의 공개 메서드를 가진 클래스 — 보통 기능이 밖으로 나오려는 신호입니다.
- 공유 'utils' 패키지에 버려진 도우미 함수들이 모여 있는 경우.
- 테스트를 통과시키기 위해 테스트 대상 자체를 모의(mock)하는 경우.
- "그 모듈은 건드리지 마세요, 아무도 더 이상 이해하지 못합니다."
- CI 빌드 시간이 수십 분 단위로 측정되는 경우.