Skip to main content
Glama
clean-code-guide.md9.07 kB
# 클린 코드 작성 가이드 이 문서는 읽기 쉽고 유지보수하기 좋은 클린 코드를 작성하기 위한 실용적인 가이드입니다. ## 📋 목차 1. [네이밍 규칙](#네이밍-규칙) 2. [함수 작성 원칙](#함수-작성-원칙) 3. [주석 작성 가이드](#주석-작성-가이드) 4. [코드 구조화](#코드-구조화) 5. [에러 처리](#에러-처리) 6. [리팩토링 팁](#리팩토링-팁) ## 네이밍 규칙 ### 좋은 네이밍의 원칙 **의도를 분명히 표현하라** - ❌ 나쁜 예: `d`, `data`, `temp` - ✅ 좋은 예: `elapsedTimeInDays`, `customerData`, `userAccount` **검색하기 쉬운 이름을 사용하라** - ❌ 나쁜 예: 숫자나 짧은 약어 (`e`, `x1`, `MAX`) - ✅ 좋은 예: 의미 있는 이름 (`employee`, `maxConnections`) **클래스 이름은 명사나 명사구** - ✅ 좋은 예: `Customer`, `Account`, `AddressParser` **함수 이름은 동사나 동사구** - ✅ 좋은 예: `getUser()`, `calculateTotal()`, `isValid()` ### 네이밍 예시 ```javascript // ❌ 나쁜 예 function proc(d) { let t = 0; for (let i = 0; i < d.length; i++) { t += d[i].amt; } return t; } // ✅ 좋은 예 function calculateTotalAmount(orders) { let totalAmount = 0; for (let order of orders) { totalAmount += order.amount; } return totalAmount; } ``` ## 함수 작성 원칙 ### 작게 만들어라 함수는 가능한 한 작게 작성해야 합니다. 한 함수는 한 가지 일만 해야 합니다. ```javascript // ❌ 나쁜 예: 여러 가지 일을 하는 함수 function processUser(user) { // 사용자 검증 if (!user.email || !user.name) { return { error: "Invalid user" }; } // 데이터베이스 저장 db.save(user); // 이메일 발송 emailService.sendWelcomeEmail(user.email); // 로그 기록 logger.log(`User created: ${user.email}`); return { success: true }; } // ✅ 좋은 예: 각각의 책임을 분리 function validateUser(user) { if (!user.email || !user.name) { throw new Error("Invalid user"); } } function saveUser(user) { return db.save(user); } function sendWelcomeEmail(email) { return emailService.sendWelcomeEmail(email); } function processUser(user) { validateUser(user); const savedUser = saveUser(user); sendWelcomeEmail(savedUser.email); logger.log(`User created: ${savedUser.email}`); return { success: true }; } ``` ### 함수 인자는 적게 함수의 인자는 0개가 가장 좋고, 1개, 2개 순서로 좋습니다. 3개 이상은 피하는 것이 좋습니다. ```javascript // ❌ 나쁜 예: 인자가 너무 많음 function createUser(name, email, age, address, phone, role, department) { // ... } // ✅ 좋은 예: 객체로 묶기 function createUser(userData) { const { name, email, age, address, phone, role, department } = userData; // ... } ``` ### 부수 효과를 일으키지 마라 함수는 한 가지 일만 해야 하며, 예상치 못한 부수 효과를 만들면 안 됩니다. ```javascript // ❌ 나쁜 예: 부수 효과가 있는 함수 let password = "default123"; function checkPassword(input) { if (input === password) { password = "changed"; // 예상치 못한 부수 효과! return true; } return false; } // ✅ 좋은 예: 순수 함수 function checkPassword(input, expectedPassword) { return input === expectedPassword; } ``` ## 주석 작성 가이드 ### 좋은 주석 **복잡한 알고리즘 설명** ```javascript // 이진 탐색 알고리즘: 정렬된 배열에서 O(log n) 시간 복잡도로 검색 function binarySearch(sortedArray, target) { // ... } ``` **의도를 설명하는 주석** ```javascript // 사용자 권한을 확인하기 위해 세션을 먼저 검증해야 함 // (보안 정책에 따라) if (!validateSession(userSession)) { return unauthorized(); } ``` ### 나쁜 주석 **코드 자체를 설명하는 주석 (불필요)** ```javascript // ❌ 나쁜 예: 코드가 이미 명확함 // i를 0부터 시작해서 10까지 증가시킴 for (let i = 0; i < 10; i++) { // ... } ``` **주석 처리된 코드** ```javascript // ❌ 나쁜 예: 주석 처리된 코드는 삭제해야 함 // function oldFunction() { // return "deprecated"; // } ``` **너무 많은 주석** ```javascript // ❌ 나쁜 예: 코드가 주석으로 가려짐 // 이 함수는 사용자를 생성합니다 // 사용자 데이터를 받아서 // 검증하고 // 데이터베이스에 저장합니다 function createUser(user) { // ... } ``` ## 코드 구조화 ### 일관성 유지 코드 스타일과 구조를 일관되게 유지하세요. ```javascript // ✅ 좋은 예: 일관된 구조 class UserService { constructor(database) { this.db = database; } async getUser(id) { return await this.db.findUser(id); } async createUser(userData) { return await this.db.saveUser(userData); } async updateUser(id, userData) { return await this.db.updateUser(id, userData); } } ``` ### 중복 제거 (DRY 원칙) 같은 코드를 반복하지 마세요. 함수나 클래스로 추출하세요. ```javascript // ❌ 나쁜 예: 중복된 코드 function calculateOrderTotal(order) { let total = 0; for (let item of order.items) { total += item.price * item.quantity; } total += total * 0.1; // 세금 return total; } function calculateInvoiceTotal(invoice) { let total = 0; for (let item of invoice.items) { total += item.price * item.quantity; } total += total * 0.1; // 세금 return total; } // ✅ 좋은 예: 중복 제거 function calculateItemsTotal(items) { return items.reduce((sum, item) => { return sum + item.price * item.quantity; }, 0); } function applyTax(amount, taxRate = 0.1) { return amount + amount * taxRate; } function calculateOrderTotal(order) { const subtotal = calculateItemsTotal(order.items); return applyTax(subtotal); } function calculateInvoiceTotal(invoice) { const subtotal = calculateItemsTotal(invoice.items); return applyTax(subtotal); } ``` ## 에러 처리 ### 명확한 에러 메시지 에러가 발생했을 때 무엇이 잘못되었는지 명확히 알 수 있어야 합니다. ```javascript // ❌ 나쁜 예: 모호한 에러 function divide(a, b) { if (b === 0) { throw new Error("Error"); } return a / b; } // ✅ 좋은 예: 명확한 에러 메시지 function divide(a, b) { if (b === 0) { throw new Error(`Cannot divide ${a} by zero`); } return a / b; } ``` ### 예외 처리 예외를 적절히 처리하고, 예상치 못한 상황에 대비하세요. ```javascript // ✅ 좋은 예: 적절한 예외 처리 async function fetchUserData(userId) { try { const user = await database.findUser(userId); if (!user) { throw new NotFoundError(`User with ID ${userId} not found`); } return user; } catch (error) { if (error instanceof NotFoundError) { throw error; // 예상된 에러는 재발생 } logger.error(`Unexpected error fetching user ${userId}:`, error); throw new Error("Failed to fetch user data"); } } ``` ## 리팩토링 팁 ### 코드 냄새(Code Smell) 감지 다음과 같은 상황이 보이면 리팩토링을 고려하세요: 1. **긴 함수**: 함수가 20줄 이상이면 분리 고려 2. **긴 매개변수 목록**: 3개 이상의 매개변수는 객체로 묶기 3. **중복 코드**: 같은 코드가 여러 곳에 있으면 함수로 추출 4. **매직 넘버**: 숫자 상수는 이름 있는 상수로 변경 5. **주석 처리된 코드**: 삭제하거나 버전 관리에 맡기기 ### 리팩토링 예시 ```javascript // ❌ 리팩토링 전 function processOrder(order) { if ( order.status === "pending" && order.items.length > 0 && order.total > 100 ) { order.status = "processing"; // 0.1은 세금율 order.finalTotal = order.total * 1.1; sendEmail(order.customerEmail, "Your order is being processed"); } } // ✅ 리팩토링 후 const TAX_RATE = 0.1; const MINIMUM_ORDER_AMOUNT = 100; function isOrderProcessable(order) { return ( order.status === "pending" && order.items.length > 0 && order.total > MINIMUM_ORDER_AMOUNT ); } function calculateFinalTotal(subtotal) { return subtotal * (1 + TAX_RATE); } function processOrder(order) { if (isOrderProcessable(order)) { order.status = "processing"; order.finalTotal = calculateFinalTotal(order.total); sendEmail(order.customerEmail, "Your order is being processed"); } } ``` ## 마무리 클린 코드는 한 번에 완성되지 않습니다. 지속적인 리팩토링과 개선을 통해 점진적으로 발전시켜 나가세요. **핵심 원칙:** - 코드는 읽기 쉬워야 합니다 - 작은 함수, 작은 클래스 - 의미 있는 이름 사용 - 중복 제거 - 테스트 가능한 코드 작성 **기억하세요:** 코드는 작성하는 시간보다 읽는 시간이 더 많습니다. 미래의 자신과 동료를 위해 클린 코드를 작성하세요.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/geunu97/-teams-guide-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server