CleanCode 완벽 마스터
CleanCode의 핵심 개념과 실전 활용법
학습 항목
이미지 로딩 중...
Refactoring 베스트 프랙티스 완벽 가이드
코드 품질을 높이는 리팩토링 기법을 실전 예제와 함께 학습합니다. 중급 개발자를 위한 실용적인 리팩토링 패턴과 안티패턴 해결 방법을 다룹니다.
들어가며
이 글에서는 Refactoring 베스트 프랙티스 완벽 가이드에 대해 상세히 알아보겠습니다. 총 10가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- 함수_추출하기
- 매직_넘버_제거하기
- 조건문_단순화하기
- 객체_구조화하기
- 중복_코드_제거하기
- 명확한_변수명_사용하기
- 삼항_연산자_개선하기
- 배열_메서드_활용하기
- 에러_처리_개선하기
- 순수_함수로_만들기
1. 함수_추출하기
개요
긴 함수를 작은 함수로 분리하여 가독성과 재사용성을 높입니다. 각 함수는 하나의 명확한 책임만 가져야 합니다.
코드 예제
// Before
function processOrder(order) {
const total = order.items.reduce((sum, item) =>
sum + item.price * item.quantity, 0);
const tax = total * 0.1;
return total + tax;
}
// After
function calculateSubtotal(items) {
return items.reduce((sum, item) =>
sum + item.price * item.quantity, 0);
}
function calculateTax(amount) {
return amount * 0.1;
}
function processOrder(order) {
const subtotal = calculateSubtotal(order.items);
const tax = calculateTax(subtotal);
return subtotal + tax;
}
설명
계산 로직을 독립적인 함수로 분리하여 각 함수의 역할이 명확해지고 테스트와 재사용이 쉬워집니다.
2. 매직_넘버_제거하기
개요
코드에 직접 박힌 숫자를 의미 있는 상수로 교체하여 코드의 의도를 명확히 합니다.
코드 예제
// Before
function calculateDiscount(price) {
return price > 10000 ? price * 0.15 : price * 0.05;
}
// After
const PREMIUM_THRESHOLD = 10000;
const PREMIUM_DISCOUNT_RATE = 0.15;
const STANDARD_DISCOUNT_RATE = 0.05;
function calculateDiscount(price) {
const isPremium = price > PREMIUM_THRESHOLD;
const rate = isPremium ? PREMIUM_DISCOUNT_RATE : STANDARD_DISCOUNT_RATE;
return price * rate;
}
설명
상수명을 통해 숫자의 의미를 명확히 전달하고, 값 변경 시 한 곳만 수정하면 됩니다.
3. 조건문_단순화하기
개요
복잡한 조건문을 early return과 guard clause를 사용하여 중첩을 줄이고 가독성을 향상시킵니다.
코드 예제
// Before
function getShippingCost(order) {
if (order) {
if (order.items.length > 0) {
if (order.total > 50000) {
return 0;
} else {
return 3000;
}
}
}
return null;
}
// After
function getShippingCost(order) {
if (!order || order.items.length === 0) return null;
if (order.total > 50000) return 0;
return 3000;
}
설명
early return을 사용하여 중첩을 제거하고 정상 흐름을 먼저 처리하여 코드 이해가 쉬워집니다.
4. 객체_구조화하기
개요
긴 매개변수 목록을 객체로 묶어 함수 호출을 명확하게 만들고 확장성을 높입니다.
코드 예제
// Before
function createUser(name, email, age, address, phone) {
return { name, email, age, address, phone };
}
createUser('김철수', 'kim@example.com', 30, '서울', '010-1234-5678');
// After
function createUser({ name, email, age, address, phone }) {
return { name, email, age, address, phone };
}
createUser({
name: '김철수',
email: 'kim@example.com',
age: 30,
address: '서울',
phone: '010-1234-5678'
});
설명
객체 구조 분해를 사용하면 매개변수 순서에 신경 쓸 필요가 없고, 각 값의 의미가 명확해집니다.
5. 중복_코드_제거하기
개요
반복되는 로직을 공통 함수로 추출하여 DRY(Don't Repeat Yourself) 원칙을 지킵니다.
코드 예제
// Before
function validateEmail(email) {
if (!email || email.trim() === '') return false;
return email.includes('@');
}
function validatePhone(phone) {
if (!phone || phone.trim() === '') return false;
return phone.length >= 10;
}
// After
function isNotEmpty(value) {
return value && value.trim() !== '';
}
function validateEmail(email) {
return isNotEmpty(email) && email.includes('@');
}
function validatePhone(phone) {
return isNotEmpty(phone) && phone.length >= 10;
}
설명
공통 검증 로직을 별도 함수로 분리하여 코드 중복을 제거하고 유지보수를 쉽게 만듭니다.
6. 명확한_변수명_사용하기
개요
약어나 모호한 이름 대신 의도를 명확히 드러내는 변수명을 사용합니다.
코드 예제
// Before
function calc(arr) {
let s = 0;
for (let i = 0; i < arr.length; i++) {
s += arr[i].p * arr[i].q;
}
return s;
}
// After
function calculateTotalPrice(cartItems) {
let totalPrice = 0;
for (const item of cartItems) {
totalPrice += item.price * item.quantity;
}
return totalPrice;
}
설명
변수명만으로도 코드의 의도를 파악할 수 있어 주석 없이도 이해하기 쉬운 코드가 됩니다.
7. 삼항_연산자_개선하기
개요
복잡한 삼항 연산자를 명확한 if-else나 객체 매핑으로 변경하여 가독성을 높입니다.
코드 예제
// Before
const msg = status === 'success' ? '성공' :
status === 'error' ? '실패' :
status === 'pending' ? '대기중' : '알수없음';
// After
const STATUS_MESSAGES = {
success: '성공',
error: '실패',
pending: '대기중'
};
const message = STATUS_MESSAGES[status] || '알수없음';
설명
객체 매핑을 사용하면 조건이 추가되어도 구조가 명확하고, 상태-메시지 관계를 한눈에 파악할 수 있습니다.
8. 배열_메서드_활용하기
개요
전통적인 for 루프를 map, filter, reduce 등의 배열 메서드로 교체하여 함수형 프로그래밍 스타일을 적용합니다.
코드 예제
// Before
function getActiveUserNames(users) {
const result = [];
for (let i = 0; i < users.length; i++) {
if (users[i].isActive) {
result.push(users[i].name);
}
}
return result;
}
// After
function getActiveUserNames(users) {
return users
.filter(user => user.isActive)
.map(user => user.name);
}
설명
배열 메서드 체이닝으로 데이터 변환 과정이 명확해지고, 불변성을 유지하며 부작용을 줄일 수 있습니다.
9. 에러_처리_개선하기
개요
일관된 에러 처리 패턴을 사용하여 예외 상황을 명확하게 관리합니다.
코드 예제
// Before
function getUser(id) {
const user = database.find(id);
if (!user) return null;
return user;
}
// After
class UserNotFoundError extends Error {
constructor(id) {
super(`사용자를 찾을 수 없습니다: ${id}`);
this.name = 'UserNotFoundError';
}
}
function getUser(id) {
const user = database.find(id);
if (!user) {
throw new UserNotFoundError(id);
}
return user;
}
설명
명시적인 에러 처리로 문제를 빠르게 발견할 수 있고, 호출하는 쪽에서 적절히 대응할 수 있습니다.
10. 순수_함수로_만들기
개요
외부 상태를 변경하지 않고 입력에만 의존하는 순수 함수로 리팩토링하여 예측 가능성을 높입니다.
코드 예제
// Before
let discount = 0.1;
function applyDiscount(price) {
return price * (1 - discount);
}
// After
function applyDiscount(price, discountRate) {
return price * (1 - discountRate);
}
const STANDARD_DISCOUNT = 0.1;
const finalPrice = applyDiscount(10000, STANDARD_DISCOUNT);
설명
외부 변수에 의존하지 않는 순수 함수는 테스트가 쉽고, 동일한 입력에 항상 같은 결과를 보장합니다.
마치며
이번 글에서는 Refactoring 베스트 프랙티스 완벽 가이드에 대해 알아보았습니다. 총 10가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#JavaScript #Refactoring #CleanCode #CodeQuality #BestPractices