--- id: wiki-2026-0508-code-smells title: Code Smells category: 10_Wiki/Topics status: verified canonical_id: self aliases: [코드 악취, code smell, refactoring catalog, Fowler, bloater, coupler, dispensable] duplicate_of: none source_trust_level: A confidence_score: 0.93 verification_status: applied tags: [refactoring, code-smell, fowler, software-quality, technical-debt, oop, code-review] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: language-agnostic framework: refactoring catalog --- # Code Smells ## 📌 한 줄 통찰 > **"매 code 의 surface 의 sign 의 deeper problem"**. Martin Fowler 의 catalog. 매 syntax 의 OK 가, 매 design 의 ill. 매 refactoring 의 trigger. 매 modern: 매 SonarQube / Semgrep / AI review 의 자동 detect. ## 📖 핵심 ### 매 Fowler 의 6 category #### 1. Bloater - **Long Method**: 매 single function 의 거대. - **Large Class**: 매 god class. - **Primitive Obsession**: 매 string / int 의 abuse. - **Long Parameter List**: 매 4+ parameter. - **Data Clump**: 매 같이 쓰이는 data 의 group X. #### 2. OO Abuser - **Switch Statement**: 매 polymorphism 의 missed. - **Temporary Field**: 매 일부 case 만 의 사용 field. - **Refused Bequest**: 매 inherit 가, 매 일부 의 X. - **Alternative Classes with Different Interface**: 매 same job, 매 다른 method name. #### 3. Change Preventer - **Divergent Change**: 매 1 class 의 매 다른 reason 의 수정. - **Shotgun Surgery**: 매 1 변경 의 매 N class 의 수정. - **Parallel Inheritance Hierarchies**: 매 두 hierarchy 의 동시 의 grow. #### 4. Dispensable - **Duplicate Code** (DRY violation). - **Lazy Class**: 매 도움 X. - **Data Class**: 매 anaemic (case-by-case). - **Dead Code**: 매 unused. - **Speculative Generality**: 매 hypothetical 의 design. - **Comments**: 매 reason 의 explain 의 X 의 case. #### 5. Coupler - **Feature Envy**: 매 method 의 다른 class 의 더 사용. - **Inappropriate Intimacy**: 매 internal 의 over-share. - **Message Chain**: `a.b().c().d()` 의 chain. - **Middle Man**: 매 delegation 만. #### 6. Other - **Mysterious Name**: 매 unclear identifier. - **Magic Number**: 매 unnamed constant. - **Insider Trading**: 매 inappropriate field access. - **Incomplete Library Class**. ### 매 modern addition (Fowler 2nd ed) - **Mutable Data**. - **Global Data**. - **Loops** (Stream / functional 의 lieu). - **Repeated Switches**. ### 매 detection - **Manual review**. - **Linter**: ESLint, RuboCop, Pylint. - **SAST**: SonarQube, CodeClimate. - **Semgrep**: 매 custom rule. - **AI review**: CodeRabbit, Greptile. ### 매 refactoring (corresponding) - **Extract Method**: Long Method. - **Extract Class**: Large Class. - **Replace Conditional with Polymorphism**: Switch. - **Move Method**: Feature Envy. - **Hide Delegate**: Message Chain. - **Introduce Parameter Object**: Long Parameter / Data Clump. ### 매 priority - 매 not all smells 의 fix 의 immediate. - 매 changing area 의 first. - 매 boy scout rule (better than found). ## 💻 패턴 ### Long Method (extract) ```ts // ❌ Long Method function processOrder(order: Order) { // 매 50+ lines: validate, calculate, save, notify, log... } // ✅ Extract Method function processOrder(order: Order) { validate(order); const total = calculateTotal(order); save(order, total); notify(order); } function validate(order: Order) { ... } function calculateTotal(order: Order) { ... } ``` ### Primitive Obsession → Value Object ```ts // ❌ function transfer(amount: number, currency: string) { ... } // ✅ class Money { constructor(public amount: bigint, public currency: string) {} add(other: Money) { if (this.currency !== other.currency) throw new Error(); return new Money(this.amount + other.amount, this.currency); } } function transfer(money: Money) { ... } ``` ### Switch → Polymorphism ```ts // ❌ function area(shape: Shape) { switch (shape.type) { case 'circle': return Math.PI * shape.r ** 2; case 'square': return shape.side ** 2; case 'rectangle': return shape.w * shape.h; } } // ✅ abstract class Shape { abstract area(): number; } class Circle extends Shape { constructor(public r: number) {} area() { return Math.PI * this.r ** 2; } } class Square extends Shape { constructor(public side: number) {} area() { return this.side ** 2; } } ``` ### Feature Envy → Move Method ```ts // ❌ class Order { total(customer: Customer) { // 매 모든 logic 의 customer 의 사용 return customer.discount * customer.tax * ...; } } // ✅ Move to Customer class Customer { applyDiscount(amount: number) { return amount * this.discountRate; } } ``` ### Message Chain → Hide Delegate ```ts // ❌ Chain order.getCustomer().getAddress().getCountry().getName(); // ✅ Hide class Order { customerCountry() { return this.customer.address.country.name; } } ``` ### Detection (Semgrep) ```yaml # 매 long parameter list detection rules: - id: long-parameter-list pattern-either: - pattern: function $F($A, $B, $C, $D, $E, ...) { ... } message: "Function has 5+ parameters — consider Parameter Object" severity: WARNING languages: [typescript, javascript] ``` ### SonarQube quality gate ```properties # 매 cognitive complexity sonar.javascript.cognitive-complexity-threshold=15 # 매 duplicate threshold sonar.cpd.minimumLines=20 sonar.duplicatedLines.maximum=3.0 ``` ### AI review (CodeRabbit) ```yaml # .coderabbit.yaml language: en reviews: profile: chill high_level_summary: true poem: false auto_review: enabled: true drafts: false # 매 auto-detect: long methods, missing tests, complexity, etc. ``` ### Refactor metric (cyclomatic complexity) ```bash # 매 radon (Python) radon cc src/ -a -nb # 매 ESLint complexity rule echo '{ "rules": { "complexity": ["error", 10] } }' > .eslintrc.json ``` ### Bobby tables (refactor cadence) ```python # 매 boy scout rule def visit(file): if needs_change(file): # 매 main change do_main_change() # 매 small refactor (touching area) if has_smell(file): small_refactor() ``` ## 🤔 결정 기준 | Smell | Refactor | |---|---| | Long Method | Extract Method | | Large Class | Extract Class | | Primitive Obsession | Value Object | | Long Parameter | Parameter Object | | Duplicate | DRY (Extract) | | Switch | Polymorphism | | Feature Envy | Move Method | | Data Clump | Class | | Comments (bad) | Rename / Restructure | | Magic Number | Named Constant | **기본값**: 매 fix-as-you-touch + 매 priority queue (changing area). ## 🔗 Graph - 부모: [[Refactoring_Best_Practices|Refactoring]] · [[Code-Quality]] - 변형: [[Bloater]] · [[Coupler]] · [[Dispensable]] - 응용: [[Replace-Conditional-with-Polymorphism]] - 비판: [[Anaemic-Domain-Model]] (Data Class) - Adjacent: [[Architecture-Anti-Patterns]] · [[Quality_Code_Review_Modern]] · [[Clean-Code-Principles]] · [[SOLID]] ## 🤖 LLM 활용 **언제**: 매 code review. 매 refactor planning. 매 onboarding (smell 의 catalog 인지). **언제 X**: 매 prototype (premature). 매 throwaway script. ## ❌ 안티패턴 - **모든 smell 의 fix 의 obsession**: 매 productivity ↓. - **No measure**: 매 better 의 prove 의 X. - **Smell 의 ignore**: 매 technical debt 의 accumulate. - **Refactor without test**: 매 regression. - **Big bang refactor**: 매 risky. - **Clean Code 의 dogma**: 매 sometimes wrong. ## 🧪 검증 / 중복 - Verified (Fowler "Refactoring", Beck "Implementation Patterns", SonarQube rules). - 신뢰도 A. - Related: [[Architecture-Anti-Patterns]] · [[Anaemic-Domain-Model]] · [[Quality_Code_Review_Modern]] · [[Clean-Code-Principles]]. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — 6 category + refactor + 매 TS / Semgrep / SonarQube code |