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
- Küçük adımlar - Her seferinde bir değişiklik
- Testler ile güvence - Refactoring öncesi test yaz
- Commit sık - Her başarılı refactoring'i commit et
- Davranışı koruma - Fonksiyonalite değişmemeli
Extract Method
// ❌ 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
// ❌ 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
// ❌ 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
// ❌ Ç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
// ❌ 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
// ❌ 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
// ❌ 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
# Kullanılmayan export'ları bul
npx ts-prune
# Kullanılmayan dependencies
npx depcheck
# ESLint no-unused-vars
npm run lint
Refactoring Checklist
Önce
Sırasında
Sonra
Code Smells → Refactoring Mapping
| Smell |
Refactoring |
| Long Method |
Extract Method |
| Large Class |
Extract Class |
| Long Parameter List |
Introduce Parameter Object |
| Switch Statements |
Replace with Polymorphism |
| Nested Conditionals |
Guard Clauses |
| Magic Numbers |
Replace with Constants |
| Duplicate Code |
Extract Method/Class |
| Feature Envy |
Move Method |
| Data Clumps |
Introduce Parameter Object |