← Назад к вопросам

Как ты занимаешься рефакторингом?

1.2 Junior🔥 201 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Процесс рефакторинга кода

Рефакторинг — это процесс улучшения внутреннего качества кода без изменения его внешнего поведения. Это не добавляет новые фичи, это делает код лучше.

Этапы рефакторинга

1. Анализ и идентификация проблем

# Плохой код — что нужно улучшить?
def process_user_data(user_list):
    result = []
    for u in user_list:
        if u['age'] > 18 and u['status'] == 'active':
            result.append({
                'name': u['name'],
                'age': u['age'],
                'email': u['email']
            })
    return result

Проблемы:

  • Имена переменных неинформативны (u, result)
  • Без типизации
  • Логика смешана с трансформацией
  • Нет документации

2. Написание тестов ДО рефакторинга

import pytest

def test_process_active_adults():
    users = [
        {"name": "Alice", "age": 25, "status": "active", "email": "alice@ex.com"},
        {"name": "Bob", "age": 17, "status": "active", "email": "bob@ex.com"},
        {"name": "Charlie", "age": 30, "status": "inactive", "email": "ch@ex.com"},
    ]
    
    result = process_user_data(users)
    
    assert len(result) == 1
    assert result[0]["name"] == "Alice"

def test_empty_input():
    assert process_user_data([]) == []

3. Рефакторинг — шаг 1: типизация

from typing import TypedDict, List

class User(TypedDict):
    name: str
    age: int
    status: str
    email: str

class ProcessedUser(TypedDict):
    name: str
    age: int
    email: str

def process_user_data(users: List[User]) -> List[ProcessedUser]:
    return [
        {"name": u["name"], "age": u["age"], "email": u["email"]}
        for u in users
        if u["age"] > 18 and u["status"] == "active"
    ]

4. Рефакторинг — шаг 2: выделение функций

def is_adult_and_active(user: User) -> bool:
    """Проверяет, является ли пользователь активным взрослым"""
    return user["age"] > 18 and user["status"] == "active"

def extract_public_fields(user: User) -> ProcessedUser:
    """Извлекает только публичные данные пользователя"""
    return {
        "name": user["name"],
        "age": user["age"],
        "email": user["email"]
    }

def process_user_data(users: List[User]) -> List[ProcessedUser]:
    """Получает данные активных взрослых пользователей"""
    return [
        extract_public_fields(u)
        for u in users
        if is_adult_and_active(u)
    ]

5. Рефакторинг — шаг 3: использование классов

from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int
    status: str
    email: str
    
    def is_adult_and_active(self) -> bool:
        return self.age > 18 and self.status == "active"
    
    def public_data(self) -> dict:
        return {
            "name": self.name,
            "age": self.age,
            "email": self.email
        }

class UserFilter:
    @staticmethod
    def get_active_adults(users: list[User]) -> list[dict]:
        return [
            user.public_data()
            for user in users
            if user.is_adult_and_active()
        ]

6. Запуск тестов — убеждаемся, что поведение не изменилось

pytest test_user.py -v
# Все тесты должны быть зелёные

Техники рефакторинга

Extract Method

# До
def calculate_total():
    subtotal = sum(item.price for item in items)
    tax = subtotal * 0.1
    total = subtotal + tax
    return total

# После
def calculate_total():
    subtotal = _calculate_subtotal()
    tax = _calculate_tax(subtotal)
    return subtotal + tax

def _calculate_subtotal():
    return sum(item.price for item in items)

def _calculate_tax(subtotal):
    return subtotal * 0.1

Remove Duplication

# До
def validate_email(email):
    if not email or "@" not in email:
        raise ValueError("Invalid email")

def validate_username(username):
    if not username or "@" in username:
        raise ValueError("Invalid username")

# После
def validate_not_empty(value: str, field_name: str):
    if not value:
        raise ValueError(f"{field_name} cannot be empty")

def validate_email(email):
    validate_not_empty(email, "Email")
    if "@" not in email:
        raise ValueError("Invalid email format")

Rename for clarity

# До
data = {"u": users, "a": active_only, "s": sorted_by_date}

# После
filtered_data = {
    "users": all_users,
    "active_only": filter_active(users),
    "sorted_by_date": sort_by_date(users)
}

Инструменты рефакторинга в Python

# Форматирование кода
black myfile.py

# Статический анализ
flake8 myfile.py
ruff check myfile.py

# Type checking
mypy myfile.py

# Анализ сложности
radon cc myfile.py

# Удаление неиспользуемого кода
vulture myfile.py

SOLID принципы в рефакторинге

# S — Single Responsibility
class UserValidator:  # Только валидация
    def validate(self, user):
        pass

class UserRepository:  # Только доступ к данным
    def save(self, user):
        pass

# O — Open/Closed
class Shape:
    def area(self):
        raise NotImplementedError

class Circle(Shape):
    def area(self):
        return 3.14 * self.radius ** 2

class Square(Shape):
    def area(self):
        return self.side ** 2

Чек-лист рефакторинга

  1. Написать/обновить тесты — они вам помогут
  2. Запустить тесты — убедиться что работает
  3. Сделать изменение — маленькое, локальное
  4. Запустить тесты — проверить что не сломалось
  5. Повторить — шаги 3-4 много раз
  6. Code review — попроси коллегу посмотреть
  7. Commit — понятное сообщение: "Refactor: extract method X"

Когда рефакторить

✅ Когда:

  • Код сложный и непонятный
  • Duplication очевидна
  • Нужно добавить фичу
  • Тесты покрывают функцию

❌ Когда:

  • Нет тестов
  • Срочный дедлайн
  • Код работает и никто не трогает
  • Ты не понимаешь что делает код