Skip to main content

Анализ сложности проектов на python

Идея описана в статье моего блога - Управление простотой.

Кратко

Утилита для скоринга относительной сложности проекта. Сравнивать между собой проекты с её помощью не имеет большого смысла, идея в отслеживании динамики усложнения проекта в процессе его жизненного цикла. Комплексная метрика - попугаи.

Формат вывода

Запуск на самого себя. Если null в тестах это проблема - надо писать тесты, а не ныть.

app:
  lines: 437
  files: 5
  dependencies: 0
  directories: 0
  max_directory_depth: 0
  web:
    html:
      lines: 150
      files: 3
    css:
      lines: 200
      files: 1
    js:
      lines: 156
      files: 3
  functions:
    count: 34
    size_stats:
      min: 1
      mean: 10
      p90: 21
      p95: 27
      max: 31
  classes:
    count: 10
    size_stats:
      min: 2
      mean: 40
      p90: 295
      p95: 295
      max: 295
  imports:
    count: 26
    size_stats:
      min: 2
      mean: 5
      p90: 11
      p95: 11
      max: 11
tests:
  lines: 0
  files: 0
  dependencies: 0
  directories: 0
  max_directory_depth: 0
  functions:
    count: 0
    size_stats: null
  classes:
    count: 0
    size_stats: null
  imports:
    count: 0
    size_stats: null
logical:
  api_endpoints: 0
  event_subscriptions: 0
  periodic_tasks: 0
  integrated_systems: 0
complexity_score: 172

Длинно

Писалось по такому ТЗ (обвесил комментариями и отметил нереализованные пункты).

  1. Анализ физической структуры проекта:

    • Подсчёт строк кода (LOC) раздельно для основного кода и тестов
    • Подсчёт количества файлов (.py) раздельно для app и tests
    • Подсчёт количества директорий раздельно для app и tests
    • Определение максимальной глубины вложенности директорий (кажется почти бесполезным).
    • Подсчёт строк кода и количества файлов для веб-ресурсов (HTML, CSS, JS, Jinja2) в секции app.web
  2. Анализ кодовой базы:

    • Подсчёт количества классов раздельно для app и tests
    • Подсчёт количества функций раздельно для app и tests
    • Расчёт статистики размеров (min, mean, p90, p95, max) для классов и функций (p90, p95 и max совпадают в небольших проектах и не имеют значения).
    • Определение максимальной глубины наследования классов (кажется почти бесполезным).
  3. Анализ зависимостей:

    • Определение зависимостей из pyproject.toml
      • PEP 621
      • Poetry
    • Анализ requirements.txt, requirements-dev.txt, requirements-test.txt
    • Разделение зависимостей на основные (app) и тестовые (tests)
  4. Анализ логической структуры:

    • Обнаружение API эндпоинтов (FastAPI)
    • Подсчёт асинхронных событий (FastStream)
    • Выявление подписок на события (FastStream)
    • Обнаружение периодических задач (FastStream - оказалось ненужным).
    • Определение интеграций с внешними системами
      • PostgreSQL, Redis и др. (кажется почти бесполезным)
      • HTTP-клиенты / SDK в микросервисной архитектуре
  5. Расчёт комплексной метрики:

    • Вычисление единого коэффициента сложности проекта
    • Использование логарифмического масштабирования метрик
    • Жёстко заданные весовые коэффициенты для разных аспектов сложности, которые можно поправить "под себя", но я бы не стал. Всё равно это попугаи.
    • Учёт метрик веб-ресурсов (HTML, CSS, JS) при расчёте коэффициента сложности
  6. Фильтрация и игнорирование:

    • Автоматическое использование .gitignore
    • Автоматическое разделение на основной код и тесты по шаблонам имён
    • Пропуск бинарных и не-Python/веб файлов
  7. Обработка ошибок:

    • Устойчивость к синтаксическим ошибкам в коде
    • Обработка проблем с кодировкой файлов
  8. Вывод результатов:

    • Машинно- и человеко-читаемый YAML-подобный вывод.
    • Разделение метрик на логические группы (app, tests, logical, complexity_score).
    • Включение всех рассчитанных метрик
    • Чёткое отделение финального коэффициента сложности
    • Отображение метрик веб-ресурсов только в секции app, не в tests
  9. Производительность:

    • Никаких требований, но работает быстро.
  10. Интерфейс:

    • Принимает только один обязательный аргумент: путь к директории проекта
  11. Поддержка технологий:

    • Совместимость с FastAPI и FastStream
    • Поддержка Poetry и стандартных requirements.txt
    • Распознавание async/await функций
    • Поддержка HTML, CSS, JavaScript и Jinja2-шаблонов
  12. Статистическая обработка:

    • Корректная обработка пустых выборок
    • Устойчивость к выбросам в данных
  13. Архитектура:

    • Решил отклониться от "один python-скрипт без зависимостей"
    • "Плагинная" архитектура - достаточно докинуть новых файлов в plugins для поддержки других фреймворков, в том числе и самопальных/корпоративных.
  14. Практическая полезность:

    • Выявление "раздутых" компонентов (большие классы/функции)
    • Возможность сравнения динамики усложнения проекта (см /contrib/git-retrospective).

Например мой проект умного дома:

$ git-retrospective ../mqtt-automator/
1749975046 234
1740035384 232
1739383604 232
1738518493 232
1736532815 230
1735987780 228
1735918929 227
1735265996 219
1735189505 219
1735149143 216
1726594246 214
1726510704 214
1722049469 214
1716868950 214
1716783122 213
1716610147 211
1716539087 204
1716310019 201
1716027458 200
1715889436 191
1715882189 191

Эти данные можно использовать для отгрузки в какой-нибудь InfluxDB + добавить такое сканирование при каждом коммите и потом любоваться на графике в Grafana тем, как сложность проекта неуклонно ползла вверх и никакие рефакторинги этому не помогали.

Metadata

Release files for complexity-meter 0.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for complexity-meter 0.0.3
File Size Uploaded Provenance
complexity_meter-0.0.3.tar.gz 14.3 kB Without provenance Details

Release files / complexity_meter-0.0.3.tar.gz

Download URL complexity_meter-0.0.3.tar.gz
Size 14.3 kB
Tags Source
SHA-256 checksum
How to use checksums
359ac698b87551e5c39886ac61d2edbfa28ab4d3cddd6a729eb0618fdf7c374a
BLAKE2b-256 checksum
How to use checksums
4b8f8e0f084f3c487a2b9727b6f8b6b5750c17175816ab93573ebcf627d6fa0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.10.12

Security for complexity-meter 0.0.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page