$ sudo teach|
    $ sudo teach|
    IT school
  • Telegram
  • Партнёрам
  • Все курсы
$ sudo teach IT
OOO "SALEPROFIT"Контакты и реквизитыIT-Park Logo

Школа

  • Блог
  • Проверить сертификат

Сотрудничество

  • Стать учителем
  • Партнёрская программа
  • О проекте

Право

  • Оферта
  • Политика конфиденциальности

© 2023–2026 $ sudo teach IT™. All Rights Reserved. Public user contributions licensed under CC BY-SA 4.0 license with attribution required
TelegramGitHubYouTube
ГлавнаяБлогRuff и форматирование: как добиться “нулевых” стычек в команде и ускорить PR

Ruff и форматирование: как добиться “нулевых” стычек в команде и ускорить PR

$ sudo teach IT
·13 сентября 2026 г.·11 мин·54
Ruff и форматирование: как добиться “нулевых” стычек в команде и ускорить PR

Поговорим о стратегии внедрения ruff и автоформатирования: единый конфиг, правила для разных веток, pre-commit/CI и как договориться о форматах без долгих споров. В результате получите понятный процесс, который делает ревью быстрее и безопаснее.

Содержание
Почему конфликты в PR возникают даже при наличии линтеровПринцип “один источник истины”: единый конфиг для командыЕдиный файл конфигурации и контроль через репозиторийПочему “разные конфиги под разные ветки” опасныНастройка Ruff под форматирование: что именно вы хотите автоматизироватьЛокальная автоматизация: pre-commit как минимально болезненный входПочему pre-commit — лучший “первый шаг” для командыКонфиг .pre-commit-config.yamlПодводные камни pre-commitCI как гарантия: разные режимы для разных веток без хаосаВ чём смысл CI: не “обсуждать”, а “останавливать”Разделение режимов: “strict” для main, “informational” для developВажно: не допускайте несовместимости форматовТиповая стратегия миграции: как не остановить разработкуПодход A: постепенная очистка через “окно” (new code only)Подход B: “один большой форматный коммит” + затем строгий режимПодход C: гибридный — формат всегда, линт постепенноДоговорённость о правилах: как снизить споры до нуляФормула “код, который не проходит — не обсуждается”Как оформить правила так, чтобы они были понятныКонкретные команды: как разработчикам быстро приводить код к стандартуПроверка линтаАвтоисправления там, где это безопасно и настроеноПроверка форматирования (без изменений)Применить форматирование к файламЗапуск на конкретных файлах (удобно для локальной итерации)Как избежать типичных ошибок при внедрении RuffОшибка 1: несогласованная версия RuffОшибка 2: слишком агрессивные правила с первого дняОшибка 3: “per-file-ignores” без стратегииОшибка 4: форматирование не обязательное в целевой веткеНастройка “разных веток” без раздвоения истины: рабочая модельУскорение PR: что именно меняется в процессе ревьюRuff и автоформат: как понять, что вы действительно достигли “нулевых” стычекМини-курс как способ закрепить практикуВывод: форматирование как часть пайплайна, а не предмет дискуссий

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

Хорошая новость: большую часть конфликтов можно устранить технически. В экосистеме Python эту задачу последовательно закрывают форматтеры и линтеры, и в последние годы заметно усиливается инструмент Ruff. Он одновременно действует как быстрый статический анализатор (линтер) и как инструмент автоформатирования (через механизмы, связанные с форматтером). Но чтобы добиться “нулевых” стычек в команде, недостаточно “просто включить Ruff”. Нужна стратегия внедрения: единый конфиг, правила для разных веток, интеграция в pre-commit и/или CI, а также организационная договорённость, которая превращает форматирование в предсказуемый процесс.

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


Почему конфликты в PR возникают даже при наличии линтеров

Конфликт обычно не из воздуха. Он рождается из несовпадения трёх вещей:

  1. Версия инструментов (Ruff/форматтер может обновляться).
  2. Правила (какие проверки включены и как именно они трактуются).
  3. Момент применения (кто и когда приводит код к виду: локально, в pre-commit, в CI, при мердже).

Если хоть один из пунктов “плывёт”, ревьюер будет видеть расхождения, которые автор не мог (или не успел) устранить. В результате возникают “мелкие” комментарии, которые на дистанции превращаются в затяжные PR.

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


Принцип “один источник истины”: единый конфиг для команды

Единый файл конфигурации и контроль через репозиторий

Стандартная практика — хранить настройки Ruff в репозитории: например, в pyproject.toml. Это делает правила неизменными между участниками и окружениями.

Типовая структура секций:

  • настройки линтера (какие правила включаем/выключаем);
  • настройки выбора кодов ошибок/предупреждений;
  • настройки форматирования (если вы используете режимы, связанные с автоформатированием);
  • настройки исключений (ignore, per-file-ignores, exclude).

Пример “скелета” конфигурации:

code
[tool.ruff]
target-version = "py312"
line-length = 88

[tool.ruff.lint]
select = ["E", "F", "I"]  # пример: ошибки/провалы + импорты
ignore = []

[tool.ruff.lint.isort]
known-first-party = ["your_package"]

Ключевая идея: конфиг — в git, и “правила форматирования” не обсуждаются каждый раз в комментариях. Они просто применяются.

Почему “разные конфиги под разные ветки” опасны

Иногда команды хотят ускорить работу: например, в main строгие правила, а в develop — мягче. Если делать это неаккуратно, вы получите эффект “код проходит в одной ветке, но падает в другой”. Это не только тормозит, но и формирует неприятный режим “гоняем PR в зависимости от статуса ветки”.

Решение — не плодить разные правила без необходимости, а договориться о режиме применения: например, вы допускаете временно предупреждения в отдельных ветках, но в “целевой” ветке они не должны попадать. Логику можно выразить через:

  • различие “где считается качество” (например, только в CI для main);
  • использование разных команд Ruff в CI (с разными параметрами);
  • постепенный переход (deprecations/allowed fixes).

Главный принцип: внутри одной ветки правила должны быть предсказуемыми.


Настройка Ruff под форматирование: что именно вы хотите автоматизировать

Важно уточнить: когда команда говорит “форматирование”, она обычно имеет в виду разные вещи:

  1. Локальные правки, которые не требуют раздумий: перенос строк, пробелы, кавычки, порядок импорта.
  2. Стиль, который близок к “линту”: запреты на определённые конструкции, ограничения по длине строк и т.д.
  3. Рефакторинг по стилю: например, перестроение импорта или приведение к определённым шаблонам.

Ruff полезен именно на стыке (1) и (2). Для (1) вы используете автоформатирование, для (2) — линт. А конфликт возникает, когда команда не понимает, что именно делает каждый инструмент.

Практическая стратегия такая:

  • Используйте Ruff как первую линию: он проверяет правила и может приводить код к формату (в зависимости от ваших настроек/режимов).
  • Закройте “неформатируемое” обсуждением в PR там, где действительно есть содержание: имена, структура, корректность.
  • Для импорта обычно достаточно ruff+isort-подсистемы, но нужно правильно указать “first-party” и “known” пакеты, иначе будут постоянные перестановки.

Локальная автоматизация: pre-commit как минимально болезненный вход

Почему pre-commit — лучший “первый шаг” для команды

CI — это хорошо, но CI всегда позднее: он отрабатывает после того, как код уже прошёл через вашу локальную итерацию. pre-commit позволяет сдвинуть большую часть “форматных” правок в момент коммита.

Это принципиально снижает число итераций PR:

  • автор сам приводит код к стандарту;
  • ревьюер видит согласованную форму;
  • ревью фокусируется на смысле.

Конфиг .pre-commit-config.yaml

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

code
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.6.4
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

Если ваш проект использует только линт без “форматного” хука, тогда оставляйте один ruff. Если важно автоматизировать порядок импортов и формат, добавляйте ruff-format (или ваш форматтерный хук в рамках Ruff-экосистемы).

Подводные камни pre-commit

  1. Разные версии у участников
    pre-commit фиксирует версию через rev. Это снижает дрейф правил. Обновление делайте контролируемо: например, раз в спринт и с регенерацией форматного результата.

  2. Непредсказуемость “fix”
    Флаг --fix может исправлять часть проблем автоматически. Это хорошо, но не должно приводить к “внезапным” изменениям, которые автор не ожидал. Команда должна понимать, что определённые категории правок будут внесены автоматически.

  3. Время выполнения
    Ruff быстрый, но всё же проект может быть крупным. Дайте pre-commit только то, что реально нужно на commit (например, ruff и ruff-format), а более тяжёлые проверки перенесите в CI.


CI как гарантия: разные режимы для разных веток без хаоса

В чём смысл CI: не “обсуждать”, а “останавливать”

CI должен давать два эффекта:

  • если код не соответствует стандартам целевой ветки — PR не проходит;
  • форматирование должно считаться “не предметом спора”, а “условием входа”.

Разделение режимов: “strict” для main, “informational” для develop

Вместо раздельных конфигов можно применять разные команды или параметры.

Пример идеи:

  • Для main: Ruff в режиме, где нарушения формат/линта считаются ошибкой (например, --output-format=github и ненулевой exit code).
  • Для develop: те же правила, но допускается мягкое состояние (например, разрешить warnings или запускать только определённые группы проверок).

На практике это означает, что команды CI могут различаться:

code
# main
ruff check . --output-format=github
ruff format --check .

# develop (пример мягче — зависит от ваших требований)
ruff check . --output-format=github
ruff format --check .

Если вы используете ruff format как обязательный шаг, то “мягкость” скорее не про формат, а про часть линтинга (например, не все группы правил включены).

Важно: не допускайте несовместимости форматов

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

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


Типовая стратегия миграции: как не остановить разработку

Внедрение Ruff часто ломает процесс не из-за инструмента, а из-за объёма “технического долга” в текущем репозитории: линтер увидит много проблем и проект “покраснеет” сразу.

Есть несколько рабочих подходов:

Подход A: постепенная очистка через “окно” (new code only)

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

Технически это делается через:

  • исключения старых файлов (например, exclude или per-file-ignores);
  • запуск Ruff только на изменённых файлах в CI (через diff);
  • строгий режим на main, но мягкий на проверках “полного дерева”.

Это снижает психологическое сопротивление: команда не обязана “переписать всё” за один день.

Подход B: “один большой форматный коммит” + затем строгий режим

Если вы готовы к одномоментному улучшению, вы:

  1. фиксируете версию Ruff;
  2. прогоняете форматирование и автофиксы на всём репозитории;
  3. делаете один коммит с изменениями стиля;
  4. включаете жёсткий CI.

Плюсы: быстрый возврат к нормальному режиму. Минусы: большой diff может усложнить навигацию по истории изменений. Хорошо работает, если команда хорошо понимает риски и готова к большому PR внутри репозитория (например, “style unification”).

Подход C: гибридный — формат всегда, линт постепенно

Компромисс, который часто выигрывает: автоформат и импортный порядок включаются жёстко сразу, а линт-группы расширяются постепенно.

Это даёт:

  • моментальный эффект “меньше разногласий”;
  • снижение шумов в ревью;
  • управляемое снижение долгов.

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

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

Формула “код, который не проходит — не обсуждается”

Рекомендованный принцип:

  • если CI или pre-commit не пропустили изменение — автор исправляет автоматически/локально;
  • ревьюер не обсуждает формат вручную, потому что формат уже “зафиксирован” инструментом.

Для команды это означает смену ментальной модели: формат — это не часть ревью как процесса принятия решений, а часть процесса “входа”.

Как оформить правила так, чтобы они были понятны

В репозитории обычно достаточно файла CONTRIBUTING.md (или раздела в README):

  • команду установки dev-зависимостей;
  • как запускать pre-commit;
  • как запускать Ruff вручную (на случай “надо посмотреть перед коммитом”).

Пример формулировки (схематично):

  • Перед коммитом запусти: pre-commit run --all-files.
  • Линт и форматирование выполняются автоматически.
  • Если CI ругается — применяй автофиксы Ruff.

Это не требует многословия, но снимает главную проблему: “а что от нас хотят?”.


Конкретные команды: как разработчикам быстро приводить код к стандарту

Ниже набор команд, которые обычно составляют “минимальный набор” для новичков в проекте.

Проверка линта

code
ruff check .

Автоисправления там, где это безопасно и настроено

code
ruff check . --fix

Проверка форматирования (без изменений)

code
ruff format --check .

Применить форматирование к файлам

code
ruff format .

Запуск на конкретных файлах (удобно для локальной итерации)

code
ruff check path/to/file.py
ruff format path/to/file.py

Важно: разработчики должны получать один и тот же результат, что уменьшает “почему у меня проходит, а у тебя нет?”.


Как избежать типичных ошибок при внедрении Ruff

Ошибка 1: несогласованная версия Ruff

Решение: фиксировать версию в pre-commit и явно указать её в tooling документации (или использовать lock-файл, если вы ставите Ruff через зависимости проекта).

Если вы используете Python tooling (например, poetry или pip-tools), убедитесь, что Ruff попадает в dev-зависимости и фиксируется версией.

Ошибка 2: слишком агрессивные правила с первого дня

Если включить все проверки сразу, команда упрётся в массу автокоммитов и начнёт “прятать” проблемы. Лучше начать с ядра правил:

  • базовые ошибки (E, F),
  • импорты (I),
  • формат и упорядочивание,
  • затем расширять покрытие.

Ошибка 3: “per-file-ignores” без стратегии

Локальные ignore — полезны для временных участков, но без дисциплины игнор превращается в “вечное исключение”. Хорошая практика:

  • использовать per-file-ignores временно;
  • вести список исключений и план их удаления;
  • документировать причину (почему игнор и какой ожидаемый срок).

Ошибка 4: форматирование не обязательное в целевой ветке

Если формат не является обязательным условием прохождения CI для ветки мерджа — вы не устраните конфликт, вы лишь перенесёте его. Держите ruff format --check . как обязательную часть проверки для ветки, куда принимаете PR.


Настройка “разных веток” без раздвоения истины: рабочая модель

Практическая модель, которая обычно хорошо работает:

  1. Форматирование — едино для всех веток, где живут PR в будущее (например, develop и main). Это устраняет “почему у меня отформатировано иначе”.
  2. Линт — одинаковый по правилам, но различается по строгости:
    • где-то вы можете показывать результаты как предупреждения/комментарии, а на main — блокировать;
    • или включать не все группы правил на ранних стадиях.

Технически это реализуется не через два разных конфига, а через разные команды в CI. Один источник истины остаётся единым: pyproject.toml. Меняется лишь момент “взять вето или нет”.


Ускорение PR: что именно меняется в процессе ревью

Когда формат “схлопнут” до автоматического, ревью действительно ускоряется. Но не магически — меняется конкретная статистика:

  • Становится меньше комментариев уровня “перенеси строку / переставь импорт”.
  • Меньше ситуаций, когда автор отвечает “да, я поправлю, но позже”, потому что позже — это уже “встроенная задача инструмента”.
  • Меньше циклов “CI не проходит → локально исправь → снова запроси ревью”.

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


Ruff и автоформат: как понять, что вы действительно достигли “нулевых” стычек

Есть простые метрики процесса:

  1. Доля комментариев в PR по форматированию
    Если это “заметная часть” — форматирование не обязательное или не согласованное.

  2. Количество итераций до merge
    После внедрения pre-commit и CI обычно падает число кругов “исправь стиль — исправь стиль снова”.

  3. Частота фраз “у меня проходит”
    Если они появляются — значит версии/правила несовместимы. Решение обычно: фиксировать версии и унифицировать конфиги.

  4. Объём “стилевых” диффов
    Если диффы оказываются огромными на каждый PR — вы либо форматируете не так, либо инструмент применяется не в том месте (например, форматирование не делается до коммита).


Мини-курс как способ закрепить практику

Если вы только начинаете и хотите не разбираться с Ruff “по кусочкам” через справку и случайные заметки, полезной отправной точкой может стать курс “ruff – для начинающих!”. Его стоит воспринимать как структурированный способ собрать модель: какие проверки включать, как настроить базовый конфиг и как выстроить рабочий процесс под команду.


Вывод: форматирование как часть пайплайна, а не предмет дискуссий

Ruff и автоформатирование могут реально превратить ревью в процесс обсуждения качества, а не стиля. Но эффект появляется только при наличии стратегии:

  • держите единый pyproject.toml как источник истины;
  • автоматизируйте формат и линт на локальном уровне через pre-commit;
  • в CI обеспечьте обязательность форматирования для ветки мерджа;
  • используйте “разные режимы” на разных ветках не через раздвоение конфигов, а через различия команд/строгости;
  • планируйте миграцию, чтобы не получить “красный репозиторий” на старте;
  • фиксируйте версии инструментов, иначе вы не устраните конфликты, а просто сделаете их непредсказуемыми.

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

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

Автор

$ sudo teach IT

ruff – для начинающих!

Курс по теме

ruff – для начинающих!

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

Бесплатно
Открыть курс

Продолжите обучение

Все курсы
Python – для начинающих!

Python – для начинающих!

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

Перейти к курсу
Простыми словами о защищенном соединении

Простыми словами о защищенном соединении

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

Перейти к курсу
Ботостроение Telegram

Ботостроение Telegram

Лёгкий, быстрый и доступный способ познакомиться с миром ботостроения в Telegram. Видео, конспекты, практика и помощь – всё у нас на курсе.

Перейти к курсу
Сервис, который не падает - как построить безопасную зашифрованную сеть

Сервис, который не падает - как построить безопасную зашифрованную сеть

Практический курс по безопасности сети: как собрать собственный сервис защищённого доступа - от пустого сервера до подписки с автовыбором - и, что важнее, как потом не уронить его своими руками.

Перейти к курсу

Другие статьи

Запуск и поддержка проекта на Ruff в команде: формат “как в CI”, а не “как договорились”
запуск

Запуск и поддержка проекта на Ruff в команде: формат “как в CI”, а не “как договорились”

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

16 сентября 2026 г.
1050
Введение в ruff-линтеры для старта: правила, которые быстрее всего окупаются
введение

Введение в ruff-линтеры для старта: правила, которые быстрее всего окупаются

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

14 сентября 2026 г.
650
Создание Telegram бота в 2026 легко и просто! Полный курсы!
создание

Создание Telegram бота в 2026 легко и просто! Полный курсы!

19 июня 2026 г.
1431
Как выбрать, куда идти в IT: веб, боты, данные — без хаоса
выбрать

Как выбрать, куда идти в IT: веб, боты, данные — без хаоса

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

5 октября 2026 г.
580
Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть
путь

Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть

Разберём структуру репозитория, как упаковать проект в понятную историю (проблема → решение → запуск → метрики качества) и какие артефакты повышают доверие: скринкасты, архитектурная схема, чек-лист продакшн-готовности.

17 сентября 2026 г.
1090
Как понять, какой язык программирования учить первым: простой тест и выбор
понять

Как понять, какой язык программирования учить первым: простой тест и выбор

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

2 октября 2026 г.
630

Комментарии

Станьте первым в обсуждении

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

Содержание

Почему конфликты в PR возникают даже при наличии линтеровПринцип “один источник истины”: единый конфиг для командыЕдиный файл конфигурации и контроль через репозиторийПочему “разные конфиги под разные ветки” опасныНастройка Ruff под форматирование: что именно вы хотите автоматизироватьЛокальная автоматизация: pre-commit как минимально болезненный входПочему pre-commit — лучший “первый шаг” для командыКонфиг .pre-commit-config.yamlПодводные камни pre-commitCI как гарантия: разные режимы для разных веток без хаосаВ чём смысл CI: не “обсуждать”, а “останавливать”Разделение режимов: “strict” для main, “informational” для developВажно: не допускайте несовместимости форматовТиповая стратегия миграции: как не остановить разработкуПодход A: постепенная очистка через “окно” (new code only)Подход B: “один большой форматный коммит” + затем строгий режимПодход C: гибридный — формат всегда, линт постепенноДоговорённость о правилах: как снизить споры до нуляФормула “код, который не проходит — не обсуждается”Как оформить правила так, чтобы они были понятныКонкретные команды: как разработчикам быстро приводить код к стандартуПроверка линтаАвтоисправления там, где это безопасно и настроеноПроверка форматирования (без изменений)Применить форматирование к файламЗапуск на конкретных файлах (удобно для локальной итерации)Как избежать типичных ошибок при внедрении RuffОшибка 1: несогласованная версия RuffОшибка 2: слишком агрессивные правила с первого дняОшибка 3: “per-file-ignores” без стратегииОшибка 4: форматирование не обязательное в целевой веткеНастройка “разных веток” без раздвоения истины: рабочая модельУскорение PR: что именно меняется в процессе ревьюRuff и автоформат: как понять, что вы действительно достигли “нулевых” стычекМини-курс как способ закрепить практикуВывод: форматирование как часть пайплайна, а не предмет дискуссий