JavaScript
클린 코드 작성법: JavaScript 편
읽기 쉽고 유지보수하기 좋은 코드를 작성하는 실전 원칙들을 알아봅니다.
코드는 작성하는 시간보다 읽는 시간이 훨씬 깁니다. 6개월 뒤에 내가 작성한 코드를 다시 봤을 때, 또는 팀원이 내 코드를 봤을 때 쉽게 이해할 수 있어야 합니다.
의미 있는 이름 짓기
변수, 함수, 클래스의 이름은 그 역할을 명확히 설명해야 합니다.
// 나쁜 예
const d = new Date();
const arr = users.filter(u => u.a > 18);
function calc(x, y) { return x * y * 0.1; }
// 좋은 예
const currentDate = new Date();
const adultUsers = users.filter(user => user.age > 18);
function calculateTax(price, quantity) {
const TAX_RATE = 0.1;
return price * quantity * TAX_RATE;
}
이름 짓기 규칙
- 변수: 명사 또는 명사구 (user, userList, selectedItem)
- 함수: 동사 또는 동사구 (getUser, calculateTotal, validateEmail)
- 불리언: is, has, can 접두사 (isActive, hasPermission, canEdit)
- 상수: 대문자와 언더스코어 (MAX_RETRY_COUNT, API_BASE_URL)
함수는 한 가지 일만
함수는 한 가지 작업만 수행해야 합니다. 함수 이름으로 설명할 수 없는 작업이 포함되어 있다면 분리가 필요합니다.
// 나쁜 예 - 여러 가지 일을 함
function processUser(user) {
// 유효성 검사
if (!user.email || !user.name) {
throw new Error('Invalid user');
}
// 데이터 정규화
user.email = user.email.toLowerCase();
user.name = user.name.trim();
// 저장
database.save(user);
// 이메일 발송
sendWelcomeEmail(user.email);
}
// 좋은 예 - 각 함수가 한 가지 일만
function validateUser(user) {
if (!user.email || !user.name) {
throw new Error('Invalid user');
}
}
function normalizeUser(user) {
return {
...user,
email: user.email.toLowerCase(),
name: user.name.trim(),
};
}
function createUser(userData) {
validateUser(userData);
const user = normalizeUser(userData);
database.save(user);
sendWelcomeEmail(user.email);
}
함수 매개변수 줄이기
매개변수가 많으면 함수 사용이 어렵습니다. 3개 이상이면 객체로 묶는 것을 고려합니다.
// 나쁜 예
function createUser(name, email, age, country, role, isActive) {
// ...
}
createUser('홍길동', 'hong@email.com', 25, 'Korea', 'admin', true);
// 좋은 예
function createUser({ name, email, age, country, role, isActive }) {
// ...
}
createUser({
name: '홍길동',
email: 'hong@email.com',
age: 25,
country: 'Korea',
role: 'admin',
isActive: true,
});
객체를 사용하면 매개변수 순서를 기억할 필요가 없고, 어떤 값이 무엇인지 명확합니다.
조건문 개선하기
부정 조건 피하기
// 나쁜 예
if (!isNotLoggedIn) { ... }
// 좋은 예
if (isLoggedIn) { ... }
조건을 함수로 추출
// 나쁜 예
if (user.age >= 18 && user.hasId && !user.isBanned) {
allowAccess();
}
// 좋은 예
function canAccessAdultContent(user) {
return user.age >= 18 && user.hasId && !user.isBanned;
}
if (canAccessAdultContent(user)) {
allowAccess();
}
조기 반환 활용
// 나쁜 예 - 중첩된 조건문
function getPaymentAmount(user) {
let amount = 0;
if (user) {
if (user.subscription) {
if (user.subscription.isActive) {
amount = user.subscription.price;
}
}
}
return amount;
}
// 좋은 예 - 조기 반환
function getPaymentAmount(user) {
if (!user) return 0;
if (!user.subscription) return 0;
if (!user.subscription.isActive) return 0;
return user.subscription.price;
}
주석보다 코드로 설명
주석이 필요한 코드는 대부분 코드 자체를 개선할 수 있습니다.
// 나쁜 예
// 사용자가 관리자이고 활성 상태인지 확인
if (user.role === 'admin' && user.status === 'active') { ... }
// 좋은 예
const isActiveAdmin = user.role === 'admin' && user.status === 'active';
if (isActiveAdmin) { ... }
// 또는 함수로
function isActiveAdmin(user) {
return user.role === 'admin' && user.status === 'active';
}
하지만 "왜" 이렇게 했는지는 주석으로 남기는 것이 좋습니다.
// 레거시 API 호환성을 위해 deprecated 필드도 포함
const response = {
data: result,
result: result, // deprecated: v2.0에서 제거 예정
};
에러 처리
에러를 무시하지 마세요. 최소한 로깅이라도 해야 합니다.
// 나쁜 예
try {
doSomething();
} catch (error) {
// 무시
}
// 좋은 예
try {
doSomething();
} catch (error) {
console.error('작업 실패:', error);
// 또는 에러 리포팅 서비스로 전송
reportError(error);
}
마무리
클린 코드는 처음부터 완벽하게 작성되지 않습니다. 작동하는 코드를 먼저 작성하고, 리팩토링을 통해 개선해 나가면 됩니다.
중요한 것은 꾸준히 코드 품질에 신경 쓰는 습관입니다. 오늘 작성하는 코드가 미래의 나와 팀을 위한 투자라고 생각하면 동기 부여가 됩니다.