НовостиОбзорыСобытияIT@WorkРеклама
ИТ-менеджмент:
Продуктовое мышление требует новых инструментов. Ваш Jira тянет?
Российский рынок разработки продолжает рост, корпоративным заказчикам нужны инструменты для управления процессами, услугами …
Чем занимается Applied Scientist в Big Tech: от математического моделирования до бизнес-влияния
Кто расставляет акценты в маркетинговой реальности. Роль Applied Scientist через опыт Дмитрия Тимошенко. По данным …
Как модульный подход меняет разработку AI-агентов
Разнообразие low-code и no-code решений серьезно упростило создание IT-продуктов, в том числе, и на основе …
Российский ИИ — реальному сектору экономики РФ
Системы, использующие искусственный интеллект, сегодня внедряют многие российские компании. Конечно, чтобы был эффект …
Лучшие видеоредакторы для новичков и любителей
Начать монтаж видео сегодня довольно просто, т.к. любой видеоредактор работает по понятной логике «импорт — …
 

«Инструмент, без которого уже не пишут на Go»: интервью с автором golangci-lint Денисом Исаевым

Юрий Николаев | 24.09.2025

При разработке на Go активно используются линтеры — программы для статического анализа кода. Металинтер golangci-lint позволяет запустить десятки линтеров одновременно, чтобы сократить время выполнения до нескольких секунд. Мы поговорили с создателем golangci-lint Денисом Исаевым — среди российских разработчиков он внес, возможно, самый большой вклад в экосистему Go (Golang). Денис рассказал, как родилась идея металинтера, и как golangci-lint за несколько лет превратился из личного pet-проекта в стандарт, которым пользуются тысячи команд по всему миру.

Денис Исаев

Денис, как вам пришла идея создать golangci-lint, и пересекался ли этот проект с вашими рабочими задачами на тот момент?

В 2017-2018 году я работал в Mail.Ru на проекте BeepCar в качестве Head of Backend and Frontend. BeepCar задумывался как онлайн-сервис по поиску попутчиков в автомобильные поездки. Бэкенд мы писали на языке программирования Go (Golang).

Цикл разработки устроен так, что сначала мы пишем код, а затем запускаем автоматические тесты, которые проверяют его корректность. Чтобы ускорить процесс проверки, после автотестов мы используем линтеры — программы-анализаторы, которые выявляют потенциальные ошибки, стилистические нарушения и другие недочеты.

На тот момент существовало около 20 линтеров, и они позволяли покрывать значительный класс ошибок в Go. Но их работа занимала на нашем проекте около 3 минут — это довольно значительное время, если необходимо провести несколько проверок за день. Уже тогда я начал думать над тем, как сократить это процесс — например, создать металинтер, который мог бы параллельно запускать все проверки.

Когда в 2018 году я устроился в Яндекс, у меня была пара свободных недель перед выходом на работу. И я решил, что успею реализовать свою идею. На тот момент в Яндексе не был распространен язык Go, и я создал golangci-lint просто из интереса, без какой-либо коммерческой выгоды.

Какие проблемы решал ваш металинтер в момент запуска, и изменилось ли это со временем?

Главной задачей было превратить 3 минуты проверки кода в 10 секунд. Так и получилось — а с развитием проекта скорость только нарастала. Через год после запуска металинтера он работал уже в 100 раз быстрее, чем исходное решение, а через пару лет удалось ускорить его еще в 3-5 раз.

Заслуга здесь не только моей идеи и команды open-source контрибьютеров, но и специалистов из core-команды самого языка Go. Увидев, с какими проблемами сталкиваются разработчики линтеров, они выпустили набор библиотек, стандартов и рекомендаций, с помощью которых можно было значительно ускорить работу.

Как устроена архитектура golangci-lint? Что позволило сделать его таким быстрым?

Я уже был знаком с проектом gometalinter, который запускает 20 линтеров параллельно. Я погрузился в его работу и понял, что примерно 90% действий каждого линтера дублируется: прочитать исходный код проекта, распарсить его, прогнать по нему базовый анализ и передать в логику конкретного линтера. И у меня появилась идея: сделать так, чтобы эти 90% работы делать только один раз.

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

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

Это было специфическое и довольно рискованное решение. На старте оно даже вызвало отторжение в сообществе. Чтобы объединить линтеры в свой golangci-lint мне пришлось клонировать каждый из них, и у других разработчиков появились опасения, что основная версия будет развиваться отдельно, а мой форк останется позади. При этом в каждый линтер я отправил pull request, чтобы разработчики забрали мои изменения к себе — но на практике половина из них не отреагировали.

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

Ваш проект стал по сути стандартом статического анализа кода в Go. Как вы думаете, в чем его главное преимущество перед другими линтерами, и почему именно он так широко распространился?

Ключевой особенностью проекта стала скорость — ни одно решение не позволяло так упростить и ускорить тестирование кода. Также golangci-lint очень приятен в использовании — своеобразный iPhone в мире open source. Немногие продукты с открытым кодом в то время могли таким похвастаться.

Чтобы достичь такого эффекта, я использовал более удобный формат конфигурации. В прошлом решении — gometalinter — применялся JSON-формат. Он более «машиночитаемый», но просматривать и редактировать его не так комфортно. Я перешел в своем решении на YAML, с которым человеку работать гораздо удобнее.

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

В развитии продукта мне помогла обратная связь. Например, golangci-lint внедрили в работу мои бывшие коллеги из Mail.Ru Group. Они рассказали, что металинтер крайне сложно использовать в крупном проекте, который существует уже несколько лет. Если запустить линтер на всю кодовую базу, он покажет миллионы ошибок, накопленных за эти годы — и их исправление займет колоссальное количество времени.

Я придумал, как с этим справиться — нужно было научить металинтер запускать проверку кода только для внесенных изменений. Например, разработчик пишет код, меняя 1% кодовой базы — и только эту часть проверяет линтером. Мое усовершенствование помогло сделать golangci-lint еще более универсальным — чтобы его можно было применять на проектах любого объема.

Как golangci-lint повлиял на экосистему Go?

Прежде всего, мне хочется отметить, как он повлиял на саму команду разработки языка Go в Google — мы пообщались с ними на конференции GopherCon в 2019 году. Увидев golangci-lint, разработчики Go увидели проблему использования линтеров, с которой мне пришлось бороться — так появился стандарт интерфейса, который теперь используется во всех линтерах. Таким образом, я поспособстовал тому, чтобы облегчить работу всем разработчикам Go.

С 2019 года golangci-lint стал использоваться в большинстве новых проектов на Go — и это привело к двум следствиям. Во-первых, линтеров стало значительно больше — по умолчанию через golangci-lint запускается около 40-50. Если бы не существовало моего решения, то работа всех этих линтеров занимала бы 6-8 минут — это крайне долго. Возможно, из-за этого линтеры перестали бы создаваться, потому что никому не хотелось бы тратить столько времени на тестирование.

Во-вторых, я показал, как быстро делать новые линтеры, написав туториал по их разработке и встраиванию в golangci-lint. С тех пор энтузиасты со всего мира создали десятки или даже сотни линтеров, развивая наше сообщество. Так у разработчиков появился широкий выбор — какие именно решения использовать для своего проекта на Go.

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

Было ожидание, что я решу проблему, которая заботит не только меня, но и коллег — и в целом сделаю интересный open-source продукт. Но я не думал, что он станет таким популярным, и его будут использовать почти все разработчики на Go.

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

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

Если бы вы запускали golangci-lint сегодня, что бы вы сделали иначе? Есть ли у вас уже идеи для следующего большого проекта — в области автоматизации кода или чего-то еще?

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

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

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

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

Другие спецпроекты
ПечатьПечать без изображений

Комментарии

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

Регистрация
Авторизация

ПОДГОТОВЛЕНО ITWEEK EXPERT

 
Интересно
ИИ побеждает: исследование Google демонстрирует повсеместное принятие ИИ разработчиками
Согласно новому отчёту Google «2025 DORA State of AI-assisted Software Development Report», 90% команд …
Путеводитель по аренде: как выбрать между HaaS и Dedicated
Современные компании все чаще сочетают облачные решения с арендой физического оборудования. Причины очевидны: максимальная …
«Инструмент, без которого уже не пишут на Go»: интервью с автором golangci-lint Денисом Исаевым
При разработке на Go активно используются линтеры — программы для статического анализа кода. Металинтер golangci-lint …
Шесть фреймворков для эффективного инференса LLM
Направление вывода (инференс, генерация ответов на запросы пользователей) на основе больших языковых моделей (LLM …
Gartner: как ИИ изменит роль CIO к 2030 году
Развитие искусственного интеллекта заставляет переосмыслить роль CIO. К 2030 г. CIO будут руководить гибридными …