이커머스 프로젝트 초기 설정으로 협업·코드 리뷰 품질 잡기
목차
빈 디렉토리를 받았을 때 손이 먼저 가는 곳이 어디냐에 따라 그 사람이 지금까지 어떤 프로젝트에서 데여봤는지 보인다. 나는 이번 이커머스 사이드 프로젝트를 시작하면서 기능 코드보다 설정 파일을 먼저 깔았다. config/, .eslintrc, .prettierrc, .gitignore — 총 4개. 첫 커밋 메시지는 initial commit이었고 diff 전체에 실제 로직은 한 줄도 없었다.
이게 낭비처럼 보일 수 있는데, 저 1시간이 이후 작업 흐름에서 얼마나 본전을 뽑았는지 정리해두고 싶었다.
ESLint·Prettier 분리 운영이 핵심이었던 이유
처음엔 ESLint 하나에 포매팅 룰까지 몰아넣는 방식을 고민했다. 파일 수가 줄고 설정이 한 곳에 모이니 단순해 보였다. 근데 이 방식은 나중에 디버깅할 때 고통스럽다. ESLint가 "이 코드가 나쁜 패턴"이라고 말할 때와 Prettier가 "이 줄이 너무 길다"고 말할 때는 맥락이 완전히 다른데, 한 파일에 섞이면 규칙 충돌 에러가 났을 때 원인 추적이 귀찮아진다.
그래서 역할을 분리했다.
- Prettier: 포매팅 전담. 들여쓰기, 따옴표, 세미콜론, 줄 길이 같은 것들.
- ESLint: 코드 품질 전담. 미사용 변수,
any타입 남용, 잠재적 버그 패턴.
eslint-config-prettier를 붙여서 ESLint가 포매팅 영역에 손대지 못하게 막는 게 포인트다.
// .eslintrc.json
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier" // 반드시 마지막 — prettier 관련 ESLint 룰 전부 off
],
"rules": {
"no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "warn"
}
}
// .prettierrc
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "all"
}
이렇게 분리해두면 format-on-save 설정 이후로는 포매팅을 머리로 신경 쓸 일이 없어진다. PR 리뷰에서 "탭이냐 스페이스냐", "세미콜론 있냐 없냐" 같은 대화가 물리적으로 불가능해지는 구조가 된다. 리뷰어가 집중할 수 있는 건 로직뿐.
협업자가 추가될 때 온보딩이 npm run lint && npm run format:check 한 줄이면 되는 것도 이 구조 덕분이다.
.gitignore — 이커머스 특성을 반영한 부분
.gitignore는 gitignore.io나 GitHub 템플릿 그대로 복붙하면 될 줄 알았다. 근데 이커머스 프로젝트는 결제대행사 연동 키, 웹훅 시크릿 같은 게 환경변수로 들어올 가능성이 처음부터 있다. 그 부분을 초기부터 강하게 잡아두지 않으면 나중에 팀원이 .env.local을 실수로 푸시하는 사고가 터진다.
| 패턴 | 이유 |
|---|---|
.env* (.env.example 제외) |
결제 키, API 시크릿 유출 방지 |
dist/, build/ |
빌드 산출물은 재생성 가능, 리포지토리 오염 방지 |
.DS_Store, Thumbs.db |
OS 잡 파일 |
coverage/ |
테스트 커버리지 리포트, CI가 생성하는 것 |
*.local |
로컬 오버라이드 설정 전체 차단 |
.env.example만 커밋 대상으로 남기는 패턴은 흔한 방식인데, 이번에 .gitignore 작성하다가 !.env.example 예외 라인을 빠뜨리고 push 직전에 발견했다. 아무 내용 없는 더미 파일이라 다행이었지 실제 키가 들어간 뒤였으면 히스토리 클렌징까지 가야 했다.
git-secrets 같은 훅을 붙이는 것도 방법인데, 이 단계에서는 팀 규모가 작아서 .gitignore 강화로 먼저 대응했다. 프로젝트가 커지면 pre-commit 훅으로 시크릿 스캔을 자동화하는 게 맞다.
config 폴더와 구조 선점의 의미
config/ 폴더는 첫 커밋에 빈 상태로 들어갔다. .gitkeep 하나만 넣어서 빈 디렉토리를 추적 가능하게 만들었고, 안에 실제 파일은 없었다.
"빈 폴더 커밋이 의미 있나?" 싶었는데, 막상 다음 커밋에서 config/database.ts, config/env.ts 추가할 때 경로 고민이 없었다. 이미 자리가 정해져 있으니까. 구조를 먼저 잡고 채우는 흐름이 거꾸로 채우다가 정리하는 것보다 훨씬 빠르다는 건 경험적으로 알고 있었는데, 이번에도 확인됐다.
환경별 설정 분기도 이 시점에 방향만 잡아뒀다. config/ 아래에 dev, prod를 어떻게 나눌지, 환경변수 로딩을 어디서 할지. 실제 구현은 다음 커밋이었지만 방향이 정해져 있으니 결정 비용이 거의 없었다.
첫 커밋에 1시간 쓴 게 맞나
결론부터 말하면 맞았다. 기능 코드 한 줄 없는 커밋에 1시간 넘게 쓰는 건 낭비처럼 보이지만, 이후에 "ESLint 규칙 뭐 쓸까", "이 파일 커밋해도 되나", "포매팅 이게 맞나" 같은 판단을 매번 해야 하는 비용과 비교하면 확실히 싸다.
특히 협업 환경에서 포매팅 차이는 PR diff를 오염시킨다. 로직 변경 2줄짜리 PR이 포매팅 diff 때문에 50줄로 늘어나면 리뷰어가 집중하기 힘들다. 이걸 초기 설정 한 번으로 막을 수 있다면, 그 1시간은 팀 전체 시간으로 환산하면 몇 배로 돌아온다.
다음 커밋부터 실제 도메인 모델이 들어가는데, 설정이 이미 다 깔려있으니 코드만 생각하면 된다. 그게 이 첫 커밋의 목적이었다.
댓글 0
첫 댓글 달아줘.