Files
2nd/10_Wiki/Topics/AI_and_ML/Code_Smells.md
T
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

7.8 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-code-smells Code Smells 10_Wiki/Topics verified self
코드 악취
code smell
refactoring catalog
Fowler
bloater
coupler
dispensable
none A 0.93 applied
refactoring
code-smell
fowler
software-quality
technical-debt
oop
code-review
2026-05-10 pending
language framework
language-agnostic 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)

// ❌ 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

// ❌
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

// ❌
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

// ❌
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

// ❌ Chain
order.getCustomer().getAddress().getCountry().getName();

// ✅ Hide
class Order {
  customerCountry() {
    return this.customer.address.country.name;
  }
}

Detection (Semgrep)

# 매 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

# 매 cognitive complexity
sonar.javascript.cognitive-complexity-threshold=15

# 매 duplicate threshold
sonar.cpd.minimumLines=20
sonar.duplicatedLines.maximum=3.0

AI review (CodeRabbit)

# .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)

# 매 radon (Python)
radon cc src/ -a -nb

# 매 ESLint complexity rule
echo '{ "rules": { "complexity": ["error", 10] } }' > .eslintrc.json

Bobby tables (refactor cadence)

# 매 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

🤖 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.

🧪 검증 / 중복

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — 6 category + refactor + 매 TS / Semgrep / SonarQube code