Качество кода на Python: инструменты и Best Practices

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

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

Что такое качество кода?

Естественно, вы хотите, чтобы ваш код был качественным (кто ж не хочет?). Но для этого нужно сначала определиться с тем, что следует понимать под словом «качество».

Быстрый поиск в Google выдает множество результатов с определениями качества кода. И, как выясняется, этот термин разные люди понимают по-разному.

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

  • он делает то, что должен делать,
  • он не имеет дефектов и проблем,
  • его легко читать, поддерживать и расширять.

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

Почему качество кода имеет значение?

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

Код НЕ делает то, что должен делать

Удовлетворение требований — это основа любого продукта, хоть программного, хоть нет. Мы создаем программы, чтобы они что-то делали. Если в конечном итоге они это «что-то» не делают, о высоком качестве ПО речь определенно не идет. Если конечный продукт не соответствует требованиям, вряд ли стоит говорить даже о низком качестве.

Код содержит дефекты и проблемы

Если что-либо, чем вы пользуетесь, создает вам проблемы, вы вряд ли назовете такой продукт высококачественным. А если этот продукт будет достаточно плох, вы вообще прекратите им пользоваться.

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

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

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

Код сложно читать, поддерживать или расширять

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

Если код легко понять, вы сможете куда быстрее проанализировать проблему и предложить решение. А если код сложный и запутанный, вы и провозитесь дольше, и, возможно, сделаете какие-то неверные допущения.

Также хорошо, когда в программе можно легко добавить новую фичу, не затрагивая остальной функционал. Если код сложно расширять, ваша новая фича может сломать что-нибудь.

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

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

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

Как улучшить качество кода на Python

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

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

Итак, давайте начнем с самой догматичной темы: стиля кода.

Руководства по стилю

О, да. Старый добрый спор: пробелы или табы.

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

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

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

Что касается Python, в его экосистеме есть общепринятый стандарт написания кода. Он был написан (частично) создателем самого языка.

PEP 8 — руководство по стилю написания кода на Python, которым разработчики пользуются чаще всего. Если не знаете, с чего начать, это прекрасная отправная точка.

(Аббревиатура PEP расшифровывается как Python Enhancement Proposals — «предложения по улучшению Python». PEP-ов много, все посвящены разным темам. Для удобства им присвоены индексы. Почитать подробнее можно здесь, — прим. ред. Pythonist.ru).

PEP 257 описывает соглашения по написанию docstrings — строк, предназначенных для документирования модулей, классов, функций и методов. Если документационные строки пишутся последовательно, то в качестве дополнительного бонуса они могут служить инструментом для генерирования документации прямо из кода.

Эти руководства определяют то, каким должен быть стиль написания кода. Но как принудительно внедрить этот стиль? И как насчет дефектов и проблем в коде: их-то как обнаружить? Вот тут в игру вступают линтеры.

Линтеры

Что такое линтер?

Для начала давайте поговорим о ворсинках (англ. lint — «пушинки, ворсинки», — прим. перев.). Этих маленьких надоедливых штуках, которые неизвестно откуда появляются на вашей одежде. Без ворсинок одежда выглядит куда лучше и опрятнее. Ваш код в этом плане не отличается от одежды. Мелкие ошибки, стилистические отклонения и опасная логика не улучшают самочувствие вашего кода.

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

(Линтеры также называют статическими анализаторами. Самый первый такой анализатор был создан в 1978 году для языка C; эта утилита называлась lint. Со временем название перешло на все подобные инструменты, — прим. ред. Pythonist.ru).

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

Линтеры анализируют код в поисках самых разных «ворсинок». Эти недостатки кода можно условно разделить на следующие категории:

1. Логические ошибки

  • Ошибки в коде
  • Код, который может выдать непредусмотренный результат
  • Опасные паттерны кода

2. Стилистические ошибки

  • Код, не соответствующий определенным соглашениям.

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

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

Какие линтеры можно выбрать для кода на Python?

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

Flake8: распознает и логические, и стилистические ошибки. В нем проверки стиля и сложности, выполняемые pycodestyle, добавлены к поиску логических ошибок PyFlakes. Этот инструмент объединяет следующие линтеры:

  • PyFlakes
  • pycodestyle (прежде — pep8)
  • Mccabe

Pylama: инструмент проверки кода, составленный из многочисленных линтеров и прочих инструментов для анализа кода. В его составе вы найдете:

  • pycodestyle (прежде — pep8)
  • pydocstyle (прежде — pep257)
  • PyFlakes
  • Mccabe
  • Pylint
  • Radon
  • gjslint

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

ЛинтерКатегорияОписание
Pylintлогика и стильПроверяет ошибки, пытается принудительно приводить код к стандартному виду, ищет запахи кода
PyFlakesлогикаАнализирует программы на предмет разнообразных ошибок
pycodestyleстильПроверяет, соответствует ли код соглашениям в PEP 8
pydocstyleстильПроверяет, соответствует ли код соглашениям относительно docstring
BanditлогикаАнализирует код на предмет распространенных проблем безопасности
MyPyлогикаПроверяет статические типы

А вот несколько инструментов для анализа и форматирования кода:

ИнструментКатегорияОписание
MccabeанализПроверяет цикломатическую сложность
RadonанализАнализирует различные показатели кода (количество строк, сложность и т. д.)
BlackформатированиеБескомпромиссно форматирует код на Python
IsortформатированиеФорматирует импорты, сортируя их в алфавитном порядке и разбивая по разделам

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