Cyclomatic complexity, coupling, cohesion, technical debt ratio
Метрики не говорят всей правды, но помогают найти проблемные места. Используйте их как сигнал, а не как приговор.
Цикломатическая сложность — количество линейно независимых путей в коде. Равна числу точек ветвления + 1.
Точки ветвления: if, elif, for, while, and, or, case, except, ?:
# Сложность = 1 (базовая)
def simple_add(a, b):
return a + b
# Сложность = 4 (1 базовая + 3 if)
def calculate_discount(user, amount):
if user.is_vip: # +1
discount = 0.2
elif user.is_premium: # +1
discount = 0.1
elif amount > 1000: # +1
discount = 0.05
else:
discount = 0
return amount * (1 - discount)
# Сложность = 6 (1 + 3 if + 2 and)
def validate_user(user):
if user.is_active and user.email_verified and user.age >= 18: # +3
return True
if user.is_admin: # +1
return True
if user.is_moderator and user.is_active: # +2
return True
return False| Сложность | Оценка | Действие |
|---|---|---|
| 1-5 | ✅ Отлично | |
| 6-10 | ⚠️ Нормально | Следить |
| 11-20 | ❌ Высокая | Рефакторинг |
| 21+ | 🚫 Критично | Немедленно разбить |
# ❌ Сложность 15: трудно тестировать
def process_order(order):
if order.status == 'draft':
if order.items:
if order.user:
if order.user.is_active:
if order.total > 0:
# ... 50 строк
else:
# ...
else:
# ...
else:
# ...
else:
# ...
elif order.status == 'pending':
# ... ещё 100 строк
# ✅ Сложность 3-4 на функцию
def process_order(order):
validate_order_status(order)
validate_order_items(order)
validate_user(order.user)
save_order(order)Низкая связность (хорошо):
# Модуль зависит только от абстракции
class UserService:
def __init__(self, db: Database, email: EmailService):
self.db = db
self.email = emailВысокая связность (плохо):
# Модуль зависит от конкретных реализаций
class UserService:
def __init__(self):
from mysql.connector import connect
from sendgrid import SendGrid
self.db = connect(...)
self.email = SendGrid(...)Высокое сцепление (хорошо):
# Все методы относятся к одной задаче
class UserAuth:
def login(self, ...): ...
def logout(self, ...): ...
def reset_password(self, ...): ...
def verify_email(self, ...): ...Низкое сцепление (плохо):
# Методы не связаны по смыслу
class Utils:
def parse_user(self, ...): ...
def calculate_tax(self, ...): ...
def send_email(self, ...): ...
def connect_db(self, ...): ...| Метрика | Порог | Описание |
|---|---|---|
| Complexity | ≤ 15 | Цикломатическая сложность |
| Cognitive Complexity | ≤ 15 | Сложность для понимания |
| Duplication | ≤ 3% | Дублирование кода |
| Coverage | ≥ 80% | Покрытие тестами |
| Technical Debt Ratio | ≤ 5% | Отношение времени на исправление к времени разработки |
# Установка
pip install radon
# Цикломатическая сложность
radon cc myapp/
# Вывод:
myapp/services.py
F 12:0 process_order - D (сложность 15)
F 45:0 validate_user - B (сложность 8)
# Поддержание кода (100 = отлично, 0 = ужасно)
radon mi myapp/
# Вывод:
myapp/services.py - B (85.5)Ключевая мысль: Метрики — инструмент, а не цель. Используйте их для поиска проблемных мест, но не оптимизируйте метрики в ущерб читаемости.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.