AgentSkillsCN

refactoring-patterns

重构技术与模式。在重构、代码优化或清理技术债务时,自动应用这些优化策略。

SKILL.md
--- frontmatter
name: refactoring-patterns
description: "Refactoring teknikleri ve pattern'ları. REFACTORING, KOD İYİLEŞTİRME veya TEKNİK BORÇ temizleme işlerinde otomatik uygula."
allowed-tools:
  - Read
  - Grep
  - Glob
  - Edit
  - Write

Refactoring Patterns

Temel Prensipler

  1. Küçük adımlar - Her seferinde bir değişiklik
  2. Testler ile güvence - Refactoring öncesi test yaz
  3. Commit sık - Her başarılı refactoring'i commit et
  4. Davranışı koruma - Fonksiyonalite değişmemeli

Extract Method

typescript
// ❌ Uzun fonksiyon
async function processOrder(order: Order) {
  // Validate
  if (!order.items.length) throw new Error('Empty order')
  if (!order.userId) throw new Error('No user')
  
  // Calculate totals
  let subtotal = 0
  for (const item of order.items) {
    subtotal += item.price * item.quantity
  }
  const tax = subtotal * 0.18
  const total = subtotal + tax
  
  // Save
  order.subtotal = subtotal
  order.tax = tax
  order.total = total
  await orderRepository.save(order)
  
  // Notify
  await emailService.send(order.userId, 'Order confirmed', { orderId: order.id })
}

// ✅ Refactored
async function processOrder(order: Order) {
  validateOrder(order)
  const totals = calculateTotals(order.items)
  await saveOrder(order, totals)
  await notifyUser(order)
}

function validateOrder(order: Order): void {
  if (!order.items.length) throw new ValidationError('Empty order')
  if (!order.userId) throw new ValidationError('No user')
}

function calculateTotals(items: OrderItem[]): OrderTotals {
  const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0)
  const tax = subtotal * 0.18
  return { subtotal, tax, total: subtotal + tax }
}

Replace Conditional with Polymorphism

typescript
// ❌ Switch/if-else chain
function calculateDiscount(customer: Customer): number {
  switch (customer.type) {
    case 'gold':
      return customer.total * 0.20
    case 'silver':
      return customer.total * 0.10
    case 'bronze':
      return customer.total * 0.05
    default:
      return 0
  }
}

// ✅ Strategy Pattern
interface DiscountStrategy {
  calculate(total: number): number
}

class GoldDiscount implements DiscountStrategy {
  calculate(total: number) { return total * 0.20 }
}

class SilverDiscount implements DiscountStrategy {
  calculate(total: number) { return total * 0.10 }
}

const discountStrategies: Record<string, DiscountStrategy> = {
  gold: new GoldDiscount(),
  silver: new SilverDiscount(),
  bronze: new BronzeDiscount(),
}

function calculateDiscount(customer: Customer): number {
  const strategy = discountStrategies[customer.type]
  return strategy?.calculate(customer.total) ?? 0
}

Replace Magic Numbers/Strings

typescript
// ❌ Magic values
if (user.role === 'admin') { ... }
if (order.status === 1) { ... }
const timeout = 30000

// ✅ Constants/Enums
enum UserRole {
  ADMIN = 'admin',
  USER = 'user',
  GUEST = 'guest',
}

enum OrderStatus {
  PENDING = 1,
  PROCESSING = 2,
  COMPLETED = 3,
}

const CONFIG = {
  TIMEOUT_MS: 30000,
  MAX_RETRIES: 3,
  PAGE_SIZE: 20,
} as const

if (user.role === UserRole.ADMIN) { ... }
if (order.status === OrderStatus.PENDING) { ... }

Introduce Parameter Object

typescript
// ❌ Çok parametre
function searchUsers(
  query: string,
  page: number,
  limit: number,
  sortBy: string,
  sortOrder: 'asc' | 'desc',
  filters: Record<string, unknown>
) { ... }

// ✅ Parameter object
interface SearchParams {
  query: string
  pagination: {
    page: number
    limit: number
  }
  sort?: {
    field: string
    order: 'asc' | 'desc'
  }
  filters?: Record<string, unknown>
}

function searchUsers(params: SearchParams) { ... }

Replace Nested Conditionals with Guard Clauses

typescript
// ❌ Deep nesting
function processPayment(payment: Payment) {
  if (payment) {
    if (payment.amount > 0) {
      if (payment.method) {
        if (isValidMethod(payment.method)) {
          // actual logic
          return processTransaction(payment)
        } else {
          throw new Error('Invalid method')
        }
      } else {
        throw new Error('No method')
      }
    } else {
      throw new Error('Invalid amount')
    }
  } else {
    throw new Error('No payment')
  }
}

// ✅ Guard clauses (Early return)
function processPayment(payment: Payment) {
  if (!payment) {
    throw new ValidationError('No payment')
  }
  if (payment.amount <= 0) {
    throw new ValidationError('Invalid amount')
  }
  if (!payment.method) {
    throw new ValidationError('No method')
  }
  if (!isValidMethod(payment.method)) {
    throw new ValidationError('Invalid method')
  }
  
  return processTransaction(payment)
}

Extract Class

typescript
// ❌ God class
class User {
  // User data
  id: string
  name: string
  email: string
  
  // Address (should be separate)
  street: string
  city: string
  country: string
  zipCode: string
  
  // Preferences (should be separate)
  theme: string
  language: string
  notifications: boolean
  
  getFullAddress() { ... }
  formatAddress() { ... }
  updatePreferences() { ... }
}

// ✅ Separated concerns
class User {
  id: string
  name: string
  email: string
  address: Address
  preferences: UserPreferences
}

class Address {
  street: string
  city: string
  country: string
  zipCode: string
  
  format(): string { ... }
}

class UserPreferences {
  theme: string
  language: string
  notifications: boolean
  
  update(changes: Partial<UserPreferences>): void { ... }
}

Rename for Clarity

typescript
// ❌ Belirsiz isimler
const d = new Date()
const temp = users.filter(u => u.a)
function calc(x, y) { return x + y }

// ✅ Açıklayıcı isimler
const currentDate = new Date()
const activeUsers = users.filter(user => user.isActive)
function calculateTotal(subtotal, tax) { return subtotal + tax }

Remove Dead Code

bash
# Kullanılmayan export'ları bul
npx ts-prune

# Kullanılmayan dependencies
npx depcheck

# ESLint no-unused-vars
npm run lint

Refactoring Checklist

Önce

  • Mevcut testler geçiyor
  • Değişiklik scopu belirlendi
  • Commit yapılmış (clean state)

Sırasında

  • Küçük adımlarla ilerleniyor
  • Her adımda testler çalıştırılıyor
  • Davranış korunuyor

Sonra

  • Tüm testler geçiyor
  • Code review yapıldı
  • Dokümantasyon güncellendi

Code Smells → Refactoring Mapping

SmellRefactoring
Long MethodExtract Method
Large ClassExtract Class
Long Parameter ListIntroduce Parameter Object
Switch StatementsReplace with Polymorphism
Nested ConditionalsGuard Clauses
Magic NumbersReplace with Constants
Duplicate CodeExtract Method/Class
Feature EnvyMove Method
Data ClumpsIntroduce Parameter Object