name: "clean-code" description: "클린 코드 원칙 및 적용 가이드를 실행합니다." user-invocable: true
Clean Code Skill
클린 코드 원칙 및 적용 가이드를 실행합니다.
네이밍
의도를 드러내는 이름
// ❌ Bad
const d = 86400;
const list = users.filter(u => u.a > 18);
// ✅ Good
const SECONDS_PER_DAY = 86400;
const adultUsers = users.filter(user => user.age > 18);
검색 가능한 이름
// ❌ Bad
setTimeout(fn, 86400000);
// ✅ Good
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
setTimeout(fn, MILLISECONDS_PER_DAY);
발음 가능한 이름
// ❌ Bad
const yyyymmdstr = moment().format('YYYY/MM/DD');
// ✅ Good
const currentDate = moment().format('YYYY/MM/DD');
함수
작게 만들기
// ❌ Bad: 너무 긴 함수
function processOrder(order) {
// 100줄의 코드...
}
// ✅ Good: 작은 함수들로 분리
function processOrder(order) {
validateOrder(order);
calculateTotal(order);
applyDiscounts(order);
saveOrder(order);
sendConfirmation(order);
}
하나의 일만 하기
// ❌ Bad: 여러 일을 함
function emailClients(clients) {
clients.forEach(client => {
const record = database.lookup(client);
if (record.isActive()) {
email(client);
}
});
}
// ✅ Good: 하나의 일만
function emailActiveClients(clients) {
clients
.filter(isActiveClient)
.forEach(email);
}
function isActiveClient(client) {
const record = database.lookup(client);
return record.isActive();
}
인수 최소화
// ❌ Bad: 인수가 많음
function createUser(name, email, age, address, phone, role) {}
// ✅ Good: 객체로 전달
function createUser({ name, email, age, address, phone, role }) {}
// 또는 Builder 패턴
new UserBuilder()
.setName('John')
.setEmail('john@example.com')
.build();
부수 효과 없애기
// ❌ Bad: 숨겨진 부수 효과
function checkPassword(user, password) {
if (cryptographer.decrypt(user.password) === password) {
Session.initialize(); // 숨겨진 부수 효과!
return true;
}
return false;
}
// ✅ Good: 명확한 의도
function checkPassword(user, password) {
return cryptographer.decrypt(user.password) === password;
}
function loginUser(user, password) {
if (checkPassword(user, password)) {
Session.initialize();
return true;
}
return false;
}
주석
코드로 의도 표현
// ❌ Bad: 주석으로 설명
// 직원이 혜택을 받을 자격이 있는지 확인
if (employee.flags & HOURLY_FLAG && employee.age > 65) {}
// ✅ Good: 코드가 설명
if (employee.isEligibleForFullBenefits()) {}
좋은 주석
// 정규표현식 설명 (복잡한 패턴)
// Format: kk:mm:ss EEE, MMM dd, yyyy
const pattern = /\d{2}:\d{2}:\d{2} \w{3}, \w{3} \d{2}, \d{4}/;
// TODO: 임시 해결책, #123 이슈에서 수정 예정
// WARNING: 이 메서드는 O(n²) 복잡도를 가짐
// NOTE: 외부 API 제한으로 인해 이 방식 사용
나쁜 주석
// ❌ 피해야 할 주석
i++; // i를 증가시킴 (불필요)
// 작성자: John, 날짜: 2024-01-15 (버전 관리 사용)
// function oldMethod() { ... } (죽은 코드)
에러 처리
예외 사용
// ❌ Bad: 에러 코드 반환
function withdraw(amount) {
if (balance < amount) return -1;
balance -= amount;
return 0;
}
// ✅ Good: 예외 던지기
function withdraw(amount) {
if (balance < amount) {
throw new InsufficientFundsError(amount, balance);
}
balance -= amount;
}
의미있는 예외
// ❌ Bad
throw new Error('Error');
// ✅ Good
throw new ValidationError('Email format is invalid', { field: 'email' });
객체와 자료구조
디미터 법칙
// ❌ Bad: 기차 충돌 (Train Wreck)
const outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
// ✅ Good
const options = ctxt.getOptions();
const scratchDir = options.getScratchDir();
const outputDir = scratchDir.getAbsolutePath();
// 또는 더 좋은 방법
const outputDir = ctxt.getOutputDirectory();
클래스
작게 유지
// 클래스는 하나의 책임만
// 메서드 수보다 책임의 수가 중요
// ❌ Bad: God Class
class Employee {
// 급여 계산, 세금 계산, HR 보고서, 이메일 발송 등...
}
// ✅ Good: 분리된 책임
class Employee { /* 직원 데이터 */ }
class PayrollCalculator { /* 급여 계산 */ }
class TaxCalculator { /* 세금 계산 */ }
class HRReporter { /* HR 보고서 */ }
응집도
// 높은 응집도: 모든 메서드가 모든 인스턴스 변수 사용
class Stack {
private items = [];
push(item) { this.items.push(item); }
pop() { return this.items.pop(); }
peek() { return this.items[this.items.length - 1]; }
isEmpty() { return this.items.length === 0; }
}
체크리스트
함수
- 20줄 이하
- 인수 3개 이하
- 하나의 일만 수행
- 부수 효과 없음
- 추상화 수준 일관성
이름
- 의도가 명확
- 발음/검색 가능
- 일관된 용어 사용
클래스
- 작은 크기 (200줄 이하 권장)
- 단일 책임
- 높은 응집도
출력 형식
## Clean Code Review
### Issues Found
| 유형 | 위치 | 문제 | 개선안 |
|------|------|------|--------|
| 네이밍 | line 10 | 불명확한 변수명 | d → dayCount |
### Refactoring
```javascript
// Before
...
// After
...
Metrics
- 함수 평균 길이: XX줄
- 최대 함수 길이: XX줄
- 인수 평균: X개
---
요청에 맞는 클린 코드 분석 및 개선안을 제시하세요.