Что такое закон Гудхарта?

Что такое закон Гудхарта?


Закон Гудхарта в Python: когда метрики становятся врагами качества

Введение
Закон Гудхарта, сформулированный экономистом Чарльзом Гудхартом, гласит: «Когда мера становится целью, она перестает быть хорошей мерой». В контексте Python-разработки это означает, что слепое стремление к оптимизации конкретных метрик (например, покрытия тестами или скорости выполнения) часто приводит к обратным результатам: код становится хрупким, нечитаемым или даже менее эффективным. В статье разберем, как закон Гудхарта проявляется в Python-проектах и как избежать его ловушек.


Что такое закон Гудхарта?

Закон предупреждает: когда разработчики фокусируются на достижении конкретного численного показателя, они начинают игнорировать общий контекст. Примеры из Python-практики:

  • Погоня за 100% coverage: тесты пишутся ради «галочки», а не проверки реальной логики.
  • Оптимизация производительности любой ценой: код превращается в нечитаемую «магию» с использованием ctypes или хаков.
  • Слепое следование PEP8: формальное соблюдение стиля без учета здравого смысла (например, разбивка логичного выражения на строки только ради лимита в 79 символов).

Примеры проявления закона Гудхарта в Python

1. Тесты ради покрытия, а не качества

Проблемный код

# test_calculator.py (антипример)
def test_add():
    assert 1 + 1 == 2  # Тест тривиального случая

def test_multiply():
    assert 2 * 2 == 4  # Еще один тривиальный тест

# Полезные тесты для сложной логики отсутствуют.

Результат: pytest --cov=app показывает 100% покрытие, но критические баги в бизнес-логике остаются незамеченными.

Решение

  • Пишите тесты для сложных сценариев, а не тривиальных операций.
  • Используйте property-based тестирование (например, библиотека hypothesis).

2. Оптимизация производительности в ущерб читаемости

Проблемный код

# Избыточная оптимизация списка
data = [x for x in range(10**6) if (x >> 3) & 0xF == 0xA]

Проблема: использование битовых операций вместо понятных условий (x % 16 == 10) делает код непрозрачным.

Решение

data = [x for x in range(10**6) if x % 16 == 10]

Оптимизируйте только после профилирования (с помощью cProfile или line_profiler) и только там, где это действительно нужно.


3. Злоупотребление линтингами

Жесткое требование соответствия flake8 или pylint может привести к абсурду:

# Попытка "удовлетворить" линтер
result = some_very_long_function_name(
    arg1, arg2, arg3
)  # Вынужденный перенос строки, хотя код стал менее понятным

Решение
Настраивайте линтеры гибко. Например, в pyproject.toml добавьте:

[tool.flake8]
max-line-length = 120  # Вместо слепого следования PEP8
ignore = E203, W503   # Игнорировать спорные правила

Как избежать ловушек закона Гудхарта: советы

  1. Используйте метрики, но не абсолютизируйте их

    • Coverage — не самоцель. Пишите тесты для критически важной логики.
    • Скорость выполнения — оптимизируйте только после выявления узких мест через профайлеры.
  2. Баланс между качеством и «правильностью»

    • Иногда нарушение PEP8 оправдано для улучшения читаемости.
    • Документируйте неочевидные решения:
      # Причина использования списка вместо генератора: 
      # многократный обход данных требуется в 90% сценариев.
      data = list(process(x) for x in dataset)
  3. Код-ревью и коллективная ответственность

    • Обсуждайте, почему метрика важна, а не только как ее достичь.
    • Избегайте токсичных KPI вроде «увеличить coverage на 20% за спринт».
  4. Инструменты с умом

    • mypy для типов, но без фанатизма (# type: ignore в исключительных случаях допустим).
    • black для форматирования, но с настройкой длины строки.
  5. Фокус на бизнес-ценность
    Спросите себя:

    • «Поможет ли эта оптимизация пользователям?»
    • «Станет ли код устойчивее после рефакторинга?»

Заключение

Закон Гудхарта напоминает: метрики — это инструменты, а не цели. В Python, где сообщество ценит читаемость и прагматизм, важно сохранять баланс:

  • Используйте pytest, но тестируйте смысл, а не цифры.
  • Оптимизируйте код, но не превращайте его в ребус.
  • Следуйте PEP8, но знайте, когда его нарушить.

Как говорится в The Zen of Python:

Practicality beats purity.  
Readability counts.  

Помните об этом, и ваш код избежит участи стать жертвой закона Гудхарта.