JavaScript 코드 포맷팅: 도구와 표준 가이드
풀 리퀘스트를 열었는데 변경 사항의 절반이 공백 수정이라면, 그 고통은 즉시 체감됩니다. 포맷팅 불일치는 시간을 낭비하고, 코드 리뷰를 지저분하게 만들며, 로직과는 전혀 관계없는 병합 충돌을 유발합니다. 해결 방법은 간단합니다: 포맷팅 표준을 정하고, 자동화로 강제한 다음, 다시는 신경 쓰지 않으면 됩니다.
이 가이드에서는 JavaScript 포맷팅을 완전히 해결해 주는 도구와 표준을 살펴봅니다.
일관된 포맷팅이 중요한 이유
포맷팅은 미학의 문제가 아니라 팀 생산성의 문제입니다. 모든 개발자가 각기 다른 들여쓰기, 중괄호 위치, 줄 길이를 사용하면 세 가지 문제가 발생합니다:
코드 리뷰가 느려집니다. 리뷰어가 로직을 평가하는 대신 낯선 포맷팅을 해독하는 데 정신적 에너지를 소모합니다. 코드베이스의 나머지 부분과 다르게 보이는 함수는 엉뚱한 이유로 시선을 끌게 됩니다.
병합 충돌이 기하급수적으로 늘어납니다. 개발자 A가 탭으로 파일을 재포맷하고, 개발자 B가 스페이스를 사용하면 Git은 모든 줄이 변경된 것으로 표시합니다. 실제로는 세 줄짜리 버그 수정인데, 그것이 묻혀버립니다.
인지 부하가 증가합니다. 스타일이 다른 파일들을 오가며 작업하면 뇌가 끊임없이 구조를 다시 파싱해야 합니다. 일관된 포맷팅은 코드를 산문처럼 읽을 수 있게 해줍니다 — 눈이 어디를 봐야 할지 자연스럽게 알게 됩니다.
해결책은 어떤 스타일이 최고인지 논쟁하는 것이 아닙니다. 하나를 정해서 자동화하는 것입니다.
주요 JavaScript 스타일 가이드
도구를 선택하기 전에, JavaScript 포맷팅 관행을 형성한 주요 스타일 가이드를 이해하는 것이 도움이 됩니다.
Airbnb Style Guide
가장 널리 채택된 JavaScript 스타일 가이드입니다. 세미콜론을 필수로 하고, 작은따옴표를 선호하며, 여러 줄 구조에서 후행 쉼표를 요구하고, 2칸 들여쓰기를 사용합니다. ESLint 설정(eslint-config-airbnb)에는 포맷팅과 코드 품질 모두를 다루는 수백 개의 규칙이 포함되어 있습니다.
// Airbnb style
const getUserData = (userId) => {
const user = findUser(userId);
return {
name: user.name,
email: user.email,
};
};
Standard Style
세미콜론에 대해 정반대의 접근 방식을 취합니다 — 세미콜론을 절대 사용하지 않습니다. 2칸 들여쓰기와 작은따옴표를 사용합니다. standard 패키지에는 자체 린터가 포함되어 있어 별도의 ESLint 설정이 필요 없습니다.
// Standard style
const getUserData = (userId) => {
const user = findUser(userId)
return {
name: user.name,
email: user.email
}
}
Google Style Guide
Airbnb와 유사하지만 JSDoc 요구 사항과 네이밍 규칙에서 몇 가지 차이가 있습니다. 2칸 들여쓰기를 사용하고, 세미콜론을 필수로 하며, 작은따옴표를 선호합니다.
각 스타일 가이드에는 장단점이 있습니다. 중요한 것은 어떤 것을 선택하느냐가 아니라 일관성입니다. 그리고 점점 더 많은 팀들이 Prettier에게 결정을 맡기며 논쟁 자체를 건너뛰고 있습니다.
Prettier: 자기 주장이 확고한 포맷터
Prettier는 대부분의 결정을 없애버림으로써 JavaScript 포맷팅을 바꿔놓았습니다. 코드를 AST(추상 구문 트리)로 파싱한 다음 자체 규칙에 따라 다시 출력합니다. 개별 포맷팅 항목을 일일이 설정하는 것이 아니라, 몇 가지 상위 수준의 옵션만 정하면 나머지는 Prettier가 알아서 처리합니다.
설치
npm install --save-dev prettier
.prettierrc 설정 파일을 생성합니다:
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "always"
}
주요 설정 옵션
printWidth (기본값: 80) — Prettier가 코드를 줄 바꿈하는 줄 길이입니다. 이것은 엄격한 제한이 아니라, 표현식을 여러 줄로 나눌 시점에 대한 가이드라인입니다. 와이드 모니터를 사용하는 팀에서는 100이나 120으로 설정하는 경우도 흔합니다.
semi (기본값: true) — 문장 끝에 세미콜론을 추가할지 여부입니다. Standard 스타일을 선호한다면 false로 설정하세요.
singleQuote (기본값: false) — 큰따옴표 대신 작은따옴표를 사용합니다. 대부분의 JavaScript 개발자가 작은따옴표를 선호하므로 true가 더 일반적인 설정입니다.
trailingComma (기본값: "all") — 유효한 모든 위치에 후행 쉼표를 추가합니다. 이렇게 하면 Git diff가 더 깔끔해지는데, 목록에 새 항목을 추가할 때 두 줄이 아닌 한 줄만 변경된 것으로 표시되기 때문입니다.
// 후행 쉼표 없이 — "d"를 추가하면 두 줄이 변경됨
const items = [
- "a",
- "b",
- "c"
+ "a",
+ "b",
+ "c",
+ "d"
];
// 후행 쉼표 사용 — "d"를 추가하면 한 줄만 변경됨
const items = [
"a",
"b",
"c",
+ "d",
];
arrowParens (기본값: "always") — 화살표 함수의 매개변수가 하나일 때 괄호로 감쌀지 여부입니다. "always"는 (x) => x, "avoid"는 x => x를 의미합니다.
Prettier 실행하기
# 모든 파일 포맷팅
npx prettier --write .
# 수정 없이 검사만 수행
npx prettier --check .
# 특정 파일 유형만 포맷팅
npx prettier --write "src/**/*.{js,jsx,ts,tsx}"
생성된 파일을 건너뛰기 위해 .prettierignore 파일을 추가합니다:
node_modules
dist
build
coverage
*.min.js
압축된 JavaScript를 다루고 있다면, Code Minifier가 압축을 적절하게 처리해 줍니다 — 압축된 코드를 직접 수정하지 마세요.
ESLint: 포맷팅을 넘어서
ESLint는 Prettier와는 다른 목적을 가지고 있습니다. Prettier가 코드의 모양을 다루는 반면, ESLint는 코드의 동작을 검사합니다. ESLint 규칙은 두 가지 범주로 나뉩니다:
포맷팅 규칙 — 들여쓰기, 간격, 중괄호 위치. 이들은 Prettier와 겹치며, 두 도구를 함께 사용할 때는 일반적으로 비활성화해야 합니다.
코드 품질 규칙 — 사용되지 않는 변수, 도달할 수 없는 코드, 암묵적 타입 변환, 누락된 에러 처리. 이것이 ESLint가 진정으로 빛나는 영역입니다.
권장 설정
npm install --save-dev eslint @eslint/js
간단한 eslint.config.js 설정:
import js from '@eslint/js';
export default [
js.configs.recommended,
{
rules: {
'no-unused-vars': 'warn',
'no-console': 'warn',
'eqeqeq': 'error',
'no-implicit-coercion': 'error',
},
},
];
TypeScript 프로젝트의 경우 typescript-eslint를 추가합니다:
npm install --save-dev typescript-eslint
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommended,
);
Prettier + ESLint 통합
두 도구를 조율 없이 함께 실행하면 충돌이 발생합니다 — ESLint의 포맷팅 규칙이 Prettier의 출력과 싸우게 됩니다. 해결책은 eslint-config-prettier로, Prettier와 충돌하는 모든 ESLint 규칙을 비활성화합니다.
npm install --save-dev eslint-config-prettier
import js from '@eslint/js';
import prettierConfig from 'eslint-config-prettier';
export default [
js.configs.recommended,
prettierConfig,
{
rules: {
// 여기에는 코드 품질 규칙만 작성
'no-unused-vars': 'warn',
'eqeqeq': 'error',
},
},
];
이 설정으로 Prettier가 포맷팅을 담당하고, ESLint가 코드 품질을 담당합니다. 충돌도 없고, 혼란도 없습니다.
EditorConfig로 에디터 간 일관성 확보
팀의 모든 구성원이 같은 에디터를 사용하는 것은 아닙니다. EditorConfig는 VS Code, WebStorm, Vim, Sublime Text 및 대부분의 다른 에디터에서 작동하는 기본 설정을 제공합니다.
프로젝트 루트에 .editorconfig 파일을 생성합니다:
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
EditorConfig는 Prettier가 실행되기 전에 기본적인 부분 — 들여쓰기, 줄 끝 문자, 후행 공백 — 을 처리합니다. 이를 통해 Windows 개발자가 Unix 기반 프로젝트에 \r\n 줄 끝 문자를 도입하는 흔한 문제를 방지할 수 있습니다.
Husky와 lint-staged를 활용한 Git 훅
자동 포맷팅은 실제로 실행되어야만 의미가 있습니다. 매 커밋 전에 개발자가 npx prettier --write를 기억해서 실행하는 것에 의존하는 방식은 확장할 수 없습니다. Git 훅이 이 문제를 해결합니다.
설정
npm install --save-dev husky lint-staged
npx husky init
package.json에 다음을 추가합니다:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.{json,md,css}": [
"prettier --write"
]
}
}
Husky pre-commit 훅(.husky/pre-commit)을 업데이트합니다:
npx lint-staged
이제 매 커밋 시 스테이징된 파일이 자동으로 포맷팅되고 ESLint 수정이 실행됩니다. 개발자는 포맷팅에 대해 전혀 생각할 필요가 없습니다 — 그저 자동으로 처리됩니다.
이것이 팀 프로젝트의 최적 표준입니다: Prettier가 포맷팅하고, ESLint가 버그를 잡고, Husky가 모든 커밋에서 둘 다 강제합니다.
세미콜론 논쟁
JavaScript 포맷팅 논의에서 세미콜론 문제를 빼놓을 수 없습니다. 실용적인 답은 이렇습니다: 팀 내에서 일관성만 유지한다면 어떤 쪽이든 상관없습니다.
세미콜론 찬성: 명시적인 문장 종결이 ASI(자동 세미콜론 삽입)의 엣지 케이스를 방지합니다. Airbnb와 Google 스타일 가이드는 세미콜론을 필수로 합니다.
세미콜론 반대: JavaScript의 ASI가 자동으로 종결을 처리합니다. 시각적 잡음이 줄어들어 코드가 더 깔끔해집니다. Standard 스타일 가이드는 세미콜론을 생략합니다.
사람들이 경고하는 ASI의 함정 — (이나 [로 시작하는 줄 같은 경우 — 은 ESLint의 no-unexpected-multiline 규칙이 잡아냅니다. 실무에서 적절한 린팅과 함께 세미콜론 없이 작업하는 것은 완전히 안전합니다.
하나를 선택하고, Prettier의 semi 옵션을 설정한 다음, 이 주제는 접으세요. Prettier가 어느 쪽이든 일관되게 추가하거나 제거해 줍니다.
JavaScript에서 탭 vs 스페이스
JavaScript 생태계는 압도적으로 스페이스를 사용합니다 — 구체적으로 2칸 들여쓰기입니다. 이것은 보편적이진 않지만(Go는 탭을, Python은 4칸 스페이스를 사용), JavaScript에서는 확고한 관행입니다.
왜 2칸 스페이스인가? JavaScript의 중첩 콜백 패턴과 체이닝 메서드는 들여쓰기를 빠르게 깊어지게 합니다. 2칸 스페이스는 깊게 중첩된 코드를 화면 오른쪽 끝으로 밀어내지 않으면서도 가독성을 유지합니다.
왜 탭은 안 되는가? 탭은 각 개발자가 자체 표시 너비를 설정할 수 있어서 좋아 보이지만, 이는 에디터마다 코드 정렬이 깨진다는 뜻입니다. 스페이스를 사용하면 자신이 보는 것이 모든 사람이 보는 것과 동일합니다.
Prettier(tabWidth: 2, useTabs: false)와 EditorConfig(indent_style = space, indent_size = 2)에서 한 번 설정하면 문제가 해결됩니다.
흔한 포맷팅 함정
일관성 없는 화살표 함수
// 일관성 없음 — 피해야 할 패턴
const double = x => x * 2;
const add = (a, b) => a + b;
const greet = (name) => {
return `Hello, ${name}`;
};
// 일관됨 — Prettier의 arrowParens: "always" 설정
const double = (x) => x * 2;
const add = (a, b) => a + b;
const greet = (name) => {
return `Hello, ${name}`;
};
객체 구조 분해 스타일
// 빽빽함 — 읽기 어려움
const {name,email,role} = user;
// 포맷팅됨 — Prettier가 자동으로 처리
const { name, email, role } = user;
// 속성이 많을 때는 여러 줄로
const {
name,
email,
role,
department,
startDate,
} = user;
import 문 정리
Prettier는 import를 정렬하지 않습니다 — 이는 포맷팅이 아닌 코드 품질의 문제입니다. eslint-plugin-import나 simple-import-sort 플러그인을 사용하세요:
// 정리된 imports
import React from 'react';
import { useState, useEffect } from 'react';
import { Button } from '@/components/Button';
import { Modal } from '@/components/Modal';
import { formatDate } from '../utils/dates';
import { validateEmail } from '../utils/validation';
긴 삼항 표현식
// 읽기 어려운 한 줄 표현
const label = isAdmin ? 'Admin Dashboard' : hasEditPermission ? 'Editor View' : 'Read Only';
// Prettier가 읽기 쉬운 여러 줄로 재포맷
const label = isAdmin
? 'Admin Dashboard'
: hasEditPermission
? 'Editor View'
: 'Read Only';
새 프로젝트 설정하기
새로운 JavaScript 또는 TypeScript 프로젝트를 위한 완전한 설정 체크리스트입니다:
-
의존성 설치:
npm install --save-dev prettier eslint eslint-config-prettier husky lint-staged -
.prettierrc생성 — 팀의 선호 설정을 반영 -
.editorconfig생성 — 에디터 간 기본 설정 통일 -
ESLint 설정 — 코드 품질 규칙만 포함 (포맷팅 규칙 제외)
-
Husky + lint-staged 설정 — pre-commit 단계에서 강제 적용
-
npm 스크립트 추가:
{ "scripts": { "format": "prettier --write .", "format:check": "prettier --check .", "lint": "eslint .", "lint:fix": "eslint --fix ." } } -
전체 코드베이스에 초기 포맷팅 실행:
npm run format -
포맷팅된 코드를 단일 커밋으로 커밋 —
git blame에서--ignore-rev옵션으로 쉽게 건너뛸 수 있도록
실전에서의 포맷팅
포맷팅 파이프라인이 설정되면 일상적인 개발 경험이 극적으로 변합니다:
- 원하는 대로 코드를 작성하세요. Prettier가 저장하거나 커밋할 때 재포맷합니다.
- 풀 리퀘스트에는 로직 변경만 표시됩니다. 더 이상 공백 잡음이 없습니다.
- 새로운 팀원이 즉시 생산적으로 일할 수 있습니다. 스타일 가이드 문서 없이도 도구가 표준을 강제합니다.
- 스타일에 대한 논쟁이 사라집니다. 개별 개발자가 아닌 Prettier가 권위자입니다.
작업 중인 JSON 데이터의 구조를 확인해야 할 때, JSON Formatter를 사용하면 간편하게 검사할 수 있습니다 — 아무 JSON이나 붙여넣으면 브라우저에서 바로 읽기 쉬운 포맷으로 변환됩니다.
관련 리소스
코드 포맷팅과 개발 도구에 대해 더 알아보려면:
- Code Minification Guide — 프로덕션을 위한 JavaScript 압축의 시기와 방법
- Naming Conventions in Programming — 일관된 네이밍은 가독성 높은 코드의 나머지 절반
- SQL Formatting Best Practices — 데이터베이스 쿼리에도 동일한 포맷팅 원칙 적용하기
일관된 포맷팅은 즉각적인 효과를 내면서도 계속해서 보답하는, 드문 엔지니어링 투자 중 하나입니다. 한 번 설정하고, 자동화하고, 정말 중요한 코드에 에너지를 집중하세요.