Python linter что это

Сравнение линтеров для кода на Python и советы по их применению

Хочешь знать больше о Python?

Подпишись на наш канал о Python в Telegram!

Python linter что это. omar tursic 7vli jop750 unsplash 1280x1000 1 1024x682 1. Python linter что это фото. Python linter что это-omar tursic 7vli jop750 unsplash 1280x1000 1 1024x682 1. картинка Python linter что это. картинка omar tursic 7vli jop750 unsplash 1280x1000 1 1024x682 1

В первой части статьи, опубликованной на pythonist.ru (с которой мы уже знакомили вас ранее), разбиралось, почему качество кода имеет такое большое значение, какой код можно считать качественным и на какие стандарты можно ориентироваться.

Представляем вам вторую часть статьи, в которой подробнее рассматривается, на что способны различные линтеры и как выглядит результат их работы.

Для сравнения пропустим одинаковый код через несколько линтеров с дефолтными настройками.

Проверять будем следующий код. В нем есть целый ряд логических и стилистических ошибок:

В таблице ниже мы разместили список используемых линтеров и время, которое им понадобилось на анализ этого файла. Следует отметить, что все эти инструменты служат разным целям, поэтому сравнивать, возможно, не совсем правильно. PyFlakes, например, не выявляет стилистические ошибки, как это делает Pylint.

ЛИНТЕРКОМАНДАВРЕМЯ
Pylintpylint code_with_lint.py1,16 с
PyFlakespyflakes code_with_lint.py0,15 с
pycodestylepycodestyle code_with_lint.py0,14 с
pydocstylepydocstyle code_with_lint.py0,21 с

Теперь давайте посмотрим на результаты.

Pylint

Pylint это один из самых старых линтеров (работает с 2006 года), но при этом он хорошо поддерживается. Можно сказать, что этот инструмент проверен временем. Контрибьюторы уже давно пофиксили все основные баги, а главный функционал хорошо отшлифовали.

Самые распространенные жалобы на Pylint — медленная работа, излишняя многословность по умолчанию и необходимость долго копаться в настройках, чтобы сделать все по своему вкусу. Если отбросить скорость работы, все остальные пункты — палка о двух концах. Многословность объясняется скрупулезностью. Большое количество настроек позволяет подогнать под свои нужды очень многие вещи.

Итак, вот результат запуска Pylint для приведенного выше кода:

Имейте в виду, что похожие строки в тексте заменены многоточиями. Разобраться довольно сложно, но в этом коде много ошибок.

Обратите внимание, что Pylint добавляет к каждой проблемной области префикс R, C, W, E или F, что означает:

PyFlakes

Pyflakes «торжественно клянется никогда не жаловаться на стиль и очень усердно стараться не допускать ложнопозитивных срабатываний». То есть Pyflakes не сообщит вам о пропущенных docstrings или о том, что имена аргументов не соответствуют стилю нейминга. Он фокусируется на логических проблемах в коде и потенциальных ошибках.

Преимущество этого инструмента в скорости. PyFlakes обработал файл лишь за небольшую долю времени, которое потребовалось Pylint.

Вывод после запуска Pyflakes для приведенного выше кода:

Недостаток Pyflakes в том, что в результатах его работы немного труднее разобраться. Различные проблемы и ошибки никак не помечены и не упорядочены. Но будет ли это для вас проблемой, зависит от вашего использования этого инструмента.

pycodestyle (прежде — pep8)

Этот инструмент проверяет код на соответствие некоторым соглашениям из PEP 8. Нейминг не проверяется, так же как и docstrings. Ошибки и предупреждения, выдаваемые этим инструментом, можно посмотреть в таблице.

Результат использования pycodestyle для приведенного выше кода:

Что здесь хорошо, это то, что ошибки имеют метки категорий. Вы можете игнорировать определенные ошибки, если соответствие какому-то конкретному соглашению вас не заботит.

pydocstyle (прежде — pep257)

Этот инструмент очень похож на предыдущий, pycodestyle, за исключением того, что проверяет код не на соответствие PEP 8, а на соответствие PEP 257.

Результат запуска для приведенного выше кода:

Как и pycodestyle, pydocstyle помечает и разбивает по категориям найденные ошибки. Этот список не конфликтует ни с чем из pycodestyle, поскольку все ошибки имеют приставку D (означающую docstring). Список ошибок можно посмотреть здесь.

Код без ошибок

Если учесть предупреждения и исправить ошибки, найденные линтерами, вы получите примерно такой код:

Согласно «мнению» приведенных выше линтеров, этот код больше не имеет «ворсинок». И хотя логика сама по себе бессмысленная, вы можете заметить, что, как минимум, этот код отличается единообразием.

В рассмотренном случае мы запускали линтеры на уже написанном коде. Но это не единственный способ проверки качества кода.

Python linter что это. thea ye 1bgl ow pe unsplash 1280x1000 1 1024x682 1. Python linter что это фото. Python linter что это-thea ye 1bgl ow pe unsplash 1280x1000 1 1024x682 1. картинка Python linter что это. картинка thea ye 1bgl ow pe unsplash 1280x1000 1 1024x682 1

Когда можно проверять качество кода?

Вы можете проверять качество своего кода:

Проверять код при помощи линтеров лучше почаще. Если в многочисленной команде или на большом проекте такие проверки не автоматизированы, там будет легко упустить из виду ухудшение качества кода. Оно происходит постепенно, конечно. Какая-нибудь плохо прописанная логика, какой-то код, формат которого не соответствует соседнему коду. Со временем все эти шероховатости накапливаются, и в конечном итоге у вас на руках может оказаться трудночитаемый, трудноисправляемый и гарантирующий головную боль при поддержке код с кучей багов.

Чтобы этого избежать, проверяйте качество кода почаще!

Проверка кода по мере его написания

Вы можете использовать линтеры по мере написания кода, но для этого может понадобиться дополнительно настроить вашу среду разработки. Чаще всего вам нужно будет найти подходящий плагин для вашей IDE или редактора. Но большинство IDE имеют и встроенные линтеры.

По ссылкам вы сможете найти полезную информацию по этой теме для разных редакторов:

Проверка кода перед его отправкой

Если вы используете Git, можно настроить Git hooks для запуска линтеров перед коммитом. Другие системы контроля версий имеют схожие методы для запуска скриптов в привязке к определенным действиям в системе. При помощи этих методов можно блокировать любой новый код, не соответствующий стандартам качества.

Это может показаться слишком радикальным подходом, но прогон каждого кусочка кода через линтеры — важный шаг на пути к обеспечению стабильно высокого качества. Автоматизация этих проверок — лучший способ избежать шероховатостей в коде.

При запуске тестов

Вы можете вставить линтеры в любую систему, которую используете для непрерывной интеграции. Линтеры при этом могут быть настроены таким образом, чтобы сборка в принципе не была возможна, если код не соответствует стандартам.

Опять же, это может показаться слишком радикальным решением, особенно если в уже существующем коде есть много ошибок, вылавливаемых линтерами. Но эту проблему можно обойти. В некоторых системах непрерывной интеграции можно выбрать опцию, при которой сборка проваливается только если новый код увеличивает число ошибок, найденных линтером. Таким образом вы сможете улучшать качество кода, не переписывая заново всю кодовую базу.

Заключение

Высококачественный код делает то, что он должен делать, не ломаясь при этом. Его легко читать, поддерживать и расширять. Он функционирует без проблем, в нем нет дефектов, а еще он написан так, чтобы следующему программисту было легко с ни м работать.

Естественно, каждый хочет, чтобы его код отличался высоким качеством. К счастью, есть методы и инструменты, позволяющие повысить качество кода.

Благодаря руководствам по стилю ваш код может стать единообразным. PEP8 — отличная отправная точка, если речь идет о Python. Линтеры помогут вам обнаружить проблемные места и стилевые несоответствия. Использовать эти инструменты можно на любой стадии процесса разработки; их можно даже автоматизировать, чтобы код с «пухом» не прошел слишком далеко.

Использование линтеров позволяет избежать ненужных дискуссий о стиле в ходе код-ревью. Некоторым людям морально легче получить объективный фидбэк от инструментов, а не от товарищей по команде. Кроме того, некоторые ревьюеры могут просто не хотеть «придираться» к стилю проверяемого кода. Линтеры не озабочены всеми этими политесами и экономией времени: они жалуются на любое несоответствие.

Кроме того, все линтеры, упомянутые в этой статье, имеют различные опции для ввода в командной строке и настройки, позволяющие подогнать инструмент под свои нужды. Важно понимать, что вы можете быть настолько строги или снисходительны, насколько захотите.

Улучшение качества кода это процесс. Вы можете предпринимать некоторые шаги в этом направлении и не выбрасывая весь несоответствующий стандарту код. Осведомленность — прекрасный первый шаг. Чтобы его сделать, нужно только осознать, насколько важно поддерживать высокое качество кода.

Источник

Линтеры в Python

В сообществе Python, как и в любой другой группе людей, существует некое коллективное знание. Множество людей прошлось по всем возможным граблям и получило опыт через набитые шишки. Затем через какое-то время, благодаря выступлениям на конференциях, официальным заявлениям, документам, статьям в блогах, код-ревью и личному общению, это знание стало коллективным. Теперь мы просто называем его “хорошими практиками”.

К таким хорошим практикам можно отнести, например, следующие.

Соблюдать (и даже просто помнить) все хорошие практики — не самая простая задача. Зачастую люди плохо справляются с тем, чтобы отсчитывать пробелы и контролировать переменные, и вообще склонны допускать ошибки по невнимательности. Таковы люди, ничего не поделаешь. Машины, наоборот, прекрасно справляются с такими хорошо определёнными задачами, поэтому появились инструменты, которые контролируют следование хорошим практикам.

В компилируемых языках ещё на этапе компиляции программист может получить по щщам первый полезный фидбэк о написанном коде. Компилятор проверит, что код валиден и может быть скомпилирован, а также может выдать предупреждения и рекомендации, как сделать код лучше или читаемее. Т.к. Python является интерпретируемым языком, где этап компиляции как таковой отсутствует, линтеры особенно полезны. На самом деле, это очень важно и круто — узнать, что твой код как минимум является валидным Python-кодом, даже не запуская его.

В этом посте я рассмотрю два самых популярных линтера для Python:

Термин “lint” впервые начал использоваться в таком значении в 1979 году. Так называлась программа для статического анализа кода на C, которая предупреждала об использовании непортабельных на другие архитектуры языковых конструкций. С тех пор “линтерами” называют любые статические анализаторы кода, которые помогают находить распространённые ошибки, делать его однообразным и более читаемым. А названо оно «lint» в честь вот такой штуки:

Python linter что это. lint roller. Python linter что это фото. Python linter что это-lint roller. картинка Python linter что это. картинка lint roller

flake8

Установка

Источник

Качество кода на Python: сравнение линтеров и советы по их применению

Python linter что это. omar tursic 7vli jop750 unsplash 1280x1000 1. Python linter что это фото. Python linter что это-omar tursic 7vli jop750 unsplash 1280x1000 1. картинка Python linter что это. картинка omar tursic 7vli jop750 unsplash 1280x1000 1

В первой части статьи мы разобрались, почему качество кода имеет такое большое значение, какой код можно считать качественным и на какие стандарты можно ориентироваться.

Теперь давайте подробнее рассмотрим, на что способны различные линтеры и как выглядит результат их работы. Для этого пропустим одинаковый код через несколько линтеров с дефолтными настройками.

Проверять будем следующий код. В нем есть целый ряд логических и стилистических ошибок:

В таблице ниже мы разместили список используемых линтеров и время, которое им понадобилось на анализ этого файла. Следует отметить, что все эти инструменты служат разным целям, поэтому сравнивать, возможно, не совсем правильно. PyFlakes, например, не выявляет стилистические ошибки, как это делает Pylint.

ЛинтерКомандаВремя
Pylintpylint code_with_lint.py1,16 с
PyFlakespyflakes code_with_lint.py0,15 с
pycodestylepycodestyle code_with_lint.py0,14 с
pydocstylepydocstyle code_with_lint.py0,21 с

Теперь давайте посмотрим на результаты.

Pylint

Pylint это один из самых старых линтеров (работает с 2006 года), но при этом он хорошо поддерживается. Можно сказать, что этот инструмент проверен временем. Контрибьюторы уже давно пофиксили все основные баги, а главный функционал хорошо отшлифовали.

Самые распространенные жалобы на Pylint — медленная работа, излишняя многословность по умолчанию и необходимость долго копаться в настройках, чтобы сделать все по своему вкусу. Если отбросить скорость работы, все остальные пункты — палка о двух концах. Многословность объясняется скрупулезностью. Большое количество настроек позволяет подогнать под свои нужды очень многие вещи.

Итак, вот результат запуска Pylint для приведенного выше кода:

Имейте в виду, что похожие строки в тексте заменены многоточиями. Разобраться довольно сложно, но в этом коде много ошибок.

Обратите внимание, что Pylint добавляет к каждой проблемной области префикс R, C, W, E или F, что означает:

PyFlakes

Pyflakes «торжественно клянется никогда не жаловаться на стиль и очень усердно стараться не допускать ложнопозитивных срабатываний». То есть Pyflakes не сообщит вам о пропущенных docstrings или о том, что имена аргументов не соответствуют стилю нейминга. Он фокусируется на логических проблемах в коде и потенциальных ошибках.

Преимущество этого инструмента в скорости. PyFlakes обработал файл лишь за небольшую долю времени, которое потребовалось Pylint.

Вывод после запуска Pyflakes для приведенного выше кода:

Недостаток Pyflakes в том, что в результатах его работы немного труднее разобраться. Различные проблемы и ошибки никак не помечены и не упорядочены. Но будет ли это для вас проблемой, зависит от вашего использования этого инструмента.

pycodestyle (прежде — pep8)

Этот инструмент проверяет код на соответствие некоторым соглашениям из PEP 8. Нейминг не проверяется, так же как и docstrings. Ошибки и предупреждения, выдаваемые этим инструментом, можно посмотреть в таблице.

Результат использования pycodestyle для приведенного выше кода:

Что здесь хорошо, это то, что ошибки имеют метки категорий. Вы можете игнорировать определенные ошибки, если соответствие какому-то конкретному соглашению вас не заботит.

pydocstyle (прежде — pep257)

Этот инструмент очень похож на предыдущий, pycodestyle, за исключением того, что проверяет код не на соответствие PEP 8, а на соответствие PEP 257.

Результат запуска для приведенного выше кода:

Как и pycodestyle, pydocstyle помечает и разбивает по категориям найденные ошибки. Этот список не конфликтует ни с чем из pycodestyle, поскольку все ошибки имеют приставку D (означающую docstring). Список ошибок можно посмотреть здесь.

Код без ошибок

Если учесть предупреждения и исправить ошибки, найденные линтерами, вы получите примерно такой код:

Согласно «мнению» приведенных выше линтеров, этот код больше не имеет «ворсинок». И хотя логика сама по себе бессмысленная, вы можете заметить, что, как минимум, этот код отличается единообразием.

В рассмотренном случае мы запускали линтеры на уже написанном коде. Но это не единственный способ проверки качества кода.

Python linter что это. thea ye 1bgl ow pe unsplash 1280x1000 1. Python linter что это фото. Python linter что это-thea ye 1bgl ow pe unsplash 1280x1000 1. картинка Python linter что это. картинка thea ye 1bgl ow pe unsplash 1280x1000 1

Когда можно проверять качество кода?

Вы можете проверять качество своего кода:

Проверять код при помощи линтеров лучше почаще. Если в многочисленной команде или на большом проекте такие проверки не автоматизированы, там будет легко упустить из виду ухудшение качества кода. Оно происходит постепенно, конечно. Какая-нибудь плохо прописанная логика, какой-то код, формат которого не соответствует соседнему коду. Со временем все эти шероховатости накапливаются, и в конечном итоге у вас на руках может оказаться трудночитаемый, трудноисправляемый и гарантирующий головную боль при поддержке код с кучей багов.

Чтобы этого избежать, проверяйте качество кода почаще!

Проверка кода по мере его написания

Вы можете использовать линтеры по мере написания кода, но для этого может понадобиться дополнительно настроить вашу среду разработки. Чаще всего вам нужно будет найти подходящий плагин для вашей IDE или редактора. Но большинство IDE имеют и встроенные линтеры.

По ссылкам вы сможете найти полезную информацию по этой теме для разных редакторов:

Проверка кода перед его отправкой

Если вы используете Git, можно настроить Git hooks для запуска линтеров перед коммитом. Другие системы контроля версий имеют схожие методы для запуска скриптов в привязке к определенным действиям в системе. При помощи этих методов можно блокировать любой новый код, не соответствующий стандартам качества.

Это может показаться слишком радикальным подходом, но прогон каждого кусочка кода через линтеры — важный шаг на пути к обеспечению стабильно высокого качества. Автоматизация этих проверок — лучший способ избежать шероховатостей в коде.

При запуске тестов

Вы можете вставить линтеры в любую систему, которую используете для непрерывной интеграции. Линтеры при этом могут быть настроены таким образом, чтобы сборка в принципе не была возможна, если код не соответствует стандартам.

Опять же, это может показаться слишком радикальным решением, особенно если в уже существующем коде есть много ошибок, вылавливаемых линтерами. Но эту проблему можно обойти. В некоторых системах непрерывной интеграции можно выбрать опцию, при которой сборка проваливается только если новый код увеличивает число ошибок, найденных линтером. Таким образом вы сможете улучшать качество кода, не переписывая заново всю кодовую базу.

Заключение

Высококачественный код делает то, что он должен делать, не ломаясь при этом. Его легко читать, поддерживать и расширять. Он функционирует без проблем, в нем нет дефектов, а еще он написан так, чтобы следующему программисту было легко с ни м работать.

Естественно, каждый хочет, чтобы его код отличался высоким качеством. К счастью, есть методы и инструменты, позволяющие повысить качество кода.

Благодаря руководствам по стилю ваш код может стать единообразным. PEP8 — отличная отправная точка, если речь идет о Python. Линтеры помогут вам обнаружить проблемные места и стилевые несоответствия. Использовать эти инструменты можно на любой стадии процесса разработки; их можно даже автоматизировать, чтобы код с «пухом» не прошел слишком далеко.

Использование линтеров позволяет избежать ненужных дискуссий о стиле в ходе код-ревью. Некоторым людям морально легче получить объективный фидбэк от инструментов, а не от товарищей по команде. Кроме того, некоторые ревьюеры могут просто не хотеть «придираться» к стилю проверяемого кода. Линтеры не озабочены всеми этими политесами и экономией времени: они жалуются на любое несоответствие.

Кроме того, все линтеры, упомянутые в этой статье, имеют различные опции для ввода в командной строке и настройки, позволяющие подогнать инструмент под свои нужды. Важно понимать, что вы можете быть настолько строги или снисходительны, насколько захотите.

Улучшение качества кода это процесс. Вы можете предпринимать некоторые шаги в этом направлении и не выбрасывая весь несоответствующий стандарту код. Осведомленность — прекрасный первый шаг. Чтобы его сделать, нужно только осознать, насколько важно поддерживать высокое качество кода.

Источник

Холиварный рассказ про линтеры

Все мы пишем код. Много кода. Само собой, бывают ошибки. Иногда это просто кривой код, а иногда цена ошибки — взорванный космический корабль. Конечно, никто не делает намеренных косяков, все в меру возможностей стараются следить за качеством, но без инструментов статического анализа вряд ли можно быть уверенным, что всё идеально.

Линтеры помогают приводить код к единому стилю и избегать ошибок. Правда, только в том случае, если вы готовы к страданиям, а не отмахиваетесь в конце концов «pylint: disable», только чтобы оно отстало. Какой должен быть линтер, и почему таки не обойтись Pylint, знает Никита Соболев (sobolevn), который понимает и любит линтеры настолько, что даже свою компанию назвал так, чтобы их не расстраивать — wemake.services.

Ниже текстовая версия доклада на Moscow Python Conf++ про линтеры, как их делать правильно и как не нужно. В выступлении было много интерактива, онлайна и общения с аудиторией. Спикер по ходу дела проводил опросы и старался переубедить слушателей: смотрел на тренд, и как в дебатах, пытался выровнять соотношение и поменять общественное мнение. Какая-то часть с опросами попала в расшифровку, но не вся, поэтому для полноты картины прилагается видео.

Зачем нам линтеры?

Самая важная задача линтеров — приводить код к единообразию. Есть много вариантов написать одно и то же на Python: поставить запятую здесь или там, забыть закрыть скобки или не забыть. Когда люди долго пишут код, он становится похож на лоскутное одеяло из сшитых в разное время разрозненных кусков. Работать с таким одеялом неприятно, он отбивает желание читать код, а это очень плохо.

Линтеры облегчают жизнь на ревью. Я прихожу на код-ревью и думаю: «Я не хочу это делать! Сейчас будут лишние пробелы и прочая ерунда!» Хочется, чтобы кто-то другой подготовил хороший код, а после этого я оценю большие концептуальные вещи.

Иногда я смотрю на код и думаю, что вроде всё нормально, а потом вижу в какой-то функции слишком много переменных или ошибку, на которую я не обратил внимание. Автоматика нашла бы эту ошибку, а я просмотрел. Чтобы не попадать в такие ситуации — я использую линтер — он находит все, что скрыто и трудно найти.

Какие бывают линтеры?

Самые простые проверяют только стиль, например, Flake8. В какой-то степени ещё и Black, но скорее это автоформатор-линтер. Линтеры сложнее проверяют семантику, а не только стилистику: что вы делаете, зачем, и бьют вас по рукам, если пишете с ошибками. Хороший пример — Pylint, который мы все знаем, пользуемся и любим. Я называю такие линтеры — Best practices. Третий тип — Type checking, эти линтеры немного в стороне. Type checking в Python — новинка, её сейчас делают две конкурирующие платформы: Mypy и Pyre.

Как применять линтеры?

Я не утверждаю, что линтеры — это панацея и замена всему. Это не так. Линтеры — первая ступенька пирамиды, по которой код попадает в продакшен.

Ступеней в пирамиде три:

Это необходимые шаги, чтобы код попал в продакшен. Если вы не прошли одну ступень, что-то забыли или ревьюер, сказал, что так не пойдёт, вы увидите надпись: failed — плохой код в продакшен не попадает.

Используете ли вы на работе линтер?

Если спросить разработчиков из сурового enterprise, в котором трудятся по 7 дней в неделю, применяют ли они линтер, то выяснится, что хотя бы треть из них используют линтеры очень строго: CI падает, проверки суровы. Остальные примерно в равной степени применяют линтеры только для проверки стиля, никогда и как отчётную систему: запускают линтер, генерируют отчет и смотрят, насколько всё плохо. Линтеры используются, и это хорошо. В нашей компании всё построено очень сурово: жёсткий линтинг, очень много проверок, двойной код-ревью.

Код-ревью

Проблемы возникают как раз на этом этапе. Это верхняя и самая сложная ступень пирамиды: код-ревью автоматизировать не получится, а если и возможно, то это приведёт к автоматизации написания кода. Тогда и программисты станут не нужны.

Стандартно процесс выглядит так: код приходит на ревью, я нахожу ошибки, и не хочу больше их допускать. Например, я увидел, что разработчик поймал BaseException: «Не надо так. Пожалуйста, не лови!». Спустя 10 дней то же самое. Ещё раз напоминаю:

BaseException мы не ловим.
Хорошо, я понял.

Проходит год — та же самая ошибка. Приходит новый человек — та же самая ошибка. Я думаю — как же всё автоматизировать, чтобы ситуация не повторялась, и на ум приходит только: «Давайте запилим свой линтер?» Создадим открытый пакет, поместим туда все правила, которые используем в работе и автоматизируем проверку правил, чтобы каждый раз на код-ревью не писать руками. Автоматизируем всё хорошо и сразу!

Естественно, вы можете сказать: «Готовые линтеры уже есть они работают, все ими пользуются — зачем делать своё?», и будете совершенно правы, потому что линтеры действительно есть. Посмотрим, какие именно и что они делают.

Pylint

В эфире рубрика «Почему не Pylint?» Этот вопрос я слышал много раз. Отвечу на него помягче. Pylint — прекрасный инструмент, рок-звезда для кода на Python, но у него есть особенности, которые я не хочу видеть в своём линтере.

Ещё одна особенность, скрытая от пользователя — у Pylint собственная реализация Abstract syntax tree в Python. Это то, как выглядит код, когда вы его распарсили и получили информацию о дереве узлов, из которых состоит код. Я не очень доверяю собственным реализациям, потому что они всегда ошибаются.

Кроме Pylint есть и другие линтеры, которые тоже выполняют свою работу.

SonarQube

Прекрасный, но отдельный инструмент, который живёт где-то рядом с вашим проектом.

Достоинство SonarQube в том, что у него очень крутые проверки, которые показывают сложность, возможные скрытые ошибки и баги. Проверки мне нравятся, я бы их оставил, а платформу — поменял.

Flake8

Замечательный линтер — очень простой, но с одной проблемой: мало правил, с помощью которых он проверяет, насколько код хорошо написан. При этом у Flake8 есть очень много очень простых плагинов: минимальный плагин — это 2 метода, которые нужно реализовать. Я подумал — давайте возьмём Flake8 как основу и напишем плагины, но со своим пониманием пользы для компании. И мы так и сделали.

Самый строгий линтер в мире

Мы сделали инструмент, в котором собрали всё, что считаем правильным для Python и назвали wemake-python-styleguide. Плагин выложили публично, так как я считаю, что Open Source by Default — это хорошая практика. Я глубоко убежден, что многие инструменты выиграют, если их выложат в Open Source. Для нашего инструмента мы придумали слоган: «Самый строгий линтер в мире!»

Ключевое слово в нашем линтере — строгий, что значит боль и страдания.

Если вы пользуетесь линтером, и он не заставляет вас страдать так, что хватаешься за голову: «Да что же тебе ещё не нравится, будь ты проклят», то это плохой линтер. Он пропускает ошибки, недостаточно следит за качеством кода, и нам не нужен. Нам нужен самый строгий в мире, который многое проверяет. Сейчас у нас порядка 250 разных проверок в обоих категориях: стилистических и Best practices, но без Type checking. Им занимается Mypy, мы к нему никак не относимся.

У нашего линтера нет компромиссов. У нас нет правил из разряда «Не хотелось бы это делать, но если сильно хочется, то можно». Нет, мы всегда говорим жёстко — это не делаем, потому что плохо. Потом приходят люди и говорят: «Есть же 2,5 use case, где это в принципе возможно!». Если такие кейсы, явно напиши, что здесь эта строчка позволительна, чтобы линтер её игнорировал, но объясни почему. Это должен быть комментарий, почему ты разрешил какую-то странную практику и зачем это делаешь. Этот подход еще и полезен для документирования кода.

Самый строгий линтер не требует настроек (WIP). У нас пока есть настройки, но мы хотим от них избавиться: имея свободу, пользователь обязательно настроит так, что линтер будет работать неправильно.

Хороший инструмент в настройках не нуждается — в нем хорошие значения по умолчанию.

С таким подходом код будет консистентный и будет работать у всех одинаково, по крайней мере, в теории. Мы над этим ещё работаем, и пока настройки есть, можете пользоваться нашим инструментом и настраивать его под себя.

От кого зависим?

От большого количества инструментов.

Что проверяем?

Есть 4 группы правил, которые мы используем и заставляем соблюдать.

Сложность — это самая большая проблема. Мы не знаем, что такое сложность и не видим её в коде. Смотрим на код, с которым работаем каждый день и кажется, что он не сложный — бери, читай, все работает. Это не так. Несложный код — привычный код. У сложности есть четкие критерии, которые мы проверяем. О самих критериях — позже. Если код нарушает критерии, то мы говорим: «Код сложный, переписывай!»

Имена для переменных — это нерешённая проблема программирования. Кто будет читать, когда и в каком контексте — непонятно. Мы стараемся делать имена максимально консистентными и понятными, но хотя и стараемся — проблему пока до конца не решили.

Для консистентности у нас есть простое правило — писать везде одинаково. Если есть какой-то утвержденный подход, используй его везде. Неважно, нравится он тебе или нет, консистентность важнее.

Мы стараемся использовать только лучшие практики. Если мы знаем, что какая-то практика не очень хороша, то запрещаем её использовать. Если разработчику хочется использовать запрещенную практику, то мы ждем от него аргументации: зачем и почему применять. Возможно, во время процесса описания придет понимание, почему она плоха.

Что такое сложность?

У сложности есть конкретные метрики, на которые можно посмотреть и сказать — сложно или нет. Их много.

Arguments, Statements и Returns. Это количественные метрики: сколько аргументов в функции или в методе, сколько внутри тела этой функции или метода statements и returns.

Cohesion и Coupling — популярные метрики из мира ООП. Cohesion показывает связанность класса внутри. Например, есть класс, и ты внутри используешь все методы и свойства — всё, что объявил. Это хороший класс с высокой связанностью внутри. Coupling — это насколько связаны разные части системы: модули и классы. Мы хотим добиться максимальной связанности внутри класса и минимальной связанности вовне. Тогда система легко поддерживается и хорошо работает.

Мы смотрим на эти важные метрики и еще на некоторые другие, которых гораздо больше, и определяем — подходит код или нет. В нашем понимании сложность — это водопад.

Водопад сложности

Сложность начинается с того, что мы написали строчку, и она пока хорошая. Но потом приходит бизнес и говорит, что цены поднялись в два раза, и мы умножаем на 2. В этот момент Jones Complexity сходит с ума и сообщает, что теперь строчка слишком сложная — там слишком много логики.

Хорошо, заводим новую переменную, а анализатор сложности функций говорит:

Нет, так нельзя — теперь слишком много переменных внутри функции.

Сделаю новый метод, и в него передам аргументы. Теперь проверка количества аргументов функции, либо количества методов внутри класса говорит, что так тоже нельзя — слишком сложный класс и надо разбивать на две части. Разбили, выделив другой класс. Теперь стало больше классов и все хорошо, но проверка сложности модуля сообщает, что теперь модуль слишком сложный и надо рефакторить. Почему?!

Это называется страданием. Как раз поэтому я говорю, что линтер должен заставлять страдать. Мы начали с того, что умножили на 2 в одной строчке, а закончили рефакторингом всей системы. Добавление маленького кусочка кода ведет к рефакторингу целых модулей, потому что сложность расползается, как водопад, и закрывает собой все, что можно.

«Нужно рефакторить» — эта штука заставляет вас рефакторить код. Нельзя просто отсидеться: «Этот код не трогаю, вроде он работает». Нет, однажды ты поменяешь код в другом месте, и водопад сложности затопит модуль, который не трогал и тебе придется его рефакторить. Я считаю, что рефакторинг — это хорошо, и чем его больше — тем стабильнее и лучше работает твоя система. А все остальное субъективно!

Теперь поговорим про вкусы. Это холиварная и интерактивная часть!

Холивар

Давайте похоливарим, комментарии открыты. Сначала, напомню, что имена — сложная и нерешенная проблема. Можно подраться из-за того, как назвать переменную, но у нас есть некоторые подходы, которые помогают хотя бы не сделать явных ошибок.

Имена

Как вам такие: var, value, item, obj, data, result? Что такое data? Какие-то данные. Что такое result? Какой-то результат. Часто вижу переменную result и вызов какого-то адского метода у непонятного класса — и думаю: «Что это за result? Зачем он здесь?»

Есть много разработчиков, которые со мной не согласны, и говорят, что value — вполне нормальное имя переменной:

Я всегда использую key и value!
Почему бы использовать не key и value, а сказать, что ключ — имя, а value — фамилия? Почему нельзя назвать first_name и last_name — теперь есть контекст.

Обычно люди соглашаются, но все равно спорят. Это очень холиварная штук: как минимум 3 человека потратили на меня по часу своей жизни, чтобы про это со мной поспорить.

Называть переменные одной буквой — нормально?

Половина разработчиков считает, что называть переменные i, х, у, z — это нормально.

Я считаю, что называть имена одной буквой нельзя. Хочу больше контекста и хорошо, что со мной согласна вторая половина разработчиков. Если в C это еще как-то допустимо из-за исторического наследия, то в Python это очень большая проблема и так делать не надо.

Консистентность

Давайте просто выберем один способ из многих, и скажем: «Давайте делать так». Хорош он или плох — уже не важно — просто консистентно.

Мы говорим только про Python 3, легаси вообще не рассматриваем.

У меня есть аргумент: когда мы наследуемся от чего-то, то должны знать, от чего — неплохо бы увидеть имя родителя. Самое смешное, что обычно мы видим имя родителя, кроме случая, когда это object. Поэтому я сформулировал для себя правило: когда пишу класс, от чего-то наследуюсь — всегда пишу имя родителя. Неважно, что это будет — Model, object или еще что-то.

Две трети разработчиков привычнее второй вариант, и я даже знаю, почему. Моя гипотеза: все из-за того, что мы долго мигрировали из второй версии Python на третью, и теперь показываем, что пишем именно на третьем Python. Не знаю, насколько гипотеза правильная, но мне кажется, это так.

F-строки ужасны?

Во время доклада количество противников f-строк выросло с 33 до 38% — это маленькая, но победа.

Числа

Пожалуйста, умножь на 147.
Почему на 147?
У нас такая тарификация.

Я умножил и забыл, или долго подбирал какое-то значение коэффициента, чтобы все заработало — а потом забываю, как подобрал и почему. Получается, что важная исследовательская работа осталась скрыта за числом без названия. Я даже не знаю, что это за число, а могу только по коммиту потом как-то найти, вспомнить и восстановить.

Почему бы не делать по-другому — все сложные числа выносить в собственную переменную с именем и документацией? Например, для числа 69 написать, что это средний показатель на рынке, и теперь константа имеет имя и контекст. Я напишу комментарий, что константу взял на сайте вот такого исследования. Если исследование в будущем изменится, то зайду и обновлю данные.

Таким образом мы гарантируем, что никакие магические числа не проберутся наш код и не усложнят его изнутри. Они пробираются через проверку сложности каждой строчки и говорят: «Вот тебе число 4766. Что это такое, я не знаю, разбирайся сам!» Для меня это было большим открытием.

В итоге мы осознали, что за этим нужно следить, и никакие магические числа в код не пропускаем. Хорошо, что с нами согласны почти 100% коллег, и тоже не используют такие числа.

Но есть исключения — это числа от −10 до 10, числа 100, 1000 и подобные, просто потому, что они часто встречаются и без них сложно. Мы жесткие, но не садисты и немного думаем.

Используете ли вы ’@staticmethod’?

Давайте подумаем, что такое staticmethod. Задумывались ли вы, зачем он в Python? Я — нет. У меня был прекрасный Pylint, который говорил:

Я погуглил вопрос, и он оказался глубоким, как кроличья нора. Есть много других языков программирования, в которых staticmethod тоже не любят. Причем аргументировано — staticmethod ломает объектную модель. В результате я понял — staticmethod здесь не место, и мы его выпилили. Теперь, если мы используем декоратор staticmethod, линтер скажет: «Нет, извини, рефактори!»

Большинство разработчиков со мной не согласны, но примерно половина все-таки считает, что лучше писать вместо staticmethod либо обычные методы, либо обычные функции.

Логика в __init__.ру — хорошо или плохо?

Это моя любимая тема. Наверняка, когда вы создаете новый пакет и как-то его называете — у него создаётся __init__.ру и вы задумываетесь, что в него положить? Что поместить в __init__.ру, а что — в файлики рядышком? Для меня это был нетривиальный вопрос, и я всегда терялся: наверное, что-то самое важное? Потом я подумал — нет, наоборот, самое важное помещу в самый понятный контекст. Если положить что-то в __init__.ру, и потом это все импортить, получаются циклические импорты — тоже плохо.

Я посмотрел разные популярные библиотеки, полазил по их __init__.ру, и заметил, что в основном там либо мусор, либо обратная совместимость. Для меня этот вопрос встал остро, когда я начал создавать большие пакеты с множеством подпакетов — теряешься. В итоге мы решили выносить всю возможную логику в отдельные модули, и это работает. Никто не ломает Python, все хорошо, как и прежде, просто в __init__.ру логики нет, и 90% опрошенных коллег с нами согласны.

Вы скажете — хорошо, ты поменял API, но хочешь, чтобы пользователи по-прежнему импортировали то, что хотят, и откуда хотят? Да, так можно, потому что вопрос совместимости стоит отдельно. Мы не хотим ломать пользовательский API рефакторингом внутреннего кода. Поэтому есть случаи, в которых в __init__.ру может быть какая-то логика: импорты, редефиниции того, что вы удалили.

Но есть настройка, которая называется I_CONTROL_CODE — я контролирую код. Это тот случай, когда она обоснована. Когда я контролирую код, которым пользуюсь, в __init__.ру логики нет — только документация. Но если код не контролирую, им пользуются другие люди, которые скачивают мою библиотеку, что-то делают, тогда можно туда положить редефиниции и импорты.

Функция hasattr часто вам нужна?

Как часто нужна функция hasattr? Мне кажется, что достаточно часто, потому что в Python динамическая типизация — утиная. Нам hasattr иногда нужен, чтобы проверить наличие аргумента или атрибута у класса (провокация).

На самом деле, я считаю, что в hasattr нет надобности, эта функция работает не так, как вы думаете. Когда я разговаривал с разработчиками и спрашивал, как работает hasattr, они часто отвечали, что функция смотрит на наличие атрибута. Из-за того, что Python динамически и утино-типизированный, hasattr может выполнить вообще все что угодно. Иногда может даже в базу данных ходить, а вы об этом даже не будете знать. Поэтому лучше применять getattr и подход «Лучше попросить извинения, чем разрешения». С комбинацией этих двух подходов вы откажетесь от функции hasattr — либо getattr, либо exception.

На конференции зал разделился 50 на 50 — пожалуй, это была самая упорная борьба из всех опросов, но все равно мой кандидат проиграл на выборах.

Что мы хотим добавить в наш линтер

Этого нет в нашем линтере, но мы очень хотим layer-linter. Что он делает? Вы задаете в текстовом формате контракты: что можно импортировать, а что нет, в каких местах можно импортировать, а в каких нет. Вы создаете контракт на то, как внутри вашего кода бизнес-логика будет поделена на слои. Благодаря этому вы получаете отличный прирост качества без каких-либо телодвижений. Очень рекомендую.

Я уже говорил про cohesion. У нас нет этого плагина в основе, но мы его используем. Cohesion смотрит, насколько связан ваш класс внутри. У него есть достаточно много False Positive ошибок и использовать его в продакшене нельзя, но мы его применяем для аналитики — смотрим, какие классы хорошие, какие плохие.

Плагин vulture использует поиск неиспользуемого кода в Python и позволяет его удалять. Из-за того, что Python очень динамический язык, плагин дает много погрешностей. Поэтому мы его применяем как сohesion.

Radon позволяет смотреть разные метрики вашего кода, их очень много: Halstead, Maintainability Index, цикломатическая сложность. Попробуйте, прогоните код и посмотрите его коэффициент — это круто.

Final type

Я люблю Final-классы в Python. Их недавно добавили в Typing Extensions, а до этого у меня был собственный пакет, который я написал сам. Я считаю, что если ты сделал какой-то класс, и его больше нельзя наследовать — это хорошо, потому что ты просто зафиксировал реализацию. Если человек говорит, что он все-таки хочет что-то изменить, то зачем? Не надо. Используй композицию. Если что-то менять — напиши документацию, и тогда, возможно, можно.

Gratis

Наш линтер появился благодаря труду многих людей, и я им очень благодарен.

Все контрибьюторы линтера вынесены на этот слайд, чтобы сказать им публичное спасибо.

Если вы хотите контрибьютить наш линтер, вы тоже можете это сделать. Присылайте пул реквесты, будем их ревьюить. Мы вместе будем делать крутую штуку, которая поможет нашему Python-коду стать намного чище, качественнее и приятнее.

Кстати, Никита Соболев вступил в программный комитет Moscow Python Conf++, и помогает в подготовке классной программы. Конференция через два месяца, а у нас уже отобрано две трети докладов, можно изучить их тут и решить участвовать в нашем продуктивном мероприятии для Python-программистов.

А теперь разожжем немного холивара посредством интерактива. Результаты голосования во время выступления под спойлером. Проголосуйте и проверьте, а так ли поступает большинство разработчиков, или читерски подсмотрите, а потом топите за свой вариант.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *