что такое линтер кода

Линтер — это чистый код для ленивых

Зачем нужен и как работает расчёсывальщик кода.

Ситуация: вы с коллегами параллельно работаете над разными частями одного кода. При очередном объединении исходников вы замечаете, что они пишут код не так, как вы: его сложно читать, у него сложный синтаксис и странно объявлены функции. Коллеги то же самое говорят про ваш код. В результате все правят код друг друга, приводят его к общему виду, а работа идёт долго.

👉 Линтер — это программа, которая автоматизирует всю эту возню и сама «причёсывает» код по определённым правилам. Даёшь ей чумазый и неуклюжий код, она чистит на уровне каких-то простых правил.

В чём может быть проблема, когда программистов много

Когда вы пишете код самостоятельно и для себя, его можно писать как угодно — в одну строчку без пробелов или отделяя функции друг от друга тремя пустыми строками. Главное, что вы понимаете, что здесь написано.

Как только вы начинаете участвовать с кем-то в совместном проекте, нужно установить общие правила написания кода. Сюда может относиться:

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

Что делает линтер

Линтер на основании заданных правил перерабатывает код за секунду:

Умные линтеры

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

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

что такое линтер кода. image1 3. что такое линтер кода фото. что такое линтер кода-image1 3. картинка что такое линтер кода. картинка image1 3. Зачем нужен и как работает расчёсывальщик кода.Линтер нашёл стилистическую ошибку в CSS — нужно поменять эти команды местами, потому что в компании принято сначала описывать верхние отступы, а потом уже боковые

Один линтер — один язык

Есть много разных линтеров для каждого языка программирования. Они отличаются по глубине настройки и возможностям анализа кода — как глубоко они могут его анализировать. Например, для JavaScript есть JSLint, JSHint и ESlint — это всё линтеры, которые делают плюс-минус одно и то же и различаются в деталях.

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

Что дальше

Сделаем подборку линтеров для веб-разработки — HTML, JavaScript, CSS. Не пропустите, если хотите отдать часть своих задач машине.

Источник

Линтеры для начинающих

Красивый код с самого начала.

Недавно мы писали про линтеры: как они проверяют код на ошибки и делают его более красивым. Если коротко, то линтеры работают так:

Всё это — чтобы исправлять неаккуратности за программистами.

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

👉 Линтеры из обзора мы проверяли в VS Code и Sublime text 3. Для запуска проверки и форматирования открытого кода в VS Code нажмите в пустом месте правой кнопкой мыши и выберите пункт «Форматировать документ с помощью…» или «Format Document With…»:

что такое линтер кода. image6. что такое линтер кода фото. что такое линтер кода-image6. картинка что такое линтер кода. картинка image6. Зачем нужен и как работает расчёсывальщик кода.

Beautify — линтер для HTML

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

что такое линтер кода. image5 1. что такое линтер кода фото. что такое линтер кода-image5 1. картинка что такое линтер кода. картинка image5 1. Зачем нужен и как работает расчёсывальщик кода.Было: стили в одну строку, комментарии на той же строке, что и команды, несколько html-тегов на строке подряд что такое линтер кода. image2 4. что такое линтер кода фото. что такое линтер кода-image2 4. картинка что такое линтер кода. картинка image2 4. Зачем нужен и как работает расчёсывальщик кода.Стало: красиво и понятно, каждая команда и комментарий — на своей строке

Если вы пишете не очень большой CSS-код, вам вполне хватит того же Beautify. Но если вы решили заняться стилями всерьёз и установили CSS-препроцессор, чтобы писать код ещё быстрее, посмотрите на Beautify css/sass/scss/less.

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

JavaScript

JSLint — один из самых старых и самых строгих линтеров для JavaScript. Он проверяет вообще всё:

Если ваш код проверил JSLint и не нашёл ни одной ошибки — поздравляем, вы постигли JS-дзен.

что такое линтер кода. image1 5. что такое линтер кода фото. что такое линтер кода-image1 5. картинка что такое линтер кода. картинка image1 5. Зачем нужен и как работает расчёсывальщик кода.В Sublime Text 3 JSLint подсвечивает строки с ошибкой и даёт подробное описание, что именно здесь не так

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

что такое линтер кода. image4 3. что такое линтер кода фото. что такое линтер кода-image4 3. картинка что такое линтер кода. картинка image4 3. Зачем нужен и как работает расчёсывальщик кода.JSHint может показать все ошибки прямо в окне редактора кода

PyLint — линтер для Python

Pylint.org — самый популярный линтер для Python, который проверяет почти всё:

Если вам нужно что-то проверить в коде, скорее всего, PyLint сможет вам помочь.

что такое линтер кода. image3 3. что такое линтер кода фото. что такое линтер кода-image3 3. картинка что такое линтер кода. картинка image3 3. Зачем нужен и как работает расчёсывальщик кода.Если нажать на строчку с ошибкой, курсор перейдёт к нужному участку кода

Источник

О линтерах, качестве кода, качестве вообще и управлении качеством

Бойтесь своих желаний, они могут исполниться.
Народная мудрость.

что такое линтер кода. 880d74b2944ff10e50b5a6430d4e034b. что такое линтер кода фото. что такое линтер кода-880d74b2944ff10e50b5a6430d4e034b. картинка что такое линтер кода. картинка 880d74b2944ff10e50b5a6430d4e034b. Зачем нужен и как работает расчёсывальщик кода.

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

Очень абстрактная часть о качестве

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

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

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

Представьте что у нас есть магазин фруктов и есть проблема, наши фрукты стали хуже продаваться, а у конкурента очереди прям. Мы проводим исследование и узнаём что запах возле наших прилавков не нравится посетителям. А запах у лавок конкурента нравится. О мы нашли проблему, индекс удовлетворённости посетителя запахом! Давайте её решим, есть же аромамаркетинг, просто поставим автоматические установки возле прилавков и получим прекрасный запах яблоневого сада. Сделали. И индекс удовлетворённости покупателя запахом закономерно запахом попёр вверх. Только вот покупателей теперь ещё меньше.

Если взглянуть серьёзно то изначальная проблема могла быть совершенно разной:

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

Ещё более гиперболизировано

У вас есть зелёные помидоры, а вы знаете что продаются только красные. Не надо красить помидоры. Это хорошо, что можно ускорить созревание при помощи этилена. И это будет полноценное созревание, а не покраска. Если бы ускорить было нельзя то нужно было бы выкинуть эти помидоры и добыть новые, уже хорошие.

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

Ну вы поняли. Если что-то плохо пахнет, духи не помогут.

В меру абстрактная часть о качестве кода

Среди свойств хорошего кода мы найдём (не сортируя по важности):

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

Теперь проведём аналогию с помидорами. Наш недостаточно созрел. Автоматический линтер скажет нам: «Смотри надо вот тут и тут не нужный цвет». Что сделает программист? Очень часто покрасит. И в этом кроется основная идея моей критики линтеров. Сейчас я приведу конкретный пример, а потом сделаем вывод.

Конкретика

PixiJS 2 февраля 2018 года (год назад).

Прилетает пул реквест. Суть в том, что ранее для рисования кривой использовалось константное количество точек, что очевидно не оптимально. Предложено использовать хитрый алгоритм для оценки длины кривой. Алгоритм не rocket science, но точно не очевидный, опубликован в 2013 году и приведён со ссылкой на статью его автора (наблюдаются проблемы с https). Счастье что он вообще сохранился на личной страничке.

Там приведён код на С (16 строк):

А в пул реквесте прислан следующий код (JS):

Код оформлен в полном соответствии с настройками линтера. Указаны описания всех параметров, ссылка на изначальный алгоритм, куча констов, в соответствии с требованием линтера «no-mixed-operators»: 1 расставлены скобочки. Даже для производительности апи сделано не объектным, а с отдельными параметрами, так действительно обычно лучше в JS.
Есть одна проблема. Этот код делает полную херню. (Попытка калькировать на русском выражение fucked up, которое вполне используется в западных публикациях для выражения степени проблемы и вроде как уместно).

Возвращается огромная длина, и на неё выделяется много точек, хорошо, что там было ограничение сверху, по нему оно и работало. Раньше этот режим был отключен по дефолту, но потом включился для всех (из-за другого бага кстати). Фикс уже вмержили кстати. Я не связывался с автором коммита и не спрашивал его, почему он решил расставить скобки, но чувствую что он запустил линтер, файл конфигурации которого уже есть в PixiJS. Это линтер ему сказал, твой код плох, потому что в нём не хватает скобок, добавь скобки. Опция «no-mixed-operators» говорит что вы не имеете права написать

потому что это может привести к плохой читаемости. Эту опцию кто-то создал, потом кто-то включил в проект, что говорит о том, что многие люди считают её полезной.

Вывод

Я не хочу сказать что линтеры зло, но вот такое применение их я считаю злом. Мы (в смысле человечество) смогли автоматизировать обнаружение только малой части признаков хорошего кода, в основном это косметика типа расставленных скобок. Линтеры хороши как инструменты анализа качества кода, но как только мы возводим соблюдение требований линтера в рамки обязательного требования мы получаем это самое соблюдение требований. Ничего кроме соблюдения требований мы не приобретаем. Это как поставить камеру на конвеер с помидорами и отправлять на покраску все которые недостаточно красные. Пока мы не давали разработчику инструмент оценки качества внешнего вида кода он мог прислать плохой код, и мы могли это увидеть. Теперь плохой код будет лучше замаскирован. Он будет мимикрировать под хороший, потому что все внешние признаки хорошего кода на нём есть. И мы потеряем линтер как инструмент оценки, ведь весь код соответствует. У нас был инструмент оценки, а теперь его нет, зато код со скобочками, правда не там иногда, но это детали. Итого линтеры считаю классным инструментом, но только если соблюдение требований не становится целью.

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

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

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

Источник

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

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

Линтеры помогают приводить код к единому стилю и избегать ошибок. Правда, только в том случае, если вы готовы к страданиям, а не отмахиваетесь в конце концов «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 не будет опубликован. Обязательные поля помечены *