Делал ли рефакторинг кода
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Опыт рефакторинга кода
Да, я регулярно выполняю рефакторинг и вижу это как неотъемлемую часть профессиональной разработки. Рефакторинг не стоит путать с переписыванием — это улучшение кода без изменения его функциональности.
Что такое рефакторинг
Рефакторинг — это процесс улучшения внутренней структуры кода без изменения его внешнего поведения. Цели:
- Улучшить читаемость
- Снизить сложность (cyclomatic complexity)
- Убрать дублирование (DRY)
- Улучшить тестируемость
- Облегчить поддержку
Категории рефакторинга
1. Извлечение функций (Extract Function)
До рефакторинга:
def process_user_order(user_id, items):
# Получаем пользователя
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise ValueError('User not found')
# Вычисляем сумму
total = 0
for item in items:
product = db.query(Product).filter(Product.id == item['id']).first()
price = product.price * item['quantity']
if user.discount > 0:
price *= (1 - user.discount / 100)
total += price
# Создаём заказ
order = Order(user_id=user_id, total=total)
db.add(order)
db.commit()
return order
После рефакторинга:
def process_user_order(user_id, items):
user = get_user(user_id)
total = calculate_order_total(user, items)
order = create_order(user_id, total)
return order
def get_user(user_id):
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise ValueError('User not found')
return user
def calculate_order_total(user, items):
total = 0
for item in items:
price = get_item_price(item)
price = apply_discount(price, user.discount)
total += price
return total
def get_item_price(item):
product = db.query(Product).filter(Product.id == item['id']).first()
return product.price * item['quantity']
def apply_discount(price, discount):
if discount > 0:
return price * (1 - discount / 100)
return price
def create_order(user_id, total):
order = Order(user_id=user_id, total=total)
db.add(order)
db.commit()
return order
Плюсы: Код читается как проза, легко тестировать, легко переиспользовать.
2. Замена условного оператора на полиморфизм
До рефакторинга:
def calculate_price(user_type, base_price):
if user_type == 'premium':
return base_price * 0.8
elif user_type == 'regular':
return base_price * 0.9
elif user_type == 'guest':
return base_price
else:
raise ValueError('Unknown user type')
После рефакторинга:
from abc import ABC, abstractmethod
class UserType(ABC):
@abstractmethod
def calculate_price(self, base_price):
pass
class PremiumUser(UserType):
def calculate_price(self, base_price):
return base_price * 0.8
class RegularUser(UserType):
def calculate_price(self, base_price):
return base_price * 0.9
class GuestUser(UserType):
def calculate_price(self, base_price):
return base_price
def calculate_price(user: UserType, base_price):
return user.calculate_price(base_price)
Плюсы: Легко добавлять новые типы пользователей без изменения основного кода (Open/Closed Principle).
3. Удаление дублирования (DRY)
До рефакторинга:
def validate_email(email):
if not email:
raise ValueError('Email is required')
if '@' not in email:
raise ValueError('Invalid email format')
if len(email) > 255:
raise ValueError('Email is too long')
return email
def validate_password(password):
if not password:
raise ValueError('Password is required')
if '@' not in password: # Глупо, но дублирование
raise ValueError('Invalid password format')
if len(password) > 255:
raise ValueError('Password is too long')
return password
После рефакторинга:
def validate_field(value, field_name, validators=None):
validators = validators or []
if not value:
raise ValueError(f'{field_name} is required')
for validator in validators:
if not validator(value):
raise ValueError(f'Invalid {field_name} format')
if len(str(value)) > 255:
raise ValueError(f'{field_name} is too long')
return value
def validate_email(email):
return validate_field(email, 'Email', [lambda x: '@' in x])
def validate_password(password):
return validate_field(password, 'Password', [
lambda x: len(x) >= 8,
lambda x: any(c.isupper() for c in x)
])
4. Упрощение сложного условия
До рефакторинга:
if user.is_active and user.has_subscription and user.subscription.is_valid and not user.is_banned and user.balance > 0:
process_payment(user)
После рефакторинга:
if is_eligible_for_payment(user):
process_payment(user)
def is_eligible_for_payment(user):
return (
user.is_active
and user.has_subscription
and user.subscription.is_valid
and not user.is_banned
and user.balance > 0
)
5. Переименование переменных
До рефакторинга:
users = get_users()
for u in users:
if u.age > 18 and u.status == 'active':
u.send_promo_email() # Непонятно что происходит
После рефакторинга:
active_adult_users = get_active_adult_users()
for user in active_adult_users:
user.send_promotional_email()
Типичные метрики улучшения
После рефакторинга обычно улучшаются:
| Метрика | Улучшение |
|---|---|
| Cyclomatic Complexity | Снижение на 30-50% |
| Дублирование кода | Снижение на 20-40% |
| Test Coverage | Увеличение на 10-30% |
| Time to fix bugs | Снижение на 40-60% |
| Onboarding time | Снижение для новичков |
Когда делать рефакторинг
✅ Делать:
- Когда функция больше 30 строк
- Когда cyclomatic complexity > 5
- Перед добавлением нового функционала
- Когда нужно исправить баг и код непонятный
- Когда вспоминаешь код дольше, чем его переписываешь
❌ Не делать:
- Во время критичного падежа (fix fast first)
- Без покрытия тестами
- Одновременно с добавлением функционала
- Если это наносит вред performance
Boy Scout Rule
Это мой подход:
- Каждый раз когда трогаю код — немного его улучшу
- Не нужно идеальное решение за один раз
- Мелкие улучшения накапливаются
- Главное — оставить код лучше, чем был
Инструменты для рефакторинга
# Анализ кода
# pylint, flake8, black — форматирование и анализ
# Refactoring IDE — PyCharm умеет много автоматизировать
# Тестирование перед рефакторингом
def test_order_calculation():
user = create_test_user(discount=20)
items = [{'id': 1, 'quantity': 2}]
total = calculate_order_total(user, items)
assert total > 0
# Тесты гарантируют, что поведение не изменилось
Вывод
Рефакторинг — это не факультативный процесс, а обязательная часть профессиональной разработки. Я регулярно его делаю, следуя SOLID, DRY и KISS принципам. Главное правило: без хороших тестов не делай рефакторинг, они гарантируют, что ты ничего не сломал.