모든 개발 팀에는 이런 이야기가 있습니다. 풀 리퀘스트(pull request)가 반나절 동안 열려 있습니다. 로직이 잘못되었거나 API 규약이 변경되어서가 아니라, 객체 리터럴에 마지막 쉼표(trailing comma)가 필요한지를 두고 두 리뷰어의 의견이 갈리기 때문입니다. 스레드는 길어집니다. 누군가는 스타일 가이드 링크를 올리고, 다른 누군가는 다른 가이드를 제시하며 반박합니다. 코드가 머지될 때쯤이면, 관련된 모든 사람이 실제로 만들고 있던 기능에 대한 맥락을 놓치게 됩니다.
이런 논쟁은 비용이 많이 듭니다. 시니어 엔지니어의 시간을 낭비하게 하고, 팀원 간의 미묘한 불만을 만들며, 주니어 개발자들에게 소프트웨어 엔지니어링이란 결국 세미콜론을 두고 논쟁에서 이기는 것이라고 믿게 만듭니다. 최악인 점이 무엇일까요? 제품은 상관하지 않는다는 것입니다. 사용자는 스페이스와 탭의 차이를 결코 알아차리지 못합니다. 하지만 따옴표를 두고 논쟁하느라 고치지 못한 버그는 반드시 알아차릴 것입니다.
일관성은 중요합니다. 한 사람이 작성한 것처럼 보이는 코드베이스는 읽기 쉽고, 리뷰하기 쉬우며, 디버깅하기도 쉽습니다. 실수하는 지점은 그 일관성을 수동으로 강제하려 한다는 것입니다.
지루한 일은 자동화하세요
해결책은 간단합니다. 포맷팅에서 인간의 판단을 완전히 배제하십시오. 자존심도 없고 지치지도 않는 도구에 맡기면 됩니다.
세 가지 도구가 이 작업을 깔끔하게 처리합니다.
Prettier는 코드를 가져와 자동으로 재포맷팅합니다. 허락을 구하지 않습니다. 줄 길이, 따옴표 스타일, 또는 긴 함수 시그니처를 여러 줄로 나누는 방법 등에 대해 더 이상 고민할 필요가 없습니다. 파일을 저장하기만 하면 Prettier가 일관되게 만들어 줍니다.
ESLint는 Prettier가 건드리지 않는 문제들을 처리합니다. 사용하지 않는 변수, 도달할 수 없는 코드, React hook의 누락된 의존성, 그리고 역사적으로 버그를 유발했던 패턴들을 잡아냅니다. 올바르게 설정하면 포맷팅은 건드리지 않고 실제 코드 품질에만 집중합니다.
Husky는 자동화된 검사를 통과할 때까지 어떤 코드도 저장소에 들어오지 못하도록 차단하는 pre-commit hook을 설치합니다. Git 파이프라인을 단순한 제안함이 아닌 수문장(gatekeeper)으로 바꿔줍니다.
이 도구들은 함께 작동하며 긴밀한 루프를 형성합니다. 로컬에서는 원하는 대로 코드를 작성하세요. 커밋할 때 도구들이 코드를 정리하고 검사합니다. 그제야 코드가 여러분의 컴퓨터를 떠나게 됩니다.
이 특정 스택이 효과적인 이유
ESLint 규칙을 수동으로 조정하는 데 몇 주를 보낼 수도 있습니다. 그런 유혹을 뿌리치십시오. 여기서의 목표는 스타일 논쟁을 멈추는 것이지, 스타일 가이드 큐레이터라는 새로운 전업 직업을 만드는 것이 아닙니다.
Prettier는 의도적으로 자기 주관이 뚜렷합니다(opinionated). 설정 옵션이 제한적인 이유는 모든 옵션이 미래의 논쟁거리가 될 수 있기 때문입니다. 기본 설정은 합리적입니다. 필요한 재정의(override) 사항을 소수만 골라 한 번 작성한 뒤, 다음 단계로 넘어가십시오.
ESLint를 그대로 두면 코드 품질뿐만 아니라 세미콜론 사용이나 들여쓰기 크기와 같은 포맷팅 규칙까지 강제하려 할 것입니다. 이는 두 도구가 동일한 문자를 수정하려고 시도하기 때문에 Prettier와 충돌을 일으킵니다. eslint-config-prettier 패키지는 Prettier와 충돌하는 모든 ESLint 규칙을 비활성화함으로써 이 문제를 해결합니다. 이러한 역할 분담이 매우 중요합니다. Prettier는 외관(cosmetics)을 담당하고, ESLint는 로직을 담당합니다.
CI(지속적 통합)에서만 검사를 실행하는 것은 너무 늦습니다. CI가 실패할 때쯤이면 이미 지저분한 코드를 커밋했고, 다른 작업으로 맥락이 전환되었으며, 어쩌면 이미 풀 리퀘스트를 열었을 수도 있습니다. 이를 수정하려면 또 다른 커밋, 또 다른 푸시, 그리고 또 다른 대기 사이클이 필요합니다. Husky는 이 피드백 루프를 단 몇 초로 단축합니다. lint-staged는 매 커밋마다 전체 저장소를 스캔하는 대신 실제로 변경한 파일에 대해서만 도구를 실행하여 속도를 높여줍니다.
단계별 설정 방법
다음 설정은 현대적인 JavaScript 또는 React 프로젝트를 대상으로 하지만, 약간의 조정만 거치면 TypeScript, Vue 또는 Node 프로젝트에도 적용할 수 있습니다. 각 단계는 프로젝트 루트에서 실행하십시오.
먼저 모든 것을 dev dependencies로 설치하는 것부터 시작합니다:
npm install -D prettier eslint husky lint-staged eslint-config-prettier
