<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>changeloop blog</title><description>Релиз-ноты на практике и changelog как артефакт сборки.</description><link>https://changeloop.dev/</link><language>ru-RU</language><item><title>Release notes об исправлении багов: как писать записи</title><link>https://changeloop.dev/blog/ru/bug-fix-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/bug-fix-release-notes/</guid><description>Release notes об исправлении багов работают, когда запись называет симптом, охват и действие. Примеры до и после, правила для безопасности и данных.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Хорошие release notes об исправлении багов описывают, что пользователь увидел сломанным, а не что было неправильно в коде. Каждая запись говорит, кого это задело, с какого момента, полностью ли исправлено и нужно ли читателю что-то делать, даже если это лишь «действий не требуется».&lt;/p&gt;
&lt;p&gt;Большинство команд копирует строку из сообщения коммита. В таблице шесть переписанных примеров, а разделы после неё объясняют правила.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;До (сообщение коммита)&lt;/th&gt;
&lt;th&gt;После (симптом)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Fixed null pointer in export handler&lt;/td&gt;
&lt;td&gt;Экспорты больше не падают с «Что-то пошло не так», если в проекте нет тегов. Запустите заново экспорты, упавшие с 3 сентября.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolved race condition in sync worker&lt;/td&gt;
&lt;td&gt;Правки, сделанные на двух устройствах с разницей в несколько секунд, больше не затирают друг друга. Делать ничего не нужно.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fix timezone bug&lt;/td&gt;
&lt;td&gt;Отчёты по расписанию снова идут в заданное время. Аккаунты восточнее UTC получали отчёты на целый день раньше с 12 августа. Менять ничего не нужно.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patched XSS in comment renderer&lt;/td&gt;
&lt;td&gt;Безопасность: специально составленный комментарий мог выполнить скрипт в браузере другого пользователя. Обновитесь до 4.2.1 сегодня. В наших логах следов эксплуатации нет.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed regression from 4.1.0&lt;/td&gt;
&lt;td&gt;Поиск снова работает для запросов с дефисом. Он сломался в 4.1.0 и исправлен в 4.1.1.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bug fixes and performance improvements&lt;/td&gt;
&lt;td&gt;Назовите, какие именно. См. последний раздел.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Как написать запись об исправлении бага в release notes?&lt;/h2&gt;
&lt;p&gt;Начните с симптома словами пользователя, затем скажите, кого это задело и с какого времени, затем в каком состоянии исправление, затем что делать. Обычно хватает одного-двух предложений. Причина в коде относится к pull request, где её будет искать инженер.&lt;/p&gt;
&lt;p&gt;Читатель ищет одно: «это было со мной?» Почти любую запись закрывают четыре части:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Симптом.&lt;/strong&gt; Что появилось на экране, в ответе API или в счёте. Процитируйте текст ошибки, если она была, потому что люди ищут по нему.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Охват.&lt;/strong&gt; Какой план, платформа, версия API или вид данных. «Аккаунты с более чем 50 000 строк» можно проверить. «Некоторые пользователи» нельзя.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Период.&lt;/strong&gt; С какого релиза или даты, чтобы читатель мог решить, был ли вчерашний странный результат этим багом.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Действие.&lt;/strong&gt; Запустить заново, синхронизировать заново, обновиться, убрать обходной путь или ничего.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Если пользователи придумали обходной путь, именно в строке действия вы говорите им, что его можно удалить.&lt;/p&gt;
&lt;h2&gt;В чём разница между release note и changelog?&lt;/h2&gt;
&lt;p&gt;Changelog это полный непрерывный журнал изменений. Release notes это отобранное, переписанное сообщение об одном релизе для тех, кто решает, стоит ли им обращать внимание. Для исправлений баги changelog перечисляет все исправления, а заметки ведут с тех, которые читатель мог заметить.&lt;/p&gt;
&lt;p&gt;Опечатка во всплывающей подсказке относится только к changelog. Неверная ставка налога в счетах относится к обоим. Полное разделение описано в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;changelog vs release notes&lt;/a&gt;, а форма хорошего набора заметок в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;как писать release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt; удобное соглашение для стороны журнала. Оно держит «Fixed» для любых исправлений багов и отдельный заголовок «Security» для уязвимостей, и это то же разделение, которое эта статья делает для читателя.&lt;/p&gt;
&lt;h2&gt;Является ли исправление бага обновлением?&lt;/h2&gt;
&lt;p&gt;Да. Исправление бага меняет продукт, так что его выпуск это обновление. По &lt;a href=&quot;https://semver.org/&quot;&gt;семантическому версионированию&lt;/a&gt; обратно совместимое исправление это патч-релиз, например с 4.2.0 до 4.2.1.&lt;/p&gt;
&lt;p&gt;Нужно ли читателю что-то делать, это отдельный вопрос, и заметка должна на него отвечать. Исправление, меняющее то, что видит корректный вызывающий, близко к breaking change, а где проходит эта граница, объясняет статья &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;breaking changes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Когда исправлению нужна отдельная запись, а когда это мелкое исправление?&lt;/h2&gt;
&lt;p&gt;Давайте исправлению отдельную запись, когда пользователь мог заметить баг, потерять из-за него время или данные или построить вокруг него обходной путь. Группируйте его в короткий список «Мелкие исправления», когда никто вне команды не мог его увидеть. Судите по опыту читателя, а не по размеру диффа.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Отдельная запись&lt;/th&gt;
&lt;th&gt;В список мелких исправлений&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Сообщил клиент или столкнулись многие&lt;/td&gt;
&lt;td&gt;Косметический сбой на редко открываемом экране&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Давал неверный результат, упавшие задачи или потерянную работу&lt;/td&gt;
&lt;td&gt;Опечатка, отступ, сдвинутая иконка&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Требует действия от читателя&lt;/td&gt;
&lt;td&gt;Исправление во внутреннем инструменте или админке&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Регрессия из недавнего релиза&lt;/td&gt;
&lt;td&gt;Сбой, который виден только в тестовой среде&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Затрагивает оплату, права или данные&lt;/td&gt;
&lt;td&gt;Формулировка в логе, обновления зависимостей без влияния на пользователя&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Каждая строка в группе всё равно должна что-то говорить: «Исправлены некоторые проблемы интерфейса» это заглушка.&lt;/p&gt;
&lt;h2&gt;Как писать о регрессии?&lt;/h2&gt;
&lt;p&gt;Назовите релиз, внёсший её, назовите это регрессией и назовите релиз, который её исправляет. Те, кто столкнулся с багом, и так знают, что что-то сломалось, поэтому короткое прямое признание служит им лучше расплывчатой формулировки.&lt;/p&gt;
&lt;p&gt;Например: «В 4.1.0 поиск по запросам с дефисом возвращал пустой результат. Это исправлено в 4.1.1. Если вы меняли запросы, чтобы обойти дефисы, можно вернуть прежние».&lt;/p&gt;
&lt;p&gt;«Улучшена надёжность поиска» читается как увёртка для всякого, кто потерял на этом баге вечер. Если причина ещё уточняется, скажите об этом, как советует руководство по &lt;a href=&quot;https://changeloop.dev/blog/ru/emergency-release-notes/&quot;&gt;экстренным release notes&lt;/a&gt;: заметка никогда не должна звучать увереннее, чем команда.&lt;/p&gt;
&lt;h2&gt;Как объявить об исправлении уязвимости?&lt;/h2&gt;
&lt;p&gt;Прямо назовите серьёзность, укажите затронутые версии и версию с исправлением, скажите, насколько срочно обновляться, и добавьте идентификатор CVE, если он есть. Раскрывайте подробности только тогда, когда пользователи могут применить исправление, и придерживайтесь процесса скоординированного раскрытия, если был сообщивший.&lt;/p&gt;
&lt;p&gt;Порядок важен: сообщивший пишет вам приватно, вы выпускаете исправление, а публичная заметка выходит, когда пользователи могут защититься. &lt;a href=&quot;https://www.cisa.gov/coordinated-vulnerability-disclosure-process&quot;&gt;Процесс скоординированного раскрытия уязвимостей CISA&lt;/a&gt; координирует сообщение об уязвимости, её анализ и публичное раскрытие. &lt;a href=&quot;https://www.cve.org/ResourcesSupport/AllResources/CNARules&quot;&gt;Правила CVE Numbering Authority&lt;/a&gt; определяют, как записи CVE присваиваются и публикуются, а на GitHub &lt;a href=&quot;https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-repository-security-advisories&quot;&gt;repository security advisory&lt;/a&gt; позволяет приватно подготовить бюллетень и запросить идентификатор.&lt;/p&gt;
&lt;p&gt;Запись о безопасности обычно несёт четыре факта:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Что мог сделать атакующий, одним предложением и без proof of concept.&lt;/li&gt;
&lt;li&gt;Затронутые версии и версия, которая это исправляет.&lt;/li&gt;
&lt;li&gt;Насколько срочно: «обновитесь сегодня» или «обновитесь в следующем релизе».&lt;/li&gt;
&lt;li&gt;Видели ли вы эксплуатацию и благодарность сообщившему, если он согласился.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Шаги эксплуатации не публикуйте.&lt;/p&gt;
&lt;h2&gt;Что заметка должна сказать об исправлении потери данных?&lt;/h2&gt;
&lt;p&gt;Скажите, какие данные были затронуты, как понять, задело ли ваши, и можно ли их восстановить. «Действий не требуется» здесь редко бывает правдой, а первый вопрос читателя: «мои данные пропали?»&lt;/p&gt;
&lt;p&gt;В полезной записи есть условие, при котором данные терялись («удаление папки во время работающей синхронизации»), период, когда это было возможно, способ проверки («откройте корзину и поищите элементы с датами с 3 по 9 сентября») и путь восстановления. Если данные восстановить нельзя, так и скажите. Свяжитесь с затронутыми клиентами ещё и напрямую: release note не должна быть единственным местом, где человек узнаёт, что его данные пострадали.&lt;/p&gt;
&lt;h2&gt;Почему «Исправления багов и улучшения производительности» плохая заметка?&lt;/h2&gt;
&lt;p&gt;Она не даёт читателю ничего, на что можно опереться, и прячет исправления, которых кто-то ждал. Клиент, сообщивший о падении, не может понять, исправлено ли оно, а клиент с обходным путём не может понять, стоит ли его убрать.&lt;/p&gt;
&lt;p&gt;Есть две честные альтернативы. Если в релизе нет ничего, что читатель мог бы заметить, не публикуйте для него заметок и оставьте запись за changelog. Если исправления есть, перечислите их словами читателя:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;До:
  Исправления багов и улучшения производительности.

После:
  Исправлено: экспорт CSV падал для проектов без тегов.
  Исправлено: в тёмной теме не был виден курсор в поле
  комментария.
  Быстрее: панель открывается быстрее для рабочих
  пространств со 100+ проектов.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Откуда берутся заметки об исправлении багов?&lt;/h2&gt;
&lt;p&gt;Они берутся из pull request, который исправил баг, и из сообщения, с которого всё началось. Если слова сообщившего доезжают вместе с исправлением, половина симптома уже написана.&lt;/p&gt;
&lt;p&gt;Почему правильная пометка сообщения решает, кому оно достанется, объясняет статья &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-vs-bug-report/&quot;&gt;запрос на функцию или ошибка&lt;/a&gt;. В Changeloop баг, о котором сообщили через виджет, становится задачей GitHub с меткой &lt;code&gt;bug&lt;/code&gt;, а запись в changelog составляется из влитого pull request и удерживается до одобрения человеком перед публикацией. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;Шаблон release notes&lt;/a&gt; даёт ту же форму записи для ручного письма: симптом, охват, период, действие.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Что должны включать release notes об исправлении багов?&lt;/strong&gt;
Каждая запись должна называть симптом, который видел пользователь, кого это задело, с какого релиза или даты, полностью ли исправлено и что нужно сделать читателю, включая «ничего».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужно ли перечислять в release notes каждое исправление бага?&lt;/strong&gt;
Нет. Перечисляйте те, которые пользователь мог заметить, на которые потерял время или которые обходил, а косметические и внутренние группируйте в короткий список «Мелкие исправления». Changelog хранит каждое исправление для тех, кому нужно что-то найти.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как писать release notes о баге, который внесли вы?&lt;/strong&gt;
Скажите, что это была регрессия, назовите релиз, который её внёс, и релиз, который исправляет, и сообщите читателям, могут ли они убрать обходной путь. Прямое утверждение читается лучше смягчённого.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как найти release notes продукта, которым вы пользуетесь?&lt;/strong&gt;
Ищите страницу changelog или release notes по ссылке в меню помощи продукта, подвале или документации, а для проектов с открытым кодом на вкладке релизов репозитория.&lt;/p&gt;
</content:encoded></item><item><title>Как попросить обратную связь у клиентов в софтовом продукте</title><link>https://changeloop.dev/blog/ru/how-to-ask-for-customer-feedback/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/how-to-ask-for-customer-feedback/</guid><description>Задайте один конкретный вопрос сразу после действия пользователя, прямо там, где он работает. Готовые формулировки для каждого момента и плохие вопросы.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Чтобы получить обратную связь от клиентов в софтверном продукте, задайте один конкретный вопрос о том, что пользователь только что сделал, и в том месте, где он это сделал. «Как прошёл экспорт этого отчёта?» сразу после экспорта получает ответ. «Расскажите, что вы думаете о нашем продукте» в подвале сайта получает тишину. Остальная часть страницы это моменты, каналы и точные формулировки.&lt;/p&gt;
&lt;p&gt;Большинство советов на эту тему написано для магазинов и сервисных стоек. Команда, делающая софт, точно знает, что пользователь сделал секунду назад, поэтому вопрос можно задать именно об этом.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Момент&lt;/th&gt;
&lt;th&gt;Где спрашивать&lt;/th&gt;
&lt;th&gt;Готовая формулировка&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Сразу после завершения задачи&lt;/td&gt;
&lt;td&gt;В приложении, рядом с результатом&lt;/td&gt;
&lt;td&gt;«Этот экспорт сделал то, что вам было нужно?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;После первого использования новой функции&lt;/td&gt;
&lt;td&gt;В приложении, один раз&lt;/td&gt;
&lt;td&gt;«Что вы пытались сделать с помощью массового редактирования?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;После закрытия обращения в поддержку&lt;/td&gt;
&lt;td&gt;В переписке с поддержкой&lt;/td&gt;
&lt;td&gt;«Это помогло или что-то всё ещё не так?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Когда пользователь застрял или бросил сценарий&lt;/td&gt;
&lt;td&gt;Письмо на следующий день&lt;/td&gt;
&lt;td&gt;«Вы остановились на шаге 3 настройки. Что помешало?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;После 30 дней регулярной работы&lt;/td&gt;
&lt;td&gt;Письмо от конкретного человека&lt;/td&gt;
&lt;td&gt;«Что одно вы бы изменили?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Когда пользователь отменяет подписку&lt;/td&gt;
&lt;td&gt;В процессе отмены&lt;/td&gt;
&lt;td&gt;«Почему вы решили уйти именно сегодня?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;После выпуска того, что они просили&lt;/td&gt;
&lt;td&gt;Там, где они просили&lt;/td&gt;
&lt;td&gt;«Вы просили импорт CSV. Он готов. Он закрывает ваш случай?»&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Когда лучше всего просить обратную связь?&lt;/h2&gt;
&lt;p&gt;Лучшее время наступает сразу после того, как пользователь что-то закончил, пока детали ещё свежи в голове. Вопрос, идущий за действием, получает ответ об этом действии. Вопрос, пришедший ниоткуда, получает ответ о настроении человека в этот момент или не получает никакого.&lt;/p&gt;
&lt;p&gt;Не спрашивайте при регистрации, потому что никто ещё ничем не пользовался. Не спрашивайте посреди задачи, потому что вы прерываете то, о чём хотите узнать. А когда человек ответил, оставьте его в покое, пока вам нечего ему сообщить.&lt;/p&gt;
&lt;h2&gt;Где спрашивать обратную связь у клиентов?&lt;/h2&gt;
&lt;p&gt;Спрашивайте там, где произошёл опыт. Подсказка в приложении подходит для вопроса об экране. Переписка с поддержкой подходит для вопроса об исправлении. Письмо подходит для вопроса о неделе использования или о сценарии, который человек бросил. Звонок подходит для вопросов, которые нельзя предугадать.&lt;/p&gt;
&lt;p&gt;Каждый канал даёт ответы своего рода:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;В приложении:&lt;/strong&gt; коротко, сразу и конкретно, но только от тех, кто сейчас рядом. От ушедших пользователей вы не услышите ничего.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Переписка с поддержкой:&lt;/strong&gt; от людей, которым уже было достаточно плохо, чтобы написать. Хорошо для поиска сломанного, плохо для оценки остального продукта.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Письмо:&lt;/strong&gt; более длинные ответы от меньшего числа людей и единственный способ достучаться до замолчавших пользователей. Пишите его как короткую записку от человека с именем, с одним вопросом внутри.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Интервью:&lt;/strong&gt; способ понять, почему люди делают то, что делают. Попросите показать, как они работают, и молчите, пока они показывают.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;О том, как взвешивать то, что говорит каждый канал, рассказывает статья &lt;a href=&quot;https://changeloop.dev/blog/ru/feedback-signal-quality/&quot;&gt;качество сигнала в обратной связи&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Как профессионально попросить обратную связь?&lt;/h2&gt;
&lt;p&gt;Будьте конкретны в предмете, объясните, зачем спрашиваете, и сделайте так, чтобы ответ занимал меньше минуты. Профессиональная просьба называет момент, даёт понять, что ответ прочтёт человек, и не извиняется за беспокойство.&lt;/p&gt;
&lt;p&gt;Назовите точное действие («экспорт, который вы только что запустили»), просите об одном, дайте текстовое поле без обязательных полей и подпишитесь именем.&lt;/p&gt;
&lt;h2&gt;Какая фраза хороша для просьбы об обратной связи?&lt;/h2&gt;
&lt;p&gt;Хорошая фраза это вопрос о конкретном моменте, на который можно ответить несколькими словами. Сравните две колонки ниже. На левые можно ответить пожатием плеч. Правые требуют вспомнить что-то настоящее.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Слабый вопрос&lt;/th&gt;
&lt;th&gt;Сильный вопрос&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;«Есть отзывы?»&lt;/td&gt;
&lt;td&gt;«Что было самым трудным при настройке?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;«Как вам наш продукт?»&lt;/td&gt;
&lt;td&gt;«Для чего вы использовали это на прошлой неделе?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;«Оцените впечатление от 1 до 10.»&lt;/td&gt;
&lt;td&gt;«Вы сделали сегодня то, ради чего пришли?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;«Расскажите, как нам стать лучше.»&lt;/td&gt;
&lt;td&gt;«Что одно замедлило вас на этой неделе?»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;«Порекомендуете ли вы нас?»&lt;/td&gt;
&lt;td&gt;«Кому вы показывали это в последний раз и что сказали?»&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Ещё один вопрос, который работает почти везде: «Чем вы пользуетесь вместо этого, когда это вам не подходит?» Он выявляет настоящего конкурента, которым часто оказывается таблица.&lt;/p&gt;
&lt;h2&gt;Какие просьбы об обратной связи хуже всего?&lt;/h2&gt;
&lt;p&gt;Хуже всего просьбы слишком широкие, ранние, длинные или наводящие. У них общая проблема: человек не может ответить, не проделав мыслительную работу, которую должны были сделать вы.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;«Пожалуйста, заполните наш опрос из 20 вопросов».&lt;/strong&gt; Дойдут до конца те, у кого больше всего свободного времени или самые сильные мнения.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Всплывающее окно на первой странице после входа.&lt;/strong&gt; Пользователь пришёл что-то сделать, а вы ему помешали. Единственный разумный ответ на него это закрыть окно.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;«Мы будем рады вашему отзыву!» без вопроса.&lt;/strong&gt; Это просит пользователя самого придумать тему.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Наводящий вопрос: «Насколько вам нравится новая панель?»&lt;/strong&gt; Вы получите согласие и ничего не узнаете.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Оценка без уточняющего вопроса.&lt;/strong&gt; Шесть из десяти говорят о настроении. Что менять, они не говорят.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Спросить и замолчать.&lt;/strong&gt; Это стоит вам следующего раунда, о чём ниже.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Как называется обратная связь клиентов о продукте?&lt;/h2&gt;
&lt;p&gt;Обратную связь о продукте обычно называют отзывами о продукте, и она делится на два вида. Сообщение об ошибке говорит, что что-то работает не так, как задумано. Запрос на функцию говорит, что чего-то не хватает. От различия зависит, кто посмотрит первым, и эту границу проводит статья &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-vs-bug-report/&quot;&gt;запрос на функцию или ошибка&lt;/a&gt;. Третий вид, похвала, стоит сохранять и цитировать с разрешения.&lt;/p&gt;
&lt;p&gt;Форма обратной связи, которая первым выбором предлагает «Ошибка» и «Запрос на функцию», делает эту первую сортировку за вас.&lt;/p&gt;
&lt;h2&gt;Что делать с ответами?&lt;/h2&gt;
&lt;p&gt;Складывайте каждый ответ туда, где команда уже работает, сохраняя слова человека. Одна строка цитаты лучше вашего пересказа. Пометьте её типом и примерной срочностью, объедините повторы и решите: делать, отложить или отказать.&lt;/p&gt;
&lt;p&gt;Отказ тоже ответ. «Мы не будем это делать, и вот почему» заканчивает ожидание, а формулировки для него есть в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/declining-feature-requests/&quot;&gt;отказ в запросах на функции&lt;/a&gt;. Про техническую сторону рассказывает &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;отслеживание запросов на функции&lt;/a&gt;: как собрать запросы из пяти каналов в один список. Если вы принимаете запросы в письменном виде, &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-template/&quot;&gt;шаблон запроса на функцию&lt;/a&gt; делает их сопоставимыми.&lt;/p&gt;
&lt;p&gt;Виджет Changeloop заводит каждое обращение как GitHub issue, так что отзыв попадает рядом с кодом, который его исправит. С любым инструментом правило одно: один список, один владелец, ни одного ответа, забытого во входящих у кого-то в почте.&lt;/p&gt;
&lt;h2&gt;Зачем рассказывать о выпущенном?&lt;/h2&gt;
&lt;p&gt;Он показывает человеку, что ответ стоил его времени. Пользователь, который вам что-то сказал, а потом услышал «это выпущено, спасибо», получает причину ответить снова. Тот, кто не услышал ничего, делает вывод, что поле никто не читает.&lt;/p&gt;
&lt;p&gt;Поэтому последний шаг в просьбе об обратной связи это ответ. Сообщите каждому, кто просил, когда его запрос выпущен, в его терминах и по тому каналу, которым он пользовался. Механизм описан в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;как замкнуть петлю обратной связи клиента&lt;/a&gt;: опубликованная запись в changelog запускает сообщение, поэтому автору запроса говорят только тогда, когда изменение уже работает. В Changeloop, если отзыв из виджета стал задачей GitHub, а влитый pull request её закрывает, одобрение записи оставляет комментарий «Shipped» на этой задаче и показывает автору запись в виджете; для задач, заведённых вручную, и для репозиториев GitLab или Bitbucket комментарий не оставляется. Наша документация описывает &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;настройку виджета и ленты&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ответ может быть коротким: «Вы просили импорт CSV в марте. Сегодня он готов, вот как он работает». Он же даёт лучший следующий вопрос: закрывает ли это то, что было нужно.&lt;/p&gt;
&lt;h2&gt;С чего начать&lt;/h2&gt;
&lt;p&gt;Выберите один момент из таблицы в начале, тот, где пользователи чаще всего добиваются цели или сдаются. Напишите для него один вопрос, поставьте его в один канал и две недели читайте каждый ответ, прежде чем добавлять второй. Отвечайте всем, кто дал вам что-то конкретное.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Как часто стоит спрашивать клиентов об обратной связи?&lt;/strong&gt;
Привязывайте вопросы к событиям, а не к календарю. Пользователь должен видеть не больше одного вопроса в неделю и ни одного сразу после ответа на предыдущий. Следующим сообщением после отзыва должен быть ответ о том, что с ним стало.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как просить обратную связь, не раздражая пользователей?&lt;/strong&gt;
Спрашивайте после задачи, а не посреди неё, ограничьтесь одним вопросом и дайте возможность легко отказаться. Уважайте отказ несколько недель.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужно ли предлагать вознаграждение за обратную связь?&lt;/strong&gt;
Обычно не нужно. Конкретный вопрос и заметный ответ весят больше, чем подарочная карта, а вознаграждение привлекает тех, кому нужна награда. Оставьте его для интервью, где вы просите 20 минут чужого времени.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что делать, если никто не отвечает?&lt;/strong&gt;
Сузьте вопрос и приблизьте его к моменту, например один экран, вопрос сразу после его использования. Если тишина остаётся, напишите нескольким пользователям лично и используйте эти разговоры, чтобы составить вопросы получше.&lt;/p&gt;
</content:encoded></item><item><title>Примеры product roadmap: шесть форматов и их слабые места</title><link>https://changeloop.dev/blog/ru/product-roadmap-examples/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/product-roadmap-examples/</guid><description>Шесть примеров product roadmap с реалистичными пунктами: Now/Next/Later, квартальный, тематический, по результатам, публичный и релизный. Кому они нужны.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Примеры product roadmap, которые стоит брать за образец, делятся на шесть форматов: Now/Next/Later, квартальный график, тематический roadmap, roadmap по результатам, публичный roadmap и внутренний релизный roadmap. Каждый отвечает на свой вопрос для своего читателя, поэтому подходящий пример тот, что совпадает с вашим читателем. Внешний вид выбирается в последнюю очередь.&lt;/p&gt;
&lt;p&gt;Все примеры ниже относятся к выдуманному продукту, небольшому приложению для задач в команде, и все пункты придуманы. Важна форма: что стоит в каждой ячейке, как выглядит настоящая запись и из-за чего формат ломается через квартал.&lt;/p&gt;
&lt;h2&gt;Какие бывают хорошие примеры product roadmap?&lt;/h2&gt;
&lt;p&gt;Хороший пример roadmap короткий, адресован конкретному читателю и даёт обещание одного рода. Формат выбирают по тому обещанию, которое вы готовы выполнить: направление, дата, тема работ, результат, публичное обязательство или график поставки.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Формат&lt;/th&gt;
&lt;th&gt;Для кого&lt;/th&gt;
&lt;th&gt;Работает, когда&lt;/th&gt;
&lt;th&gt;Ломается, когда&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Now/Next/Later&lt;/td&gt;
&lt;td&gt;Вся компания&lt;/td&gt;
&lt;td&gt;Планы часто меняются&lt;/td&gt;
&lt;td&gt;«Next» разрастается и превращается в очередь&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Квартальный график&lt;/td&gt;
&lt;td&gt;Продажи, поддержка, руководство&lt;/td&gt;
&lt;td&gt;Даты действительно жёсткие&lt;/td&gt;
&lt;td&gt;Даты сдвигаются, а их никто не обновляет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Тематический&lt;/td&gt;
&lt;td&gt;Руководство, новички&lt;/td&gt;
&lt;td&gt;Нужно объяснить, зачем это делается&lt;/td&gt;
&lt;td&gt;Темы так широки, что подходит любой пункт&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;По результатам&lt;/td&gt;
&lt;td&gt;Продукт и разработка&lt;/td&gt;
&lt;td&gt;Цель можно измерить&lt;/td&gt;
&lt;td&gt;У метрики нет владельца или данных&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Публичный&lt;/td&gt;
&lt;td&gt;Клиенты&lt;/td&gt;
&lt;td&gt;Его удаётся держать небольшим&lt;/td&gt;
&lt;td&gt;Он превращается в свалку бэклога&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Внутренний релизный&lt;/td&gt;
&lt;td&gt;Разработка, QA, поддержка&lt;/td&gt;
&lt;td&gt;Несколько команд выпускают вместе&lt;/td&gt;
&lt;td&gt;Его принимают за стратегию&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Как выглядит каждый пример product roadmap?&lt;/h2&gt;
&lt;p&gt;Ниже каждый формат показан на реалистичных записях, а затем описано, кому он подходит, когда выдерживает нагрузку и как обычно ломается.&lt;/p&gt;
&lt;h3&gt;Now/Next/Later&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;NOW (делаем в этом месяце)
  Сохранённые виды во входящих
  Экспорт CSV, который работает на больших аккаунтах
NEXT (решено, порядок не зафиксирован)
  SSO для плана Team
  Уведомления в Slack
LATER (направление, без обязательств)
  Мобильное приложение
  Журнал аудита
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Этот формат подходит компании, которая не хочет обещать даты, а так живут многие команды на ранней стадии. Он держится потому, что три колонки описывают степень уверенности: «now» в работе, «next» решено, «later» надежда. Он ломается, когда «later» становится местом, куда складывают все идеи, которые жалко отклонить, и когда у «next» незаметно появляются порядок и дата, хотя вслух это никто не называет графиком.&lt;/p&gt;
&lt;h3&gt;Временная шкала, или квартальный roadmap&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Q4 2026
  Окт   Сохранённые виды во входящих
  Ноя   SSO в бете с пятью партнёрами
  Дек   SSO, общий доступ
Q1 2027
  Янв   Уведомления в Slack
  Мар   Журнал аудита (только экспорт)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Он подходит продажам, поддержке и финансам, которым нужно во что-то упираться при планировании. Работает, когда даты действительно жёсткие: контракт, конференция, срок по комплаенсу. Ломается, когда даты взяты с потолка, потому что месяц в roadmap через несколько недель превращается в обещание в презентации отдела продаж. Если вы выбрали этот формат, помечайте каждый квартал как «обязательство» или «прогноз» и делайте второй квартал заметно менее определённым, чем первый.&lt;/p&gt;
&lt;h3&gt;Тематический roadmap&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ТЕМА: Первая неделя в продукте
  Импорт из CSV и Trello
  Стартовые шаблоны
ТЕМА: Готовность к большим командам
  SSO
  Журнал аудита
  Права по ролям
ТЕМА: Меньше ручных действий
  Уведомления в Slack
  Повторяющиеся задачи
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Подходит для отчётов руководству и для новых сотрудников, потому что сначала объясняет, зачем нужна работа, и только потом перечисляет её. Держится, когда каждая тема соответствует причине, по которой клиенту это важно. Ломается, когда темы слишком широкие («Рост», «Качество»), так что любой пункт подходит под любую из них, и тогда группировка ничего не объясняет.&lt;/p&gt;
&lt;h3&gt;Roadmap по результатам&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ЦЕЛЬ: Больше новых команд завершают настройку
  Метрика: настройка за 7 дней, с 40% до 55%
  Ставки: импорт из CSV, стартовые шаблоны
ЦЕЛЬ: Меньше обращений по экспорту
  Метрика: обращений по экспорту в неделю, с 30 до 10
  Ставки: починка экспорта на больших аккаунтах,
  страница статуса экспорта
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Цифры условные, а важна раскладка: цель, одна метрика с исходным и целевым значением и ставки, которые вы собираетесь проверить. Формат подходит командам продукта и разработки, которым доверяют выбор решения. Работает, когда метрика существует и у неё есть владелец. Ломается, когда цель нельзя измерить или когда «ставки» остаются прежним списком функций, к которому сверху приклеили предложение про результат.&lt;/p&gt;
&lt;h3&gt;Публичный roadmap для клиентов&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ПЛАНИРУЕМ
  Сохранённые виды во входящих
В РАБОТЕ
  Уведомления в Slack
ВЫПУЩЕНО
  Экспорт CSV для больших аккаунтов
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Это самый маленький формат и самое сильное обещание. Он подходит клиентам, которые хотят знать, услышали ли их запрос. Держится при очень малом числе пунктов, без дат и с названиями словами клиента. Ломается, когда превращается в свалку бэклога: каждое «может быть» в списке это обещание, о котором кто-нибудь спросит позже. Как вести такой roadmap из трекера задач, описано в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;публичная roadmap в трёх колонках&lt;/a&gt;, поэтому здесь это не повторяется.&lt;/p&gt;
&lt;h3&gt;Внутренний релизный roadmap&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Релиз&lt;/th&gt;
&lt;th&gt;Срок&lt;/th&gt;
&lt;th&gt;Владелец&lt;/th&gt;
&lt;th&gt;Зависит от&lt;/th&gt;
&lt;th&gt;Статус&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;5.2&lt;/td&gt;
&lt;td&gt;14 окт&lt;/td&gt;
&lt;td&gt;Платформа&lt;/td&gt;
&lt;td&gt;Обновление сервиса авторизации&lt;/td&gt;
&lt;td&gt;Код готов&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.3&lt;/td&gt;
&lt;td&gt;11 ноя&lt;/td&gt;
&lt;td&gt;Входящие&lt;/td&gt;
&lt;td&gt;API сохранённых видов&lt;/td&gt;
&lt;td&gt;В работе&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.4&lt;/td&gt;
&lt;td&gt;9 дек&lt;/td&gt;
&lt;td&gt;Платформа&lt;/td&gt;
&lt;td&gt;Контракт с поставщиком SSO&lt;/td&gt;
&lt;td&gt;Заблокирован&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Он подходит разработке, QA и поддержке, которым нужно знать, что выходит вместе и что от чего зависит. Работает, когда точен до недели и у каждой строки есть владелец. Ломается, когда его принимают за стратегию: график поставки говорит, что и когда покидает здание, и ничего не говорит о том, были ли эти релизы правильными ставками.&lt;/p&gt;
&lt;h2&gt;Какой формат product roadmap выбрать?&lt;/h2&gt;
&lt;p&gt;Выбирайте сначала по читателю, затем по тому, насколько вы на самом деле уверены. Если вы не можете назвать, кто читает roadmap и какое решение он помогает принять, ни один из примеров выше его не спасёт.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Клиенты спрашивают: «вы меня услышали?»&lt;/strong&gt; Берите публичный формат и ограничьтесь горсткой пунктов.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Продажи и поддержка спрашивают: «можно назвать клиенту дату?»&lt;/strong&gt; Берите квартальный график, где обязательства и прогнозы чётко разделены.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Руководство спрашивает: «зачем эта работа?»&lt;/strong&gt; Берите темы, а если есть данные, то результаты.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Команда меняет направление каждый месяц.&lt;/strong&gt; Берите Now/Next/Later и не ставьте дат.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Инженеры спрашивают: «что и когда выходит?»&lt;/strong&gt; Берите релизный roadmap и держите его отдельно от стратегического.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Большинство команд в итоге ведут два документа: стратегический roadmap в одном из первых четырёх форматов и график релизов под ним. Публичный roadmap тогда становится отфильтрованным видом стратегического и показывает только то, за что вы готовы отвечать.&lt;/p&gt;
&lt;h2&gt;Как составить product roadmap?&lt;/h2&gt;
&lt;p&gt;Составляйте roadmap так: назовите читателя, выберите формат под его вопрос, внесите только пункты, которые вы готовы защищать на встрече, и дайте каждому статус и владельца. Затем решите, как часто его будут пересматривать, прежде чем публиковать.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Назовите читателя и решение.&lt;/strong&gt; «Поддержка решает, что говорить клиентам про SSO» это причина. «Все должны видеть roadmap» не даёт ничего, под что можно проектировать.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Начните с того, что уже знаете.&lt;/strong&gt; Открытые запросы, &lt;a href=&quot;https://changeloop.dev/blog/ru/prioritizing-feature-requests/&quot;&gt;упорядоченные по понятному правилу&lt;/a&gt;, лучший материал, чем мозговой штурм.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Пишите каждый пункт как результат для клиента.&lt;/strong&gt; «Сохранять фильтр, которым пользуешься часто» читается лучше, чем «Реализовать сохранение состояния видов», и сразу показывает клиенту, его ли это проблема.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Решите, чего в roadmap не будет.&lt;/strong&gt; Обычно это даты, оценки и склад идей.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Назначьте дату пересмотра.&lt;/strong&gt; У roadmap без запланированного пересмотра есть незапланированные похороны.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Как поддерживать product roadmap в актуальном состоянии?&lt;/h2&gt;
&lt;p&gt;Поддерживайте актуальность, двигая пункты, когда движется работа, и из того же места, где работа отслеживается, а когда пункт выпущен или отброшен, записывайте, что произошло. Roadmap, который кто-то правит вручную в отдельном инструменте, устаревает, потому что это ничья ежедневная задача.&lt;/p&gt;
&lt;p&gt;Самый дешёвый источник правды это трекер задач. Если каждая колонка roadmap соответствует метке на задаче, roadmap меняется вместе с меткой, и ничего не набирается заново. В Changeloop это устроено через метки &lt;code&gt;roadmap:planned&lt;/code&gt;, &lt;code&gt;roadmap:building&lt;/code&gt; и &lt;code&gt;roadmap:shipped&lt;/code&gt;, а когда на задаче две метки, побеждает самая продвинутая. Перенос карточки в «выпущено» остаётся отдельной сменой метки, поэтому сделайте его частью проверки, на которой вы одобряете запись в changelog.&lt;/p&gt;
&lt;p&gt;Эта запись вторая половина дела. Когда пункт выпущен, changelog описывает изменение в терминах клиента, а тому, кто просил об этом, можно сообщить. Замкнуть эту петлю и есть смысл &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;петли обратной связи клиента&lt;/a&gt;, а roadmap это отрезок этой петли, который клиент видит до того, как что-либо выпущено. Если вы отказались от пункта, скажите об этом; публичное «нет» закрывает и этот запрос, а как его сформулировать, описано в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/declining-feature-requests/&quot;&gt;отказ в запросах на функции&lt;/a&gt;. Тем, кто хочет увидеть, как читаются готовые записи, пригодятся &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Какой формат product roadmap самый простой?&lt;/strong&gt;
Now/Next/Later. В нём три колонки, не нужны даты, а пункты группируются по степени уверенности. Для небольшой команды, которая часто меняет направление, в нём ещё и труднее всего опозориться.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сколько пунктов должно быть в product roadmap?&lt;/strong&gt;
Меньше, чем вам кажется. Публичному roadmap хватает менее десяти пунктов на все колонки, а внутреннему стратегическому редко нужно больше дюжины. Сверх этого получается бэклог с красивым заголовком.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужно ли указывать даты в product roadmap?&lt;/strong&gt;
Только если даты действительно жёсткие, и то лишь для ближайшего квартала. Дальше используйте колонки или темы. Дата в roadmap становится обязательством в разговоре с продажами, хотите вы этого или нет.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Чем product roadmap отличается от плана релизов?&lt;/strong&gt;
Roadmap говорит, что вы собираетесь строить и зачем. План релизов говорит, какая сборка выходит в какую дату и кто за неё отвечает. Roadmap меняется, когда меняется стратегия, а план релизов меняется, когда меняется работа.&lt;/p&gt;
</content:encoded></item><item><title>Процесс управления релизами для частых выпусков</title><link>https://changeloop.dev/blog/ru/release-management-process/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/release-management-process/</guid><description>Процесс управления релизами для софтверных команд в семь шагов, с владельцем и критерием выхода для каждого, плюс метрики DORA и ещё один показатель.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Процесс управления релизами это набор шагов, который доводит изменение от состояния «влито» до состояния «работает в продакшене и объяснено тем, кого оно касается». Для команды, которая выпускает часто, он сводится к семи шагам: спланировать объём, изолировать изменение, собрать и протестировать, одобрить, выкатить и проверить, сообщить и разобрать итоги. У каждого шага должен быть один названный владелец и один критерий выхода, иначе шаг тихо перестаёт выполняться.&lt;/p&gt;
&lt;p&gt;Это руководство рассчитано на команду из 5-50 инженеров, которая выкатывает раз в неделю или каждый день и хочет, чтобы процесс не мешал.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Шаг&lt;/th&gt;
&lt;th&gt;Владелец&lt;/th&gt;
&lt;th&gt;Критерий выхода&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1. Спланировать объём&lt;/td&gt;
&lt;td&gt;Продакт или техлид&lt;/td&gt;
&lt;td&gt;Список изменений в этом релизе записан, рискованное отмечено&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Ветка или флаг&lt;/td&gt;
&lt;td&gt;Инженер, которому принадлежит изменение&lt;/td&gt;
&lt;td&gt;Работа в короткоживущей ветке или за флагом, так что main остаётся готовым к выпуску&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Сборка и тесты&lt;/td&gt;
&lt;td&gt;CI, автор на связи при сбоях&lt;/td&gt;
&lt;td&gt;Пайплайн зелёный на том самом коммите, который пойдёт в релиз&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Одобрение&lt;/td&gt;
&lt;td&gt;Ревьюер, а для рискованных изменений ещё и релиз-менеджер&lt;/td&gt;
&lt;td&gt;Ревью пройдено, путь отката назван, решение «go» или «no-go» записано&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Выкатка и проверка&lt;/td&gt;
&lt;td&gt;Релиз-менеджер или дежурный инженер&lt;/td&gt;
&lt;td&gt;Выкачено, smoke-проверки проходят, доля ошибок и задержка совпадают с уровнем до релиза&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Сообщить&lt;/td&gt;
&lt;td&gt;Тот, кто понимает изменение, с правкой от того, кто не понимает&lt;/td&gt;
&lt;td&gt;Release notes опубликованы там, где их читают пользователи, поддержка и продажи в курсе&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. Разбор итогов&lt;/td&gt;
&lt;td&gt;Релиз-менеджер&lt;/td&gt;
&lt;td&gt;Метрики прочитаны, у всего, что пошло не так, есть владелец и исправление&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что такое процесс управления релизами?&lt;/h2&gt;
&lt;p&gt;Это повторяемый путь, который проходит изменение, чтобы дойти до пользователей: объём, сборка, тесты, одобрение, выкатка, проверка, объявление и взгляд назад. Смысл записать его в том, что каждый релиз идёт одним и тем же путём, и тот, кто в отпуске, новичок или дежурный инженер в два часа ночи могут пройти его, не спрашивая никого, как это делается.&lt;/p&gt;
&lt;h2&gt;Какие бывают типы управления релизами?&lt;/h2&gt;
&lt;p&gt;Есть три практических типа: непрерывная выкатка, релизы по расписанию и регулируемое управление изменениями. Они различаются тем, сколько происходит до релиза и сколько автоматизировано. Непрерывная выкатка выпускает каждое влитое изменение, релизы по расписанию собирают изменения в «поезд», а регулируемое управление изменениями добавляет формальное одобрение и журнал для аудита.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Непрерывная выкатка&lt;/th&gt;
&lt;th&gt;Релизы по расписанию&lt;/th&gt;
&lt;th&gt;Регулируемое управление изменениями (ITIL)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Единица релиза&lt;/td&gt;
&lt;td&gt;Один влитый pull request&lt;/td&gt;
&lt;td&gt;Пакет, раз в неделю или две&lt;/td&gt;
&lt;td&gt;Запрос на изменение&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Шаг объёма&lt;/td&gt;
&lt;td&gt;Неявный, объём это слияние&lt;/td&gt;
&lt;td&gt;Встреча по планированию релиза&lt;/td&gt;
&lt;td&gt;Запись об изменении с оценкой риска&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Одобрение&lt;/td&gt;
&lt;td&gt;Ревью кода и автоматические проверки&lt;/td&gt;
&lt;td&gt;Релиз-менеджер подписывает пакет&lt;/td&gt;
&lt;td&gt;Совет по изменениям или делегированный утверждающий&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Контроль риска&lt;/td&gt;
&lt;td&gt;Флаги функций, канарейки, быстрый откат&lt;/td&gt;
&lt;td&gt;Выдержка на стенде, релиз-кандидат&lt;/td&gt;
&lt;td&gt;Задокументированный план отката, окно обслуживания&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Обычный ритм&lt;/td&gt;
&lt;td&gt;Много раз в день&lt;/td&gt;
&lt;td&gt;От раза в неделю до раза в месяц&lt;/td&gt;
&lt;td&gt;Задаётся календарём изменений&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Слабое место&lt;/td&gt;
&lt;td&gt;Никто не говорит пользователям, что изменилось&lt;/td&gt;
&lt;td&gt;Большие пакеты прячут изменение, которое всё сломало&lt;/td&gt;
&lt;td&gt;Время на процесс превышает время самого изменения&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Большинство команд смешивают подходы. SaaS-продукт может выкатываться непрерывно, мобильное приложение выходить еженедельным «поездом», а единственный платёжный сервис, который интересует аудиторов, идти по формальной записи об изменении. Выбирайте тип для каждого сервиса, а не для всей компании. Там, где изменения открываются постепенно, выпуск и объявление становятся отдельными событиями, и этот случай разобран в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-flags-feature-requests/&quot;&gt;release notes для функций за флагом&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Какие обязанности у релиз-менеджера?&lt;/h2&gt;
&lt;p&gt;Релиз-менеджер отвечает за путь, который изменение проходит до продакшена. Он ведёт календарь релизов, решает, готово ли изменение, запускает или контролирует выкатку, принимает решение об откате, следит, чтобы пользователям сообщили, и проводит разбор после.&lt;/p&gt;
&lt;p&gt;Перед релизом он подтверждает объём и проверяет, что у каждого рискованного изменения есть путь отката. Во время релиза проходит по чек-листу выкатки, следит за метриками продакшена в первые минуты и откатывает без промедления. После релиза убеждается, что заметки вышли, и записывает, что исправить в процессе.&lt;/p&gt;
&lt;p&gt;В небольшой команде меняйте эту роль каждую неделю и пишите чек-лист так, чтобы не требовалось устное знание. &lt;a href=&quot;https://changeloop.dev/blog/ru/monorepo-changelogs/&quot;&gt;Монорепозиторию&lt;/a&gt; со множеством независимо выпускаемых пакетов обычно нужен владелец релиза на каждый пакет, иначе роль превращается в узкое место.&lt;/p&gt;
&lt;h2&gt;Какие ключевые KPI у управления релизами?&lt;/h2&gt;
&lt;p&gt;Отслеживайте метрики доставки ПО DORA и добавьте одну свою: сколько времени проходит, прежде чем пользователям сообщат. Исследование DORA выделяет пять метрик, разделённых на пропускную способность (время изменения до выкатки, частота выкатки, время восстановления после неудачной выкатки) и нестабильность (доля неудачных изменений, доля доработок после выкатки).&lt;/p&gt;
&lt;p&gt;Руководство DORA определяет их простыми словами (&lt;a href=&quot;https://dora.dev/guides/dora-metrics/&quot;&gt;dora.dev, software delivery metrics&lt;/a&gt;):&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;KPI&lt;/th&gt;
&lt;th&gt;Что измеряет&lt;/th&gt;
&lt;th&gt;На что смотреть&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Время изменения (change lead time)&lt;/td&gt;
&lt;td&gt;Время от коммита в системе контроля версий до выкатки в продакшен&lt;/td&gt;
&lt;td&gt;Рост обычно означает очереди на ревью или одобрение&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Частота выкатки&lt;/td&gt;
&lt;td&gt;Как часто вы выкатываете или сколько проходит между выкатками&lt;/td&gt;
&lt;td&gt;Падение частоты значит, что пакеты растут&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Время восстановления после неудачной выкатки&lt;/td&gt;
&lt;td&gt;Время восстановления после выкатки, которая требует немедленного вмешательства&lt;/td&gt;
&lt;td&gt;Здесь видны проблемы с откатом и алертами&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Доля неудачных изменений&lt;/td&gt;
&lt;td&gt;Доля выкаток, которым нужен откат или хотфикс&lt;/td&gt;
&lt;td&gt;Растёт, когда пакеты слишком велики или тестов мало&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Доля доработок после выкатки&lt;/td&gt;
&lt;td&gt;Доля незапланированных выкаток, вызванных инцидентом в продакшене&lt;/td&gt;
&lt;td&gt;Признак того, что исправления выходят быстрее, чем усваиваются уроки&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Время до уведомления пользователей&lt;/td&gt;
&lt;td&gt;Минуты от выкатки в продакшен до опубликованной пользовательской заметки&lt;/td&gt;
&lt;td&gt;Измеряйте сами, ни один фреймворк этого не даёт&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;В более старых материалах говорится о четырёх ключевых метриках, а восстановление называется «time to restore». В нынешнем руководстве используются пять метрик выше.&lt;/p&gt;
&lt;p&gt;То же руководство предостерегает от превращения их в цели. Установка вроде «к концу года всё выкатывается несколько раз в день» побуждает команды подгонять цифры, а сами метрики предназначены для чтения по каждому приложению или сервису, а не усреднённо по компании. Его практический совет для улучшения всех метрик: уменьшать размер каждого изменения, потому что мелкие изменения легче проверять, проводить через пайплайн и откатывать.&lt;/p&gt;
&lt;h2&gt;Как коммуникация о релизе вписывается в процесс управления релизами?&lt;/h2&gt;
&lt;p&gt;Это шаг шесть, и у него, как у любого другого, есть владелец и критерий выхода: заметки опубликованы там, где их читают пользователи, и внутренние команды в курсе. Чаще всего этот шаг пропускают, потому что инструменты выкатки сообщают об успехе в тот момент, когда код уже работает.&lt;/p&gt;
&lt;p&gt;Самый дешёвый способ держать этот шаг в графике: писать запись, когда изменение вливается, а не когда релиз выходит. В pull request уже есть заголовок, автор, связанная задача и контекст. Черновик, собранный из него, правят, а не пишут по памяти неделю спустя. На этом строится идея &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;автоматизации changelog&lt;/a&gt;: получить черновик при слиянии, удержать его до одобрения человеком и опубликовать везде из одного источника. Changeloop работает именно так: составляет записи из влитых pull request с помощью ИИ и удерживает их до одобрения, прежде чем что-либо публикуется.&lt;/p&gt;
&lt;p&gt;Стоит заранее предусмотреть два варианта. Поддержке и продажам нужна другая заметка, чем клиентам, и для этого существуют &lt;a href=&quot;https://changeloop.dev/blog/ru/internal-release-notes/&quot;&gt;внутренние release notes&lt;/a&gt;. У релиза, вызванного инцидентом, нет времени на обычный цикл черновиков, поэтому держите короткий шаблон наготове, как описано в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/emergency-release-notes/&quot;&gt;экстренные release notes&lt;/a&gt;. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;Шаблон release notes&lt;/a&gt; даёт исходную форму для пользовательской версии.&lt;/p&gt;
&lt;h2&gt;Как сохранить процесс лёгким?&lt;/h2&gt;
&lt;p&gt;Автоматизируйте каждый критерий выхода, который может проверить машина, а людям оставьте суждения. Зелёный пайплайн, отметка выкатки на дашбордах и черновик записи в changelog на каждый влитый pull request проверяются машиной. Убедителен ли план отката и понятны ли заметки клиенту, решает человек.&lt;/p&gt;
&lt;p&gt;Чтобы проверить процесс, возьмите релиз прошлого месяца и спросите, мог ли человек вне команды по одной только письменной записи понять, что выпущено, кто одобрил, как проверено и когда пользователям сообщили. Любой пробел это ваше следующее улучшение.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Чем управление релизами отличается от управления изменениями?&lt;/strong&gt;
Управление релизами собирает, тестирует, выкатывает и объявляет набор изменений. Управление изменениями в смысле ITIL это процесс одобрения и оценки риска вокруг каждого изменения. Команды, которые выпускают часто, вносят одобрение в ревью кода и автоматические проверки.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как часто нужно выпускать релизы?&lt;/strong&gt;
Так часто, как позволяют ваши тесты и путь отката, а для многих веб-команд это ежедневно и чаще. Совет DORA: уменьшать размер каждого изменения, потому что мелкие изменения легче проверять и откатывать.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли небольшим командам релиз-менеджер?&lt;/strong&gt;
Им нужны обязанности, но не обязательно должность. Меняйте роль между инженерами, дайте дежурному письменный чек-лист и убедитесь, что у каждого из семи шагов есть владелец.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что должен включать чек-лист релиза?&lt;/strong&gt;
Подтверждённый объём, зелёный пайплайн на выпускаемом коммите, названный путь отката, записанное одобрение, smoke-проверки после выкатки, сравнение метрик с исходным уровнем, опубликованные release notes, уведомлённая поддержка и назначенный разбор. Умещайте на одной странице.&lt;/p&gt;
</content:encoded></item><item><title>Примеры release notes для каждого вида изменений</title><link>https://changeloop.dev/blog/ru/release-notes-examples/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/release-notes-examples/</guid><description>Примеры release notes для новой функции, исправления, breaking change, уязвимости, депрекации, заметки в сторе и внутренней заметки, с разбором слов.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Лучшие примеры release notes коротки, называют, кого это касается, и говорят, что делать дальше. Ниже по одному примеру на каждый вид изменений, который вам предстоит выпускать, с объяснением, почему он работает, чтобы вы могли взять форму и подставить свои факты.&lt;/p&gt;
&lt;p&gt;Все примеры выдуманы, для вымышленного приложения для выставления счетов Tidepool.&lt;/p&gt;
&lt;h2&gt;Что общего у хороших примеров release notes?&lt;/h2&gt;
&lt;p&gt;Они говорят пользователям, что изменилось и что им с этим делать, если нужно что-то делать, и говорят это словами пользователей. У каждого вида изменений своя задача, поэтому форма записи от вида к виду меняется.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Вид изменения&lt;/th&gt;
&lt;th&gt;Запись должна сказать&lt;/th&gt;
&lt;th&gt;Где размещать&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Новая функция&lt;/td&gt;
&lt;td&gt;Что читатель теперь может и у кого это есть&lt;/td&gt;
&lt;td&gt;Начало заметок&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Улучшение&lt;/td&gt;
&lt;td&gt;Что стало быстрее или проще, с цифрой, если она есть&lt;/td&gt;
&lt;td&gt;После функций&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Исправление бага&lt;/td&gt;
&lt;td&gt;Симптом, который видел читатель, и что он исправлен&lt;/td&gt;
&lt;td&gt;После улучшений&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Breaking change&lt;/td&gt;
&lt;td&gt;Кого касается, дата, миграция&lt;/td&gt;
&lt;td&gt;Всегда первым&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Исправление уязвимости&lt;/td&gt;
&lt;td&gt;Что было открыто, использовали ли это, что делать&lt;/td&gt;
&lt;td&gt;Первым&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Депрекация&lt;/td&gt;
&lt;td&gt;Что исчезает, дата окончания, замена&lt;/td&gt;
&lt;td&gt;Ближе к началу&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Заметка в сторе&lt;/td&gt;
&lt;td&gt;Одно простое предложение на изменение, в пределах лимита символов&lt;/td&gt;
&lt;td&gt;Страница в сторе&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Внутренняя заметка&lt;/td&gt;
&lt;td&gt;Что изменилось и что говорить клиентам&lt;/td&gt;
&lt;td&gt;Каналы поддержки и продаж&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Как выглядит хорошая заметка о новой функции?&lt;/h2&gt;
&lt;p&gt;Хорошая заметка о функции начинается с того, что читатель теперь может сделать, и называет планы или роли, которым это доступно. Реализацию она пропускает.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Отправляйте счета на языке клиента.&lt;/strong&gt;
Теперь для каждого клиента можно выбрать язык, и его счета, напоминания и страница оплаты будут
на нём. Французский, немецкий, испанский и португальский доступны на всех планах. Настройка
находится на странице клиента, в разделе «Настройки оплаты».&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Заголовок это фраза, которую читатель сказал бы вслух, а текст даёт охват и место настройки. Читатель, пробежавший глазами только жирную строку, всё равно знает, что выпущено. Общий метод разобран в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;как писать release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Как выглядит хорошая заметка об улучшении?&lt;/h2&gt;
&lt;p&gt;Заметка об улучшении описывает изменение, которое читатель почувствует, и ставит измеренную цифру, если она есть. Если цифры нет, скажите, что читателю больше не нужно делать.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Список счетов загружается примерно в три раза быстрее.&lt;/strong&gt;
Аккаунты с более чем 5 000 счетов раньше ждали список около девяти секунд. Теперь он
открывается примерно за три. Действий не требуется.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;«Улучшения производительности» ничего не говорят читателю, а девять секунд против трёх это утверждение, которое он проверит в понедельник утром. Завершающее «Действий не требуется» отвечает на вопрос, который есть у каждого читателя.&lt;/p&gt;
&lt;h2&gt;Как выглядит хорошая заметка об исправлении бага?&lt;/h2&gt;
&lt;p&gt;Заметка об исправлении описывает симптом, который видел пользователь, а не причину в коде, и говорит, нужно ли ему что-то повторять. Исправления, которых никто не заметил, можно вынести в список внизу.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Исправлено: напоминания уходили дважды в день оплаты.&lt;/strong&gt;
Некоторые клиенты получали по два одинаковых напоминания, если срок счёта выпадал на последний
день месяца. Это исправлено. Уже отправленные напоминания не затронуты, и повторно
отправлять ничего не нужно.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Заголовок начинается со слова «Исправлено», чтобы пробегающий глазами мог отсортировать запись с первого взгляда, а настоящее условие (последний день месяца) идёт сразу следом.&lt;/p&gt;
&lt;h2&gt;Как писать release notes о breaking change?&lt;/h2&gt;
&lt;p&gt;Заметка о breaking change начинается с даты и затронутой группы, а затем в той же записи даёт миграцию. В release notes она идёт первой, потому что это единственная запись, которую читатель не должен пропустить.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Подписи вебхуков станут обязательными с 1 декабря 2026 года.&lt;/strong&gt;
С этой даты Tidepool перестаёт отправлять неподписанные payload вебхуков. Это касается всех,
кто принимает вебхуки без проверки заголовка &lt;code&gt;Tidepool-Signature&lt;/code&gt;. Для миграции проверяйте
заголовок с помощью секрета в разделе «Настройки, Разработчикам». Если вы уже проверяете
подписи, действий не требуется.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Дата стоит в заголовке, поэтому переживает беглое чтение. Затронутая группа названа по тому, что она делает, а последнее предложение отпускает тех, у кого всё в порядке, и это снижает нагрузку на поддержку. Руководство по &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;breaking changes&lt;/a&gt; объясняет, как решить, считается ли изменение таковым.&lt;/p&gt;
&lt;h2&gt;Как выглядит заметка об исправлении уязвимости?&lt;/h2&gt;
&lt;p&gt;Заметка о безопасности говорит, что было открыто, использовал ли это кто-нибудь, кого это касается и что им нужно сделать. Пишите фактами и спокойно.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Безопасность: ссылки для сброса пароля можно было использовать повторно.&lt;/strong&gt;
С 3 по 17 сентября 2026 года ссылка для сброса пароля оставалась действительной после первого
использования. Признаков того, что этим пользовались, мы не нашли. Это исправлено, а все
неиспользованные ссылки аннулированы. Если вы запрашивали сброс в этот период, запросите новую
ссылку.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Точный период позволяет читателю оценить собственный риск, а фраза об использовании отвечает на первый вопрос, который задаёт любой. «Потенциальная проблема» выглядит как сокрытие, поэтому пишите то, что вам известно.&lt;/p&gt;
&lt;h2&gt;Как написать уведомление о депрекации?&lt;/h2&gt;
&lt;p&gt;Уведомление о депрекации называет, что убирается, даёт твёрдую дату окончания и указывает замену.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Endpoint счетов v1 объявлен устаревшим и перестанет работать 1 марта 2027 года.&lt;/strong&gt;
&lt;code&gt;GET /v1/invoices&lt;/code&gt; продолжает работать до 1 марта 2027 года, после чего будет возвращать
&lt;code&gt;410 Gone&lt;/code&gt;. Используйте &lt;code&gt;GET /v2/invoices&lt;/code&gt;, который возвращает те же поля плюс &lt;code&gt;currency&lt;/code&gt;.
Ответы v1 теперь содержат заголовок &lt;code&gt;Sunset&lt;/code&gt; с датой окончания. Руководство по миграции
с примерами рядом есть в документации.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Название endpoint стоит в заголовке, потому что те, кого это касается, ищут именно его, а замена стоит рядом с удалением. Заголовок &lt;code&gt;Sunset&lt;/code&gt; показывает разработчикам, какие вызовы всё ещё идут на старую версию. Более подробно это разобрано в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;депрекация API&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Как выглядит заметка о релизе в сторе приложений?&lt;/h2&gt;
&lt;p&gt;Заметка в сторе это два-три простых предложения, потому что большинство читает только первую строку. Начните с изменения, которое пользователь заметит.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Сфотографируйте бумажный чек, и Tidepool сам заполнит сумму, дату и поставщика. Тёмная тема
теперь следует настройке телефона. Ещё мы исправили падение при открытии счёта из уведомления.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Самое полезное изменение стоит первым, а исправление называет ситуацию, в которой было падение. Нет номера версии и нет фразы «исправления ошибок и улучшения». Правила, специфичные для сторов, разобраны в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/mobile-app-release-notes/&quot;&gt;release notes для мобильных приложений&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Что должна включать внутренняя заметка о релизе?&lt;/h2&gt;
&lt;p&gt;Внутренняя заметка это версия для поддержки и продаж. Она добавляет то, что публичная заметка опускает: что говорить и что не обещать.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Счета на нескольких языках выпущены сегодня (все планы).&lt;/strong&gt;
Поддержка: клиенты задают язык в «Настройках оплаты», а уже выставленные счета сохраняют
исходный язык. Итальянского пока нет. Продажи: функция открыта на всех планах, так что не
подавайте её как повод для апгрейда.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;У каждой аудитории своя подписанная строка, а заметка проводит границу («Итальянского пока нет») раньше, чем клиент спросит. Формат и каналы разобраны в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/internal-release-notes/&quot;&gt;внутренние release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Как выглядит плохая заметка о релизе после переписывания?&lt;/h2&gt;
&lt;p&gt;Плохая заметка перечисляет, что сделала команда, а не что получает читатель. Исправьте её, вынеся результат вперёд и убрав внутренний словарь.&lt;/p&gt;
&lt;p&gt;До:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;v3.8.1&lt;/strong&gt; Рефакторинг планировщика напоминаний. Исправлено состояние гонки в &lt;code&gt;ReminderJob&lt;/code&gt;.
Обновлён &lt;code&gt;bull&lt;/code&gt; до 4.12. Прочие улучшения.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;После:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Напоминания больше не уходят дважды.&lt;/strong&gt;
Клиенты со счётом, срок которого выпадал на последний день месяца, могли получить два
напоминания. Это исправлено, а уже отправленные напоминания повторно отправлять не нужно.
Действий не требуется.&lt;/p&gt;
&lt;p&gt;Также в 3.8.1: &lt;code&gt;bull&lt;/code&gt; обновлён до 4.12.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Обновление зависимости опустилось в строку внизу, а состояние гонки стало симптомом, который клиент узнает.&lt;/p&gt;
&lt;h2&gt;Как сохранять единообразие release notes от релиза к релизу?&lt;/h2&gt;
&lt;p&gt;Составляйте черновик каждой записи, когда изменение вливается, и пусть человек одобряет его до выпуска.&lt;/p&gt;
&lt;p&gt;Changeloop работает именно так: он составляет запись из каждого влитого pull request с помощью ИИ и удерживает её до одобрения человеком. На шаге одобрения редактор применяет правила выше. Чтобы сначала определиться с форматом, начните с &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;шаблона release notes&lt;/a&gt;, а как выглядят готовые страницы, смотрите в &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примерах changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Что такое новые release notes?&lt;/strong&gt;
Новые release notes это сообщение, которое публикуется вместе с последним релизом продукта и описывает, что изменилось и что нужно сделать пользователям. Они охватывают функции, улучшения, исправления и breaking changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Чем release note отличается от changelog?&lt;/strong&gt;
Changelog хранит всё, для всех, кому нужна вся история. Release note выбирает из него: один релиз, написанный для читателей, которые решают, важен ли он им. Полное сравнение есть в статье &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;changelog vs release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что значит release notes?&lt;/strong&gt;
Release notes сообщают пользователям, что изменилось в релизе. Так называют всё, что объясняет, что выпущено, от текста «Что нового» в сторе приложений до страницы на сайте компании.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой длины должна быть каждая запись в release notes?&lt;/strong&gt;
Для большинства записей хватает двух-четырёх предложений: результат, кого это касается и что делать. Breaking change или исправление уязвимости могут быть длиннее, потому что им нужны дата или миграция.&lt;/p&gt;
</content:encoded></item><item><title>Версионирование API Stripe: как оно работает и что перенять</title><link>https://changeloop.dev/blog/ru/stripe-api-versioning/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/stripe-api-versioning/</guid><description>Версионирование API Stripe привязывает аккаунт к версии с датой и даёт переопределить её в запросе. Как это работает, чего стоит и что взять малому API.</description><pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Версионирование API Stripe устроено по датам. Каждый аккаунт привязан к версии API, названной по дате релиза, а любой отдельный запрос может переопределить эту привязку заголовком &lt;code&gt;Stripe-Version&lt;/code&gt;. На момент написания (октябрь 2026 года) текущая версия в документации Stripe это &lt;code&gt;2026-09-30.endive&lt;/code&gt;, и ту же схему гораздо меньший API может повторить за выходные.&lt;/p&gt;
&lt;p&gt;Все факты о Stripe ниже взяты со страниц самого Stripe, со ссылками там, где они используются.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Механизм&lt;/th&gt;
&lt;th&gt;Что делает Stripe&lt;/th&gt;
&lt;th&gt;Источник&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Название версии&lt;/td&gt;
&lt;td&gt;Дата, а с 2024 года ещё и название релиза (&lt;code&gt;2026-09-30.endive&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Versioning&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Версия по умолчанию&lt;/td&gt;
&lt;td&gt;Закреплена за аккаунтом, меняется в Workbench&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Versioning&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Переопределение в запросе&lt;/td&gt;
&lt;td&gt;Заголовок &lt;code&gt;Stripe-Version&lt;/code&gt; или параметр SDK&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/upgrades&quot;&gt;Upgrades&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Вебхуки&lt;/td&gt;
&lt;td&gt;Формируются в версии, заданной для endpoint&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/upgrades&quot;&gt;Upgrades&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ритм&lt;/td&gt;
&lt;td&gt;Ежемесячные релизы без breaking changes, мажорный релиз дважды в год&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Versioning&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Старые версии&lt;/td&gt;
&lt;td&gt;Продолжают работать благодаря внутренним модулям изменения версии&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://stripe.com/blog/api-versioning&quot;&gt;Engineering post&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Как работает версионирование API Stripe?&lt;/h2&gt;
&lt;p&gt;Stripe даёт каждому аккаунту версию API по умолчанию, и каждый запрос, не называющий версию, использует её. Вызывающие сами выбирают, когда переходить: меняют версию по умолчанию или задают версию в отдельных запросах.&lt;/p&gt;
&lt;p&gt;В инженерной статье Stripe сказано, что аккаунт закрепляется при первом запросе к API: он «автоматически закрепляется за самой свежей доступной версией», и с тех пор каждому вызову неявно присваивается эта версия.&lt;/p&gt;
&lt;p&gt;Строка версии это дата. Начиная с релиза &lt;code&gt;2024-09-30.acacia&lt;/code&gt; в ней есть ещё и название, как в &lt;code&gt;2026-09-30.endive&lt;/code&gt;. Дата упорядочивает версии, а название показывает, к какому семейству мажорных релизов версия относится.&lt;/p&gt;
&lt;h2&gt;Как выбрать версию для отдельного запроса?&lt;/h2&gt;
&lt;p&gt;Отправьте в запросе заголовок &lt;code&gt;Stripe-Version&lt;/code&gt; или задайте версию в SDK. Руководство Stripe по обновлению показывает форму с заголовком, и тот же вызов работает и в боевой, и в тестовой среде.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl https://api.stripe.com/v1/charges \
  -u &amp;quot;$STRIPE_SECRET_KEY:&amp;quot; \
  -H &amp;quot;Stripe-Version: 2026-09-30.endive&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В руководстве Stripe отмечено, что если вы задаёте версию глобально или для запроса в SDK, объекты в ответах приходят в этой версии.&lt;/p&gt;
&lt;p&gt;Stripe также советует не полагаться на версию аккаунта по умолчанию. По его словам, указывайте версию в каждом запросе, заголовком или закреплённым SDK, чтобы версию определял ваш код, а не настройка в панели.&lt;/p&gt;
&lt;p&gt;SDK закрепляют версию по-разному в зависимости от языка. В документации сказано, что свежие версии библиотек для динамически типизированных языков используют ту версию API, которая была последней на момент выхода релиза SDK, а строго типизированные (Java, Go и .NET) жёстко к ней привязаны. Установить версию библиотеки значит, по сути, выбрать версию API.&lt;/p&gt;
&lt;h2&gt;Что происходит с вебхуками при смене версии?&lt;/h2&gt;
&lt;p&gt;Событие вебхука формируется в версии API, привязанной к его endpoint, а не в той, которую использует код вашего сервера. В документации Stripe сказано, что события используют версию, заданную при создании endpoint, а если её нет, то версию аккаунта по умолчанию. Смена версии SDK не меняет то, что получает ваш обработчик вебхуков.&lt;/p&gt;
&lt;p&gt;Поэтому путь запросов и путь событий могут находиться на двух разных версиях. Для приёмников событий &lt;code&gt;snapshot_api_version&lt;/code&gt; задаётся только при создании приёмника, так что другая версия означает новый приёмник.&lt;/p&gt;
&lt;p&gt;Путь обновления у Stripe для этого такой: параллельный запуск. Создайте новый endpoint с целевой версией, отправляйте одни и те же события на оба, научите обработчик обрабатывать один и игнорировать другой, затем переключитесь и отключите старый endpoint. Поскольку в период перекрытия каждое событие приходит дважды, обработчик должен быть идемпотентным. Это хороший приём для любого API, которое рассылает события, а &lt;a href=&quot;https://changeloop.dev/blog/ru/webhook-changelog/&quot;&gt;changelog вебхуков&lt;/a&gt; это место, где вы объявляете изменения payload, делающие его необходимым.&lt;/p&gt;
&lt;h2&gt;Что такое ежемесячные и мажорные релизы?&lt;/h2&gt;
&lt;p&gt;Начиная с релиза &lt;code&gt;2024-09-30.acacia&lt;/code&gt; Stripe выпускает новую версию API ежемесячно без breaking changes и дважды в год выпускает новый мажорный релиз, который начинается с версии с breaking changes. На странице версионирования сказано, что перейти на любой ежемесячный релиз можно без изменения кода, а мажорный релиз может потребовать правок.&lt;/p&gt;
&lt;p&gt;У мажорных релизов есть названия. Страница версионирования приводит пример Basil, а в анонсе процесса Stripe сказано, что названия берутся из растений, начиная с Acacia, и что ежемесячные релизы сохраняют название предшествующего мажорного, чтобы название сигнализировало: на них безопасно переходить. В &lt;a href=&quot;https://docs.stripe.com/changelog&quot;&gt;changelog&lt;/a&gt; Stripe перечислены используемые названия, и на момент написания самая новая запись это &lt;code&gt;2026-09-30.endive&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Так что дата отвечает на вопрос «насколько свежая», а название на вопрос «это граница breaking changes?». Анонс Stripe оставляет место и для исключений: компания оставляет за собой право выпустить внеплановое breaking change, если без него интеграция серьёзно пострадает. Анонс находится по адресу &lt;a href=&quot;https://stripe.com/blog/introducing-stripes-new-api-release-process&quot;&gt;Stripe&amp;#39;s new API release process&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Какая последняя версия API Stripe?&lt;/h2&gt;
&lt;p&gt;На момент написания (октябрь 2026 года) на странице версионирования Stripe указано, что текущая версия это &lt;code&gt;2026-09-30.endive&lt;/code&gt;, и в его changelog та же версия значится самой новой. Stripe публикует новую версию ежемесячно, поэтому любая строка в статье быстро стареет. Прочитайте живой changelog, прежде чем что-то закреплять, и закрепляйте ту версию, на которой тестировали.&lt;/p&gt;
&lt;h2&gt;Как Stripe сохраняет работу старых версий?&lt;/h2&gt;
&lt;p&gt;Stripe держит старые версии живыми, записывая каждое breaking change как самостоятельный модуль изменения версии и применяя модули в обратном порядке, от самой новой формы данных. Механизм описан в &lt;a href=&quot;https://stripe.com/blog/api-versioning&quot;&gt;инженерной статье о версионировании API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Каждый модуль объявляет, что он меняет, документирует изменение и содержит функцию преобразования. В статье приведён пример поля, которое из строки превращается в хеш. Чтобы собрать ответ, система определяет целевую версию, затем идёт назад во времени и применяет каждый встретившийся по пути модуль, пока не дойдёт до этой версии.&lt;/p&gt;
&lt;p&gt;Из такой конструкции вытекают два побочных эффекта, и оба названы в статье. Поскольку модули объявляют поля и ресурсы, которых касаются, Stripe может генерировать свой changelog API из них при деплое. А поскольку версия аккаунта известна, документация может подстраиваться под неё и предупреждать об обратно несовместимых изменениях, появившихся с этой версии.&lt;/p&gt;
&lt;h2&gt;Чего это стоит и что взять небольшому API?&lt;/h2&gt;
&lt;p&gt;Версионирование стоит инженерного внимания, и Stripe это признаёт. В инженерной статье упомянута нагрузка на сопровождение и поставлена цель: чем меньше нужно думать о старом поведении при написании нового кода, тем лучше. Там же описаны лёгкие проверки API перед релизом, чтобы вообще не нуждаться в смене версии.&lt;/p&gt;
&lt;p&gt;Небольшой API не может позволить себе цепочку модулей на каждую старую версию и не нуждается в ней. Берите части, в которых вся ценность:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Версии с датой.&lt;/strong&gt; Дате не нужно суждение о том, что считать «мажорным», и вызывающие её читают. Статья &lt;a href=&quot;https://changeloop.dev/blog/ru/api-versioning-best-practices/&quot;&gt;лучшие практики версионирования API&lt;/a&gt; сравнивает это со схемами через URL и заголовок.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Закреплённая версия по умолчанию.&lt;/strong&gt; Закрепите аккаунт или ключ за версией при первом использовании, чтобы API никогда не менялось под работающей интеграцией.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Переопределение в запросе.&lt;/strong&gt; Заголовок, позволяющий вызывающему проверить новую версию на одном вызове, в боевой среде, до того как переходить.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Версия на endpoint вебхука.&lt;/strong&gt; Payload событий это то место, где вызывающих чаще всего ждёт сюрприз.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Одна запись changelog на версию.&lt;/strong&gt; Пусть в ней будут версия, дата, кого это касается и что делать. &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Что считается breaking&lt;/a&gt; это проверка того, что вообще принадлежит новой версии, а саму запись разбирает статья &lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;changelog API&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Цепочку модулей пропустите, пока число поддерживаемых версий этого не потребует. Две-три живые версии можно держать несколькими ветвлениями и датой sunset, о чём рассказывает статья &lt;a href=&quot;https://changeloop.dev/blog/ru/sunsetting-api-version/&quot;&gt;вывод версии API из эксплуатации&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Если вы публикуете changelog с датами, история версий хороша ровно настолько, насколько хороши записи. В &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;Changeloop&lt;/a&gt; из каждого влитого pull request создаётся черновик записи, и он удерживается до одобрения человеком, а затем публикуется на странице changelog и в ленте. Именно здесь пишется запись на версию, а единственный человеческий барьер это проверка, говорящая, что должен сделать вызывающий.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Какая последняя версия API Stripe?&lt;/strong&gt;
На момент написания (октябрь 2026 года) на странице версионирования Stripe указано, что текущая версия это &lt;code&gt;2026-09-30.endive&lt;/code&gt;. Stripe выпускает новую версию ежемесячно, так что проверьте его changelog перед закреплением и впишите версию в код, а не полагайтесь на версию аккаунта по умолчанию.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как задать версию API Stripe в запросе?&lt;/strong&gt;
Отправьте заголовок &lt;code&gt;Stripe-Version&lt;/code&gt;, например &lt;code&gt;Stripe-Version: 2026-09-30.endive&lt;/code&gt;, или задайте версию в серверном SDK глобально либо для запроса. Без того и другого запрос использует версию вашего аккаунта по умолчанию, которую вы задаёте в Workbench.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Используют ли вебхуки ту же версию API Stripe, что и мои запросы?&lt;/strong&gt;
Не обязательно. События вебхуков используют версию, заданную при создании endpoint, а если её нет, версию аккаунта по умолчанию. Обновление SDK не меняет payload, который получает ваш обработчик, поэтому обновляйте endpoint отдельно и тестируйте их параллельно.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Подходит ли небольшому API версионирование по датам в стиле Stripe?&lt;/strong&gt;
Версии с датой, закреплённая версия по умолчанию, заголовок в запросе и одна запись changelog на версию дёшевы и их стоит перенять. Внутренняя цепочка модулей изменения версии не стоит усилий, пока вы не поддерживаете много старых версий одновременно. Начните с двух живых версий и даты sunset для старшей.&lt;/p&gt;
</content:encoded></item><item><title>Кто пишет changelog, а кто должен</title><link>https://changeloop.dev/blog/ru/changelog-entry-ownership/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/changelog-entry-ownership/</guid><description>Кто пишет changelog? Автор PR знает, что изменилось, а PM знает, почему это важно. Ни один из них в одиночку не напишет запись, полезную клиентам.</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Спросите команду, кто пишет changelog, и честный ответ обычно «кто вспомнит», что тот же режим
сбоя, который &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-ci-enforcement/&quot;&gt;принуждение записи в changelog в CI&lt;/a&gt;
существует, чтобы исправить на механическом уровне. Но принуждение к существованию записи не
решает, кто квалифицирован написать хорошую, а команды, пропускающие этот вопрос, склонны по
умолчанию выбирать того, кого проще всего обязать, обычно автора PR, не проверяя, действительно
ли это тот человек, который может написать её хорошо.&lt;/p&gt;
&lt;h2&gt;Почему автор PR не автоматически лучший автор changelog?&lt;/h2&gt;
&lt;p&gt;Потому что он знает реализацию, не обязательно влияние, а это разные виды знания. &lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;Где
останавливаются conventional commits&lt;/a&gt; разбирает этот
разрыв со стороны сообщения коммита: &lt;code&gt;fix(auth): reject expired refresh tokens&lt;/code&gt; корректно и не
говорит клиентке ничего, а тот, кто написал это исправление, часто наименее готов его перевести,
потому что думал в терминах бага часами и потерял внешний взгляд на то, что на самом деле
испытала пользовательница. Та же причина, по которой технические писательницы существуют как профессия: перевод реализации
в её влияние — отдельный навык от того, чтобы построить саму вещь, и он требует практики
независимо от того, насколько разработчик хорош в самом коде.&lt;/p&gt;
&lt;h2&gt;Значит ли это, что продукт или поддержка должны писать каждую запись вместо этого?&lt;/h2&gt;
&lt;p&gt;Нет, потому что у них противоположный разрыв: они знают, что важно пользовательницам, но не
всегда что на самом деле было выпущено, что производит записи читаемые, но иногда неверные по
охвату, утверждение «теперь поддерживает X» для функции, всё ещё скрытой за флагом, или
исправление, описанное как полное, когда покрывает только один из трёх случаев. Режим сбоя
записей, написанных разработчицами, — нечитаемо-но-точно; режим сбоя записей, написанных
PM-ками, — читаемо-но-непроверено. Ни одна роль не владеет обеими половинами того, что нужно
хорошей записи.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Роль&lt;/th&gt;
&lt;th&gt;Обычно точна в&lt;/th&gt;
&lt;th&gt;Обычно ошибается в&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Разработчица, написавшая код&lt;/td&gt;
&lt;td&gt;Точный охват изменения&lt;/td&gt;
&lt;td&gt;Формулировке для того, кто это не строил&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PM или лидер поддержки&lt;/td&gt;
&lt;td&gt;Почему это важно пользовательнице&lt;/td&gt;
&lt;td&gt;Точных границах того, что реально выпущено&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Выделенная владелица changelog&lt;/td&gt;
&lt;td&gt;Согласованном голосе, сверяет охват&lt;/td&gt;
&lt;td&gt;Нужны обе роли выше, чтобы было с чем сверять&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Как на самом деле выглядит рабочая модель ответственности?&lt;/h2&gt;
&lt;p&gt;Черновик от того, кто ближе всего к изменению, проверенный тем, кто ближе всего к пользовательнице,
с одним названным человеком, ответственным за финальную формулировку, вместо того чтобы все
предполагали, что кто-то другой поймает проблемы. Черновику важнее существовать и быть точным, чем
быть хорошим; грубое предложение, написанное разработчицей, которое верно говорит,
что изменилось, — лучшая отправная точка, чем отполированное, но непроверенное, потому что
переписать ради ясности легче, чем переписать ради правильности. Шаг review — там, где PM или
лидер поддержки читает черновик и задаёт единственный вопрос, ловящий разрыв читаемости: поняла
бы я это, если бы не видела код.&lt;/p&gt;
&lt;h2&gt;Должен ли всегда отвечать один и тот же человек, или это ротируется?&lt;/h2&gt;
&lt;p&gt;Названная и стабильная роль побеждает ротирующуюся, по крайней мере для финального одобрения.
Ротирующаяся владелица означает, что каждую запись проверяет кто-то, заново выводящий соглашения
команды с нуля, что ровно то, как голос дрейфует от записи к записи, и читательница начинает
замечать, что changelog написан комитетом. Один человек, или очень маленькая стабильная группа,
накапливает суждения со временем, когда говорить «улучшено» против называть конкретное число,
когда исправлению нужна собственная запись против сворачивания в пакет, и это суждение стоит
больше, чем равномерное распределение работы.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Черновик (разработчица, из PR):
&amp;quot;Fixed pagination cursor not respecting the `sort` param
in some edge cases.&amp;quot;

Проверено (владелица changelog, сверено с реальным PR):
&amp;quot;Исправлено: экспорт, отсортированный по дате, мог
возвращать результаты не по порядку после первой
страницы. Теперь согласовано на всех страницах.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Нужно ли маленькой команде столько процесса ради одной строки текста?&lt;/h2&gt;
&lt;p&gt;Не роли как отдельные люди, но два шага всё равно важны даже соло. Команда из одного человека —
и разработчица, и ревьюер одновременно, и дисциплина, выживающая на таком масштабе, — делать
review отдельным ментальным проходом, не прыгая прямо от написания исправления к публикации его
описания на одном дыхании. Ловушка на малом масштабе — в полном пропуске второго прохода, а не в отсутствии второго человека,
потому что никто извне его не требует, а разрыв точности,
который этот проход призван поймать, не исчезает только потому, что тот же человек теоретически
мог бы заметить собственное слепое пятно.&lt;/p&gt;
&lt;h2&gt;Что происходит, когда никто не отвечает за финальную запись?&lt;/h2&gt;
&lt;p&gt;Changelog деградирует неровно вместо того, чтобы сломаться явно, что хуже, потому что никто не
замечает, пока читательница на это не укажет. Некоторые записи остаются чёткими, потому что тому,
кто их писал, было не всё равно; другие становятся размытыми, «различные улучшения и исправления
ошибок», потому что тот, кто их писал, спешил, и никто не поймал это до публикации. Ограничения
формата &lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt; ловят структурный дрейф,
пропущенные даты, неверные категории, но ничто в шаблоне не ловит размытую запись, которая
технически хорошо отформатирована, а это ровно тот разрыв, который названная владелица призвана
закрыть.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должна ли владелица changelog быть инженерной ролью или продуктовой?&lt;/strong&gt;
Любая может работать, если у человека есть и техническая беглость, чтобы проверять охват, и
достаточная дистанция от реализации, чтобы писать для внешней читательницы; должность важна
меньше, чем то, может ли она делать обе половины, или знает, у кого спросить о половине, которую
не может сделать сама.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Подходит ли ротирующийся дежурный график для ответственности за changelog?&lt;/strong&gt;
Для объёма иногда, если команда слишком мала, чтобы один человек проверял всё; для голоса и
суждения нет, потому что это ровно то, что размывает ротация. Ротация, разделяющая нагрузку
черновиков при сохранении одной стабильной ревьюерки, получает выгоду без дрейфа.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой самый быстрый признак, что с текущей настройкой ответственности что-то не так?&lt;/strong&gt;
Записи, точные, но нечитаемые, или читаемые, но неверные по охвату, в шаблоне, следующем за тем,
кто их написал. Если качество коррелирует с автором вместо того, чтобы оставаться стабильным,
разрыв — в ответственности, а не в умении писать.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Уменьшает ли автоматизация то, насколько важна ответственность?&lt;/strong&gt;
Она уменьшает объём необходимого письма, а не объём необходимого суждения. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;Автоматизация
changelog&lt;/a&gt; разбирает, что pipeline может безопасно генерировать,
форматирование, публикацию, кросс-постинг; формулировка, группировка и что считается достойным
упоминания остаются человеческими решениями независимо от того, насколько автоматизирован
pipeline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что если автор PR и ревьюер расходятся во мнении о формулировке?&lt;/strong&gt;
Решает ревьюер, потому что вопрос, на который он отвечает, поймёт ли это внешняя читательница, —
именно тот, ради которого существует роль. Это не делает мнение разработчика бесполезным: если
разногласие о точности, а не о формулировке, ревьюер уступает, потому что охват — половина автора,
за которую отвечает он. Разделение двух видов разногласий, формулировка против точности,
останавливает большинство из них до того, как они превратятся в противостояние.&lt;/p&gt;
</content:encoded></item><item><title>Экстренные Release Notes: Под Давлением Реального Времени</title><link>https://changeloop.dev/blog/ru/emergency-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/emergency-release-notes/</guid><description>Релизы, вызванные инцидентом, требуют заметок, написанных за минуты, а не дни, и обычный процесс написания предполагает время, которого у вас нет.</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Большинство release notes пишутся после готовности кода, спокойно проверяются, и публикуются по
расписанию, не имеющему отношения к тому, насколько срочно кому-то нужно их прочитать. Экстренные
релизы, патчи безопасности, баги с потерей данных, исправления сбоев, переворачивают все эти
условия разом: заметка должна существовать до того, как большинство людей обычно начали бы её
писать, почти не получает проверки, и её читает встревоженная, а не спокойная аудитория. &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;Как
писать release notes&lt;/a&gt; разбирает нормальный процесс; это о
том, что меняется, когда не остаётся времени ему следовать.&lt;/p&gt;
&lt;h2&gt;Что одно должны сделать правильно экстренные release notes, даже если больше ничего?&lt;/h2&gt;
&lt;p&gt;Нужно ли читателю что-то сделать, сказано в первом предложении, без всякого обрамления до этого.
Читательница, находящая заметку об инциденте, часто уже встревожена, потому что услышала о
проблеме со страницы статуса, из треда поддержки, или от собственных пользователей, а заметка,
открывающаяся контекстом перед пунктом действия, читается как удержание информации именно в
обстоятельствах, где удержание читается хуже всего. «Действий не требуется, это закрывает
уязвимость, которая не требовала пользовательских данных для эксплуатации» и «Обновите немедленно:
этот релиз исправляет баг, который мог показывать данные одного аккаунта другому» — оба одно
предложение, и оба делают всю работу, нужную встревоженной читательнице, прежде чем она прочтёт
что-либо ещё.&lt;/p&gt;
&lt;h2&gt;Применимо ли обычное редактирование, когда нет времени его применять?&lt;/h2&gt;
&lt;p&gt;Инстинкт сжимать сохраняется, даже когда многопроходный процесс, который его обычно производит, —
нет. &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;Переписывание&lt;/a&gt; описывает урезание многословного
первого черновика до его сути; под временным давлением часто нет первого черновика для урезания,
что значит дисциплина должна работать в голове по мере написания, а не отдельным шагом после.
Самый быстрый подход: напишите предложение, которое произнесли бы вслух тому, кто спрашивает «что
мне нужно знать», и остановитесь, потому что это предложение обычно и самое быстрое в производстве,
и единственное, которое читательница реально обработает в таком состоянии.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Обычная release note&lt;/th&gt;
&lt;th&gt;Экстренная release note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Написана после code review, до публикации&lt;/td&gt;
&lt;td&gt;Часто пишется параллельно с исправлением, до полного review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Оптимизирована для лёгкого сканирования множества записей&lt;/td&gt;
&lt;td&gt;Оптимизирована для одной записи, читаемой изолированно, под стрессом&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Может отложить детали в связанный changelog&lt;/td&gt;
&lt;td&gt;Должна поставить один самый важный факт первым&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Обрамление и контекст уместны&lt;/td&gt;
&lt;td&gt;Обрамление перед пунктом действия читается как проволочка&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Бывает ли нормально публиковать заметку до того, как вы действительно уверены в причине проблемы?&lt;/h2&gt;
&lt;p&gt;Да, если заметка честна об этой неопределённости, а не подразумевает уверенность, которой у вас
нет. «Мы развернули исправление роста числа ошибок при оформлении заказа; мы всё ещё подтверждаем
первопричину и обновим эту заметку» — защитимо и правильно покупает время; заметка, заявляющая
конкретную причину, которую вы фактически не подтвердили, — тот тип догадки, которую позже вам
процитируют обратно, если она окажется неверной. Важная здесь дисциплина — не скорость диагностики,
а никогда не позволять уверенности заметки превышать реальную уверенность команды, потому что
неверное техническое утверждение в экстренной заметке разрушает доверие сильнее, чем признанное
незнание.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Слишком уверенно, не проверено:
&amp;quot;Fixed: a race condition in the payment webhook handler
caused duplicate charges.&amp;quot;

Честно под давлением времени:
&amp;quot;Исправлено: с некоторых клиентов дважды списывалась
оплата за один заказ. Мы остановили новые случаи и
вернули средства пострадавшим аккаунтам в течение
24 часов. Расследуем первопричину.&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Должна ли экстренная заметка упоминать причину проблемы, или только то, что она исправлена?&lt;/h2&gt;
&lt;p&gt;Скажите, что исправлено и что должна сделать читательница; приберегите первопричину для
последующей заметки, когда она реально известна, а не предполагается. Читательница в разгар
инцидента хочет ровно два факта: закрыто ли это и затрагивает ли это меня, а объяснение
первопричины, даже точное, соревнуется с этими двумя фактами за внимание в худший момент для его
потери. Постмортем, опубликованный отдельно по завершении расследования, — вот где должна быть
первопричина; смешивание обоих документов под временным давлением производит заметку, которая
пишется медленнее и читается медленнее — противоположность тому, что нужно экстренной ситуации.&lt;/p&gt;
&lt;h2&gt;Применима ли здесь же проблема принудительных обновлений мобильных приложений?&lt;/h2&gt;
&lt;p&gt;Тот же принцип, только ещё более сжатый. &lt;a href=&quot;https://changeloop.dev/blog/ru/mobile-app-release-notes/&quot;&gt;Release notes для мобильных приложений&lt;/a&gt;
разбирает принудительные обновления, где заметка должна назвать причину и крайний срок раньше
всего остального, потому что читательница уже раздражена отсутствием выбора; экстренная
веб-заметка обычно для читательницы опциональна в том смысле, что она выбирает, действовать ли на
её основе, но тот же инстинкт «назвать ограничение первым» применим, просто по другой причине: не
раздражение, а срочность.&lt;/p&gt;
&lt;h2&gt;Как избежать того, чтобы экстренная заметка читалась как признание вины, когда не должна?&lt;/h2&gt;
&lt;p&gt;Опишите исправление и его эффект, а не ошибку, и сдержите порыв извиняться чрезмерно, что
читается как наполнитель для читательницы, желающей двух фактов выше. «Мы нашли и исправили баг,
затронувший некоторые экспорты» заявляет, что произошло, без добавления к этому драмы; «Нам очень
жаль за это серьёзное неудобство, затронувшее наших ценных клиентов» откладывает полезную
информацию на целое предложение, чтобы передать эмоциональный момент, о котором читательница не
просила. Краткая, фактическая заметка — не холодность, это уважение к реальному состоянию
читательницы, которое под настоящим давлением — нетерпение, а не потребность в утешении.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли экстренные release notes проходить тот же процесс review, что и обычные?&lt;/strong&gt;
Более лёгкий, но не никакой: одна быстрая проверка, что заметка не завышает определённость,
стоит нескольких минут, которые требует, потому что риск непроверенного технического утверждения
оказаться неверным выше именно потому, что оно написано быстро.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нормально ли публиковать экстренную заметку без ссылки на дальнейшие детали?&lt;/strong&gt;
Только ненадолго. Заметка без ссылки годится как первое, что публикуется; добавьте одну на
страницу статуса или последующую заметку, как только любая из них появится, потому что
читательнице, желающей больше того единственного предложения, нужно куда пойти, даже если это
место говорит «дальнейшие детали скоро».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должна ли экстренная заметка когда-либо полностью пропускаться, позволяя исправлению выйти тихо?&lt;/strong&gt;
Только для проблем, которые ни одна читательница не могла заметить или которых не затрагивала;
если есть шанс, что читательница столкнулась с проблемой, заметка — это то, что сообщает ей, что
она закончилась, а тишина читается так, будто проблема всё ещё может быть активной.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как долго экстренная заметка должна оставаться закреплённой или заметной после устранения инцидента?&lt;/strong&gt;
Пока не закроется окно непосредственной тревоги, обычно день-два, затем она может влиться в
обычный changelog как любая другая запись; заметка, остающаяся закреплённой неделями, начинает
читаться как неразрешённая тревога, а не устранённая.&lt;/p&gt;
</content:encoded></item><item><title>Breaking changes в Protobuf: что выживает на проводе</title><link>https://changeloop.dev/blog/ru/grpc-protobuf-api-changes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/grpc-protobuf-api-changes/</guid><description>Breaking changes в Protobuf происходят на проводе, а не в URL. Одни правки полей gRPC безопасны, другие молча ломают клиентов, а в диффе неотличимы.</description><pubDate>Tue, 22 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;REST API меняется, когда меняется форма JSON, и большая часть этой формы видна в ответе, который
можно прочитать в браузере. gRPC API меняется, когда меняется файл &lt;code&gt;.proto&lt;/code&gt;, а бинарный формат
провода Protocol Buffers имеет собственные правила о том, что может стерпеть клиент, не имеющие
никакого отношения к тому, что говорят имена полей. Два изменения, выглядящие одинаково мелкими в
диффе, перенумерация поля против добавления нового, попадают по разные стороны черты, которую
&lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;breaking changes&lt;/a&gt; проводит в общем: одно невидимо для каждого
существующего клиента, другое ломает их все разом.&lt;/p&gt;
&lt;p&gt;Отличить breaking changes Protobuf от безопасных значит читать собственные правила формата
провода, а не гадать по тому, как изменение выглядит в диффе &lt;code&gt;.proto&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Почему нумерация полей важнее имени поля в Protobuf?&lt;/h2&gt;
&lt;p&gt;Потому что формат провода кодирует поля по номеру, а не по имени. Сгенерированный код на каждом
языке читает и пишет эти номера; имя поля &lt;code&gt;email&lt;/code&gt; в вашем файле &lt;code&gt;.proto&lt;/code&gt; — удобство для людей,
которое никогда не касается двоичных байтов, отправляемых по сети. Переименование поля, &lt;code&gt;email&lt;/code&gt; в
&lt;code&gt;email_address&lt;/code&gt;, безопасно в двоичном формате провода, пока номер остаётся тем же, что удивляет
инженерок, привыкших к REST, где переименованный JSON-ключ — именно тот тип изменения, что ломает
клиента. Исключение составляет тот же случай, что и в REST:
&lt;a href=&quot;https://protobuf.dev/programming-guides/json/&quot;&gt;форматы ProtoJSON и text&lt;/a&gt; сериализуют имя, поэтому
переименование ломает JSON-транскодирование (например, grpc-gateway), файлы в text-формате и field
mask. Перенумерация того же поля, с сохранением имени но изменением &lt;code&gt;1&lt;/code&gt; на &lt;code&gt;7&lt;/code&gt;, — ровно
наоборот: невидимо в code review, показывающем только имена, и портит каждое сообщение, которое
клиент отправляет или получает с этого момента.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Изменение&lt;/th&gt;
&lt;th&gt;Безопасно на проводе&lt;/th&gt;
&lt;th&gt;Почему&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Переименовать поле, сохранить номер&lt;/td&gt;
&lt;td&gt;В двоичном да, в JSON и text нет&lt;/td&gt;
&lt;td&gt;Двоичное кодирование использует номер; ProtoJSON и text-формат используют имя&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменить номер поля&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Каждое существующее сообщение теперь читается как неверное поле&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Добавить новое поле с новым номером&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Старые клиенты игнорируют незнакомые им поля&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Удалить поле, повторно использовать его старый номер для чего-то другого&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Старые данные декодируются в неверное новое поле&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Несовместимо изменить тип поля (напр. &lt;code&gt;int32&lt;/code&gt; в &lt;code&gt;string&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Кодирование провода отличается по типам&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что делает удаление поля другим, чем то же в ответе REST JSON?&lt;/h2&gt;
&lt;p&gt;Номер становится радиоактивным. &lt;a href=&quot;https://protobuf.dev/programming-guides/proto3/&quot;&gt;Собственное руководство Protobuf&lt;/a&gt; рекомендует помечать номер
удалённого поля как &lt;code&gt;reserved&lt;/code&gt;, а не позволять его повторное использование, потому что именно в
повторном использовании и происходит настоящий ущерб: клиент, всё ещё работающий на
сгенерированном коде месячной давности, отправляет сообщение, используя старый номер поля для
старого значения, а сервер, теперь ожидающий, что этот номер означает что-то другое, молча
неверно интерпретирует данные вместо того, чтобы прямо их отклонить. У REST нет эквивалентной
ловушки, потому что удалённый JSON-ключ просто перестаёт появляться; нет способа, чтобы запрос
старого клиента был тихо переинтерпретирован как что-то другое. Файл &lt;code&gt;.proto&lt;/code&gt; с &lt;code&gt;reserved 4, 9, 12;&lt;/code&gt; в начале сообщения — это постоянный шрам, и в этом весь смысл: он не даёт номеру достаться
новому полю от того, кто не знал его истории.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-protobuf&quot;&gt;message Invoice {
  reserved 4; // было `legacy_customer_id`, удалено 2026-06-01
  reserved &amp;quot;legacy_customer_id&amp;quot;; // и имя тоже, для JSON/text
  string customer_id = 5;
  string status = 6;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Требует ли добавление поля вообще записи в changelog?&lt;/h2&gt;
&lt;p&gt;Обычно не запись о breaking change, но часто обычную, потому что «безопасно на проводе» и
«невидимо для читательницы, которой это важно» — два разных утверждения. Добавление поля в
сообщение ответа структурно ничего не стоит, старые клиенты декодируют сообщение и автоматически
игнорируют новое поле. Но у того, кто строит новую интеграцию против этого сервиса, нет способа
узнать, что поле существует, если кто-то ему не скажет, потому что ничто в успешной сборке или
пройденном тесте не делает новое опциональное поле видимым. &lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;Changelog API&lt;/a&gt;
разбирает в общем, чем аддитивная запись обязана читателям; специфичная для gRPC причина всё же
её написать в том, что нет эквивалента просмотру ответа REST в отладчике, чтобы заметить появление
нового ключа.&lt;/p&gt;
&lt;h2&gt;Чем это отличается от того, с чем сталкиваются вызывающие GraphQL?&lt;/h2&gt;
&lt;p&gt;Правила для добавлений совпадают, но степень видимости разная. &lt;a href=&quot;https://changeloop.dev/blog/ru/graphql-schema-deprecation/&quot;&gt;Депрекация схемы GraphQL&lt;/a&gt;
разбирает модель, где клиент получает только те поля, которые явно запрашивает, что делает
аддитивные изменения по сути безрисковыми, а удаления — единственной реальной опасностью. Клиенты
gRPC, напротив, получают всё, что отправляет сервер, и декодируют всё против собственной
скомпилированной копии схемы; экспозиция клиента ограничена не тем, что он запросил, а только тем,
что умеет читать его сгенерированный код. Эта разница важна для написания changelog: запись
GraphQL может разумно предполагать, что клиенты защищены от полей, которые они не запрашивали, а
запись gRPC не может предполагать это вовсе.&lt;/p&gt;
&lt;h2&gt;Работает ли версионирование сервиса gRPC так же, как &lt;code&gt;/v1/&lt;/code&gt;, &lt;code&gt;/v2/&lt;/code&gt; в REST?&lt;/h2&gt;
&lt;p&gt;Механизм отличается, даже когда намерение то же. &lt;a href=&quot;https://changeloop.dev/blog/ru/api-versioning-best-practices/&quot;&gt;Что такое v1 и v2 в REST
API&lt;/a&gt; разбирает версионирование как параллельные пути
URL, обслуживающие разные контракты; сервисы gRPC обычно версионируются через имя пакета в самом
файле &lt;code&gt;.proto&lt;/code&gt;, &lt;code&gt;payments.v1.InvoiceService&lt;/code&gt; становится &lt;code&gt;payments.v2.InvoiceService&lt;/code&gt;, что меняет
полностью квалифицированное имя сервиса, которое набирает клиент, вместо сегмента URL, который он
запрашивает. Оба подхода решают одну и ту же проблему, позволяя старому контракту продолжать
работать, пока существует новый, но команда с бэкграундом REST часто ищет номер версии не в том
месте и упускает, что эту работу выполняет объявление пакета.&lt;/p&gt;
&lt;h2&gt;Что на самом деле должна называть запись changelog gRPC?&lt;/h2&gt;
&lt;p&gt;Сообщение, номер поля, и является ли изменение аддитивным или удалением, требующим миграции, в
этом порядке важности для читательницы, решающей, действовать ли. «Добавлено &lt;code&gt;shipping_address&lt;/code&gt;
(поле 8) в &lt;code&gt;Order&lt;/code&gt;» говорит интегратору всё необходимое, чтобы обновить сгенерированный код и
начать его использовать. «Зарезервировано поле 4 в &lt;code&gt;Invoice&lt;/code&gt;, &lt;code&gt;legacy_customer_id&lt;/code&gt; исчезло»
говорит ей проверить, не читает ли что-то в её кодовой базе всё ещё это поле, что заметка в стиле
REST «удалено поле из ответа» не сообщает с той же срочностью, потому что удаления REST просто
возвращают меньше данных, а повторное использование полей Protobuf активно их портит.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Может ли тип поля быть когда-либо изменён без поломки формата провода?&lt;/strong&gt;
Только в рамках конкретных совместимых групп, которые документирует Protobuf, вроде расширения
&lt;code&gt;int32&lt;/code&gt; до &lt;code&gt;int64&lt;/code&gt; в некоторых случаях. Относитесь к любому изменению типа как к breaking, если не
проверили его против собственной таблицы совместимости Protobuf; предположение совместимости по
аналогии с системой типов языка — как это идёт не так.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Работает ли депрекация поля в Protobuf как директива &lt;code&gt;@deprecated&lt;/code&gt; в GraphQL?&lt;/strong&gt;
Похожим образом: Protobuf поддерживает опцию поля &lt;code&gt;[deprecated = true]&lt;/code&gt;, которую могут показывать
инструменты. Ни то, ни другое не принуждается: сервер GraphQL всё равно отвечает на запрос
депрекированного поля, а клиент protobuf всё равно его кодирует. Оба механизма рекомендательные и
требуют той же поддержки changelog.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Безопасна ли перенумерация, если вы контролируете каждый клиент?&lt;/strong&gt;
В полностью закрытой системе, в принципе, но это устраняет всё свойство безопасности, ради
которого существуют номера полей, а «мы контролируем каждый клиент» — утверждение, которое
перестаёт быть верным в момент, когда сборка кешируется, деплой откладывается, или добавляется
клиент, о котором никто не помнил. Резервируйте номер вместо повторного использования, даже
внутри компании.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужна ли сервисам gRPC страница changelog, как публичному REST API?&lt;/strong&gt;
Только если внешние команды потребляют их, не читая диффы &lt;code&gt;.proto&lt;/code&gt; напрямую, тот же тест «кто на
другой стороне», который в общем применяют &lt;a href=&quot;https://changeloop.dev/blog/ru/internal-api-changelog/&quot;&gt;changelog внутренних API&lt;/a&gt;.
Сервис gRPC, потребляемый только другими сервисами той же команды, часто может обойтись без
формального changelog в пользу истории коммитов, потому что у любого, кто его читает, схема уже
открыта.&lt;/p&gt;
</content:encoded></item><item><title>Форматы файлов changelog: JSON, YAML или просто Markdown</title><link>https://changeloop.dev/blog/ru/changelog-file-formats/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/changelog-file-formats/</guid><description>Формат файла changelog решает, может ли он питать страницу и виджет сразу, или его читает только человек. Markdown, JSON и YAML стоят по-разному.</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Большинство команд начинают changelog как файл Markdown, потому что это путь наименьшего
сопротивления: читаемо в diff pull request&amp;#39;а, читаемо на GitHub без какого-либо рендеринга, и
знакомо любому, кто когда-либо писал README. Этот выбор работает нормально ровно до того момента,
когда файл нужно прочитать чему-то, кроме человека, странице, виджету, сводке по email, и тогда
формат перестаёт быть бесплатным. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;Автоматизация changelog&lt;/a&gt;
разбирает структурное требование в общем, тип, дата, тело и ссылка; это про то, какой формат файла
реально доставляет эту структуру и сколько стоит до неё добраться с каждым.&lt;/p&gt;
&lt;h2&gt;Что не так с простым changelog в Markdown?&lt;/h2&gt;
&lt;p&gt;Ничего, пока что-то не должно распарсить его обратно в поля. Заголовок, дата и список под ним
тривиально читать человеку и по-настоящему трудно надёжно распарсить, потому что у Markdown нет
схемы: дата может быть в заголовке, жирным на первой строке, или вовсе отсутствовать в старой
записи, и каждый из этих вариантов — валидный Markdown, который человек читает правильно, а
парсер нет. Команды, автоматизирующие changelog в Markdown, обычно заканчивают тем, что пишут
самодельный парсер на регулярках, который ломается в первый же раз, когда форматирование записи
хоть немного отклоняется, что случается часто, потому что ничто не принуждает к согласованности
при написании.&lt;/p&gt;
&lt;h2&gt;Что структурированный формат реально даёт?&lt;/h2&gt;
&lt;p&gt;Гарантию, что каждая запись имеет одну и ту же форму, проверенную при написании записи, а не
угаданную при чтении. Файл JSON или YAML с определённой схемой, тип, дата, версия, аудитория,
тело, ссылка, падает громко, если отсутствует обязательное поле, точно так же, как это сделал бы
строгий ответ API; файл Markdown просто рендерит то, что там есть, правильно это или нет. Эта
разница невидима до дня, когда скрипту нужна дата каждой записи, чтобы отсортировать поток, а у
половины записей она в другом месте.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# CHANGELOG.yml
- date: 2026-09-05
  type: breaking
  version: v2
  audience: api
  body: &amp;quot;POST /invoices now rejects a currency mismatch instead of silently converting.&amp;quot;
  link: /blog/api-changelog/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Значит ли это, что читаемый человеком файл должен исчезнуть?&lt;/h2&gt;
&lt;p&gt;Нет, и попытка заставить файл YAML или JSON служить одновременно тем, что человек читает в pull
request, обычно ошибка в обратную сторону: ревью diff вложенного JSON хуже, чем ревью предложения
прозы, а ревьюер, которому нужно мысленно распарсить структуру данных, чтобы поймать ошибку
формулировки, — это ревьюер, который в конце концов перестанет ловить ошибки формулировки. Два
формата могут сосуществовать: структурированные данные — источник истины, который читает пайплайн
автоматизации, а сгенерированный рендер в Markdown или HTML — то, что человек реально ревьюит и
читает, произведённое из структурированного файла вместо того, чтобы поддерживаться вручную рядом
с ним.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Формат&lt;/th&gt;
&lt;th&gt;Читаем человеком как есть&lt;/th&gt;
&lt;th&gt;Парсится машиной без кастомного кода&lt;/th&gt;
&lt;th&gt;Частый режим отказа&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Непоследовательная форма записей ломает наивные парсеры&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;td&gt;Плохо&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Многословный; легко вручную отредактировать в невалидный JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;td&gt;Терпимо&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Чувствителен к пробелам; неверный отступ — тихая, не громкая ошибка парсинга&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Какой структурированный формат реально легче редактировать вручную, JSON или YAML?&lt;/h2&gt;
&lt;p&gt;YAML, для тех, кто пишет записи вручную, а не через генератор, потому что он убирает
кавычки и сопоставление скобок, которые JSON требует для каждой строки и вложенного объекта.
Компромисс в том, что чувствительность YAML к пробелам ломается молча так, как обычно не ломаются
несовпадения скобок в JSON: парсер JSON прямо отклоняет некорректный ввод, тогда как парсер YAML
может принять файл с неверными отступами и просто распарсить его в неверную структуру, что худший
отказ, потому что ничто не говорит вам, что это произошло. Если записи всегда пишет только скрипт,
этот компромисс в основном исчезает, и более строгий парсинг JSON становится более безопасным
выбором по умолчанию.&lt;/p&gt;
&lt;h2&gt;Нужен ли странице changelog собственный структурированный формат, отдельный от файла, который её питает?&lt;/h2&gt;
&lt;p&gt;Не отдельный, тот же самый, отрендеренный иначе. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-page/&quot;&gt;Страница changelog&lt;/a&gt;
разбирает, как сделать саму страницу машиночитаемой через JSON-поток и разметку schema.org; этот
поток — сгенерированный вывод, а не второй источник истины, который нужно держать
синхронизированным с исходным файлом. Поддержка структурированных данных вручную в двух местах,
исходном файле и потоке страницы, это то, как эти два расходятся, так что решение о формате файла,
принятое здесь, должно быть единственным, из чего генерируется всё дальше по цепочке, страница,
виджет, email, а не копироваться вручную.&lt;/p&gt;
&lt;h2&gt;Стоит ли затрат на миграцию переводить существующий changelog в Markdown в структурированный формат?&lt;/h2&gt;
&lt;p&gt;Обычно только когда автоматизация — реальная цель, не раньше. Проект одного человека,
публикующий файл Markdown в README на GitHub, не имеет реальной потребности в автоматизации, и
преобразование его в YAML не покупает ничего, кроме церемонии. Конверсия окупает себя в момент,
когда больше одного потребителя дальше по цепочке, страница, письмо со сводкой, публичный поток,
должны читать одни и те же данные, потому что это ровно та точка, где несогласованности парсера
Markdown начинают производить заметно неправильный вывод вместо того, чтобы просто быть
раздражающими в поддержке.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Можно ли сделать changelog в Markdown парсимым без полной смены формата?&lt;/strong&gt;
Частично, с frontmatter: небольшой блок YAML в начале каждой записи (дата, тип, версия) рядом с
телом на Markdown для прозы. Это даёт структурированные поля, которые нужны парсеру, не заставляя
всю запись в JSON или YAML, и это разумная середина для команды, ещё не готовой к полной миграции.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Важен ли формат файла для SEO или для того, как ранжируется страница changelog?&lt;/strong&gt;
Не напрямую. Поисковики читают отрендеренную страницу, не исходный файл, так что формат файла для
них невидим; важно для самой страницы то, машиночитаема ли она сама по себе, что отдельный вопрос
от того, что её генерирует.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должна ли каждая запись changelog проходить через один и тот же файл, или типы можно разделить по файлам?&lt;/strong&gt;
Один файл проще, пока объём записей не сделает его неудобным для diff&amp;#39;ов или ревью; разделение по
году или категории — разумный клапан сброса давления, как только diff&amp;#39;ы одного файла становятся
слишком большими, чтобы их разумно ревьюить, но это добавляет шаг слияния прежде, чем что-либо
дальше по цепочке сможет прочитать «все записи» как один список.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Существует ли стандартный формат файла changelog, как существует стандарт для RSS?&lt;/strong&gt;
Не широко принятый. Keep a Changelog предлагает конвенцию Markdown, а несколько инструментов
имеют собственный; &lt;a href=&quot;https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md&quot;&gt;changeset&lt;/a&gt;
это файл Markdown с frontmatter на YAML, где названы пакет и тип повышения версии, то есть тот же
паттерн с frontmatter, описанный выше. Ни один из них не
формат, который другие инструменты читают из коробки так, как читатели RSS универсально понимают
RSS.&lt;/p&gt;
</content:encoded></item><item><title>Дублирующиеся запросы: объединение без потери голоса</title><link>https://changeloop.dev/blog/ru/duplicate-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/duplicate-feature-requests/</guid><description>Группировка дублирующихся запросов на функции защищает счёт. Небрежное объединение теряет формулировку, делавшую один из них полезным, потеря поменьше.</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Три клиентки просят одну и ту же возможность в три разные недели, сформулированную тремя разными
способами, и процесс триажа, построенный ловить дубли, делает свою работу: группирует их, считает
как один запрос с тремя голосами, и бэклог остаётся чистым. Это лёгкая часть. &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;Какие метки того
стоят&lt;/a&gt; разбирает группировку по базовой возможности перед
триажем по формулировке как механическое решение для дублей; чего не разбирает — что происходит со
словами самими по себе, как только три запроса становятся одной строкой, и эта потеря обычно
больше проблемы подсчёта дублей, которую она решила.&lt;/p&gt;
&lt;h2&gt;Что реально теряется, когда дубли объединяются?&lt;/h2&gt;
&lt;p&gt;Конкретная формулировка, которую использовала каждая просительница, часто более информативная, чем
счёт голосов, в который она схлопывается. Одна клиентка может попросить «способ экспортировать
отфильтрованные результаты», другая «экспорт CSV, уважающий мои сохранённые фильтры», а третья
«экспорт без скрытых колонок». Все три — один и тот же базовый запрос, правильно сгруппированный,
но каждая формулировка несёт слегка иной акцент на том, что важно этому человеку, и объединение,
сохраняющее только формулировку первой подачи, полностью отбрасывает две другие. Счёт выживает;
текстура, которая помогла бы кому-то построить правильную версию функции, нет.&lt;/p&gt;
&lt;h2&gt;Почему текстура важна, если счёт голосов уже говорит, что спрос существует?&lt;/h2&gt;
&lt;p&gt;Потому что спрос и дизайн — разные вопросы, и только конкретная формулировка отвечает на второй.
Десять голосов за «экспорт» говорят команде, что функцию стоит строить; они ничего не говорят о
том, означает ли «экспорт» CSV, PDF, запланированное письмо или endpoint API, и объединение,
отбрасывающее девять из десяти оригинальных подач в пользу формулировки первой, может тихо сузить
спецификацию до того, что случайно попросила первая просительница, даже если остальные девять
хотели чего-то тонко отличающегося. &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;Что на самом деле должен фиксировать запрос на
функцию&lt;/a&gt; разбирает именно этот пробел со стороны приёма;
объединение дублей — это место, где он снова всплывает после приёма, ровно в той точке, где
команде больше всего нужен диапазон того, что действительно просили.&lt;/p&gt;
&lt;h2&gt;Как выглядит процесс объединения, сохраняющий формулировку вместо того, чтобы её отбрасывать?&lt;/h2&gt;
&lt;p&gt;Добавление вместо замены. Канонический элемент сохраняет один заголовок для вида бэклога, но
оригинальная формулировка каждой объединённой подачи остаётся прикреплённой к нему, либо как список
цитат, либо как связанные исходные тикеты, так что любой, кто позже просматривает элемент, может
увидеть реальный диапазон того, что просили люди, вместо резюме одного члена команды. Это стоит
почти ничего построить, поле в тикете вместо новой системы, и это разница между объединением,
сжимающим информацию, и тем, что сжимает только её отображение.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Функция: Отфильтрованный экспорт CSV
Голоса: 12
Объединённые запросы:
  - «способ экспортировать отфильтрованные результаты» (acct_4421)
  - «экспорт CSV, уважающий мои сохранённые фильтры» (acct_8832)
  - «экспорт без скрытых колонок» (acct_1097)
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Заслуживает ли каждый дубль объединения, или бывают ложные совпадения?&lt;/h2&gt;
&lt;p&gt;Некоторые — ложные совпадения, и обращение с «звучит похоже» как с «это тот же запрос» — свой
собственный режим отказа. «Дайте мне экспортировать мои данные» и «дайте мне экспортировать только
отфильтрованный вид» могут быть сгруппированы совпадением ключевого слова на «экспорт», хотя на
самом деле описывают два разных объёма одной и той же общей возможности; объединение их либо
раздувает счёт голосов не за то, либо, хуже, доставляет более узкую версию, потому что она случайно
пришла первой. Человеческий проход по группировке, даже быстрый, ловит это до накопления;
автоматическое совпадение по сходству само по себе переобъединит по словарю и недообъединит по
намерению.&lt;/p&gt;
&lt;h2&gt;Когда проверку на дубли на самом деле стоит запускать — при приёме или позже?&lt;/h2&gt;
&lt;p&gt;И то, и другое, по разным причинам. Проверка при приёме ловит очевидный случай, новый запрос,
повторяющий что-то уже открытое, ещё до того, как он станет собственной неотслеженной строкой;
поиск по сходству среди открытых запросов в момент подачи закрывает большинство таких случаев без
участия человека. Второй, более медленный проход позже ловит то, что упускает приём: два запроса,
использовавшие достаточно разные формулировки, чтобы в момент подачи проскользнуть мимо совпадения
по ключевым словам или эмбеддингам, но которые, стоит команде увидеть десяток вариаций, оказываются
описанием одной и той же базовой возможности. Пропуск второго прохода оставляет почти-дубли
рассеянными под отдельными заголовками бессрочно, каждый со своим маленьким счётом голосов, который
никогда не складывается в число, которое довело бы дело до реализации.&lt;/p&gt;
&lt;h2&gt;Должна ли просительница знать, что её подача объединена с существующим элементом?&lt;/h2&gt;
&lt;p&gt;Да, и это та же дисциплина, что &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;закрытие цикла обратной связи с клиентом&lt;/a&gt;,
применённая на шаг раньше обычного: просительница, которая что-то подала и больше ничего не слышит,
заключает, что её запрос никуда не привёл, даже если он был правильно объединён с элементом с
одиннадцатью другими голосами, который в итоге выпустили. Короткое подтверждение, «мы объединили
это с существующим запросом, который делали и другие», стоит одного сообщения и предотвращает
повторную подачу клиенткой того же запроса каждые несколько месяцев, потому что у неё нет
видимости, отслеживался ли он вообще на самом деле.&lt;/p&gt;
&lt;h2&gt;Меняет ли объединение, кому засчитывается заслуга, когда функция выпущена?&lt;/h2&gt;
&lt;p&gt;Должно включать всех, не только того, кто подал первым. &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;Закрытие цикла обратной
связи&lt;/a&gt; разбирает уведомление просительниц, когда их желание
выпущено; для объединённого элемента это значит каждый аккаунт, привязанный к объединению, не
только тот, чья формулировка стала каноническим заголовком, потому что с точки зрения каждой
просительницы она попросила это, и это выпустили, независимо от того, чью формулировку случайно
сохранил процесс триажа. В Changeloop это значит, что pull request называет каждый связанный issue
(&lt;code&gt;Fixes #142, fixes #187&lt;/code&gt;); issue, который он не называет, не получает комментария.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Сколько формулировки стоит сохранять на объединённый запрос, цитату или полную ссылку на тикет?&lt;/strong&gt;
Короткой цитаты обычно достаточно для обычного случая, поскольку её цель — дать ревьюеру увидеть
диапазон формулировок с одного взгляда; сохраняйте и полную ссылку на тикет, когда в оригинале был
значительный дополнительный контекст, вроде скриншота или подробного описания рабочего процесса,
которое однострочная цитата бы сгладила.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Делает ли сохранение формулировки каждого дубля бэклог труднее для сканирования?&lt;/strong&gt;
Нет, если это свёрнуто по умолчанию. Канонический заголовок — то, что видит бегло сканирующий
ревьюер; объединённая формулировка на клик или разворот дальше, присутствует для того, кто делает
более глубокое исследование, но не загромождает вид для того, кто просто считает голоса.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что если два запроса выглядят идентичными, но оказывается, что хотят разного после постройки?&lt;/strong&gt;
Разделите их снова, как только это станет ясно, и относитесь к оригинальному объединению как к
разумному решению, принятому с доступной на тот момент информацией, а не как к ошибке, повторения
которой нужно избегать. Система группировки, которая никогда ничего не разъединяет, в итоге будет
иметь несколько неверных объединений, навсегда запечённых.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Есть ли порог голосов, после которого объединённый запрос должен получить человеческий обзор базовой формулировки?&lt;/strong&gt;
Не фиксированное число, но любой запрос, приближающийся к решению о постройке, заслуживает этого
независимо от счёта голосов, потому что это точка, где разница между «экспорт» и «экспорт как CSV
с сохранёнными фильтрами» перестаёт быть нюансом и становится спецификацией.&lt;/p&gt;
</content:encoded></item><item><title>Изменения схемы GraphQL: депрекация без номера версии</title><link>https://changeloop.dev/blog/ru/graphql-schema-deprecation/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/graphql-schema-deprecation/</guid><description>У GraphQL нет v1 или v2 в URL. Поля депрекируются по одному директивой, на общей схеме, которую используют все клиенты, и это меняет, что должен changelog.</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Changelog REST API существует, потому что вызывающий может отклонить ответ, которого не понимает,
или хотя бы залогировать ошибку достаточно громко, чтобы кто-то заметил. GraphQL имеет одну схему
на одном endpoint, и каждый клиент, мобильное приложение на прошлогодней сборке и внутренний
дашборд, развёрнутый сегодня утром, запрашивает один и тот же граф. Нет URL, который можно было бы
разветвить. Депрекация поля означает пометку его как депрекированного на месте, в схеме, от которой
уже все зависят, что делает дисциплину другой, чем в REST, хотя базовая проблема, сказать
вызывающим, что что-то исчезнет, та же самая, что в общем разбирает &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;депрекация
API&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Как GraphQL помечает поле как депрекированное, если нет версии для повышения?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://spec.graphql.org/October2021/#sec--deprecated&quot;&gt;Директивой &lt;code&gt;@deprecated&lt;/code&gt;&lt;/a&gt;, применённой прямо к полю:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;type Product {
  price: Float @deprecated(reason: &amp;quot;Use priceV2 for multi-currency support.&amp;quot;)
  priceV2: Money
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Поле остаётся доступным для запроса. Оно не исчезает, не возвращает 404, не меняет поведение; оно
просто несёт машиночитаемую заметку, которую большинство инструментов GraphQL, GraphiQL, Apollo
Studio, линтеры схем, покажут любому, кто просматривает схему или пишет запрос против неё. Это весь
механизм. Нет отдельного endpoint для депрекации, никакого заголовка, никакого сопутствующего
документа, требуемого спецификацией, что одновременно и привлекательность, и ловушка: директиву
легко добавить и легко проигнорировать, потому что ничто не заставляет клиента на неё смотреть.&lt;/p&gt;
&lt;h2&gt;Видит ли кто-то вообще причину депрекации?&lt;/h2&gt;
&lt;p&gt;Только те, кто использует схему напрямую, через интроспекцию или редактор, знающий о схеме, и это
меньшая аудитория, чем обычные читатели changelog API. Мобильное приложение, построенное против
запроса шесть месяцев назад, уже впекло этот запрос в свой бинарник; оно продолжит запрашивать
&lt;code&gt;price&lt;/code&gt; и продолжит получать ответ, депрекировано оно или нет, пока кто-то не пересоберёт
приложение с новым полем и не выпустит обновление. Директива говорит разработчице, пишущей новый
код, не использовать старое поле. Она ничего не делает для клиента, уже выпущенного и работающего.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Механизм&lt;/th&gt;
&lt;th&gt;Кого достигает&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Директива &lt;code&gt;@deprecated&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Разработчицы, просматривающие схему или пишущие новые запросы&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Сбои CI линтера схемы&lt;/td&gt;
&lt;td&gt;Команда, владеющая клиентской кодовой базой, если она такой запускает&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Запись в changelog&lt;/td&gt;
&lt;td&gt;Кто угодно, кто её читает, включая клиентскую команду без линтера&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ничего (поле просто работает)&lt;/td&gt;
&lt;td&gt;Уже построенный клиент, использующий старое поле&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Должно ли депрекированное поле всё равно получить запись в changelog?&lt;/h2&gt;
&lt;p&gt;Да, и она делает больше работы, чем одна директива, потому что changelog достигает людей, которых
директива достичь не может: команду-партнёра, которая потребляет граф, не просматривая его схему,
клиент, построенный против закешированной месяцы назад копии схемы, любого, кто заметил бы это
только прочитав прозу. &lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;Changelog API&lt;/a&gt; в общем разбирает, что запись
должна вызывающему; запись GraphQL должна одну вещь, которую REST редко приходится проговаривать
явно, потому что вызывающие REST выводят её из номера версии: работает ли старое поле сегодня
всё ещё, работает ли ещё с предупреждением, или фактически перестало возвращать данные. Одна
директива не отвечает ни на что из этого для читательницы, которая никогда не открывала схему.&lt;/p&gt;
&lt;h2&gt;Когда на самом деле безопасно удалять поле из схемы?&lt;/h2&gt;
&lt;p&gt;Только когда логи запросов показывают, что его больше никто не запрашивает, что вопрос
использования, а не календаря. Поле может нести &lt;code&gt;@deprecated&lt;/code&gt; год и всё ещё быть несущим для
одного клиента, который никогда не пересобирался; удаление его по фиксированному расписанию, как
часто делает REST-овый &lt;code&gt;Sunset&lt;/code&gt;, ломает этого клиента без какого-либо предупреждения, на которое
он мог бы среагировать, потому что GraphQL не даёт ему ничего, на что реагировать, кроме
директивы, которую он никогда не читал. Логируйте использование на уровне поля прежде чем
обязываться на дату удаления, и относитесь к любому ненулевому счётчику запросов как к паузе, а
не отсчёту.&lt;/p&gt;
&lt;h2&gt;Несёт ли добавление поля тот же риск, что и в API REST?&lt;/h2&gt;
&lt;p&gt;Меньше, для нового поля, потому что клиент GraphQL получает только те поля, о которых явно просит.
Добавление &lt;code&gt;priceV2&lt;/code&gt; рядом с &lt;code&gt;price&lt;/code&gt; не может сломать существующий запрос так, как добавление поля
в JSON-ответ REST может сломать строгий десериализатор, потому что ничто не заставляет клиента
запрашивать новое поле. Добавление значения в существующий enum стоит назвать в том же дыхании как
исключение: клиент, исчерпывающе переключающийся по каждому значению enum, к чему поощряют строго
типизированные языки, ломается в момент появления нового значения, независимо от того, запрашивал
ли его какой-либо запрос. Эта безопасность держится только для полей и членов union, в которые
клиент сам решает войти; она не держится для закрытого множества, которое код клиента перечисляет
вручную.&lt;/p&gt;
&lt;h2&gt;Что нужно записи changelog GraphQL, чего не нужно записи REST?&lt;/h2&gt;
&lt;p&gt;Форма запроса, а не только имя поля, потому что «поле &lt;code&gt;price&lt;/code&gt; депрекировано» не хватает именно той
части, которая на самом деле нужна вызывающему: какие типы и какие запросы его касаются. Полезная
запись называет тип, поле, поле-замену и, если можете это сгенерировать, реальные запросы в
продакшене, которые всё ещё запрашивают старую форму. Этот последний кусок, привязка уведомления о
депрекации к реальному использованию, это то, что вызывающие REST получают бесплатно из логов
сервера на URL, а вызывающие GraphQL нет, потому что каждый запрос попадает в один и тот же
endpoint независимо от того, что он запрашивает.&lt;/p&gt;
&lt;h2&gt;Может ли что-то, кроме поля, нести директиву &lt;code&gt;@deprecated&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;Значения enum, той же директивой на определении самого значения, а не поля:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;enum ShippingMethod {
  STANDARD
  EXPRESS
  OVERNIGHT @deprecated(reason: &amp;quot;Use EXPRESS with priority: true instead.&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Спецификация определяет &lt;code&gt;@deprecated&lt;/code&gt; ровно для двух мест, определения поля или значения enum, и
больше ни для чего по состоянию на стабильный релиз; депрекация на уровне аргумента и input-поля
существует только в более поздних черновых формулировках, не в том, что реализует большинство
серверов сегодня. Значение enum, помеченное так, остаётся допустимым значением, которое сервер
всё ещё может вернуть или принять, то же самое не-ломающее обещание, что даёт депрекированное поле,
и именно это делает безопасным выпустить пометку до того, как значение будет удалено по-настоящему.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Поддерживает ли GraphQL что-то вроде заголовка Sunset для целого endpoint?&lt;/strong&gt;
Нет, потому что обычно есть только один endpoint. Тайминг депрекации живёт на уровне поля, в
тексте причины директивы &lt;code&gt;@deprecated&lt;/code&gt; и в любом changelog или руководстве по миграции, которое
команда публикует рядом, а не в заголовке ответа, который клиент мог бы прочитать программно.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Можно ли удалить депрекированное поле и позже добавить снова с другим типом?&lt;/strong&gt;
Только под новым именем поля. Повторное введение того же имени поля с изменённым типом — это
именно тот breaking change, который цикл депрекации существует, чтобы избежать; дайте замене
собственное имя, как делает &lt;code&gt;priceV2&lt;/code&gt;, и дайте старому полностью угаснуть, прежде чем имя
освободится для повторного использования.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли текст причины &lt;code&gt;@deprecated&lt;/code&gt; вести на запись changelog?&lt;/strong&gt;
Да, когда инструменты схемы это поддерживают. Поле причины принимает обычную строку, и URL внутри
этой строки — кратчайший путь от разработчицы, смотрящей на вывод интроспекции, к более полному
объяснению, которое может дать запись changelog.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Бывает ли изменение схемы GraphQL когда-либо обратно совместимым так, как REST не бывает?&lt;/strong&gt;
Аддитивные изменения полей, да, по причине выше: клиенты получают только то, что запрашивают.
Новые значения enum — исключение, потому что клиент, перечисляющий закрытое множество, может
сломаться на значении, которого не ожидал. Удаления и изменения типов ровно так же ломающие, как
их REST-эквиваленты.&lt;/p&gt;
</content:encoded></item><item><title>Как написать гайд по миграции API</title><link>https://changeloop.dev/blog/ru/api-migration-guide/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/api-migration-guide/</guid><description>Гайд по миграции API превращает несовместимое изменение в чек-лист вместо сбоя. Что он должен содержать, и почему одной записи недостаточно.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Гайд по миграции API — это документ, который превращает несовместимое изменение в чек-лист вместо
сбоя: что изменилось, что с этим делать и к какому сроку. Запись changelog может назвать
несовместимое изменение в двух предложениях; гайд по миграции — это то, что вызывающая сторона
реально открывает, когда эти два предложения говорят «это тебя ломает», и ей нужно точно знать,
что редактировать. Публикация записи без гайда — это способ, которым вызывающая сторона узнаёт о
несовместимом изменении из тикета поддержки вместо документа, написанного, чтобы этого не
случилось.&lt;/p&gt;
&lt;h2&gt;Что такое гайд по миграции API?&lt;/h2&gt;
&lt;p&gt;Пошаговый документ, который переводит вызывающую сторону от старой формы API к новой, написанный
для того, у кого есть код для изменения, а не для того, кто ещё решает, использовать ли API
вообще. Это различие важно: гайд по миграции предполагает существующую интеграцию и существующий
production-трафик, поэтому он должен покрывать откат, частичную миграцию и то, как понять,
сработала ли миграция — ничего из этого не нужно гайду для первой интеграции.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Документ&lt;/th&gt;
&lt;th&gt;Предполагает&lt;/th&gt;
&lt;th&gt;Отвечает на&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Гайд по миграции&lt;/td&gt;
&lt;td&gt;Существующую интеграцию&lt;/td&gt;
&lt;td&gt;Как перейти от старой формы к новой?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Запись changelog&lt;/td&gt;
&lt;td&gt;Ничего, только что читательница проверяет&lt;/td&gt;
&lt;td&gt;Что изменилось, и когда?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Референс API&lt;/td&gt;
&lt;td&gt;Ничего, или первую интеграцию&lt;/td&gt;
&lt;td&gt;Что делает этот endpoint?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Уведомление о депрекейшене&lt;/td&gt;
&lt;td&gt;Интеграцию, использующую старое&lt;/td&gt;
&lt;td&gt;Когда это перестанет работать?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Гайд по миграции обычно стоит между последними двумя: уведомление о депрекейшене запускает часы,
а гайд по миграции — то, чему следует вызывающая сторона до того, как эти часы истекут.&lt;/p&gt;
&lt;h2&gt;Когда изменению нужен гайд по миграции, а не просто запись changelog?&lt;/h2&gt;
&lt;p&gt;Когда между старым и новым поведением больше одного шага, или когда изменение затрагивает
достаточно точек вызова, чтобы вызывающей стороне было полезнее проработанный пример, чем
описание. &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Что такое несовместимое изменение, и как его выпустить&lt;/a&gt;
разбирает тест на то, является ли изменение несовместимым; если ответ да, второй вопрос — это
однострочная правка или настоящая миграция. С переименованным полем вызывающая сторона может
справиться просто по записи changelog. Изменение в аутентификации, пагинации или обработке ошибок
почти всегда заслуживает гайда, потому что правильный замещающий код не очевиден из
однопредложенческого описания.&lt;/p&gt;
&lt;h2&gt;Что должен содержать гайд по миграции?&lt;/h2&gt;
&lt;p&gt;Пять вещей, и пропуск любой из них — это то, как гайд превращается в страницу, которую вызывающая
сторона читает один раз, а потом возвращается к методу проб и ошибок. Старый код, показанный так,
как он реально выглядел бы в проекте. Новый код, показанный так же, а не как абстрактное описание
разницы. Что сломается, если ничего не менять — сказано прямо, потому что «ничего» — валидный и
частый ответ, который вызывающая сторона всё равно должна услышать явно. Способ проверить, что
миграция сработала — например, поле ответа или код статуса для проверки. И график: когда старое
поведение перестаёт работать, и доступны ли обе формы тем временем.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## Миграция полей валюты с float на integer (v3.0.0)

До:
  { &amp;quot;amount&amp;quot;: 19.99 }

После:
  { &amp;quot;amount&amp;quot;: 1999 }  // наименьшая единица валюты (центы)

Что меняется: `amount` теперь целое число в наименьшей единице
валюты аккаунта. Код, читающий `amount` как float, будет читать
значение в 100 раз больше начиная с 1 октября 2026 года.

Проверка: после миграции списание $19.99 должно читаться как
`amount: 1999`, а не как `amount: 19.99`.

График: v2 продолжает возвращать float до 15 января 2027 года. v3
возвращает целые числа с момента запуска. Обе версии сейчас активны.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Каждая из этих пяти вещей отвечает на вопрос, который вызывающей стороне иначе пришлось бы
угадывать или задавать поддержке, и именно это реальная стоимость, которую экономит гайд по
миграции.&lt;/p&gt;
&lt;h2&gt;Кто должен его писать, и когда?&lt;/h2&gt;
&lt;p&gt;Тот, кто спроектировал изменение, в тот же момент, когда оно выходит — а не команда поддержки,
восстанавливающая его позже из тикетов. Тот, кто принял решение, знает, на какие части старого
поведения никто не должен был полагаться, а какие были случайным контрактом; гайд, написанный
позже кем-то без этого контекста, склонен либо слишком объяснять очевидное, либо упускать тот
единственный крайний случай, который реально ломает людей. Гайд и запись changelog, объявляющая
несовместимое изменение, должны выходить вместе, а запись должна ссылаться на гайд, а не повторять
его.&lt;/p&gt;
&lt;h2&gt;Как это связано с версионированием и changelog API?&lt;/h2&gt;
&lt;p&gt;Напрямую: гайд по миграции — это подробная версия того, что запись MAJOR в &lt;a href=&quot;https://changeloop.dev/blog/ru/semantic-versioning-changelog/&quot;&gt;semantic versioning и вашем changelog&lt;/a&gt;
только резюмирует в одном предложении. Запись changelog говорит, что изменение несовместимо, и
примерно что изменилось; гайд по миграции — это ссылка, которую должна нести эта запись.
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;Changelog API: что публиковать и кто это читает&lt;/a&gt; перечисляет гайд по
миграции как один из пяти документов, которые ведёт API, каждый отвечает на свой вопрос; это тот,
что отвечает на «как реально перейти от A к B», и он заслуживает собственной страницы именно
потому, что этот ответ обычно слишком длинный для записи changelog.&lt;/p&gt;
&lt;h2&gt;Как долго гайд по миграции должен оставаться опубликованным?&lt;/h2&gt;
&lt;p&gt;Как минимум пока старое поведение остаётся доступным, а в идеале и после. Вызывающей стороне,
мигрирующей на восемнадцать месяцев позже, проигнорировав три уведомления о депрекейшене, гайд
всё ещё нужен, и удаление его в день отключения старого поведения только гарантирует, что
вызывающая сторона, которой он нужнее всего, его не найдёт. Держите его по стабильному URL и
обновляйте раздел графика, а не отзывайте страницу. Собственный
&lt;a href=&quot;https://docs.stripe.com/upgrades&quot;&gt;гайд по апгрейдам&lt;/a&gt; Stripe служит публичным примером этого
паттерна: одна страница, которая остаётся актуальной от релиза к релизу, а не новый документ на
каждую версию, устаревающий в момент выхода следующей. Ваш собственный гайд заслуживает такого же
легко находимого места, рядом с &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;документацией&lt;/a&gt;, которую вызывающая сторона уже читает, а
не спрятанным в архиве блога.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли каждому несовместимому изменению гайд по миграции?&lt;/strong&gt;
Нет. Изменение, которое вызывающая сторона может решить просто по записи changelog — например,
одно переименованное поле с очевидной заменой — не нуждается в отдельном гайде. Изменение,
затрагивающее несколько точек вызова или требующее проработанного примера — нуждается.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли гайд по миграции жить с документацией API или в changelog?&lt;/strong&gt;
С документацией, со ссылкой из записи changelog. Запись — это то, что подписчица видит первым;
гайд — это то, что нужно, как только она решила действовать, и место ему рядом с справочными
материалами, которые вызывающая сторона уже использует.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;В чём разница между гайдом по миграции и уведомлением о депрекейшене?&lt;/strong&gt;
Уведомление о депрекейшене заявляет, что что-то исчезнет, и к какому сроку. Гайд по миграции —
это инструкции о том, что с этим делать. Уведомление о депрекейшене без привязанного гайда по
миграции даёт вызывающей стороне срок, не говоря, как его соблюсти.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли старое и новое поведение документироваться оба во время окна миграции?&lt;/strong&gt;
Да, по возможности на одной странице, чтобы вызывающая сторона видела точно, что изменилось,
вместо того чтобы собирать это из двух отдельных документов, написанных в разное время.&lt;/p&gt;
</content:encoded></item><item><title>Проверка changelog для GitHub Actions</title><link>https://changeloop.dev/blog/ru/changelog-ci-enforcement/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/changelog-ci-enforcement/</guid><description>Проверка changelog в GitHub Actions не пускает merge без записи: шаг, который держится на памяти, обязательно забывают. Как её настроить и что она ломает.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;У каждой команды, которая ведёт changelog вручную, был один и тот же разговор после одного и того
же инцидента: релиз вышел без записи, кто-то спрашивает почему, и честный ответ — человек,
который бы её написал, спешил, и шаг changelog жил только в памяти. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;Автоматизация
changelog&lt;/a&gt; разбирает, что pipeline может безопасно
автоматизировать, а что всё ещё требует человека; проверка changelog в CI — вторая половина этой
проблемы, потому что автоматизация написания не помогает, если никто не обязан вообще её запускать.
GitHub Actions — это то место, где большинство команд уже запускают свои проверки pull request&amp;#39;ов,
так что и эта проверка живёт там же.&lt;/p&gt;
&lt;h2&gt;Почему «мы просим людей добавлять запись» проваливается по предсказуемой схеме?&lt;/h2&gt;
&lt;p&gt;Потому что это конкурирует за внимание со всем остальным в pull request&amp;#39;е, и это единственная
часть без немедленного последствия за пропуск. Тесты проваливаются громко и блокируют merge.
Отсутствующая запись changelog не блокирует ничего, поэтому она проигрывает, как только кто-то
торопится, что на практике большую часть времени. Политика, поддерживаемая памятью, деградирует
именно с той скоростью, которую можно ожидать: хорошо первые несколько недель после согласия
всех, потом тихо заброшена, как только человек, которому было не всё равно, уходит в отпуск или
меняет команду.&lt;/p&gt;
&lt;h2&gt;Что на самом деле проверяет CI-check для записи changelog?&lt;/h2&gt;
&lt;p&gt;Не качество написанного, только то, что запись существует и правильно оформлена, что является
правильным объёмом для проверки changelog, работающей в CI, а не в голове человека.
Распространённая форма: check смотрит на diff PR и требует либо новый
файл в директории changeset&amp;#39;ов (шаблон, который используют &lt;a href=&quot;https://github.com/changesets/changesets&quot;&gt;Changesets&lt;/a&gt;
и похожие инструменты), либо изменённую строку в файле changelog, и проваливает build, если ни
того ни другого нет. Проверка того, что запись на самом деле говорит, по-прежнему происходит там,
где она всегда происходила, в code review, потому что это суждение не место в скрипте.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Что проверяет CI-check&lt;/th&gt;
&lt;th&gt;Что не проверяет&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Есть changeset или строка changelog в diff&lt;/td&gt;
&lt;td&gt;Ясна ли формулировка&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Запись ссылается на правильный пакет, в monorepo&lt;/td&gt;
&lt;td&gt;Заслуживает ли изменение записи вообще&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Файл синтаксически валиден (frontmatter, форма JSON)&lt;/td&gt;
&lt;td&gt;Честна ли запись о влиянии&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Нужна ли она каждому PR, или некоторые изменения освобождены?&lt;/h2&gt;
&lt;p&gt;Некоторые освобождены, и список исключений — то место, где такие системы на самом деле строятся
или забрасываются. Обновление зависимости без видимого эффекта, изменение только тестов,
внутренний рефакторинг без изменения поведения: ни одно из этого не должно заставлять
контрибьюторку выдумывать запись changelog для того, до чего никому, читающему changelog, нет
дела. Работающий шаблон — метка или флаг, которую контрибьюторка может применить
(&lt;code&gt;no-changelog-needed&lt;/code&gt;) и которая удовлетворяет CI-check без файла, проверяемый тем, кто
одобряет PR, так что само исключение проходит ту же проверку, через которую прошла бы запись.&lt;/p&gt;
&lt;h2&gt;Что происходит с законными исключениями, вроде срочного хотфикса?&lt;/h2&gt;
&lt;p&gt;Gate относится к merge, а не к деплою: хотфикс под реальным
временным давлением может смержиться с записью-заполнителем или тикетом на доработку, при
условии что CI-check удовлетворяется намерением, а не только законченным абзацем; некоторые
команды принимают однострочный stub, который мейнтейнерша шлифует перед следующим релизным
срезом. Чего gate никогда не должен позволять — тихо пропустить шаг, потому что забытый stub —
меньший провал, чем запись, которой никогда не существовало, а stub хотя бы оставляет след,
который кто-то может найти позже.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# .github/workflows/changelog-check.yml
on:
  pull_request:
    types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
  changelog:
    if: &amp;gt;-
      !contains(github.event.pull_request.labels.*.name,
      &amp;#39;no-changelog-needed&amp;#39;)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # нужна базовая ветка
      - name: Require changelog entry
        run: |
          base=&amp;quot;origin/${{ github.base_ref }}&amp;quot;
          if ! git diff --name-only &amp;quot;$base&amp;quot;...HEAD \
              | grep -q &amp;#39;^\.changeset/&amp;#39;; then
            echo &amp;quot;No changeset. Add one, or have a maintainer&amp;quot;
            echo &amp;quot;apply the no-changelog-needed label.&amp;quot;
            exit 1
          fi
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Как убедиться, что сама проверка корректна, прежде чем она начнёт блокировать реальные PR?&lt;/h2&gt;
&lt;p&gt;Сначала откройте черновой pull request в одноразовую ветку: один с changeset&amp;#39;ом, один без него и
один с меткой исключения, и убедитесь, что все три получают ожидаемый результат, прежде чем
проверка начнёт применяться к чужой работе. Проверка changelog, которая проваливается открыто,
пропуская каждый PR из-за условия, написанного задом наперёд, хуже, чем отсутствие проверки вообще,
потому что выглядит как покрытие, которого на самом деле нет. &lt;code&gt;workflow_dispatch&lt;/code&gt; на том же файле,
запущенный вручную на паре недавно смерженных PR, ловит большинство таких ошибок без необходимости
в живом pull request.&lt;/p&gt;
&lt;h2&gt;Работает ли та же идея вне GitHub Actions?&lt;/h2&gt;
&lt;p&gt;Форма переносится, меняется только синтаксис. GitLab CI выражает то же правило как блок &lt;code&gt;rules&lt;/code&gt;
джобы, проверяющий &lt;code&gt;$CI_MERGE_REQUEST_LABELS&lt;/code&gt; вместо &lt;code&gt;if&lt;/code&gt; в GitHub Actions, а обязательное
одобрение merge request может заменить собой шаг проверки исключения. Проверка, описанная в этой
статье, сделана на GitHub Actions, потому что это платформа, на которой уже находится большинство
команд, читающих её, но лежащее в основе требование — gate, проверяемый машиной, а не соглашение,
о котором просто попросили, — одинаково везде, где CI запускается перед merge.&lt;/p&gt;
&lt;h2&gt;Работает ли это так же в monorepo?&lt;/h2&gt;
&lt;p&gt;Нужна ещё одна часть: для какого пакета эта запись. &lt;a href=&quot;https://changeloop.dev/blog/ru/monorepo-changelogs/&quot;&gt;Changelog в monorepo&lt;/a&gt;
разбирает, почему единый общерепозиторный файл перестаёт работать, как только пакеты выпускаются
независимо; CI-check наследует то же требование; changeset, не называющий пакет, не является
полезным доказательством того, что нужный changelog обновится, только того, что какой-то файл
где-то изменился в diff. Инструменты, построенные для этого (Changesets — распространённый в
экосистеме JavaScript), просят контрибьюторку выбрать затронутый пакет и semver-приращение в тот
же момент, когда создаётся changeset, так что CI-check получает обе части бесплатно вместо того,
чтобы выводить их позже.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должен ли CI-check блокировать merge, или только предупреждать?&lt;/strong&gt;
Блокировать. Предупреждение функционально идентично вежливой просьбе, которая уже провалилась.
Метка исключения существует именно для того, чтобы у настоящего случая «только предупреждение»
всё равно был законный путь через тот же строгий gate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Кто проверяет, правильно ли применена метка исключения?&lt;/strong&gt;
Тот, кто одобряет pull request, как часть проверки, которую он и так уже делает. Метка никогда
не должна применяться самостоятельно и без проверки, иначе она становится той же тихой лазейкой,
которую gate должен был закрыть.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Заменяет ли принуждение в CI необходимость pipeline автоматизации changelog?&lt;/strong&gt;
Нет, оно его питает. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;Автоматизация changelog&lt;/a&gt; разбирает
превращение структурированных записей в страницу, ленту и письмо; CI-check — то, что гарантирует
существование этих структурированных записей, чтобы их вообще было что автоматизировать.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какая самая маленькая версия этого стоит того, чтобы построить первой?&lt;/strong&gt;
Один check, который проваливается, если не изменился ни один файл под назначенной директорией
changelog, с одной меткой исключения. Маршрутизация по пакетам и вывод semver для monorepo могут
прийти позже; главная привычка — запись существует, или кто-то явно сказал, что она не нужна, —
то, что стоит иметь с первого дня.&lt;/p&gt;
</content:encoded></item><item><title>Как отказать в запросе на функцию, не потеряв клиентку</title><link>https://changeloop.dev/blog/ru/declining-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/declining-feature-requests/</guid><description>Замыкание цикла обычно означает сказать кому-то, что его запрос выпущен. Более трудная половина — сказать нет, не повредив отношения с клиенткой.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Замыкание цикла обычно означает сказать кому-то, что его запрос выпущен. Более трудная половина,
для которой у большинства систем отслеживания вообще нет процесса — сказать нет. Большинство
запросов на функции никогда не выпускаются, а значит, большая часть замыкания цикла, которую
продукт реально должен своим пользовательницам — это отказ, а не анонс, и плохо оформленный отказ
стоит больше доброй воли, чем стоило бы молчание. Хорошо оформленный, он может стоить почти
ничего, потому что чаще всего попросившей хочется больше всего знать, что её услышали, а не саму
функцию.&lt;/p&gt;
&lt;h2&gt;Почему хороший отказ важен не меньше, чем хороший релиз?&lt;/h2&gt;
&lt;p&gt;Потому что молчание читается как отказ без объяснения, а объяснённое нет читается как внимание. Та,
кто ничего не слышит, предполагает, что запрос проигнорировали или потеряли, и оба вывода учат её
перестать утруждать себя вопросами — тот же результат, который продукт получает от настоящего
отказа, только достигнутый медленнее и с большей обидой по пути. Ответ, который говорит нет, ясно
и с причиной, замыкает цикл так же полно, как выпущенная функция, и делает это быстрее.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ответ&lt;/th&gt;
&lt;th&gt;Что узнаёт попросившая&lt;/th&gt;
&lt;th&gt;Стоимость для отношений&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Молчание&lt;/td&gt;
&lt;td&gt;Никто не прочитал, или никому не важно&lt;/td&gt;
&lt;td&gt;Высокая, и растёт с каждым будущим запросом&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Автоответ без причины&lt;/td&gt;
&lt;td&gt;Где-то в очереди, бессрочно&lt;/td&gt;
&lt;td&gt;Средняя; покупает время, но не доверие&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Отказ с причиной&lt;/td&gt;
&lt;td&gt;Прочитан, рассмотрен и получил ответ&lt;/td&gt;
&lt;td&gt;Низкая, если причина честная&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Отказ с альтернативой&lt;/td&gt;
&lt;td&gt;Реальная потребность действительно услышана&lt;/td&gt;
&lt;td&gt;Самая низкая; часто строит доверие&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что заставляет отказ приземлиться плохо?&lt;/h2&gt;
&lt;p&gt;Почти всегда три вещи в сочетании. Шаблонность: заготовленное «спасибо за фидбек», не
упоминающее, о чём реально просили, читается так, будто его вообще не читали, даже если читали.
Задержка: отказ, приходящий через шесть месяцев после запроса, когда попросившая уже забыла, что
спрашивала, ощущается хуже, чем быстрое нет, потому что подразумевает, что запрос лежал нетронутым
вместо того, чтобы быть рассмотренным и отклонённым. И причина, которая не выдерживает проверки:
«не в нашем roadmap» не отвечает ни на что, в то время как «это потребовало бы редизайна того, как
работают права доступа, а мы не планируем трогать это в этом году» даёт попросившей то, что она
реально может оценить и, если это достаточно важно, эскалировать или обойти.&lt;/p&gt;
&lt;h2&gt;Что реально должен говорить хороший отказ?&lt;/h2&gt;
&lt;p&gt;Четыре вещи, в этом порядке: подтверждение, называющее конкретный запрос, а не общий пересказ;
реальную причину, честно сформулированную даже когда честная причина — «это не вписывается в то,
куда движется продукт» вместо более мягкой отговорки; закрыта ли дверь или просто сейчас не
открыта, потому что это требует очень разного тона; и, когда она есть, альтернативу, отвечающую
на лежащую в основе потребность, даже если это не буквально запрошенная функция.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Привет, Джейми,

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

Если реальная боль — быстро пригласить большую команду, API
поддерживает скриптованные индивидуальные приглашения, что даёт
почти всю скорость без обхода проверки: [ссылка]. Дайте знать, если
нужна помощь это настроить.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Обратите внимание, что это делает то, чего не может шаблон: называет реальную функцию, даёт
причину, привязанную к настоящему дизайн-решению, а не к смутной политике, и предлагает путь,
решающий лежащую в основе проблему, а не просто закрывающий тикет.&lt;/p&gt;
&lt;h2&gt;Чем это отличается от замыкания цикла на выпущенной функции?&lt;/h2&gt;
&lt;p&gt;Механика похожа, тон — нет. &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;Замыкание цикла обратной связи с клиентом&lt;/a&gt;
разбирает выпущенный случай, где сообщение — хорошая новость, а главный риск — забыть его
отправить. Отказ — плохая новость, или как минимум нежеланная новость, и требует больше внимания к
данной причине и меньше автоматизации в доставке: уведомление о выпущенной функции может быть
шаблонным комментарием, запущенным изменением статуса, но отказ, читающийся как шаблонный — именно
тот провал, которого пытается избежать весь этот подход. Оба всё же разделяют одно требование:
исходный запрос должен оставаться связанным с попросившей, та же дисциплина отслеживания, которую
разбирает &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;отслеживание запросов на функции&lt;/a&gt;, иначе нет способа
отправить любое из этих двух сообщений индивидуально.&lt;/p&gt;
&lt;h2&gt;Должен ли отказ быть публичным, как статус на публичном roadmap?&lt;/h2&gt;
&lt;p&gt;Обычно не конкретная причина, хотя статус — да. &lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;Публичный roadmap&lt;/a&gt;
разбирает метки статуса, которые попросившая может проверить, не спрашивая снова, и статус
«отклонено» или «не планируется» может быть частью этой системы. Но подробная причина, особенно
когда она затрагивает внутренние приоритеты или неловкий контекст, обычно стоит больше в
индивидуальном ответе, чем на публичной странице статуса, где та же формулировка должна работать
для каждой читательницы вместо единственного человека, который реально спрашивал.&lt;/p&gt;
&lt;h2&gt;Заслуживает ли каждый отклонённый запрос индивидуального ответа?&lt;/h2&gt;
&lt;p&gt;Каждый запрос от названного, доступного человека — да, хотя бы короткого. Запросы с большим
объёмом, дубликаты или анонимные — исключение: группировка похожих запросов и ответ раз на группу,
или обновление общей метки статуса, разумны, когда индивидуальные ответы реально не
масштабируются. Границу, которую нужно держать — «мы не можем ответить всем индивидуально» должно
быть реальным операционным ограничением, проверенным против фактического объёма, а не отговоркой
по умолчанию, чтобы пропустить ответ, который занял бы две минуты.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Лучше отказать быстро со слабой причиной, или потратить время на хорошую?&lt;/strong&gt;
Быстро, с честной причиной, побеждает любое из двух по отдельности. Быстрый ответ с реальной
причиной, даже короткой, превосходит медленный ответ с отполированной; сама задержка — часть того,
что разрушает доверие.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли отказ когда-либо обещать пересмотреть запрос позже?&lt;/strong&gt;
Только если это реально вероятно и есть механизм реально его пересмотреть — например, метка,
поднимающая его снова на цикле планирования. Расплывчатое «будем иметь в виду» без такого
механизма функционально то же самое, что молчание, только сформулированное добрее.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что если честная причина — то, чем компания не может поделиться, например конкурентная озабоченность?&lt;/strong&gt;
Скажите это прямо, вместо того чтобы придумывать более мягкую причину. «Мы не можем поделиться
конкретным обоснованием здесь, но это не то, что мы планируем строить» честнее, и вызывает больше
уважения, чем выдуманное объяснение, разваливающееся при уточняющем вопросе.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Означает ли отказ в запросе, что его нужно удалить из отслеживания?&lt;/strong&gt;
Нет. Сохраните его, помеченным как отклонённый с причиной, чтобы он был частью паттерна, против
которого группируется следующий похожий запрос, и чтобы изменившийся позже контекст (новая
интеграция, новый приоритет команды) мог поднять его снова, а не начинать оценку с нуля.&lt;/p&gt;
</content:encoded></item><item><title>Как отслеживать запросы на функции, не теряя их</title><link>https://changeloop.dev/blog/ru/feature-request-tracking/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/feature-request-tracking/</guid><description>Отслеживание запросов обычно проваливается: запросы не доходят никуда, или доходят туда, куда никто не возвращается. Система, выдерживающая оба сбоя.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Отслеживание запросов на функции почти всегда проваливается одним из двух способов. Либо
запросам некуда деваться, и они живут в почтовых ящиках и тредах Slack, где их забывают по
одному, либо у них есть место, куда деваться, но туда никто не возвращается, и их забывают
все разом. Работающая система должна выдерживать оба сбоя: нужно одно место, куда попадает
каждый запрос, и причина открыть это место снова в следующем месяце.&lt;/p&gt;
&lt;h2&gt;Откуда на самом деле берутся запросы на функции?&lt;/h2&gt;
&lt;p&gt;Из большего числа каналов, чем учитывает большинство систем отслеживания. Тикет поддержки с
«было бы неплохо, если». Комментарий на публичном roadmap. Звонок продажников, где потенциальный
клиент называет ту самую вещь, которая блокирует сделку. Виджет в продукте. У каждого канала своя
владелица и свои инструменты, и именно поэтому запросы рассеиваются: очередь тикетов поддержки и
бэклог продуктовой команды редко бывают одной и той же системой, а запрос, дошедший только до
одного из них, на практике дошёл только до одного отдела.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Источник&lt;/th&gt;
&lt;th&gt;Типичная владелица&lt;/th&gt;
&lt;th&gt;Где обычно теряется&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Тикеты поддержки&lt;/td&gt;
&lt;td&gt;Команда поддержки&lt;/td&gt;
&lt;td&gt;Закрыт как решённый, больше не пересматривается&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Звонки продажников&lt;/td&gt;
&lt;td&gt;Продажи / управление аккаунтами&lt;/td&gt;
&lt;td&gt;Поле CRM, которое никто в продукте не читает&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Виджет в продукте&lt;/td&gt;
&lt;td&gt;Продукт&lt;/td&gt;
&lt;td&gt;Отправленная форма без последующих действий&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Комментарии на roadmap&lt;/td&gt;
&lt;td&gt;Кто бы ни строил roadmap&lt;/td&gt;
&lt;td&gt;Сам тред комментариев&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Соцсети / отзывы&lt;/td&gt;
&lt;td&gt;Маркетинг или никто&lt;/td&gt;
&lt;td&gt;Один раз заскриншотили, потом пропало&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Одна форма приёма для каждого канала не работает, потому что её никто не примет. Работает одно
место назначения, куда стекается каждый канал, даже если маршрутизация сначала — пять минут
копипаста в день, пока не автоматизировано.&lt;/p&gt;
&lt;h2&gt;Что на самом деле ломает отслеживание запросов на функции?&lt;/h2&gt;
&lt;p&gt;Почти всегда две вещи. Первая — отсутствующее место назначения: на запросы отвечают в том канале,
куда они пришли, и нигде не фиксируют надолго, так что один и тот же запрос от трёх разных
клиентов выглядит как три изолированных, несвязанных ответа вместо одного сигнала. Вторая, более
частая — место назначения, которое заполняется и перестаёт читаться. Таблица с 400 строками без
фильтрации — уже не система отслеживания; это архив, который случайно можно редактировать.&lt;/p&gt;
&lt;p&gt;Второй сбой опаснее, потому что кажется, будто отслеживание работает. Запросы регистрируются.
Ничего не выглядит сломанным, пока кто-нибудь не спросит «сколько людей просили X», и честный
ответ — «нам пришлось бы прочитать все 400 строк, чтобы узнать».&lt;/p&gt;
&lt;h2&gt;Что на самом деле должен фиксировать запрос на функцию?&lt;/h2&gt;
&lt;p&gt;Достаточно, чтобы позже ответить на три вопроса, не перечитывая исходное сообщение: что было
запрошено, по возможности собственными словами того, кто попросил; кто попросил, и как с ним
связаться, если ответ в итоге — «мы это построили»; и что нужно знать, чтобы понять, обычный это
запрос или единичный случай. Дословная цитата ценнее пересказа, потому что пересказ, написанный
тем, кто триажировал запрос, уже несёт в себе его собственное прочтение — и именно это
прочтение второй человек не сможет проверить шесть месяцев спустя.&lt;/p&gt;
&lt;h2&gt;Какие метки того стоят?&lt;/h2&gt;
&lt;p&gt;Две, и они отвечают на разные вопросы. Метка &lt;strong&gt;типа&lt;/strong&gt; отделяет запрос на функцию от отчёта об
ошибке, потому что обоим нужны разные владелицы и сроки, а смешивание их в одной очереди даёт
самым громким жалобам обгонять запросы. Метка &lt;strong&gt;приоритета&lt;/strong&gt;, ограниченная небольшим набором вроде
low, medium и high, отделяет «блокирует кому-то использование продукта» от «было бы приятно»,
потому что оба заслуживают очень разного времени ответа, и ни один не должен наследовать темп
другого. Правильная
установка метки &lt;strong&gt;типа&lt;/strong&gt; предполагает, что запрос — то, чем он себя называет; &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-vs-bug-report/&quot;&gt;когда запрос на
функцию на самом деле — отчёт об ошибке&lt;/a&gt; разбирает
случай, когда собственные слова клиентки направляют эту метку в неверную сторону.&lt;/p&gt;
&lt;p&gt;Автоматизированный триаж может применить обе в момент прихода запроса. В changeloop отправка
через виджет получает метку &lt;code&gt;feature-request&lt;/code&gt; или &lt;code&gt;bug&lt;/code&gt; и метку &lt;code&gt;priority:low|medium|high&lt;/code&gt; за
один проход, плюс тег &lt;code&gt;from-widget&lt;/code&gt;, чтобы источник был виден без открытия элемента. Этого
достаточно, чтобы фильтровать бэклог за минуту вместо целого дня: покажи мне каждый
высокоприоритетный запрос на функцию, пришедший через виджет в этом месяце.&lt;/p&gt;
&lt;p&gt;Третья метка стоит того, как только появляется публичный roadmap: статус, который тот, кто
попросил, может проверить сам. &lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;Публичный roadmap&lt;/a&gt; целиком разбирает
статусы planned, building и shipped; коротко — эта метка превращает приватную очередь в то, что
попросивший может посмотреть, не спрашивая снова.&lt;/p&gt;
&lt;h2&gt;Как решить, что строить дальше?&lt;/h2&gt;
&lt;p&gt;Сначала группировать, потом считать. Десять по-разному сформулированных запросов на одну и ту же
базовую возможность читаются как десять разрозненных строк в таблице, и как сильный сигнал, как
только их сгруппировали — и эта группировка обычно и есть недостающий шаг, а не подсчёт. Сырое
количество без группировки склонно вознаграждать функцию с самым цепляющим названием, а не ту, за
которой стоит больше реального спроса.&lt;/p&gt;
&lt;p&gt;Взвешивай по тому, кто просит, а не только по тому, сколько просят. Запрос от аккаунта, близкого
к продлению, несёт другую срочность, чем тот же запрос от пробной регистрации, а система
отслеживания, отбрасывающая этот контекст ради голого числа, оптимизирует под цифру, которую
проще всего посчитать, а не самую полезную.&lt;/p&gt;
&lt;p&gt;Каждое решение здесь также порождает запросы, которые проигрывают, и они тоже заслуживают
ответа; &lt;a href=&quot;https://changeloop.dev/blog/ru/declining-feature-requests/&quot;&gt;как отказать в запросе на функцию&lt;/a&gt; разбирает, что
говорить тем, чей запрос не прошёл. Группировка и взвешивание — только половина ответа на &amp;quot;что
строить дальше&amp;quot;; &lt;a href=&quot;https://changeloop.dev/blog/ru/prioritizing-feature-requests/&quot;&gt;приоритизация запросов на функции&lt;/a&gt;
разбирает реальные фреймворки, RICE, взвешивание по доходу и грубые счета, и где каждый из них
ломается.&lt;/p&gt;
&lt;h2&gt;Как замкнуть цикл, когда что-то выпущено?&lt;/h2&gt;
&lt;p&gt;Это шаг, который системы отслеживания пропускают чаще всего, и тот, что попросившие действительно
замечают. &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;Замыкание цикла обратной связи с клиентом&lt;/a&gt; целиком
разбирает механику; здесь важно то, что замыкание цикла работает только если исходный запрос
остался связан с тем, кто его сделал. Шаблон запроса на функцию, построенный из GitHub issue, с
привязкой личности попросившего к самому issue, а не спрятанной в комментарии — вот что делает
возможным автоматическое уведомление «выпущено» вместо того, которое кто-то должен вспомнить
отправить. &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-template/&quot;&gt;Шаблон запроса на функцию&lt;/a&gt; показывает конкретный
шаблон и назначение каждого поля.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Каким инструментом отслеживать запросы на функции?&lt;/strong&gt;
То, что команда уже проверяет ежедневно, побеждает любой выделенный инструмент, который никто не
открывает. Трекер issues на GitHub хорошо работает, если инженерия уже живёт там; лёгкая доска
хорошо работает, если продукт живёт там. Инструмент важен меньше, чем то, открывают ли его снова.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как избежать дублирования запросов на функции?&lt;/strong&gt;
Группировать по базовой возможности перед триажем по формулировке. Поиск среди существующих
запросов перед созданием нового ловит большинство дублей; ежемесячный проход группировки ловит
остальное.
&lt;a href=&quot;https://changeloop.dev/blog/ru/duplicate-feature-requests/&quot;&gt;Объединение дублей без потери оригинального голоса&lt;/a&gt;
разбирает, что делать с формулировкой, как только сама группировка сделана, чтобы объединение
тихо не сужало запрос до того, что попросила подача, пришедшая первой.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли каждый запрос на функцию получать ответ?&lt;/strong&gt;
Каждый должен получить подтверждение, пусть и короткое, но не каждому нужно немедленное решение.
Видимый статус, вроде метки roadmap, которую попросивший может проверить сам, заменяет
большинство индивидуальных ответов, которые команде иначе пришлось бы давать.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;В чём разница между отслеживанием запросов и публичным roadmap?&lt;/strong&gt;
Отслеживание — это внутренняя запись каждого запроса, включая те, что никогда не будут
выпущены. Публичный roadmap — подмножество, на которое команда публично берёт обязательство, со
статусом, который попросивший может увидеть, не спрашивая снова.&lt;/p&gt;
</content:encoded></item><item><title>Release notes для функции за флагом: что сказать и когда</title><link>https://changeloop.dev/blog/ru/feature-flags-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/feature-flags-feature-requests/</guid><description>Release notes для функции за флагом различают merge и выпуск: с флагом это разные события. Закрыв петлю рано, вы сообщите о функции, которую ещё не видно.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Закрытие петли по запросу на функцию предполагает чистый момент, в который вещь была выпущена.
Feature flag убирает этот момент, и именно поэтому с release notes для функции за флагом так трудно угадать время. Код мёржится, флаг существует, и днями или неделями после этого
функция одновременно жива в продакшене и невидима почти для всех, кто мог бы захотеть ею
воспользоваться, часто включая того, кто изначально её запросил. Слишком раннее уведомление
приводит человека к функции, которой ещё нет. Слишком позднее делает так, что петля, которая
должна была строить доверие, вместо этого читается как забытая.&lt;/p&gt;
&lt;h2&gt;Почему флаг ломает обычную последовательность «выпустить, уведомить»?&lt;/h2&gt;
&lt;p&gt;Потому что он разделяет одно событие как минимум на два: код, становящийся живым, и флаг,
включаемый для конкретного аккаунта. Любой процесс закрытия петли обратной связи предполагает,
что эти два события происходят вместе, что верно для большинства релизов и неверно для всего, что
находится за флагом, используемым для поэтапного раскатывания, таргетинга или как аварийный
выключатель. &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;Закрытие петли обратной связи клиента&lt;/a&gt; описывает
уведомление запросившего ровно в тот момент, когда запись changelog одобрена и опубликована; этот
шаг написан для случая, когда публикация записи и пригодность функции к использованию — один и
тот же момент, а флаг — это как раз случай, когда это не так.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Момент&lt;/th&gt;
&lt;th&gt;Что верно&lt;/th&gt;
&lt;th&gt;Нужно ли уже уведомлять запросившего&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Код смёржен, флаг выключен везде&lt;/td&gt;
&lt;td&gt;Функция существует, никто не может её использовать&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Флаг включён для аккаунта запросившего&lt;/td&gt;
&lt;td&gt;Функция существует, конкретно этот человек может её использовать&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Флаг включён для процента раскатывания, который его исключает&lt;/td&gt;
&lt;td&gt;Функция существует, этот человек всё ещё не может её использовать&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Флаг полностью убран, функция просто включена&lt;/td&gt;
&lt;td&gt;Функция существует для всех&lt;/td&gt;
&lt;td&gt;Да, если ещё не уведомлён&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Какое реальное правило для того, когда уведомлять кого-то?&lt;/h2&gt;
&lt;p&gt;Уведомляйте, когда флаг включён для его аккаунта, а не когда код смёржен и не когда флаг создан.
Это единственное правило покрывает каждую строку таблицы выше, потому что привязывает уведомление
к единственному факту, который действительно важен для запросившего: может ли он прямо сейчас
пойти и воспользоваться этой вещью. Уведомление, привязанное к мержу или созданию флага, на самом
деле является отчётом об инженерном прогрессе, а тот, кто запросил функцию, не хочет отчёт о
прогрессе — он хочет знать, когда идти смотреть.&lt;/p&gt;
&lt;h2&gt;Значит ли это, что запросившему нужен ранний или особый доступ?&lt;/h2&gt;
&lt;p&gt;Не обязательно, и принуждение к этому создаёт собственную проблему. Если флаг раскатывается
постепенно по причинам нагрузки или стабильности, перемещение одного аккаунта в начало очереди
только ради более быстрого закрытия петли подрывает саму причину, по которой раскатывание
поэтапно. Честные варианты: подождать, пока аккаунт запросившего естественным образом дойдёт до
раскатывания, и уведомить тогда, либо, если срочность это оправдывает, намеренно включить флаг
для него раньше — как реальное решение того, кто владеет раскатыванием, а не как побочный эффект
желания отправить уведомление.&lt;/p&gt;
&lt;h2&gt;А если флаг — это аварийный выключатель, а не механизм раскатывания?&lt;/h2&gt;
&lt;p&gt;Тогда безопасное предположение переворачивается. Флаг, задуманный для быстрого отключения функции,
а не для поэтапного её выпуска, обычно означает, что функция должна быть полностью живой сразу
после создания, а флаг существует ради безопасности, а не последовательности. В этом случае
уведомление запросившего в момент деплоя корректно, как и при любом релизе без флага; наличие
флага — это операционная деталь, которая не должна менять, когда закрывается петля. Различие,
которое имеет значение, — для чего нужен флаг, а не существует ли он вообще.&lt;/p&gt;
&lt;h2&gt;Меняет ли флаг то, что должны говорить release notes о функции за флагом?&lt;/h2&gt;
&lt;p&gt;Он меняет, когда запись публикуется, а не что она содержит. Запись, опубликованная ровно в
момент, когда флаг включён для 100% аккаунтов, читается точно как обычная запись changelog, и так
и должно быть; читатель, находящий её позже, не имеет причин знать, что флаг вообще когда-либо
был задействован. Чего она не должна делать — публиковаться, пока флаг включён лишь для малого
процента раскатывания, потому что публичная запись changelog отправляет всех, кто её читает,
включая аккаунты без флага, искать функцию, которую они не найдут, что является худшей версией
той же проблемы, но в масштабе всего продукта вместо масштаба одного запросившего. Это правило про
тайминг — вся разница между release notes о функции за флагом и обычной записью: содержание то же,
меняется только дата публикации. &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;Как писать release notes&lt;/a&gt;
разбирает дисциплину «действие не требуется», которая применима и здесь: читателям нужно знать,
касается ли это их, а не просто что это где-то существует.&lt;/p&gt;
&lt;h2&gt;Должны ли письма об обновлении продукта иначе обращаться с функцией за флагом?&lt;/h2&gt;
&lt;p&gt;Да, в основном откладывая, а не переписывая. &lt;a href=&quot;https://changeloop.dev/blog/ru/product-update-email/&quot;&gt;Шаблон письма об обновлении продукта&lt;/a&gt;
разбирает целевые уведомления против широких дайджестов; функция за флагом — случай, когда
таймингом целевого уведомления нужно проверять против собственного состояния флага получателя
перед отправкой, чего широкий дайджест вообще не может сделать легко, что ещё одна причина, почему
дайджест — неверный канал для всего, что всё ещё посреди раскатывания.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли говорить запросившему, что его функция «скоро появится», когда флаг существует, но ещё не включён для него?&lt;/strong&gt;
Только если к этому привязана реальная, близкая дата, и даже тогда экономно. «Скоро» без даты
читается, спустя достаточно времени, точно так же как молчание, и создаёт второе обещание,
которое тоже нужно отслеживать и выполнять.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Кто решает, когда флаг зашёл достаточно далеко, чтобы закрыть петлю?&lt;/strong&gt;
Тот, кто владеет раскатыванием, а не тот, кто владеет уведомлением. Владелец раскатывания знает,
близки ли «100% аккаунтов» или всё ещё в неделях; привязка шага закрытия петли к его состоянию, а
не к фиксированной календарной дате, сохраняет уведомление честным.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Получает ли функция за постоянным флагом (никогда полностью не убираемым) когда-либо публичную запись changelog?&lt;/strong&gt;
Да, как только она достигает того, что означает «общая доступность» для этого продукта, даже если
сам флаг остаётся в коде навсегда по операционным причинам. Запись changelog — о доступности для
читателя, а не о деталях реализации того, как эта доступность достигается.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;А если флаг убирают, и функцию убивают вместо выпуска?&lt;/strong&gt;
Это отказ, а не уведомление о выпуске, и он заслуживает той же заботы, что и любой другой отказ.
&lt;a href=&quot;https://changeloop.dev/blog/ru/declining-feature-requests/&quot;&gt;Как отказать в запросе на функцию&lt;/a&gt; разбирает, что должно
говорить это сообщение; честное закрытие петли иногда означает закрыть её отказом.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли release notes о функции за флагом отдельный шаблон, отличный от обычной записи?&lt;/strong&gt;
Шаблон не меняется, нужен только шаг проверки перед публикацией: сверить состояние флага для
аккаунта, который спрашивал, а не только то, что код смёржен, и придержать запись, пока эта
проверка не пройдена. Всё остальное в записи — формулировка, длина, дисциплина FAQ — остаётся
таким же, как в любой другой release note.&lt;/p&gt;
</content:encoded></item><item><title>Когда запрос на функцию на самом деле — отчёт об ошибке</title><link>https://changeloop.dev/blog/ru/feature-request-vs-bug-report/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/feature-request-vs-bug-report/</guid><description>Тикет поддержки с просьбой новой настройки может быть обходным путём для скрытой ошибки. Неверная метка отправляет его не той владелице и не в ту очередь.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;«Можете добавить настройку, увеличивающую лимит экспорта?» читается как запрос на функцию, и
большинство систем триажа сразу так его помечают. Иногда так и есть. Иногда экспорт падает на
числе ниже документированного лимита из-за ошибки, и клиентка, не видя код, придумала самое
правдоподобное решение, какое может описать: дайте мне число побольше, и, может, заработает.
&lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;Какие метки того стоят&lt;/a&gt; разбирает метку типа, которая делит
бэклог на запросы на функции и ошибки; это случай, когда собственные слова клиентки направляют
метку в неверную сторону, а цена ошибки — медленный дрейф к бэклогу, полному запросов, которых
никто на самом деле не хочет, стоит только заглянуть под них.&lt;/p&gt;
&lt;h2&gt;Как выглядит запрос на функцию, который на самом деле — ошибка?&lt;/h2&gt;
&lt;p&gt;Он называет обходной путь вместо проблемы. Настоящий запрос на функцию обычно описывает
результат, который продукт вообще не поддерживает: «дайте мне запланировать это на потом»,
«добавьте тёмный режим». Неверно классифицированная ошибка описывает конкретное число, порог или
поведение, которое звучит как отсутствующая настройка, но на самом деле является симптомом:
«увеличьте timeout», «добавьте опцию повторной попытки», «дайте мне экспортировать больше строк
за раз». Признак в том, что просительница предлагает реализацию, настройку, переключатель,
переопределение, вместо того чтобы описать цель, потому что она уже попробовала функцию как
документировано, и та не сделала того, что документация обещает.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Сигнал&lt;/th&gt;
&lt;th&gt;Запрос на функцию&lt;/th&gt;
&lt;th&gt;Ошибка, замаскированная под запрос на функцию&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Что описывает просительница&lt;/td&gt;
&lt;td&gt;Результат, которого продукт не может дать&lt;/td&gt;
&lt;td&gt;Параметр, который она хочет изменить&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Покрывает ли это уже документированное поведение&lt;/td&gt;
&lt;td&gt;Нет, действительно отсутствует&lt;/td&gt;
&lt;td&gt;Да, но работает не так, как документировано&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Исчезает ли запрос при больших усилиях&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Иногда, если ошибка зависит от порога&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Куда должно направляться&lt;/td&gt;
&lt;td&gt;Бэклог продукта&lt;/td&gt;
&lt;td&gt;Очередь ошибок&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Почему это важнее, чем кажется?&lt;/h2&gt;
&lt;p&gt;Потому что у двух очередей разные владелицы, сроки и критерии успеха, и ошибка, заведённая как
запрос на функцию, приоритизируется против запросов на функции, конкурируя за внимание с
настоящими пробелами продукта вместо того, чтобы быть исправленной в срок, которого заслуживает
ошибка. &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;Как отслеживать запросы на функции&lt;/a&gt; разбирает,
почему смешивание ошибок и функций в одной очереди позволяет самым громким жалобам обгонять
настоящие запросы; запрос на функцию, тайно являющийся ошибкой, наносит обратный вред, остаётся
в бэклоге продукта, собирая голоса за «функцию», которая исчезла бы, как только базовая ошибка
была бы исправлена, что тратит впустую сигнал приоритизации для всех, кто читает этот бэклог.&lt;/p&gt;
&lt;h2&gt;Как отличить, когда собственные слова клиентки указывают в неверную сторону?&lt;/h2&gt;
&lt;p&gt;Спросите, чего она ожидала, а не что хочет, чтобы вы добавили. «Экспорт упёрся в 500 строк, а
мне нужно 2000, можете поднять лимит» звучит как запрос на функцию повышения лимита, пока
уточняющий вопрос, «500 — это документированный лимит», не раскрывает, что документированное
число было 5000, и экспорт падает раньше времени. Только этот один вопрос, чего она ожидала
против того, что произошло, выполняет большую часть работы по сортировке, потому что у
настоящего запроса на функцию нет документированного поведения, которому он не соответствует;
нечего ожидать, потому что возможности ещё не существует.&lt;/p&gt;
&lt;h2&gt;Должны ли это решать агенты поддержки или инженерки?&lt;/h2&gt;
&lt;p&gt;Агенты поддержки делают первый проход, потому что видят тикет первыми, но метка должна быть
легко изменяемой и дёшево ошибочной, а не разовым решением, которое навсегда закрепляет элемент
в неверной очереди. Лёгкая вторая проверка, инженерка, еженедельно просматривающая новые метки
«запрос на функцию» на предмет всего, что пахнет замаскированной ошибкой, ловит те случаи,
которые агент поддержки без контекста кодовой базы не смог бы распознать. Это не обязательно
формально; это скорее пятиминутный взгляд, чем процесс ревью.&lt;/p&gt;
&lt;h2&gt;Меняется ли закрытие цикла после нахождения настоящей ошибки?&lt;/h2&gt;
&lt;p&gt;Да, и это улучшает сообщение, которое вы можете отправить. &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;Закрытие цикла обратной связи с
клиентом&lt;/a&gt; разбирает уведомление просительницы, когда её
просьба выполнена; переклассифицированная ошибка получает лучшую версию этого сообщения, потому
что «мы нашли и исправили ошибку за этим» звучит как компетентность, тогда как «мы построили
функцию, которую вы просили» было бы правдой только случайно, потому что настоящий запрос на
функцию, действительно более высокий лимит экспорта, может никогда не быть построен, как только
ошибка исчезнет, а исходного лимита в 5000 строк окажется достаточно.&lt;/p&gt;
&lt;h2&gt;Что происходит, если неверная классификация никогда не замечена?&lt;/h2&gt;
&lt;p&gt;Бэклог заполняется запросами, которые выглядят как настоящий спрос, но им не являются, и решения
о приоритизации, принятые против этого бэклога, наследуют искажение. «Функция» с сорока голосами
может на самом деле быть сорока людьми, натыкающимися на одну и ту же ошибку, и построение
буквального запроса, настройки для повышения лимита, который никогда на самом деле не был
ограничением, доставляет сложность, которая ничего не исправляет, пока базовая ошибка продолжает
порождать новые «запросы на функции» от клиенток, которые ещё не нашли эту ветку.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли добавлять формальный шаг для проверки каждого запроса на функцию на известные ошибки?&lt;/strong&gt;
Не формальный шаг, скорее привычку: кто бы ни триажировал новый запрос на функцию, должен
спросить «уже ли документированное поведение утверждает, что делает это», прежде чем применять
метку, потому что только этот вопрос ловит большинство неверных классификаций без добавления
процессной нагрузки.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что если клиентка настаивает, что это запрос на функцию, даже после того как ошибка найдена?&lt;/strong&gt;
Объясните, что вы нашли и почему предложенная ею настройка больше не понадобится, как только
ошибка исправлена. Большинство клиенток просят обходной путь, потому что предполагали, что
настоящее исправление недоступно, а не потому что конкретно хотели эту настройку.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Теряет ли переклассифицированный элемент голоса или комментарии, собранные как запрос на функцию?&lt;/strong&gt;
Он должен сохранить их, видимыми, потому что эти голоса — доказательство, которое привело к
нахождению ошибки в первую очередь, а скрытие этого следа затрудняет обнаружение той же неверной
классификации в следующий раз, на другом тикете.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Может ли это случиться наоборот, отчёт об ошибке, который на самом деле является запросом на функцию?&lt;/strong&gt;
Реже, но да: «это сломано» иногда означает «это не делает того, что я предполагала, что оно
будет делать», что является отсутствующей возможностью, а не дефектом. Тот же вопрос, чего
ожидала против того, что документировано, сортирует и в эту сторону.&lt;/p&gt;
</content:encoded></item><item><title>Тикеты Поддержки vs. Запросы Функций: Чему Доверять?</title><link>https://changeloop.dev/blog/ru/feedback-signal-quality/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/feedback-signal-quality/</guid><description>Тикет поддержки и доска запросов на функции измеряют разное, и приравнивание всплеска в одном к всплеску в другом даёт уверенные, но неверные приоритеты.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Доска запросов на функции фиксирует то, что пользователи просят, когда у них есть время сесть и
описать, чего они хотят. Тикет поддержки фиксирует, на чём пользователи застряли прямо сейчас,
часто раздражённые, часто без словаря, чтобы аккуратно описать лежащий в основе запрос. Оба —
реальный сигнал, и команды, смотрящие только на один из двух, в итоге уверенно решают не ту
проблему, потому что каждый канал систематически перепредставляет разный тип пользователя и разный
тип потребности. &lt;a href=&quot;https://changeloop.dev/blog/ru/prioritizing-feature-requests/&quot;&gt;Приоритизация запросов на функции&lt;/a&gt;
разбирает ранжирование уже стоящего на доске; это о разрыве между тем, что вообще доходит до доски,
и тем, что появляется только как тикет поддержки.&lt;/p&gt;
&lt;h2&gt;Почему одна и та же лежащая в основе проблема появилась бы в одном канале и не в другом?&lt;/h2&gt;
&lt;p&gt;Потому что у двух каналов разная стоимость активации, и размер этой стоимости определяет, кто её
преодолевает. Подача запроса на функцию требует инициативы: пользователь должен поверить, что
запрос стоит сформулировать, найти доску, и написать что-то связное, что отбирает вовлечённых,
терпеливых пользователей, уже инвестировавших в продукт. Подача тикета поддержки требует почти
никакой инициативы по сравнению, часто просто клик на «помощь» посреди задачи, что означает, что
она фиксирует фрустрированных пользователей в момент, включая тех, кто никогда не потрудился бы с
доской запросов. Реальный разрыв в продукте может быть невидим на доске функций и шумен в
поддержке просто потому, что пользователи, сталкивающиеся с ним, наименее склонны подавать
формальный запрос.&lt;/p&gt;
&lt;h2&gt;Означает ли объём тикетов для отсутствующей функции то же самое, что счёт голосов за неё?&lt;/h2&gt;
&lt;p&gt;Нет, потому что они измеряют разные популяции в разных условиях. Запрос на функцию со ста голосами
представляет сто человек, нашедших время найти и поддержать существующий запрос, что является
сильным сигналом устойчивого, продуманного спроса. Сто тикетов поддержки об одном и том же
лежащем в основе разрыве, поданных за тот же период, вероятно представляют пользователей,
упирающихся в стену в момент, некоторые из которых полностью забыли бы, как только непосредственное
трение проходит. Отношение к обоим как к эквивалентному сигналу «сто человек хотят этого»
переоценивает объём тикетов, потому что тикеты дёшево генерировать, а голоса нет.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Доска запросов на функции&lt;/th&gt;
&lt;th&gt;Тикеты поддержки&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Требует инициативы для подачи&lt;/td&gt;
&lt;td&gt;Требует почти никакой&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Фиксирует продуманный, устойчивый спрос&lt;/td&gt;
&lt;td&gt;Фиксирует фрустрацию в момент&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Склоняется к вовлечённым, терпеливым пользователям&lt;/td&gt;
&lt;td&gt;Фиксирует пользователей, которые никогда бы не использовали доску&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Счёт голосов — реальный сигнал приверженности&lt;/td&gt;
&lt;td&gt;Счёт тикетов отражает трение, не всегда желание&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что значит, когда у функции есть тикеты поддержки, но почти нет голосов на доске?&lt;/h2&gt;
&lt;p&gt;Часто, что запрос существует, но пользователи, сталкивающиеся с ним, не знают о существовании
доски, не верят, что голосование что-то изменит, или сталкиваются с проблемой слишком редко, чтобы
потрудиться сменить канал для формальной регистрации. Это именно та популяция, которую доска
запросов структурно упускает, и низкий счёт голосов здесь доказывает разрыв измерения, а не
низкий спрос. Относитесь к кластеру тикетов поддержки вокруг отсутствующей функции как к
собственному сигналу, который стоит самостоятельно зарегистрировать на доске от имени
пользователей, а не как к поводу не доверять тикетам, чтобы он не оставался невидимым для того,
кто приоритизирует только по счёту голосов.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Доска читается как низкий приоритет:
&amp;quot;Export to CSV&amp;quot;: 4 голоса за 6 месяцев

Поддержка рассказывает другую историю:
&amp;quot;Export to CSV&amp;quot;: 31 тикет за тот же период, каждый с
другого аккаунта, каждый закрыт с «сейчас не
поддерживается, передадим обратную связь»
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Всегда ли всплеск тикетов поддержки означает, что лежащая в основе проблема — отсутствующая функция?&lt;/h2&gt;
&lt;p&gt;Нет, и здесь два канала могут вводить в заблуждение в противоположную сторону. Всплеск тикетов так
же часто вызван запутанным интерфейсом вокруг уже существующей функции, багом, или изменением,
вышедшим без адекватного объяснения, ничто из которого не решается постройкой чего-то нового.
Чтение каждого всплеска тикетов как «пользователи хотят функцию, которой у нас нет» производит
roadmap, забитую вещами, на самом деле бывшими пробелами документации или замаскированными
проблемами юзабилити. Тикет поддержки говорит вам, где трение; он сам по себе не говорит вам,
является ли решением новая функция, изменение интерфейса, или лучшая статья помощи, и путаница
этого тратит инженерное время на неверное решение.&lt;/p&gt;
&lt;h2&gt;Как два сигнала реально должны комбинироваться при решении, что строить?&lt;/h2&gt;
&lt;p&gt;Используйте тикеты, чтобы найти, где трение, и используйте доску запросов, плюс прямой контакт
там, где доска скудна, чтобы подтвердить, как реально выглядит желаемый результат. Кластер тикетов
идентифицирует реальную, ощущаемую проблему; он редко специфицирует решение достаточно точно,
чтобы строить против него, потому что фрустрированный пользователь в разговоре с поддержкой
описывает симптомы, не спецификации. Доска запросов, когда у неё достаточно голосов по одной и той
же лежащей в основе проблеме, обычно несёт больше детали «что реально удовлетворило бы это»,
потому что написание запроса уже является актом спецификации желаемого, а не просто сообщением о
том, что не так.&lt;/p&gt;
&lt;h2&gt;Должны ли агенты поддержки сами регистрировать тикеты как запросы на функции?&lt;/h2&gt;
&lt;p&gt;Да, и это исправление с наибольшим рычагом для разрыва между двумя каналами. Агент, распознающий
тикет как замаскированный запрос на функцию, вместо того чтобы просто решить его и двигаться
дальше, может зарегистрировать его на доске от имени клиента, что напрямую закрывает разрыв
измерения вместо требования, чтобы клиент сам обнаружил и использовал второй канал. Это работает
только, если регистрация занимает у агента секунды, не минуты, чтобы трение от этого было ниже
трения от простого закрытия тикета и перехода к следующему.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли голоса запросов на функции когда-либо дисконтироваться, если все они с одного аккаунта или команды?&lt;/strong&gt;
Да, взвешивайте по отдельным аккаунтам или организациям, а не по грубому счёту голосов, потому что
пять голосов от пяти человек в одной компании представляют приоритеты одного клиента, а не пять
независимых подтверждений спроса.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли строить функцию, сильно представленную в тикетах, но почти без голосов?&lt;/strong&gt;
Часто да, при условии, что объём тикетов реально идёт с отдельных аккаунтов, а лежащая в основе
потребность подтверждена, а не предположена; относитесь к низкому счёту голосов как к артефакту
измерения стоимости активации доски, не как к доказательству, что спрос нереален.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как отличить с первого взгляда тикет о путанице интерфейса от подлинного тикета об отсутствующей функции?&lt;/strong&gt;
Смотрите, состоит ли решение в объяснении существующей возможности или извинении за отсутствующую.
Паттерн решений «о, это на самом деле прямо там» указывает на проблему интерфейса или
обнаруживаемости; паттерн «мы это ещё не поддерживаем» указывает на реальный разрыв.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Важно ли это различие настолько же при очень малом объёме поддержки?&lt;/strong&gt;
Менее механически, поскольку горстку тикетов легко читать индивидуально без необходимости в
агрегированном анализе, но лежащее в основе смещение, тикеты перепредставляют фрустрированных
пользователей и недопредставляют терпеливых, присутствует на любом масштабе и стоит держать в уме
даже когда вы читаете каждый тикет сами.&lt;/p&gt;
</content:encoded></item><item><title>Git-теги, релизы и ваш changelog</title><link>https://changeloop.dev/blog/ru/git-tags-releases-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/git-tags-releases-changelog/</guid><description>Git-тег, релиз и запись changelog — три записи одного события. Их смешивание заставляет changelog дрейфовать. Как трём этим вещам следует совпадать.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Git-тег, релиз и запись changelog — три разные записи одного и того же события, и их смешивание
заставляет changelog тихо отклоняться от того, что реально было выпущено. Тег отмечает коммит.
Релиз упаковывает этот тег с артефактами и описанием. Запись changelog объясняет — терминами,
которыми может пользоваться читательница вне репозитория — что изменилось. Обычно они происходят
близко по времени, и именно поэтому легко относиться к ним как к одному шагу вместо трёх, и
именно поэтому разрыв становится видимым только месяцы спустя, когда кто-то спрашивает «что вышло
в v2.4», и честный ответ требует настоящих раскопок.&lt;/p&gt;
&lt;h2&gt;В чём реальная разница между этими тремя?&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Запись&lt;/th&gt;
&lt;th&gt;Живёт в&lt;/th&gt;
&lt;th&gt;Написана для&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Git-тег&lt;/td&gt;
&lt;td&gt;Репозитории, как ссылка&lt;/td&gt;
&lt;td&gt;Тех, кто делает checkout именно этого коммита&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Релиз&lt;/td&gt;
&lt;td&gt;Хостинге кода (GitHub, GitLab)&lt;/td&gt;
&lt;td&gt;Тех, кто скачивает сборку&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Запись changelog&lt;/td&gt;
&lt;td&gt;Собственном changelog продукта&lt;/td&gt;
&lt;td&gt;Тех, кто пользуется продуктом, не только репо&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Тег — самая механическая из трёх: &lt;code&gt;git tag v2.4.0&lt;/code&gt; и готово, без требования, чтобы что-то
объясняло, что в нём. Релиз добавляет описание и обычно скачиваемые артефакты, и его аудитория —
всё ещё разработчицы, знающие, что такое страница релиза. Запись changelog — единственная из трёх,
написанная для читательницы, которая может никогда не открыть репозиторий, поэтому именно она
требует больше всего редакторского внимания и чаще всего пропускается под давлением дедлайнов.&lt;/p&gt;
&lt;h2&gt;Нужна ли каждому git-тегу запись changelog?&lt;/h2&gt;
&lt;p&gt;Нет, и относиться к ним один к одному — частая ошибка. Тег может отмечать внутреннюю веху, release
candidate, или hotfix, который никогда не доходит до большинства пользовательниц; ни одному из
них необязательно нужна публичная запись. Тест тот же, что решает, принадлежит ли что-то
changelog вообще: заметила бы это пользовательница или вызывающая сторона, важно ли ей это.
Большинство тегов проходят этот тест. Некоторые — например, тег, созданный только для запуска
CI-пайплайна — никогда.&lt;/p&gt;
&lt;h2&gt;Нужен ли каждой записи changelog свой тег?&lt;/h2&gt;
&lt;p&gt;Не всегда, и здесь расходятся команды с непрерывным деплоем и команды, выпускающие версионированные
пакеты. SaaS-продукт, деплоящийся несколько раз в день, может группировать несколько деплоев под
одной датированной записью changelog без тега 1:1 на деплой; библиотека, публикуемая в реестре
пакетов, обычно нуждается в теге на каждую опубликованную версию. Go modules и Swift Package Manager
резолвят версии из самих тегов; в npm или PyPI опубликованную версию хранит реестр, а тег
позволяет любому сопоставить эту версию с её исходным кодом. Репозиторию с
несколькими независимо версионируемыми пакетами нужно решать это по пакету, а не один раз для
всего репо; &lt;a href=&quot;https://changeloop.dev/blog/ru/monorepo-changelogs/&quot;&gt;changelog монорепозитория&lt;/a&gt; разбирает, как префиксы
тегов и область changelog должны следовать границам пакетов, а не папок.
&lt;a href=&quot;https://changeloop.dev/blog/ru/semantic-versioning-changelog/&quot;&gt;Semantic versioning и ваш changelog&lt;/a&gt; разбирает, как сам
номер версии должен маппиться на категории changelog; теги — механизм, делающий номер версии
проверяемым против реального кода.&lt;/p&gt;
&lt;h2&gt;Как описание релиза должно относиться к записи changelog?&lt;/h2&gt;
&lt;p&gt;Они могут быть одним и тем же текстом, но только если аудитория обоих действительно одна и та же,
что реже, чем кажется. Страницу релиза на хостинге кода читают почти исключительно
разработчицы; если у продукта есть и нетехнические пользовательницы, читающие changelog, дословное
дублирование описания релиза отправляет внутренние термины и формулировки, ориентированные на код,
читательнице, которой нужна была версия на простом языке. Самый чистый паттерн: писать запись
changelog как основной, ориентированный на читательницу артефакт, а описанию релиза либо
ссылаться на неё, либо держать более короткое, более техническое резюме для аудитории, которой уже
там комфортно.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Релиз v2.4.0 (GitHub, для разработчиц)
Поднимает пайплайн отчётов до нового движка агрегации. Смотрите
changelog для резюме, ориентированного на клиента:
https://example.com/changelog#v2.4.0

## 2026-09-07 (Changelog, ориентирован на клиента)
### Added
- Отчёты теперь загружаются меньше чем за секунду, даже для аккаунтов
  с более чем миллионом строк.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Один и тот же релиз, два документа, каждый со своей формулировкой для своей читательницы.&lt;/p&gt;
&lt;h2&gt;Откуда на самом деле берётся запись changelog?&lt;/h2&gt;
&lt;p&gt;Из двух отправных точек, и большинство реальных пайплайнов — смесь обеих. Она может генерироваться
из commit-сообщений в момент тега, что быстро и никогда не пропускает смёрженный pull request;
&lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;от conventional commits к changelog&lt;/a&gt; разбирает этот
пайплайн целиком. Или она может писаться вручную, совершенно отдельно от тега, синхронизированная
с моментом, когда фича считается готовой, а не с моментом, когда мёрджится код. Сгенерированные
записи консистентны, но наследуют каждое расплывчатое commit-сообщение; написанные вручную —
понятнее, но нужен кто-то, кто их реально напишет. Большинство команд, которые автоматизируют, всё
равно оставляют лёгкий проход редактуры по сгенерированному тексту перед тем, как он станет
публичной записью — та же дисциплина, что рекомендует &lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog на практике&lt;/a&gt;,
независимо от того, откуда изначально пришёл сырой текст.&lt;/p&gt;
&lt;h2&gt;Что ломается, когда эти три расходятся?&lt;/h2&gt;
&lt;p&gt;Доверие к тому, что читательница проверила первым. Тег, существующий без соответствующей записи
changelog, выглядит со стороны читательницы changelog так, будто на той неделе ничего не
произошло. Запись changelog без соответствующего тега или релиза делает невозможным для того, кто
отлаживает проблему в production, сделать checkout именно того кода, который был live, когда
запись публиковалась. Решение — не идеальная автоматизация, а единый источник истины для этого
соответствия: одно место, пусть даже это просто собственный чек-лист процесса релиза, говорящее,
что выпускаемое изменение получает все три, в том же коммите или pull request, который его вводит.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли записи changelog генерироваться автоматически из git-тегов?&lt;/strong&gt;
Они могут быть отправной точкой, но сам по себе тег не несёт никакого описания, ориентированного
на читательницу — только диапазон коммитов. Автоматизированная генерация должна читать
commit-сообщения внутри этого диапазона, а не просто факт существования тега, чтобы произвести
что-то пригодное для использования.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что если мы не тегируем каждый релиз?&lt;/strong&gt;
Тогда запись changelog становится основной записью, и всё равно должна нести дату и, если у
продукта она есть, номер версии, чтобы запись оставалась чем-то, на что читательница может
сослаться позже даже без соответствующего тега.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли pre-release-теги (вроде &lt;code&gt;v2.4.0-rc.1&lt;/code&gt;) иметь записи changelog?&lt;/strong&gt;
В общем случае нет. Release candidate предназначен для внутреннего или бета-тестирования, и запись
changelog для него учит читательниц ожидать записи для версий, которые могут никогда не выйти так,
как описано. Оставляйте записи для тегов, достигающих общей доступности.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Может ли одна запись changelog покрывать несколько git-тегов?&lt;/strong&gt;
Да, и часто должна для команд, тегирующих часто. Группируйте связанные теги под одной датированной
записью, описывающей чистое изменение, вместо публикации тонкой записи на тег, фрагментирующей
фичу на несколько прочтений.&lt;/p&gt;
</content:encoded></item><item><title>Внутренние changelog API: что меняется для другой команды</title><link>https://changeloop.dev/blog/ru/internal-api-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/internal-api-changelog/</guid><description>У публичного changelog API аудитория, до которой не дотянуться напрямую. У внутреннего она сидит этажом ниже, и это меняет то, что changelog ей должен.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Все остальные статьи в этом хабе предполагают, что вызывающий API находится вне компании:
инженер клиента, партнёр, кто-то, кто сам нашёл документацию. У многих API совсем другой тип
вызывающего — команда в соседней комнате или в двух этажах, — и это меняет расчёт того, чем
changelog ей обязан, потому что сообщение в Slack её достигнет, а тикет в поддержку обычно вообще
никогда не заводится. Большинство команд заключают из этого, что внутренним API changelog не
нужен. На самом деле им нужен другой.&lt;/p&gt;
&lt;h2&gt;Чем changelog внутреннего API отличается от публичного?&lt;/h2&gt;
&lt;p&gt;У аудитории есть прямая досягаемость, что убирает главную причину существования большинства
публичных changelog API — вещание на вызывающих, с которыми нельзя связаться индивидуально.
Команда-владелец внутреннего API обычно точно знает, какие другие команды его вызывают, иногда
вплоть до конкретного сервиса. Это делает целевое сообщение, а не публичную ленту, естественным
выбором по умолчанию, и именно поэтому внутренние API так часто остаются вовсе без changelog:
команда-владелец предупреждает те две-три команды, которые помнит, предполагая, что этим всё
покрыто.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Публичный changelog API&lt;/th&gt;
&lt;th&gt;Внутренний changelog API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Кто читает&lt;/td&gt;
&lt;td&gt;Любой внешний вызывающий, обычно недосягаемый напрямую&lt;/td&gt;
&lt;td&gt;Небольшой, обычно известный набор внутренних команд&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Канал по умолчанию&lt;/td&gt;
&lt;td&gt;Страница и лента&lt;/td&gt;
&lt;td&gt;Сообщение вызывающим командам, в идеале тоже со страницей&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Главный риск&lt;/td&gt;
&lt;td&gt;Вызывающий полностью пропускает запись&lt;/td&gt;
&lt;td&gt;Команда-владелец забывает вызывающего, о существовании которого не помнит&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Что заменяет «мы не знаем, кто нас вызывает»&lt;/td&gt;
&lt;td&gt;Ничего; публиковать широко&lt;/td&gt;
&lt;td&gt;Реальный, поддерживаемый в актуальном состоянии реестр вызывающих&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Почему «мы просто предупредим команды, которые нас вызывают» проваливается?&lt;/h2&gt;
&lt;p&gt;Потому что набор вызывающих никогда не бывает таким маленьким или статичным, каким его помнит
команда-владелец. Сервис, построенный для одного потребителя, обретает второго вызывающего через
шесть месяцев, через интеграцию, которую никто не анонсировал, и мысленный список «кто нас
вызывает» команды-владельца теперь неверен, а никто этого не замечает. Этот провал обычен и
распространён, это результат по умолчанию, когда полагаются на память вместо реестра, а не признак
чьей-то небрежности.
&lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Что такое breaking change&lt;/a&gt; разбирает, как решить, считается ли
изменение API ломающим вообще; внутренний случай добавляет сверху второй, более трудный вопрос —
знать, кого предупреждать.&lt;/p&gt;
&lt;h2&gt;Нужна ли внутреннему API вообще страница changelog в публичном стиле?&lt;/h2&gt;
&lt;p&gt;Обычно да, даже если основной канал — прямой. Страница даёт прямому сообщению на что сослаться,
так что уведомление может оставаться коротким («breaking change в &lt;code&gt;/v2/accounts&lt;/code&gt;, детали здесь»)
вместо попытки уместить всё объяснение в сообщение чата, которое уедет со скроллом. Она также
становится тем, что новая команда, или та, что пропустила прямое сообщение, может проверить,
когда её интеграция ломается и она пытается понять почему. Страница не обязана быть отполирована
или публична; она должна быть доступна по ссылке и пережить Slack-тред, который её анонсировал.&lt;/p&gt;
&lt;h2&gt;Кто на самом деле ведёт список вызывающих?&lt;/h2&gt;
&lt;p&gt;Команда-владелец, и к этому нужно относиться как к реальному артефакту, а не как к племенному
знанию. Самый дешёвый вариант — файл прямо в репозитории самого API, короткий список
потребляющих сервисов с ответственным на каждую запись, обновляемый каждый раз, когда строится
новая интеграция, — та же дисциплина, что и при любом объявлении зависимости. Альтернатива,
спрашивать вокруг перед каждым breaking change, работает до того единственного раза, когда кто-то
забывает спросить нужного человека, и внутренний API, тихо сломавшийся для одной команды, —
инцидент меньше публичного, но всё равно инцидент, обычно обнаруживаемый собственным дежурным
этой команды, а не владельцем API.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# consumers.yml
- service: billing-service
  owner: &amp;quot;#team-billing&amp;quot;
  since: 2026-03-01
- service: reporting-pipeline
  owner: &amp;quot;#team-analytics&amp;quot;
  since: 2026-06-14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Такой файл превращает «кого нам нужно предупредить» из вопроса в поиск. Инструменты, построенные
именно для этой задачи, вроде &lt;a href=&quot;https://backstage.io/docs/features/software-catalog/system-model/&quot;&gt;сервисного каталога
Backstage&lt;/a&gt;, моделируют API как
полноценные сущности с объявленными потребителями по той же причине: как только в организации
становится достаточно внутренних сервисов, ничья память о том, кто что вызывает, сама по себе
больше не остаётся точной, и что-то должно вести реестр вместо неё. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;Документация&lt;/a&gt; того
инструмента, который вы уже используете внутри, — обычно правильное место, куда стоит заглянуть
перед тем, как строить собственный.&lt;/p&gt;
&lt;h2&gt;Что принадлежит внутренней записи changelog, чего не понадобилось бы публичной?&lt;/h2&gt;
&lt;p&gt;Больше операционной конкретики, потому что читатель — другой инженер, который будет действовать
на основе этого в той же инфраструктуре, а не читать это как резюме. В каких окружениях изменение
живо и когда, потому что внутренние сервисы часто продвигаются через стадии, которые публичный
вызывающий никогда не видит. Требует ли изменение обновления конфигурации или клиентской
библиотеки на стороне потребителя, сформулированного как команда, если такая есть. И, поскольку
внутренние вызывающие часто могут согласовать исправление напрямую с командой-владельцем, —
названный контакт вместо канала поддержки: «напишите @maria, если это что-то сломает» — это
совершенно разумная строка во внутренней записи и странная в публичном changelog API.&lt;/p&gt;
&lt;h2&gt;Применимо ли это так же к changelog внутри монорепозитория?&lt;/h2&gt;
&lt;p&gt;Это обостряет ту же проблему, а не заменяет её. &lt;a href=&quot;https://changeloop.dev/blog/ru/monorepo-changelogs/&quot;&gt;Changelog монорепозитория&lt;/a&gt;
разбирает, когда пакету нужен собственный changelog; внутреннему API, являющемуся одним из
нескольких пакетов в монорепозитории, всё равно нужно, чтобы его потребители отслеживались явно,
потому что общий репозиторий с теми, кто его вызывает, не означает, что они заметят изменение,
если что-то не укажет им посмотреть. Близость в репо — не то же самое, что близость во внимании.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли changelog чисто внутреннему API, если у него один вызывающий?&lt;/strong&gt;
Едва ли, и прямого сообщения этой единственной команде обычно достаточно. Changelog оправдывает
себя, как только вызывающих становится больше одного, или как только список вызывающих однажды
удивил команду-владельца, потому что это сигнал, что одной памяти больше не хватает.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли внутренние изменения API проходить ту же проверку, что и публичные?&lt;/strong&gt;
Формулировки могут быть легче, поскольку читатель — коллега, а не внешний вызывающий, но решение,
является ли изменение ломающим, заслуживает той же тщательности в обоих случаях. У внутреннего
вызывающего всё равно есть продакшен-код, зависящий от старого поведения.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как узнать, кто вызывает внутренний API, если это никогда не отслеживалось?&lt;/strong&gt;
Логи сервера или данные трафика service mesh — честный ответ, если реестр потребителей никогда не
велся; относитесь к этому открытию как к моменту начать его вести, а не как к разовой уборке.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Достаточно ли сообщения в Slack, или внутреннему изменению всё равно нужна формальная запись в changelog?&lt;/strong&gt;
И то, и другое, для всего, что не является чисто аддитивным. Сообщение — это то, что читают
вовремя; запись — это то, что команда, расследующая проблему недели спустя и никогда не видевшая
сообщения, всё равно сможет найти.&lt;/p&gt;
</content:encoded></item><item><title>Внутренние release notes: кому ещё нужно знать, что вышло</title><link>https://changeloop.dev/blog/ru/internal-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/internal-release-notes/</guid><description>Саппорт и продажи обычно узнают о запуске от растерянного клиента. Внутренние release notes это решают — в форме, отличной от той, что видят клиенты.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Каждая другая статья в этом хабе предполагает, что читатель release note — клиент. Саппорт,
продажи и customer success тоже читают, или пытаются, и большинство узнаёт, что вышло, потому что
клиент спрашивает первым. Этот порядок перевёрнут, и он же принят по умолчанию в большинстве
компаний, потому что процесс релиза заканчивается в момент выхода заметки для клиентов, и никто
не выстроил второй, меньший шаг для людей, которым час спустя нужно отвечать на вопросы о ней.&lt;/p&gt;
&lt;h2&gt;Что такое внутренняя release note, и чем она отличается от заметки для клиентов?&lt;/h2&gt;
&lt;p&gt;Это более короткий документ, написанный для людей, уже глубоко знающих продукт, который говорит
им, что изменилось и что с этим делать в их конкретной работе. Агенту саппорта не нужно
отполированное оформление, которое использует анонс для клиентов; ему нужно знать, как изменение
выглядит в продукте прямо сейчас, каким будет самый вероятный вопрос о нём, и затронуты ли
открытые тикеты. Заметка для клиентов продаёт изменение. Внутренняя вооружает кого-то, чтобы с
ним справиться.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Аудитория&lt;/th&gt;
&lt;th&gt;Что ей нужно знать&lt;/th&gt;
&lt;th&gt;Где ей это нужно&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Саппорт&lt;/td&gt;
&lt;td&gt;Что изменилось в интерфейсе, вероятные вопросы, затронутые открытые тикеты&lt;/td&gt;
&lt;td&gt;Там, где он уже ищет ответы&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Продажи&lt;/td&gt;
&lt;td&gt;Что это открывает для сделки, чего оно ещё не делает&lt;/td&gt;
&lt;td&gt;Там, где готовятся к звонкам&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer success&lt;/td&gt;
&lt;td&gt;Что сказать существующим клиентам, и кто это просил&lt;/td&gt;
&lt;td&gt;Там, где планируют контакт&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Руководство&lt;/td&gt;
&lt;td&gt;Что вышло относительно обещанного, и когда&lt;/td&gt;
&lt;td&gt;Короткая, повторяющаяся сводка, не на каждый релиз&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Почему внутренние команды узнают о запусках с опозданием?&lt;/h2&gt;
&lt;p&gt;Потому что процесс релиза обычно выстроен вокруг одного артефакта — заметки для клиентов или
записи в changelog, — и предполагается, что всё внутреннее следует из чтения этого единственного
документа. Это не так. Агенты саппорта заняты тикетом перед собой, а не листают changelog в
поисках контекста, и заметка, написанная для клиента, часто опускает именно операционную
деталь, нужную агенту — например, какому плану доступна функция или как выглядит сообщение об
ошибке при сбое. К моменту, когда клиент спрашивает, агент читает ту же публичную заметку, что
клиент только что прочитал, без какого-либо преимущества.&lt;/p&gt;
&lt;h2&gt;Что внутренняя release note должна говорить такого, чего не говорит заметка для клиентов?&lt;/h2&gt;
&lt;p&gt;Операционные детали, которые заметка для клиентов намеренно опускает. Каким планам или аккаунтам
это доступно. Как выглядит ситуация, когда что-то идёт не так, и что сказать клиенту, который с
этим столкнулся. Закрывает ли это какие-то открытые запросы или тикеты, и какие — чтобы агент,
работающий над связанным тикетом, знал, что нужно проверить. Кто в команде отвечает, если вопрос
выходит за рамки того, что охватывает заметка. Ничто из этого не принадлежит версии для клиентов,
написанной для однократного прочтения кем-то за пределами компании; всё это — именно то, что
нужно тому, кто отвечает на один и тот же вопрос сорок раз в неделю.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Внутренняя заметка: массовый экспорт CSV (выходит 08.09.2026)

- Доступно только на планах Team и Enterprise. На Free и Pro без
  изменений.
- Частая ошибка: экспорт свыше 50 тысяч строк уходит в таймаут;
  известная проблема, фикс отслеживается отдельно. Сказать
  клиенту фильтровать по диапазону дат.
- Закрывает 14 открытых запросов с меткой `bulk-export`. Шаблон
  ответа в общем документе.
- Ответственный: команда platform, #platform-eng по всему, что
  выходит за рамки этой заметки.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Четыре строки, которые агент саппорта может использовать сразу, ни одна из которых не
принадлежала бы публичной записи changelog для той же функции.&lt;/p&gt;
&lt;h2&gt;Кто должен её писать, и когда?&lt;/h2&gt;
&lt;p&gt;Тот, кто пишет заметку для клиентов, обычно и есть подходящий человек, потому что у него уже
есть весь контекст, но это должен быть отдельный, короткий проход, а не попытка заставить один
документ обслуживать обе аудитории. Их объединение производит либо заметку для клиентов,
перегруженную внутренними деталями, либо внутреннюю заметку, слишком отполированную, чтобы быть
действительно полезной, и на практике быстрее написать два коротких документа, чем договариваться
об одном документе, обслуживающем две аудитории сразу. Время важнее авторства: внутренняя
заметка должна выходить раньше заметки для клиентов, хотя бы на несколько часов, чтобы саппорт
никогда не узнавал об изменении из того же места, что и клиент.&lt;/p&gt;
&lt;h2&gt;Где ей нужно жить, чтобы саппорт действительно находил её в момент тикета?&lt;/h2&gt;
&lt;p&gt;Там, где команда уже ищет вещи, когда приходит тикет, а не в отдельном changelog, который никому
не приходит в голову открывать по собственной инициативе. Команде саппорта, использующей общую
базу знаний, нужна заметка там, связанная с местом, где тикеты об этой части продукта уже
помечены. Команде, живущей в общем канале, нужно, чтобы она была опубликована там, доступна для
поиска, в момент, когда она актуальна, а не похоронена в ежедневной сводке, которую они
просматривают один раз. Паттерн для клиентов из &lt;a href=&quot;https://changeloop.dev/blog/ru/product-update-email/&quot;&gt;целевого уведомления против дайджеста&lt;/a&gt;
применим и здесь: внутренняя заметка о конкретном, предстоящем изменении должна достигать команды
напрямую, а не ждать еженедельной сводки, приходящей после того, как первый тикет уже существует.&lt;/p&gt;
&lt;h2&gt;Нужна ли ей та же строгость проверки, что и внешней?&lt;/h2&gt;
&lt;p&gt;Меньше, и это осознанно. Заметка для клиентов представляет компанию публично и заслуживает
внимательного прохода редактирования; внутренняя заметка существует, чтобы быть быстрой и
конкретной, и удерживать её на том же уровне полировки — обычно именно то, что заставляет
команды вовсе перестать её писать. Быстрая, слегка сыроватая внутренняя заметка, выходящая за час
до запуска, бьёт отполированную, приходящую на следующий день, когда первый тикет саппорта уже
пришёл в растерянности.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли внутренние release notes проходить тот же процесс утверждения, что и заметки для клиентов?&lt;/strong&gt;
Нет. Более лёгкий, быстрый проход — и есть смысл. Требование той же проверки превращает
внутреннюю заметку того же дня в заметку следующей недели, к которой саппорт уже ответил на
вопрос без неё.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Кто отвечает за внутренние release notes, если нет выделенной роли внутренних коммуникаций?&lt;/strong&gt;
Тот, кто пишет заметку для клиентов, — как второй, короткий проход сразу после. Отдельный
ответственный не нужен, нужна только привычка не относиться к заметке для клиентов как к
единственному артефакту, который производит релиз.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли внутренним release notes собственный changelog или архив?&lt;/strong&gt;
Место с поиском лучше хронологического архива, который никто не пролистывает. Если у саппорта уже
есть база знаний, заметка принадлежит туда, помеченная функцией, а не в отдельный внутренний
changelog, который помогает только тому, кто уже знает дату выхода.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;В чём риск пропускать внутренние release notes для маленьких изменений?&lt;/strong&gt;
Маленькие изменения — как раз те, по которым саппорт получает вопросы без предупреждения, потому
что маленькое изменение редко получает анонс на уровне компании. Размер release note должен
масштабироваться с размером изменения; он никогда не должен опускаться до нуля просто потому, что
изменение было незначительным.&lt;/p&gt;
</content:encoded></item><item><title>Release notes для мобильных приложений: что режет лимит</title><link>https://changeloop.dev/blog/ru/mobile-app-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/mobile-app-release-notes/</guid><description>App Store и Play Store показывают пару строк и не дают ссылок. Приёмы веб-changelog там не работают, сокращать нужно намеренно. Разбираем, что убрать.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Всё в этом хабе о написании release notes предполагает страницу, которую вы полностью
контролируете: любая длина, работающие ссылки, отображаемое форматирование. Release notes
мобильного приложения живут в чужой коробке. Apple даёт примерно 4000 символов, но показывает
только первые строки, пока не нажато «ещё»; Google даёт похожий объём с той же эффективной
проблемой предпросмотра, и ни одна из платформ не отображает кликабельную ссылку в тексте.
Правила из &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;как писать release notes, которые люди реально читают&lt;/a&gt;
всё ещё действуют: сказать, что изменилось, и что должен сделать читатель, но места для этого —
доля того, что позволяет страница changelog, и урезания должны быть намеренными, а не случайными.&lt;/p&gt;
&lt;h2&gt;Что реально помещается в видимый предпросмотр?&lt;/h2&gt;
&lt;p&gt;Первые одна-две строки, примерно 80-170 символов в зависимости от устройства и размера шрифта,
прежде чем читателю придётся нажать, чтобы развернуть. Это весь бюджет для той части release
note, которая решает, будет ли кто-то читать остальное, и это значит, что самое важное
предложение должно идти первым — не номер версии, не приветствие, не заголовок категории. Release
note, начинающаяся с «Новое в этой версии:», уже потратила треть видимого пространства на четыре
слова, которые ничего не говорят читателю.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Платформа&lt;/th&gt;
&lt;th&gt;Примерный общий лимит&lt;/th&gt;
&lt;th&gt;Эффективный предпросмотр до «ещё»&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;App Store (iOS)&lt;/td&gt;
&lt;td&gt;~4000 символов&lt;/td&gt;
&lt;td&gt;2-3 строки, примерно 80-170 символов&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Play&lt;/td&gt;
&lt;td&gt;~500 символов на язык, некоторые поля короче&lt;/td&gt;
&lt;td&gt;2-3 строки, похоже на iOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Обе&lt;/td&gt;
&lt;td&gt;Нет кликабельных ссылок в поле release notes&lt;/td&gt;
&lt;td&gt;Не применимо&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Работает ли правило «что можно сделать сейчас, что вам обязаны» на этой длине?&lt;/h2&gt;
&lt;p&gt;Да, и оно становится строже, а не иным. Одно предложение на запись, глагол первым, без вступления:
«Экспортируйте данные как CSV из Настроек.» побеждает «Мы добавили возможность для пользователей
теперь экспортировать свои данные в формате CSV», используя треть слов, чтобы сказать то же самое.
На длине страницы changelog чуть многословное предложение стоит читателю полсекунды. На длине
мобильной release note та же многословность может вытолкнуть предложение целиком за пределы
видимого предпросмотра, так что читатель никогда не увидит глагол, который сказал бы, что
изменилось.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Плохо, тратит предпросмотр на обрамление:
«Мы рады представить вам новое обновление, полное
улучшений! Читайте дальше для подробностей».

Хорошо, вся ценность в первой строке:
«Экспортируйте данные как CSV. Тёмная тема теперь
следует системной настройке. Исправлен сбой при
открытии общих ссылок».
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Что нужно урезать из того, что обычно сохранила бы запись веб-changelog?&lt;/h2&gt;
&lt;p&gt;Ссылки, во-первых, потому что ни один из двух магазинов не делает их кликабельными, так что URL
в тексте — мёртвый груз, который читателю пришлось бы перепечатывать. Если записи нужен пункт
назначения, скажите вместо этого, что нажать в приложении: «Смотрите новые фильтры в Настройках &amp;gt;
Поиск» работает; «Подробнее на example.com/blog/filters» — нет, на этой поверхности. Во-вторых,
всё условное или специфичное для аудитории: веб-changelog может сказать «если вы используете API,
это вас касается», но листинг магазина достигает каждого установившего приложение пользователя
одновременно, так что условная строка читается как шум для тех 95%, к кому она не относится.
Поместите условную деталь вместо этого во внутриприложенческое сообщение, срабатывающее для
аккаунтов, которых это реально касается.&lt;/p&gt;
&lt;h2&gt;Должен ли каждый релиз получать свои заметки, или нормально переиспользовать «исправления ошибок и улучшения производительности»?&lt;/h2&gt;
&lt;p&gt;Переиспользуйте это для релизов, которые действительно таковы, но проверяйте, насколько часто это
на самом деле правда. &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;Как писать release notes&lt;/a&gt; уже
разбирает, почему эта фраза выдаёт заметку, написанную изнутри, а не для читателя; на мобильных
устройствах это наносит двойной вред, потому что release notes магазина — одно из немногих мест,
где некоторые пользователи вообще что-то видят между обновлениями, и длинная серия «исправлений
ошибок и улучшений производительности» читается так, будто приложение не меняется, что производит
худшее впечатление, чем отсутствие заметок вовсе за этот период.&lt;/p&gt;
&lt;h2&gt;Влияют ли release notes на то, обновляют ли люди приложение вообще?&lt;/h2&gt;
&lt;p&gt;Косвенно, через видимость, а не убеждение. Большинство пользователей обновляются автоматически и
никогда не читают заметки перед обновлением; заметки важнее всего для меньшинства, которое
проверяет обновления вручную, и для рецензентов или прессы, просматривающих историю листинга
магазина. Писать для этой меньшей аудитории всё равно окупается, потому что листинг с реальной
историей конкретных, датированных записей читается как активно поддерживаемое приложение, а
листинг с годом «исправлений ошибок и улучшений производительности» — нет, независимо от того,
сколько реально было выпущено за это время.&lt;/p&gt;
&lt;h2&gt;А как насчёт принудительного обновления, где заметка должна объяснить, почему у пользователя нет выбора?&lt;/h2&gt;
&lt;p&gt;Укажите причину и срок в первой строке, прежде всего остального, потому что принудительное
обновление — единственный случай, когда читатель уже раздражён до того, как начал читать. «Это
обновление необходимо для продолжения синхронизации ваших данных. Обновите до [дата], чтобы
избежать перебоев» говорит, что делать и почему, в одном предложении; похоронить эту причину под
тремя строками несвязанных заметок о функциях читается так, будто приложение прячет неудобную
часть.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли мобильные release notes совпадать с веб-changelog того же релиза?&lt;/strong&gt;
Покрывать те же лежащие в основе изменения, но не слово в слово. Веб-changelog может позволить
себе полное объяснение; мобильной заметке нужны те же факты, сжатые в предложение с глаголом
первым, что обычно означает переписывание, а не копирование.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли локализовать мобильные release notes для каждого поддерживаемого языка?&lt;/strong&gt;
Да, больше, чем для веб-changelog, потому что листинг магазина часто единственная локализованная
поверхность, которую некоторые пользователи видят между сессиями, и обе платформы поддерживают
release notes по локали без дополнительной инженерной работы сверх самого перевода.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой длины должна быть мобильная release note, если нет лимита, вынуждающего к краткости?&lt;/strong&gt;
Всё равно короткой. Потолок в 4000 символов на iOS редко бывает реальным ограничением; им
является предпросмотр в 2-3 строки, и писать дальше того, что показывает этот предпросмотр, просто
значит, что меньше людей прочитают ту часть, которая имела значение.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли release notes номер версии в видимом тексте?&lt;/strong&gt;
Нет. Магазин уже показывает номер версии рядом с заметками. Повторение его в тексте тратит
видимые символы на информацию, которая у читателя уже перед глазами.&lt;/p&gt;
</content:encoded></item><item><title>Changelog монорепозитория: один, или по одному на пакет?</title><link>https://changeloop.dev/blog/ru/monorepo-changelogs/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/monorepo-changelogs/</guid><description>Монорепозиторий может вести один changelog на весь репозиторий или по одному на пакет. Неверный выбор делает релиз либо слишком шумным, либо разрозненным.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Монорепозиторий вмещает несколько отдельно выпускаемых вещей в одном репозитории, и changelog
должен сначала ответить на вопрос: читателю важен репозиторий или конкретный пакет внутри него?
Большинство команд никогда не решают это осознанно. Они начинают с одного changelog, потому что
есть один репозиторий, добавляют пакеты со временем и заканчивают журналом, где пользователю CLI
приходится пролистывать сорок несвязанных записей бэкенда, чтобы найти ту, что выпустила его
исправление. Правильную форму определяет не структура репозитория, а то, кто читает журнал и что
он уже знает искать.&lt;/p&gt;
&lt;h2&gt;Чем changelog монорепозитория отличается от changelog единого репозитория?&lt;/h2&gt;
&lt;p&gt;У changelog единого репозитория есть подразумеваемая аудитория — все, кто пользуется единственной
вещью, которую строит этот репозиторий. Аудитория монорепозитория делится по пакетам, и пакеты в
одном репозитории часто выпускаются по разным графикам, для разных потребителей, на разных
уровнях стабильности. Библиотека, опубликованная в реестре, и внутренний административный
инструмент могут жить в одном монорепозитории и почти не иметь ничего общего для читателя
changelog.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Форма репозитория&lt;/th&gt;
&lt;th&gt;Типичный читатель&lt;/th&gt;
&lt;th&gt;Подходящий changelog&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Одно выпускаемое приложение&lt;/td&gt;
&lt;td&gt;Все, кто пользуется продуктом&lt;/td&gt;
&lt;td&gt;Один журнал, для всего репо&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workspace библиотек (несколько публикуемых пакетов)&lt;/td&gt;
&lt;td&gt;Кто зависит от конкретного пакета&lt;/td&gt;
&lt;td&gt;Один журнал на пакет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Приложение плюс внутренние инструменты&lt;/td&gt;
&lt;td&gt;Две разные аудитории без пересечения&lt;/td&gt;
&lt;td&gt;Разделено по аудитории, не по папке&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Приложение плюс собственный SDK&lt;/td&gt;
&lt;td&gt;Пользователи продукта и интеграторы SDK&lt;/td&gt;
&lt;td&gt;Два журнала: для продукта, для SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Нужен ли каждому пакету собственный changelog?&lt;/h2&gt;
&lt;p&gt;Только тем, у кого независимая аудитория. Пакету, публикуемому в реестре, нужен собственный
журнал, потому что у устанавливающего его человека нет причин читать что-то ещё в репозитории, а
инструменты релиза для монорепозиториев, такие как &lt;a href=&quot;https://lerna.js.org/&quot;&gt;Lerna&lt;/a&gt; и Changesets,
пишут &lt;code&gt;CHANGELOG.md&lt;/code&gt; для каждого пакета рядом с его &lt;code&gt;package.json&lt;/code&gt;. Внутренней утилите с одним потребителем — приложением, уже
живущим в том же репозитории, — отдельный журнал не нужен; включение её изменений в записи этого
приложения полезнее второго файла, который никто за пределами команды не открывает.&lt;/p&gt;
&lt;p&gt;Тест тот же, что решает, принадлежит ли вообще какая-то запись changelog: заметит ли читатель это
или это его волнует, и может ли он действовать, зная это. Применяй его по пакету, не по папке, и
репозиторий с двенадцатью пакетами может закончиться двумя настоящими changelog и десятью
пакетами, которым он просто не нужен.&lt;/p&gt;
&lt;h2&gt;Как узнать, какой пакет вызвал какую запись changelog?&lt;/h2&gt;
&lt;p&gt;Помечай каждую запись её пакетом в момент написания, а не позже, изучая, какие файлы затронул
коммит. Коммит, исправляющий общую внутреннюю библиотеку, может породить запись changelog в
каждом пакете, зависящем от неё, и одни пути файлов не скажут, какую из этих нижестоящих записей
читателю действительно нужно увидеть; это может решить только человек, определяющий &amp;quot;это видно
пользователю пакета A и не видно пользователю пакета B&amp;quot;. &lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;Conventional commits&lt;/a&gt;
помогают здесь механически, называя пакет в каждом коммите, но scope всё равно даёт лишь
черновик. То же правило двух слоёв из той статьи применяется по пакету: черновик с правильным
scope всё равно нуждается в человеческом проходе, прежде чем он сформулирован для реального
читателя этого пакета.&lt;/p&gt;
&lt;h2&gt;Что нужно общему changelog, чего не нужно changelog единого репозитория?&lt;/h2&gt;
&lt;p&gt;Метка пакета на каждой записи, в самом начале, перед описанием, чтобы читатель, просматривающий
журнал, мог за один проход пропустить всё, что не его. Без этой метки общий журнал читается как
случайная лента, и читателю, интересующемуся одним пакетом, некак его отфильтровать, кроме как
запоминать, какие строки важны, чего никто не делает после первой недели.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 2026-09-07

### [cli] Добавлено
- `acme push --dry-run` показывает, что было бы отправлено,
  не отправляя это на самом деле.

### [core] Исправлено
- Backoff повторных попыток больше не сбрасывается при успешном
  запросе, возвращающем пустое тело.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Две записи, две аудитории, один взгляд, чтобы их различить. Рабочий процесс в стиле
&lt;a href=&quot;https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md&quot;&gt;Changesets&lt;/a&gt;
встраивает эту маркировку прямо в процесс релиза: контрибьютор пишет короткую заметку со scope
пакета рядом со своим изменением, а инструмент собирает changelog по пакетам и скачки версий из
этих заметок в момент релиза, вместо попытки восстановить границы пакетов постфактум из
объединённой истории коммитов.&lt;/p&gt;
&lt;h2&gt;Как версионирование связано с changelog монорепозитория?&lt;/h2&gt;
&lt;p&gt;Независимо версионируемым пакетам нужен собственный changelog, потому что у них собственный
номер версии, и общий changelog не может выразить &amp;quot;пакет A перешёл с 2.1 на 2.2, пока пакет B
остался на 1.4&amp;quot;, не превратившись в два журнала внутри одного файла. &lt;a href=&quot;https://changeloop.dev/blog/ru/semantic-versioning-changelog/&quot;&gt;Semantic versioning и ваш
changelog&lt;/a&gt; разбирает, как номер версии должен
маппиться на категории changelog; в монорепозитории это соответствие нужно применять по пакету,
потому что breaking change в одном пакете не является breaking change для соседнего пакета,
который от него не зависит.&lt;/p&gt;
&lt;p&gt;Репозиторий, выпускающий один продукт как единую выпускаемую единицу, даже если он собран из
множества внутренних пакетов, не сталкивается с этой проблемой: пакеты делят версию, потому что
всегда выпускаются вместе, и единый changelog — правильное решение.&lt;/p&gt;
&lt;h2&gt;Как git-теги вписываются в монорепозиторий?&lt;/h2&gt;
&lt;p&gt;То же правило из &lt;a href=&quot;https://changeloop.dev/blog/ru/git-tags-releases-changelog/&quot;&gt;git-тегов, релизов и вашего changelog&lt;/a&gt;
применяется по пакету: пакету с собственной версией нужен собственный префикс тега, обычно
&lt;code&gt;имя-пакета@1.4.0&lt;/code&gt; вместо голого &lt;code&gt;v1.4.0&lt;/code&gt;, который не может сказать, какому пакету он
принадлежит. Монорепозиторий, помеченный только голыми номерами версий, не может позже ответить
&amp;quot;что было в &lt;code&gt;core&lt;/code&gt;, когда &lt;code&gt;cli&lt;/code&gt; выпустил 2.2&amp;quot;, потому что ничто на диске не фиксирует, какому
пакету на самом деле принадлежал этот тег.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли отдельный changelog для каждого пакета в монорепозитории?&lt;/strong&gt;
Только для пакетов с независимой аудиторией, обычно для всего, что публикуется в реестре. Пакет с
одним внутренним потребителем, уже живущим в том же репозитории, может войти в журнал этого
потребителя вместо ведения собственного.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что помечает запись changelog правильным пакетом?&lt;/strong&gt;
Человек, пишущий запись, в момент её написания, а не автоматическое сканирование изменённых путей
файлов. Изменение в общей библиотеке может породить разную запись в каждом зависящем от неё
пакете, и только человек может решить, что на самом деле должна говорить каждая из этих
нижестоящих записей.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли монорепозиторию использовать один номер версии для всего?&lt;/strong&gt;
Только если каждый пакет всегда выпускается вместе с остальными. Если пакеты когда-либо
публикуются независимо, им нужны независимые версии, а независимым версиям нужны независимые
changelog, чтобы иметь смысл.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Заменяет ли инструмент changelog для монорепозитория этап человеческого редактирования?&lt;/strong&gt;
Нет. Инструменты вроде Changesets автоматизируют сбор и сборку заметок по пакетам в момент
релиза; сама заметка, написанная на языке читателя, а не контрибьютора, остаётся работой
человека, как и в любом другом pipeline changelog.&lt;/p&gt;
</content:encoded></item><item><title>Как анонсировать новую функцию (без тишины)</title><link>https://changeloop.dev/blog/ru/new-feature-announcement/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/new-feature-announcement/</guid><description>Большинство анонсов умирает в канале, который никто не читает дважды. Где анонсировать, что сказать первым, и до кого нужно достучаться в первую очередь.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Большинство анонсов функций умирает в канале, который никто не читает дважды: твит, пролетевший
мимо, письмо дня релиза, погребённое под двенадцатью другими, которые подписчица получила на
той неделе, сообщение в Slack в канале, который половина команды заглушила месяцы назад. Функцию
выпустили. Почти никто из тех, кто бы ей пользовался, об этом не узнал. Исправить это — меньше о
написании лучшего анонса, и больше о выборе правильного канала для правильной читательницы, и о
том, чтобы напрямую достучаться до тех, кто явно об этом просил, вместо того чтобы полагаться на
то, что они заметят общее сообщение.&lt;/p&gt;
&lt;h2&gt;Где на самом деле должна анонсироваться новая функция?&lt;/h2&gt;
&lt;p&gt;В более чем одном месте, потому что «все читают один и тот же канал» никогда не бывает правдой.
Запись changelog или feed обслуживает читательницу, которая проверяет по собственному расписанию
и хочет постоянную, датированную запись. Уведомление в приложении обслуживает читательницу,
которая уже пользуется продуктом и воспользовалась бы функцией сегодня, если бы знала о её
существовании. Письмо обслуживает читательницу, которая сейчас не в продукте, но вернулась бы
ради нужного обновления. Соцсети обслуживают охват за пределами существующих пользователей,
почти без таргетинга.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Канал&lt;/th&gt;
&lt;th&gt;Лучше всего для&lt;/th&gt;
&lt;th&gt;Слабость&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Changelog / feed&lt;/td&gt;
&lt;td&gt;Постоянная запись; читательницы своего темпа&lt;/td&gt;
&lt;td&gt;Пассивен; бесполезен для тех, кто никогда не проверяет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Уведомление в приложении&lt;/td&gt;
&lt;td&gt;Уже присутствующие пользователи, готовые действовать сегодня&lt;/td&gt;
&lt;td&gt;Не достигает никого, кто сейчас не в системе&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Письмо&lt;/td&gt;
&lt;td&gt;Неактивные пользователи, вернувшиеся бы ради этого&lt;/td&gt;
&lt;td&gt;Легко теряется среди другой почты; нужна настоящая тема&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Соцсети&lt;/td&gt;
&lt;td&gt;Охват за пределами текущих пользователей&lt;/td&gt;
&lt;td&gt;Почти без таргетинга; короткий срок жизни&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Ни один из четырёх не достаточен сам по себе. &lt;a href=&quot;https://changeloop.dev/blog/ru/what-is-a-changelog/&quot;&gt;Changelog&lt;/a&gt; — единственный документ, который должен
нести каждый релиз независимо от размера, потому что это запись, к которой всё остальное
отсылает обратно; остальные три — усиление, добавленное сверху, выбираемое по тому, насколько
функция действительно велика.&lt;/p&gt;
&lt;h2&gt;Что анонс должен сказать первым?&lt;/h2&gt;
&lt;p&gt;Результат, не механизм. «Мы добавили слой кэша к endpoint отчётов» описывает, что построила
команда. «Отчёты теперь загружаются меньше чем за секунду» описывает, что изменилось для
читательницы, и именно это предложение получает клик, потому что отвечает на «что мне с этого» в
первой фразе, а не в третьей. Механизм принадлежит записи changelog или странице деталей, а не
заголовку.&lt;/p&gt;
&lt;p&gt;Конкретика перед прилагательными. «Более быстрый, более мощный опыт работы с отчётами» не
говорит читательнице ничего, на что можно среагировать; «отчёты теперь загружаются меньше чем за
секунду и могут фильтроваться по статусу» говорит точно, что изменилось и что попробовать.
Вторая версия также выглядит более убедительно, потому что расплывчатое заявление звучит именно
так, как звучит маркетинговый текст, когда сказать конкретно нечего.&lt;/p&gt;
&lt;h2&gt;Чем это отличается от письма с обновлением продукта?&lt;/h2&gt;
&lt;p&gt;Пересекается, но не идентично. &lt;a href=&quot;https://changeloop.dev/blog/ru/product-update-email/&quot;&gt;Письмо с обновлением продукта&lt;/a&gt;
разбирает канал письма конкретно, включая частоту, темы, и когда дайджест побеждает разовую
рассылку. Анонс новой функции — это лежащее в основе событие; письмо — один из четырёх каналов
выше, которые могли бы его нести, выбираемый когда функция достаточно велика, чтобы оправдать
выделенную рассылку, вместо того чтобы ехать в следующем дайджесте. Небольшая функция заслуживает
записи changelog и, возможно, уведомления в приложении. Значимая заслуживает все четыре канала,
скоординированные по времени.&lt;/p&gt;
&lt;h2&gt;Как добраться до конкретных людей, которые об этом просили?&lt;/h2&gt;
&lt;p&gt;Это анонс с лучшим соотношением усилий и отдачи, и почти все команды его пропускают. Если десять
клиентов запросили функцию по имени, эти десять человек заслуживают прямую, личную заметку в
момент выпуска, независимо от того, какой более широкий анонс выходит. &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;Замыкание цикла обратной связи с клиентом&lt;/a&gt;
разбирает механику целиком; резюме здесь в том, что это работает только если исходный запрос
остался связан с попросившим, что скорее &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;проблема отслеживания&lt;/a&gt;,
чем проблема анонса. В changeloop, когда отзыв из виджета стал GitHub issue, а объединённый
pull request его закрывает (&lt;code&gt;fixes #142&lt;/code&gt;), одобрение записи changelog один раз публикует в этом issue
комментарий «Shipped — &lt;title&gt;», ссылающийся обратно на живую запись, а человек, отправивший отзыв,
видит выпущенную запись в виджете. Никому не нужно вспоминать, что надо ему сказать. Issue, созданные
вручную, и репозитории GitLab или Bitbucket такого комментария не получают.&lt;/p&gt;
&lt;h2&gt;Как написать саму запись?&lt;/h2&gt;
&lt;p&gt;Та же дисциплина, что и в любой другой записи release notes: начать с того, что читательница
теперь может делать, продолжить нужной настройкой, пропустить внутреннее обоснование. &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;Как писать release notes&lt;/a&gt;
разбирает полный метод; анонс новой функции — случай с самой высокой ставкой, потому что это
запись, наиболее вероятно заскриншоченная, переслана и прочитана кем-то, кто никогда не видел
changelog продукта.&lt;/p&gt;
&lt;h2&gt;Когда не стоит анонсировать широко?&lt;/h2&gt;
&lt;p&gt;Когда функция ещё раскатывается на подмножество аккаунтов, действительно является бетой, или
имеет цену или ограничение доступа такие, что девять из десяти читательниц широкого анонса ещё не
смогли бы ею воспользоваться. Широкий анонс функции, которой девять из десяти читательниц не
могут воспользоваться, читается как приманка, и сжигает доверие к следующему анонсу больше, чем
создаёт энтузиазм к этому. Решение — не тишина, а масштаб: напрямую сообщить подходящим аккаунтам
и придержать широкие каналы, пока доступность не догонит анонс.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Заслуживает ли каждая новая функция собственный анонс?&lt;/strong&gt;
Каждая заслуживает запись changelog. Только достаточно значимые, чтобы изменить то, как кто-то
пользуется продуктом, или явно запрошенные по имени, заслуживают более широких каналов вроде
письма или соцсетей.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой канал лучший для небольшой функции?&lt;/strong&gt;
Только changelog, плюс уведомление в приложении, если функцию можно обнаружить в потоке, где
пользователь уже находится. Письмо и соцсети того стоят для функций, оправдывающих просьбу
внимания.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как анонсировать функцию людям, которые именно её просили?&lt;/strong&gt;
Держать запрос связанным с попросившим с момента регистрации, затем уведомлять индивидуально
при выпуске, отдельно от любого более широкого анонса. Общая метка статуса, которую попросивший
может проверить сам, тоже снижает, сколько индивидуальных сообщений нужно в принципе.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли анонсу функции скриншот?&lt;/strong&gt;
Для всего визуального — да; описанную, но не увиденную функцию пропускают гораздо чаще, чем ту,
для которой читательницы могут увидеть превью. Для API или backend-возможности короткий пример
кода делает ту же работу, что скриншот для изменения UI.&lt;/p&gt;
</content:encoded></item><item><title>Как приоритизировать растущий поток запросов на функции</title><link>https://changeloop.dev/blog/ru/prioritizing-feature-requests/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/prioritizing-feature-requests/</guid><description>Бэклог не отвечает на главный вопрос: какой запрос делать первым. Рабочие фреймворки приоритизации, где каждый ломается и что скрывает число голосов.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Отслеживание запросов на функции решает вопрос, где они живут. Оно не решает, какой выйдет
первым, и именно на этом втором вопросе команды реально застревают. Бэклог из трёхсот
сгруппированных, помеченных запросов всё равно нуждается в правиле решения, потому что &amp;quot;строй
самое запрашиваемое&amp;quot; работает только пока два запроса близки, а у третьего есть громкая
сторонница — а так бывает большинство недель. Фреймворки ниже — не конкурирующие ответы на один
вопрос. Каждый подходит своему типу запроса, и использовать один для всех — обычно и есть
настоящая ошибка.&lt;/p&gt;
&lt;h2&gt;Чем приоритизация запросов на функции отличается от приоритизации roadmap?&lt;/h2&gt;
&lt;p&gt;Решение по roadmap начинается со стратегии и спрашивает, что строить. Решение по запросу на
функцию начинается с уже существующего спроса и спрашивает, действовать ли на его основе, и эти
два подхода достаточно часто тянут в разные стороны, что запрос может иметь высокий спрос и всё
равно быть неправильным для постройки, или иметь низкий спрос и всё равно того стоить, потому
что открывает стратегический аккаунт. Обращение с каждым запросом как с голосом за roadmap
пропускает эту проверку.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Фреймворк&lt;/th&gt;
&lt;th&gt;Что взвешивает&lt;/th&gt;
&lt;th&gt;Где ломается&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Грубый счёт запросов&lt;/td&gt;
&lt;td&gt;Сколько людей просили&lt;/td&gt;
&lt;td&gt;Награждает запоминающиеся названия, а не реальный спрос&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RICE&lt;/td&gt;
&lt;td&gt;Охват, влияние, уверенность, усилие&lt;/td&gt;
&lt;td&gt;Нужны оценки, которых ни у кого нет для свежего запроса&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Взвешенный по доходу&lt;/td&gt;
&lt;td&gt;Кто просил, по ценности аккаунта&lt;/td&gt;
&lt;td&gt;Игнорирует запросы от аккаунтов, которые пока немного стоят&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Публичные голоса&lt;/td&gt;
&lt;td&gt;Видимый сигнал с низким усилием&lt;/td&gt;
&lt;td&gt;Достигает только пользователей, уже знающих, куда смотреть&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что такое RICE, и работает ли он для запросов на функции?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.intercom.com/blog/rice-simple-prioritization-for-product-managers/&quot;&gt;RICE&lt;/a&gt; оценивает
идею по охвату, влиянию, уверенности и усилию, затем делит первые три на четвёртое, чтобы
получить сравнимое число. Он был создан для идей roadmap, в которые команда уже верит, где
сложная часть — сравнивать разные ставки друг с другом. Запросы на функции уже приходят с числом
охвата — счётом людей, попросивших об этом, — что конкретнее, чем охват, который обычно есть у
свежей идеи roadmap. Место, где RICE напрягается с запросом, — уверенность и влияние: команда
может быть уверена, что запрос реален, и всё же не иметь основы, насколько сильно он сдвинет
метрику, потому что &amp;quot;влияние&amp;quot; для запроса, у которого уже есть название и след реальных
пользователей, — это другой тип оценки, чем влияние идеи, которую никто за пределами комнаты ещё
не видел.&lt;/p&gt;
&lt;p&gt;Используй RICE для запросов, которые серьёзно рассматриваются и ещё не решены. Не применяй его к
каждому входящему запросу; усилие на оценку окупается только на тех, что достаточно близки, чтобы
нужен был тайбрейкер.&lt;/p&gt;
&lt;h2&gt;Взвешивать по доходу, или по тому, кто просил?&lt;/h2&gt;
&lt;p&gt;По тому, кто просил, но не только по доходу. Аккаунт, близкий к продлению, аккаунт, уже
эскалировавший ранее, и аккаунт, чей запрос открывает текущую сделку, несут срочность, которую
плоская цифра дохода одна не улавливает, и запрос от пробной регистрации всё равно может иметь
значение, если он блокирует решение, которое скоро станет доходом. Взвешивание по доходу — самое
простое для расчёта из всех этих подходов, и именно поэтому его легче всего переоценить: оно
корректно убирает шум от аккаунтов без реальной ставки, и так же легко может понизить запрос,
который привёл бы гораздо больший аккаунт, всё ещё находящийся в pipeline.&lt;/p&gt;
&lt;h2&gt;Какую роль на самом деле играют голоса?&lt;/h2&gt;
&lt;p&gt;Дешёвый, непрерывный сигнал для уже существующих запросов, и плохой способ узнать, какие запросы
вообще должны существовать. Счёт голосов достигает только пользователей, уже нашедших запрос и
посчитавших его достойным клика, а это значит, что сумма голосов публичной roadmap отражает
видимость не меньше, чем спрос: старый запрос ближе к верху списка продолжает собирать голоса
отчасти потому, что его легко найти, а более новый, столь же реальный запрос начинает с нуля.
Статья о &lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;публичной roadmap&lt;/a&gt; предлагает вообще не показывать голоса
на roadmap. Относись к голосам как к сигналу, который нужно группировать и
взвешивать по свежести, а не как к рейтингу, который строят по порядку.
&lt;a href=&quot;https://changeloop.dev/blog/ru/feedback-signal-quality/&quot;&gt;Тикеты поддержки vs. запросы функций&lt;/a&gt; разбирает другое слепое
пятно в счёте голосов: реальный разрыв может генерировать почти никаких голосов, если
сталкивающиеся с ним пользователи никогда не находят доску, при этом громко проявляясь в
поддержке.&lt;/p&gt;
&lt;h2&gt;Когда побеждает самый громкий клиент, и это проблема?&lt;/h2&gt;
&lt;p&gt;Иногда, и это проблема только когда никто этого не замечает. Клиент, часто эскалирующий, пишущий
подробные тикеты или имеющий прямую линию с кем-то из команды, увидит свои запросы рассмотренными
быстрее, чем более тихий клиент с не менее обоснованным запросом, и процесс приоритизации,
никогда это не проверяющий, будет систематически благоволить самому настойчивому, а не тому, у
кого дело сильнее. Громкие клиенты — не проблема, которую нужно исправлять; их запросы часто
действительно важны. Исправление — это привычка: периодически проходить бэклог по источнику и
проверять, объясняет ли одна и та же горстка аккаунтов большинство недавно выпущенного, и
спрашивать себя, совпадает ли это с тем, где реальный спрос на самом деле находится.&lt;/p&gt;
&lt;h2&gt;Как решение о приоритизации превращается в ответ?&lt;/h2&gt;
&lt;p&gt;Каждое решение здесь порождает победителей и проигравших, и оба заслуживают ответа, называющего
реальную логику, а не просто смену статуса без объяснения. &lt;a href=&quot;https://changeloop.dev/blog/ru/declining-feature-requests/&quot;&gt;Как отказать в запросе на
функцию&lt;/a&gt; разбирает, что говорить проигравшему запросу,
способом, сохраняющим отношения нетронутыми, вместо того чтобы звучать как типовой отказ. Работа
по группировке и маркировке, делающая всё это возможным с самого начала, разобрана в
&lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-tracking/&quot;&gt;отслеживании запросов на функции&lt;/a&gt;; приоритизация работает
только на запросах, уже зарегистрированных и сгруппированных достаточно хорошо, чтобы их можно
было сравнивать.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Какой фреймворк лучше всего подходит для приоритизации запросов на функции?&lt;/strong&gt;
Ни один сам по себе. Используй грубые счета, чтобы найти самый громкий сигнал, RICE — чтобы
сравнить короткий список серьёзных кандидатов, и проверку по доходу или аккаунту — чтобы поймать
случаи, когда тихий спрос от стратегического аккаунта перевешивает более громкую, но менее важную
группу.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли приоритизировать запросы на функции так же, как идеи roadmap?&lt;/strong&gt;
Нет. Идеи roadmap начинаются со стратегии; запросы на функции начинаются с уже существующего
спроса. Оценивая их вместе, хорошо обоснованная стратегическая ставка с небольшим существующим
спросом стабильно проигрывает запросу, у которого просто больше людей его попросили.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Точно ли голоса на публичной roadmap отражают спрос?&lt;/strong&gt;
Только среди людей, уже нашедших запрос. Более старые, более заметные запросы собирают голоса
быстрее, независимо от того, сколько реального спроса стоит за более новым, так что относись к
суммам голосов как к сигналу, сгруппированному и взвешенному по свежести, а не как к рейтингу,
который строят по порядку.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как часто нужно пересматривать приоритеты запросов на функции?&lt;/strong&gt;
По фиксированному циклу, а не только когда кто-то эскалирует. Ежемесячный или ежеквартальный
проход, перегруппирующий запросы и перепроверяющий взвешивание, ловит дрейф — вроде горстки
аккаунтов, доминирующих в том, что выпускается, — который чисто реактивный процесс никогда не
выявляет сам.&lt;/p&gt;
</content:encoded></item><item><title>Enterprise release notes: что меняется для одного аккаунта</title><link>https://changeloop.dev/blog/ru/private-release-notes-enterprise/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/private-release-notes-enterprise/</guid><description>Enterprise release notes для клиента на приватной сборке нужно откалибровать под его инстанс. Ошибка в калибровке сливает roadmap или путает поддержку.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Публичный SaaS-продукт отправляет одни и те же release notes всем, потому что все на одной
версии. Enterprise-клиент на закреплённой версии, выделенном инстансе, или подмножестве продукта с
feature-флагами ломает это предположение: release notes, описывающие, что изменилось для него, не
те же, что в вашем публичном блоге, а отправка публичных всё равно либо путает клиента изменениями,
которых у него ещё нет, либо, хуже, рассказывает ему о функции, о которой команда работы с
аккаунтом другого enterprise-клиента явно попросила вас придержать для их аккаунта ещё месяц.
&lt;a href=&quot;https://changeloop.dev/blog/ru/release-notes-best-practices/&quot;&gt;Лучшие практики release notes&lt;/a&gt; разбирает общее ремесло;
это о том, как писать enterprise release notes для проблемы калибровки, возникающей, когда у вас
есть клиенты, не все на одной сборке.&lt;/p&gt;
&lt;h2&gt;Почему enterprise-клиент не может просто читать публичный changelog?&lt;/h2&gt;
&lt;p&gt;Потому что он описывает версию, которую клиент, возможно, ещё не запускает, функции, к которым у
него, возможно, нет доступа, и график, не совпадающий с его собственным. Клиент, закреплённый за
квартальным циклом релизов, читающий о функции, вышедшей для публичного уровня на прошлой неделе,
не может узнать, только из публичного changelog, доберётся ли эта функция до него на следующей
неделе или в следующем квартале. Публичный changelog отвечает на «что изменилось в продукте»;
реальный вопрос enterprise-клиента — «что изменилось в версии, которую я запускаю, и когда я
получу остальное», на что публичный changelog никогда не был написан отвечать.&lt;/p&gt;
&lt;h2&gt;Что нужно приватной release note, что не нужно публичной?&lt;/h2&gt;
&lt;p&gt;Идентификатор версии или окружения, против которого клиент может реально сверить, и явное
заявление о том, что до него ещё не дошло. «Этот релиз включает улучшения массового экспорта из
нашего публичного релиза 4.3, но не новую модель разрешений, которая появится в вашем следующем
запланированном обновлении» говорит enterprise-администратору точно, где находится его инстанс
относительно продукта в целом. Публичной release note такое обрамление никогда не нужно, потому
что есть только один инстанс, относительно которого можно быть; приватная бессмысленна без него.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Публичные release notes&lt;/th&gt;
&lt;th&gt;Приватные (enterprise) release notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Одна версия, одна аудитория&lt;/td&gt;
&lt;td&gt;Несколько версий, сегментированные аудитории&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Предполагает, что у читательницы есть каждая описанная функция&lt;/td&gt;
&lt;td&gt;Должна заявлять, что есть, а чего нет у читательницы&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Синхронизированы с публичным релизом&lt;/td&gt;
&lt;td&gt;Синхронизированы с собственным окном обновления клиента&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Можно сразу сделать полностью публичной&lt;/td&gt;
&lt;td&gt;Может понадобиться скрыть пункты, которых у других клиентов ещё нет&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Бывает ли когда-нибудь нормально просто отложить отправку публичных release notes enterprise-клиентам вместо написания отдельных?&lt;/h2&gt;
&lt;p&gt;Только если его версия действительно совпадает с публичной в этот момент, что реже, чем кажется,
как только у вас больше пары enterprise-аккаунтов на разных ритмах. Откладывание публичных заметок
работает как временное решение для клиента, отставшего на одну версию и готового наверстать; это
рушится в момент, когда два enterprise-клиента находятся на разных версиях друг относительно
друга, потому что тогда нет уже единых «заметок» для откладывания, только матрица того, что есть у
каждого. В этот момент калибровка заметок по аккаунту, даже если это лишь отфильтрованный вид тех
же лежащих в основе записей, перестаёт быть опциональной.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Публичные заметки, отправленные enterprise-аккаунту,
у которого ещё нет функции:
&amp;quot;New: Bulk export now supports custom column ordering.&amp;quot;
(Путаница: админ пробует, а функции нет.)

Откалиброванные enterprise-заметки для того же аккаунта:
&amp;quot;Available in your next update (scheduled for 2026-10-15):
bulk export with custom column ordering. Not yet available
on your current version (3.8).&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Кто внутри организации клиента реально это читает, и меняет ли это способ написания?&lt;/h2&gt;
&lt;p&gt;Обычно IT-администратор или контакт по customer success, а не конечный пользователь, и это меняет,
что считается полезным. Конечному пользователю важно, что выглядит иначе на его экране;
enterprise-администратору важно, что изменилось в разрешениях, обработке данных, конфигурации SSO,
или что-либо, влияющее на то, как она управляет развёртыванием для собственных пользователей,
потому что именно она будет отвечать на внутренние вопросы. Приватная release note, читающаяся как
потребительский changelog, все сверкающие новые кнопки и никакой операционной детали, заставляет
администратора копать в поисках информации, которая реально была нужна.&lt;/p&gt;
&lt;h2&gt;Как это взаимодействует с публичной roadmap или публичным changelog, уже перечисляющим ту же функцию?&lt;/h2&gt;
&lt;p&gt;Осторожно, потому что клиент, читающий оба, заметит любую несостыковку. Если ваш публичный
changelog уже объявил функцию, которой у конкретного enterprise-аккаунта ещё нет, его приватная
release note должна признать этот разрыв, а не притворяться, что публичной записи не существует;
администратор, видевший публичное объявление и получающий приватные заметки, игнорирующие это,
предположит либо что вы о ней забыли, либо что что-то сломано. &lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;Публичная roadmap&lt;/a&gt;
разбирает, как сохранять roadmap честной насчёт того, что выпущено против запланированного;
enterprise-версия этой честности в release notes — прямо называть разрыв между тем, что публично, и
тем, что принадлежит ей.&lt;/p&gt;
&lt;h2&gt;Нужна ли маленькой компании всего с одним-двумя enterprise-клиентами вся эта структура?&lt;/h2&gt;
&lt;p&gt;Не полностью сегментированная система, но базовая дисциплина, ясно заявлять, на какой версии
находится клиент и что у него есть и чего нет, важна на любом масштабе в момент, когда у вас есть
хотя бы один клиент не на вашей последней сборке. Режим сбоя, который это предотвращает,
администратор, запутавшийся, относится ли к ней публичное объявление, стоит тикета поддержки и
удара по доверию независимо от того, есть ли у вас два enterprise-аккаунта или двести.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли приватные release notes когда-либо упоминать функции, которые уже есть у других клиентов, но нет у этого?&lt;/strong&gt;
Только если это релевантно его собственному графику, сформулировано как «появится в вашем
следующем обновлении», а не как сравнение с другими клиентами. Называть, что есть у конкретного
другого клиента, — территория, не ваша, чтобы раскрывать; называть, что придёт конкретно этому
клиенту, — именно та информация, что ему нужна.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Могут ли одни и те же лежащие в основе записи changelog питать и публичные, и приватные release notes?&lt;/strong&gt;
Да, и это обычно более поддерживаемый подход: помечайте записи, к каким версиям или уровням они
относятся, затем фильтруйте по аудитории при публикации вместо написания двух полностью отдельных
документов, неизбежно расходящихся со временем.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что, если enterprise-клиент явно просит быть на публичных release notes вместо приватной ленты?&lt;/strong&gt;
Уважьте это, но подтвердите, что он понимает, что публичные заметки предполагают публичную версию,
и сами письменно отметьте разрыв, если его версия отличается от описанного. Это письменное
подтверждение защищает вас позже, если он действует на основе публичных заметок, реально не
применимых к его сборке.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Насколько заранее enterprise-клиента следует уведомить о функции, к которой у него будет доступ в следующем релизе?&lt;/strong&gt;
Как только дата подтверждена, а не только в момент релиза, потому что enterprise-администраторам
часто нужно планировать собственную внутреннюю коммуникацию или обучение вокруг приближающейся
функции, а уведомление в тот же день не оставляет им для этого пространства.&lt;/p&gt;
</content:encoded></item><item><title>Semantic versioning и ваш changelog</title><link>https://changeloop.dev/blog/ru/semantic-versioning-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/semantic-versioning-changelog/</guid><description>Semantic versioning ещё до чтения changelog говорит, насколько болезненным будет релиз. Что обещает каждая цифра версии и что должна сказать запись.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Semantic versioning говорит вызывающей стороне, насколько больно может быть от релиза, ещё до
того, как она прочитает хоть одну запись changelog. Переход с &lt;code&gt;2.4.1&lt;/code&gt; на &lt;code&gt;2.5.0&lt;/code&gt; говорит: новая
возможность, ничего не сломано. Переход с &lt;code&gt;2.5.0&lt;/code&gt; на &lt;code&gt;3.0.0&lt;/code&gt; говорит: прочитай эту запись перед
обновлением. Changelog и номер версии должны утверждать одно и то же в двух форматах, и
большая часть трения между ними всплывает именно тогда, когда они расходятся — а это случается
чаще, чем предполагает спецификация.&lt;/p&gt;
&lt;h2&gt;Что на самом деле обещает каждая цифра версии?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://semver.org/&quot;&gt;Semantic versioning&lt;/a&gt; определяет три цифры, &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;, каждая со
строгим правилом о том, что её запускает. Скачок MAJOR означает несовместимое изменение: то, что
могла бы заметить корректная существующая интеграция, и из-за чего ей пришлось бы измениться.
Скачок MINOR означает новую, обратно совместимую функциональность: ничего существующего не
ломается, появляется что-то новое. Скачок PATCH означает обратно совместимое исправление:
поведение приближается к задокументированному, и никто, намеренно полагавшийся на старое
поведение, ничего не должен заметить.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Скачок&lt;/th&gt;
&lt;th&gt;Значение&lt;/th&gt;
&lt;th&gt;Запись должна звучать как&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;MAJOR (&lt;code&gt;1.x.x&lt;/code&gt; -&amp;gt; &lt;code&gt;2.0.0&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Несовместимое изменение&lt;/td&gt;
&lt;td&gt;«Требуется действие перед обновлением»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MINOR (&lt;code&gt;1.2.x&lt;/code&gt; -&amp;gt; &lt;code&gt;1.3.0&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Новая, совместимая возможность&lt;/td&gt;
&lt;td&gt;«Доступно уже сейчас, больше ничего не изменилось»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATCH (&lt;code&gt;1.2.3&lt;/code&gt; -&amp;gt; &lt;code&gt;1.2.4&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Совместимое исправление&lt;/td&gt;
&lt;td&gt;«Теперь ведёт себя так, как задокументировано»&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Таблица работает и в обратную сторону как проверка: если запись не читается как её строка, значит
либо номер версии неверен, либо запись занижает или завышает то, что произошло на самом деле.&lt;/p&gt;
&lt;h2&gt;Что считается несовместимым для целей версионирования?&lt;/h2&gt;
&lt;p&gt;Тот же тест, который решает, место ли чему-то в changelog API: могла бы корректная вызывающая
сторона, написанная против старого поведения и с тех пор не тронутая, повести себя иначе из-за
этого изменения. &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Что такое несовместимое изменение, и как его выпустить&lt;/a&gt;
разбирает решение целиком, включая случаи, которые выглядят несовместимыми, но не являются
таковыми, и те, что выглядят мелкими, но не являются. Коротко для версионирования: если ответ
да, скачок — MAJOR, независимо от того, сколько кода изменение на самом деле затронуло внутри.
Номера версий отслеживают последствие для вызывающей стороны, а не усилие команды.&lt;/p&gt;
&lt;h2&gt;Как запись changelog должна соответствовать скачку версии?&lt;/h2&gt;
&lt;p&gt;Одна запись, одна категория скачка, заявленная сразу. Паттерн из таблицы продолжается напрямую:
несовместимая запись стоит под версией, которая её ввела, сформулированная сначала как
предупреждение, потом как описание. Дополняющая запись стоит под своей MINOR-версией,
сформулированная как доступность. Исправление стоит под своей PATCH-версией, сформулированное
как коррекция. Смешивание категорий в одной записи — например, вписывание несовместимого
изменения в тот же абзац, что и несвязанное исправление — это способ, которым читательница
упускает именно то единственное, что действительно имело значение.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 3.0.0 (2026-09-07)

### Changed
- **BREAKING:** `GET /reports` теперь возвращает суммы как целые числа
  в наименьшей денежной единице (копейках) вместо дробей. Обновите
  код, читающий `amount` напрямую.

## 2.9.0 (2026-09-01)

### Added
- Отчёты теперь можно фильтровать по `status`.

## 2.8.4 (2026-08-28)

### Fixed
- `GET /reports?status=` возвращал пустую страницу вместо 400 для
  неизвестного статуса.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Читая сверху вниз, номер версии и метка раздела говорят одно и то же дважды — и это ровно та цель:
читательница, просматривающая только заголовки, получает верное представление о риске ещё до
открытия хоть одной строки.&lt;/p&gt;
&lt;h2&gt;Применяется ли правило о breaking changes так же и до 1.0.0?&lt;/h2&gt;
&lt;p&gt;Нет, и именно отсюда берётся большая часть путаницы «было ли это на самом деле breaking». SemVer
прямо говорит, что нулевая мажорная версия, &lt;code&gt;0.y.z&lt;/code&gt;, предназначена для начальной разработки: всё
может измениться в любой момент, и публичный API не следует считать стабильным. Скачок с &lt;code&gt;0.4.0&lt;/code&gt;
на &lt;code&gt;0.5.0&lt;/code&gt; может нести breaking change, не нарушая спецификацию, потому что гарантия мажорной
версии начинает действовать только с выпуска &lt;code&gt;1.0.0&lt;/code&gt;. Запись changelog по-прежнему обязана
читателям той же честностью о том, что сломалось; меняется только то, что сам номер версии до
1.0.0 не является сигналом, на который стоит полагаться.&lt;/p&gt;
&lt;h2&gt;А если ваш продукт не выпускает дискретные версии?&lt;/h2&gt;
&lt;p&gt;Большинство SaaS-продуктов деплоятся непрерывно и никогда не показывают номер версии вызывающей
стороне, что не отменяет потребность в этой дисциплине — только цифру, которая обычно бы её
несла. Запись changelog должна проделать всю работу сама: чётко сказать, несовместимо ли
изменение, дополняющее оно, или это исправление — теми же тремя словами, которыми пользуется
semantic versioning, даже без поля версии, к которому их привязать. Некоторые команды держат
чисто внутреннюю версию только для того, чтобы привязать записи changelog к чему-то, на что можно
сослаться, никогда не показывая её напрямую вызывающей стороне.&lt;/p&gt;
&lt;h2&gt;Как это применяется именно к changelog API?&lt;/h2&gt;
&lt;p&gt;Строже, чем почти где-либо ещё, потому что вызывающие стороны API — это код, а не люди, способные
пожать плечами на неожиданное изменение. &lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;Changelog API: что публиковать и кто это читает&lt;/a&gt;
разбирает полную форму этого документа; дисциплина версионирования здесь — то, что держит честными
его разделы breaking и additive. API, предлагающий несколько версий одновременно — например, &lt;code&gt;v1&lt;/code&gt;
и &lt;code&gt;v2&lt;/code&gt;, обслуживаемые параллельно во время окна миграции — эффективно применяет semantic
versioning в масштабе всего интерфейса, а не одного пакета, и тот же трёхсловный словарь всё ещё
применяется к каждой записи.&lt;/p&gt;
&lt;h2&gt;Что Keep a Changelog говорит о версионировании?&lt;/h2&gt;
&lt;p&gt;Он напрямую связывается по имени с semantic versioning и рекомендует тот же словарь категорий,
которым пользуется эта статья: Added, Changed, Deprecated, Removed, Fixed, Security. &lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog на практике&lt;/a&gt;
разбирает, как принять эту спецификацию, включая места, где команды обычно от неё отклоняются.
Пересечение не случайно: обе спецификации пытаются решить одну и ту же проблему с
противоположных концов — одна стандартизирует номер версии, другая — запись, которая его
объясняет.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли каждой записи changelog номер версии?&lt;/strong&gt;
Если продукт выпускает версии — да, потому что цифра позволяет читательнице сразу перейти к
«насколько это меня касается», не читая сначала запись. Если продукт деплоится непрерывно без
поля версии, формулировка записи должна нести этот сигнал сама.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;В чём разница между скачком MAJOR и записью о несовместимом изменении?&lt;/strong&gt;
Они должны описывать одно и то же событие двумя способами. Номер версии — сигнал, читаемый
машиной (инструменты вызывающей стороны могут на него реагировать); запись changelog —
объяснение, читаемое человеком, что конкретно изменилось.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Может ли релиз PATCH быть несовместимым?&lt;/strong&gt;
По определению не должен. Если такой всё же вышел, не редактируйте и не перетегируйте
опубликованную версию: &lt;a href=&quot;https://semver.org/#what-do-i-do-if-i-accidentally-release-a-backward-incompatible-change-as-a-minor-version&quot;&gt;SemVer FAQ&lt;/a&gt;
советует выпустить новую версию, восстанавливающую совместимость, или новую MAJOR, если поломка
остаётся, и задокументировать проблемную версию, чтобы пользователи знали, что её надо пропустить.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли чисто внутренним изменениям скачок версии?&lt;/strong&gt;
Нет. Semantic versioning отслеживает публичный интерфейс. Рефакторинг без наблюдаемого эффекта
для вызывающей стороны не нуждается ни в скачке, ни в записи changelog, даже если внутри это была
значительная инженерная работа.&lt;/p&gt;
</content:encoded></item><item><title>Заголовок Sunset у API и когда его отправлять</title><link>https://changeloop.dev/blog/ru/sunsetting-api-version/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/sunsetting-api-version/</guid><description>Заголовок Sunset сообщает клиенту API, когда версия перестанет отвечать, в отличие от уведомления о депрекации. Что покрывает RFC 8594 и что даёт brownout.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code&gt;Sunset&lt;/code&gt; — это один заголовок ответа, определённый в &lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8594&quot;&gt;RFC 8594&lt;/a&gt;,
который сообщает вызывающему, когда ресурс перестанет отвечать. &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;Депрекация API&lt;/a&gt;
разбирает полный график объявление-напоминание-brownout-удаление и уведомления, идущие вместе с
ним; здесь — об одном машиночитаемом сигнале в этом графике, о том, что он на самом деле говорит, и
о единственном случае, когда сам RFC советует его не отправлять.&lt;/p&gt;
&lt;h2&gt;Что говорит заголовок Sunset, а чего не говорит?&lt;/h2&gt;
&lt;p&gt;Он несёт одну HTTP-дату — момент, когда ресурс, как ожидается, перестанет отвечать:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sunset: Sat, 31 Dec 2028 23:59:59 GMT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RFC называет это подсказкой, а не гарантией: он не обещает, что ресурс продолжит работать вплоть
до этой отметки времени, и ничего не говорит о том, как будет выглядеть сбой после неё. Вызывающие
могут получить 4xx, редирект или вообще ничего; заголовок это не различает. Дата, уже находящаяся
в прошлом, означает «сейчас или в любой момент», а не ошибку в значении. Ничего из этого протокол
не обеспечивает принудительно. Клиент, никогда не читающий заголовок, ведёт себя точно так же, как
всегда, и узнаёт об исчезновении ресурса тем же способом, каким узнал бы в любом случае.&lt;/p&gt;
&lt;h2&gt;Когда его действительно стоит отправлять?&lt;/h2&gt;
&lt;p&gt;Только когда ресурс по-настоящему собирается перестать отвечать, а не когда он всего лишь перестал
быть рекомендуемым выбором. RFC явно говорит, что депрекация проходит в две стадии, и поле
заголовка Sunset относится только ко второй: во время первой стадии, объявления, что версия больше
не предпочтительна, API остаётся полностью работоспособным, и заголовок там неприменим. Он
применяется, когда версия действительно запланирована к остановке ответа.&lt;/p&gt;
&lt;p&gt;Это напрямую ложится на график депрекации: заголовок &lt;code&gt;Deprecation&lt;/code&gt; отправляется с первого дня, на
шаге объявления; &lt;code&gt;Sunset&lt;/code&gt; описывает дату, когда старое поведение реально остановится, и это та же
дата, которую &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;график из четырёх шагов&lt;/a&gt; называет удалением. Отправлять
&lt;code&gt;Sunset&lt;/code&gt; в первый день — не ошибка, раз дата уже зафиксирована к этому моменту, но отправлять его
без предшествующего объявления депрекации, или указывать в нём версию, удаление которой вы на
самом деле не подтвердили, сообщает вызывающим то, что вы сами ещё не решили.&lt;/p&gt;
&lt;h2&gt;Взаимодействует ли он с кэшированием?&lt;/h2&gt;
&lt;p&gt;Нет, и RFC говорит об этом прямо: &lt;code&gt;Sunset&lt;/code&gt; и HTTP-кэширование решают не связанные друг с другом
задачи, и их стоит читать как дополняющие, а не пересекающиеся. Заголовки кэширования говорят,
когда безопасно переиспользовать закэшированную копию; &lt;code&gt;Sunset&lt;/code&gt; ничего не говорит о текущем
состоянии ресурса, только о том, что сам ресурс перестанет существовать. Ответ может быть полностью
кэшируемым вплоть до момента своего sunset. Не используйте один заголовок как приближение другого и
не считайте, что длинный &lt;code&gt;max-age&lt;/code&gt; отменяет приближающуюся дату sunset, или наоборот.&lt;/p&gt;
&lt;h2&gt;Может ли один заголовок закрыть больше одного endpoint?&lt;/h2&gt;
&lt;p&gt;Заголовок применяется к ресурсу, который его вернул, но RFC позволяет сервису задокументировать
более широкую область действия: дата Sunset на домашнем ресурсе API может быть определена как
означающая, что уходит весь API, а не только этот один URL. Загвоздка в том, что это работает
только для вызывающих, уже знающих ваше правило области действия. Вызывающий, читающий заголовок
буквально, видит sunset только на том одном ресурсе, который запросил, и ничего больше, так что
более широкую область действия нужно где-то записать так, чтобы вызывающий мог это найти, а не
подразумевать.&lt;/p&gt;
&lt;h2&gt;Что должно идти вместе с заголовком?&lt;/h2&gt;
&lt;p&gt;Ссылка на то, где объяснено удаление. RFC 8594 регистрирует собственное отношение ссылки &lt;code&gt;sunset&lt;/code&gt;
именно для этого: указание на ресурс, описывающий политику удаления, предстоящую дату или способ
миграции, отдельно от голой отметки времени в заголовке.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Sunset: Sat, 31 Dec 2028 23:59:59 GMT
Link: &amp;lt;https://example.com/docs/sunset-policy&amp;gt;; rel=&amp;quot;sunset&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Направив эту ссылку на свои собственные &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; или отдельную
страницу миграции, вы превращаете заголовок, который почти ничей клиентский код не проверяет, в
нечто, что человек, действительно решивший поискать, находит немедленно. Скомбинируйте его с
отношением &lt;code&gt;successor-version&lt;/code&gt; из
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/#which-headers-should-a-deprecated-endpoint-send&quot;&gt;заголовков депрекации&lt;/a&gt;,
и вызывающий получает из одного только ответа и куда идти, и чем это заменяется.&lt;/p&gt;
&lt;h2&gt;Как это выглядит целиком?&lt;/h2&gt;
&lt;p&gt;Допустим, &lt;code&gt;v1&lt;/code&gt; уходит 1 марта 2027 года. Объявление о депрекации в первый день добавляет
&lt;code&gt;Deprecation&lt;/code&gt; и &lt;code&gt;Link: rel=&amp;quot;successor-version&amp;quot;&lt;/code&gt; к каждому ответу &lt;code&gt;v1&lt;/code&gt;, согласно
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;заголовкам депрекации&lt;/a&gt;, но откладывает &lt;code&gt;Sunset&lt;/code&gt; до момента, когда дата
удаления по-настоящему зафиксирована, а не является заглушкой. Как только это происходит, каждый
ответ &lt;code&gt;v1&lt;/code&gt; несёт:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Deprecation: @1756425600
Sunset: Mon, 01 Mar 2027 00:00:00 GMT
Link: &amp;lt;https://api.example.com/v2/reports&amp;gt;; rel=&amp;quot;successor-version&amp;quot;
Link: &amp;lt;https://example.com/docs/sunset-policy&amp;gt;; rel=&amp;quot;sunset&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Шлюз или мониторинг вызывающего может независимо реагировать на любой из заголовков: &lt;code&gt;Deprecation&lt;/code&gt;
говорит, что существует более новая версия, &lt;code&gt;Sunset&lt;/code&gt; — что у этой есть свои часы. Ни один из
заголовков не обязан меняться до 1 марта; меняется сам ответ, в этот день и во время любых
запланированных перед ним окон brownout.&lt;/p&gt;
&lt;h2&gt;Меняет ли brownout то, что говорит заголовок?&lt;/h2&gt;
&lt;p&gt;Само значение заголовка не обязано сдвигаться из-за запланированного brownout: дата sunset остаётся
датой sunset независимо от того, отказывает ли ресурс с перебоями до неё. Меняется ответ, а не
заголовок. Планирование коротких окон &lt;code&gt;410 Gone&lt;/code&gt; за недели до объявленной даты, как описывает
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;Депрекация API&lt;/a&gt;, — это то, что превращает первый контакт вызывающего со
сбоем в репетицию, а не в реальность в день, когда наступает дата из заголовка.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Действительно ли какие-то реальные HTTP-клиенты или инструменты читают заголовок Sunset?&lt;/strong&gt;
На стороне клиента — редко. Его ценность в основном для того, кто управляет инфраструктурой между
вами и вызывающим: API-шлюз или инструмент мониторинга, настроенный следить за этим заголовком,
может оповестить вашу собственную команду или команду партнёра задолго до того, как код вызывающего
вообще что-то заметит. Относитесь к нему как к сигналу, под который вы строите инструментарий, а не
как к тому, что у другой стороны уже наверняка есть.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Это то же самое, что &lt;code&gt;Cache-Control: max-age&lt;/code&gt;?&lt;/strong&gt;
Нет. &lt;code&gt;max-age&lt;/code&gt; о том, как долго закэшированная копия остаётся валидной; &lt;code&gt;Sunset&lt;/code&gt; о том, когда ресурс
вообще перестаёт существовать. Ответ может нести короткий &lt;code&gt;max-age&lt;/code&gt; и дату &lt;code&gt;Sunset&lt;/code&gt; через годы, или
наоборот, и ни один из заголовков не ограничивает другой.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Можно ли отправить Sunset для одного исчезающего поля, а не всего endpoint?&lt;/strong&gt;
Нет, заголовок привязан к ресурсу, то есть к URL, а не к полю внутри тела ответа. Для поля,
параметра или значения enum, которое уходит, пока сам endpoint остаётся, используйте вместо этого
заголовок &lt;code&gt;Deprecation&lt;/code&gt; и запись в changelog; &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;Депрекация API&lt;/a&gt; разбирает
объявление именно такого рода изменений.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что если дату sunset нужно сдвинуть?&lt;/strong&gt;
Обновите значение заголовка и скажите об этом в записи changelog, объявившей её изначально; тихая
смена опубликованной даты — это то, как вызывающий решает, что ни одна из ваших дат не реальна. RFC
описывает это значение как подсказку именно потому, что даты иногда действительно сдвигаются, но
сдвинутая дата без объяснения будет стоить вам доверия и к следующей.&lt;/p&gt;
</content:encoded></item><item><title>Changelog вебхуков: breaking change, который никто не просил</title><link>https://changeloop.dev/blog/ru/webhook-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/webhook-changelog/</guid><description>Изменение payload вебхука ломается тихо, потому что его некому отклонить. Что делает изменение payload breaking, и как его правильно версионировать.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Changelog REST API существует потому, что вызывающий может отклонить ответ, который не понимает,
или хотя бы залогировать ошибку достаточно громко, чтобы кто-то заметил. Получатель вебхука редко
делает то или другое. Он получает POST, читает ожидаемые поля, и если поле переместилось, сменило
тип или исчезло, эндпоинт либо тихо падает внутри фонового job&amp;#39;а, за которым никто не следит,
либо, хуже, продолжает работать с неверным значением, которое никогда не валидировал. &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Что такое
breaking change&lt;/a&gt; разбирает общее определение; payload вебхука
нуждается в собственном ответе, потому что режим отказа отличается от эндпоинта, который кто-то
вызывает намеренно.&lt;/p&gt;
&lt;h2&gt;Почему изменение payload вебхука ломается иначе, чем изменение ответа API?&lt;/h2&gt;
&lt;p&gt;Потому что направление запроса перевёрнуто. Вызывающий REST инициирует вызов и может добавить
заголовок версии, повторить попытку при 4xx или прочитать уведомление об устаревании в ответе.
Получатель вебхука ничего из этого не инициировал: ваш сервер решил отправить, решил когда, и
решил, какую форму будет иметь тело. Единственный рычаг получателя — валидация, которую он
написал, когда строилась интеграция, а большинство интеграций строятся один раз, работают, и
никто их не пересматривает, пока они не сломаются. Эта асимметрия — вся причина, почему изменение
payload вебхука заслуживает больше осторожности, чем то же изменение в теле ответа, которое
вызывающий активно запросил.&lt;/p&gt;
&lt;h2&gt;Что на самом деле считается breaking change в payload вебхука?&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Изменение&lt;/th&gt;
&lt;th&gt;Breaking для большинства получателей&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Добавление нового поля&lt;/td&gt;
&lt;td&gt;Нет, если получатели игнорируют неизвестные поля (проверьте это предположение, не принимайте его на веру)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Удаление поля&lt;/td&gt;
&lt;td&gt;Да, если что-то его читает&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Переименование поля&lt;/td&gt;
&lt;td&gt;Да, функционально идентично удалению старого&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение типа поля (строка в объект)&lt;/td&gt;
&lt;td&gt;Да, почти всегда&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение порядка полей в теле JSON&lt;/td&gt;
&lt;td&gt;Нет, для любого получателя, парсящего по ключу, а такими должны быть все&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение имени или типа события&lt;/td&gt;
&lt;td&gt;Да, если получатели фильтруют или маршрутизируют по нему&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Строка «добавление поля безопасно» — та, на которую команды опираются больше всего, и та, которую
больше всего стоит проверить, а не предполагать. Разрешающий JSON-парсер по умолчанию игнорирует
неизвестные поля, но получатель, десериализующий в строгую схему, несколько типизированных языков
делают это без дополнительной настройки, может отклонить весь payload, как только появится
неожиданное поле. Добавление поля безопасно для вашего вебхука только если вы знаете, как парсят
получатели, а не потому что сам JSON разрешающий.&lt;/p&gt;
&lt;h2&gt;Как версионировать payload вебхука?&lt;/h2&gt;
&lt;p&gt;Почти как для ответа API, с одним нюансом: получатель никогда не отправляет запрос, поэтому не
может попросить версию, и её должен указать отправитель. Её можно передать в теле или в заголовке
запроса самой доставки; &lt;a href=&quot;https://docs.github.com/en/webhooks/webhook-events-and-payloads&quot;&gt;доставки GitHub&lt;/a&gt;
несут &lt;code&gt;X-GitHub-Event&lt;/code&gt; и &lt;code&gt;X-GitHub-Hook-ID&lt;/code&gt;, а
&lt;a href=&quot;https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md&quot;&gt;спецификация Standard Webhooks&lt;/a&gt;
кладёт свои метаданные в заголовки &lt;code&gt;webhook-*&lt;/code&gt;. Поле
версии в payload (&lt;code&gt;&amp;quot;payload_version&amp;quot;: 2&lt;/code&gt;) — самый дешёвый вариант, и он работает, когда
получатели готовы ветвиться по нему. Версионированный тип события (&lt;code&gt;invoice.updated&lt;/code&gt; становится
&lt;code&gt;invoice.updated.v2&lt;/code&gt; как отдельное событие, на которое получатель подписывается добровольно)
требует больше работы для построения, но означает, что старая форма продолжает поступать тем, кто
никогда не мигрировал, что здесь важнее, чем для REST-эндпоинта, потому что вы не можете
позвонить каждому получателю с просьбой обновиться. Настройка на подписку, выбранная при
регистрации эндпоинта вебхука, принимает решение заранее вместо ветвления при каждой доставке, и
это правильный выбор, когда у вас уже есть запись подписки, к которой можно её прикрепить.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /endpoint-получателя
{
  &amp;quot;event&amp;quot;: &amp;quot;invoice.updated&amp;quot;,
  &amp;quot;payload_version&amp;quot;: 2,
  &amp;quot;data&amp;quot;: { &amp;quot;invoice_id&amp;quot;: &amp;quot;inv_123&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;paid&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Как вообще узнать, кто слушает?&lt;/h2&gt;
&lt;p&gt;Хуже, чем эквивалентная версия этой проблемы в changelog API, потому что у вебхука нет журнала
входящих запросов на вашей стороне, который называл бы вызывающего; у вас есть только собственный
журнал исходящих доставок, который говорит, что эндпоинт получил 200, а не что он сделал с телом.
Отслеживайте минимум две вещи: каждый зарегистрированный эндпоинт с владелицей, ту же дисциплину,
что &lt;a href=&quot;https://changeloop.dev/blog/ru/internal-api-changelog/&quot;&gt;changelog внутренних API&lt;/a&gt; рекомендует для внутренних
потребителей, и вашу долю неудачных доставок на эндпоинт после изменения payload. Всплеск ответов
4xx или 5xx от эндпоинта сразу после изменения — ближайшее к трассировке стека, что вы получите, и
часто единственный сигнал, что получатель сломался, потому что команда, которая им управляет,
может не заметить это днями.&lt;/p&gt;
&lt;h2&gt;Должен ли changelog вебхуков быть отдельным от changelog API?&lt;/h2&gt;
&lt;p&gt;Отдельный раздел на той же странице, а не отдельная публикация. &lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;Changelog API&lt;/a&gt;
уже устанавливает, кто его читает и как на него подписываются; изменение payload вебхука
принадлежит той же ленте, помеченное достаточно ясно, чтобы разработчица на стороне получателя,
сканирующая «затрагивает ли это мою интеграцию», могла отфильтровать по нему, потому что у
потребителя вебхука часто нет другой причины проверять общий changelog API, и он найдёт его,
только если кто-то направит его туда напрямую.&lt;/p&gt;
&lt;h2&gt;Как должно выглядеть разумное окно устаревания для payload вебхука?&lt;/h2&gt;
&lt;p&gt;Длиннее эквивалентного устаревания REST, потому что миграция на стороне получателя обычно
означает, что вторая команда, с которой у вас может не быть прямой связи, должна заметить это,
запланировать и выпустить без собственной срочности. Месяц — разумный минимум для поля, которое
получатель, вероятно, всё ещё парсит разрешающей библиотекой; три месяца или больше безопаснее
для удаления поля, которое строгая схема полностью отклонит. Отправляйте старую и новую форму
вместе в течение окна, когда это возможно (старое поле &lt;code&gt;status&lt;/code&gt; и его замена из версии 2
в одном payload), потому что получатель, читающий старое поле, продолжает работать, не
трогая свой код, а тот, кто уже мигрировал, просто игнорирует поле, которое ему больше не нужно.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли потребители вебхуков подтверждать изменение payload перед публикацией?&lt;/strong&gt;
По умолчанию не существует механизма подтверждения, и именно поэтому окно устаревания важнее
здесь, чем для REST API: никто не подтверждает готовность, поэтому окно должно быть достаточно
длинным, чтобы большинство получателей мигрировали в своём темпе до исчезновения старой формы.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Безопасно ли когда-либо добавлять неизвестные поля без уведомления?&lt;/strong&gt;
Только после того, как вы проверили, а не предположили, что ваши получатели парсят разрешающе.
Запись в changelog стоит недорого и убирает неопределённость; тихое добавление полей с
предположением, что «JSON-парсеры игнорируют лишнее», ломает любого получателя со строгой
десериализацией.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой самый быстрый способ обнаружить сломанного получателя вебхука после изменения payload?&lt;/strong&gt;
Доля неудачных доставок на эндпоинт, наблюдаемая в часы сразу после изменения. Она не скажет вам,
что сломалось, только что что-то сломалось, но это самый ранний и часто единственный сигнал,
который вы получите.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Помогает ли логика повторных попыток получателям пережить изменение payload?&lt;/strong&gt;
Нет. Повторная попытка отправляет тот же новый payload заново; она не возвращается к форме,
которую получатель может распарсить. Изменение payload ломает получателя при первой доставке и
при каждой последующей повторной попытке одинаково.&lt;/p&gt;
</content:encoded></item><item><title>Changelog: что это такое, с примером записи</title><link>https://changeloop.dev/blog/ru/what-is-a-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/what-is-a-changelog/</guid><description>Changelog, или журнал изменений, это датированный список того, что изменилось в продукте. Пример записи, отличие от release notes и где его держать.</description><pubDate>Mon, 07 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Changelog — это датированная запись того, что изменилось в продукте, написанная для людей,
которых затрагивает изменение, а не для команды, которая его выпустила. Каждая запись называет
изменение, говорит, когда оно вступило в силу, и говорит, что читательница должна с этим делать —
для большинства записей это ничего. Именно последняя часть отделяет changelog от журнала коммитов:
журнал коммитов — это запись для тех, кто писал код, а changelog — запись для тех, кто им
пользуется.&lt;/p&gt;
&lt;h2&gt;Что такое changelog, если точнее?&lt;/h2&gt;
&lt;p&gt;Список датированных записей, от новых к старым, каждая описывает одно изменение в терминах,
которые читательница может проверить. Не то, что построила команда, а то, что теперь по-другому.
«Рефакторинг сервиса биллинга» — это сообщение коммита. «Счета теперь показывают налог отдельной
строкой» — это запись changelog, потому что она говорит читательнице что-то, что та может
проверить на собственном аккаунте.&lt;/p&gt;
&lt;p&gt;Формат старый и намеренно простой: заголовок на релиз или на день, короткий список под ним,
иногда метка категории. &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt; — самая
цитируемая спецификация для этой формы, и существует она потому, что большинство проектов, минуя
спецификацию, заканчивают тем, что вываливают историю коммитов вместо неё — а это отвечает на
другой вопрос, чем тот, с которым пришла читательница.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Документ&lt;/th&gt;
&lt;th&gt;Написан для&lt;/th&gt;
&lt;th&gt;Отвечает на&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Changelog&lt;/td&gt;
&lt;td&gt;Всех, кто пользуется продуктом&lt;/td&gt;
&lt;td&gt;Что изменилось, и когда?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Журнал коммитов&lt;/td&gt;
&lt;td&gt;Команды, писавшей код&lt;/td&gt;
&lt;td&gt;Что сделано, в каком порядке?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release notes&lt;/td&gt;
&lt;td&gt;Пользователей, решающих обновляться ли&lt;/td&gt;
&lt;td&gt;Что я теперь могу, чего не мог?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Patch notes&lt;/td&gt;
&lt;td&gt;Игроков или пользователей конкретного фикса&lt;/td&gt;
&lt;td&gt;Что именно исправил этот релиз?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roadmap&lt;/td&gt;
&lt;td&gt;Всех, кто гадает, что дальше&lt;/td&gt;
&lt;td&gt;Что запланировано, и на какой стадии?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Эти пять пересекаются на практике, но это не один и тот же документ, и разница в том, кто держит
его в руках в момент чтения. Changelog построен так, чтобы его искали и на него ссылались позже,
поэтому его записям нужны стабильные даты и URL сильнее, чем остальным.&lt;/p&gt;
&lt;h2&gt;Что на самом деле входит в запись changelog?&lt;/h2&gt;
&lt;p&gt;Четыре вещи, в таком порядке: что изменилось, сформулированное в терминах того, что заметил бы
пользователь или вызывающая сторона; когда это вступило в силу; к какой категории относится
(added, fixed, changed, removed — четыре обычные); и, когда это важно, что читательница должна
с этим сделать. Ссылка на подробности — это хорошо. Абзац внутреннего обоснования — нет, потому
что читательница спросила не почему, а что.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## 2026-09-07

### Added
- Счета теперь показывают налог отдельной строкой, в валюте аккаунта
  клиента.

### Fixed
- Экспорт отчёта в CSV больше не теряет последнюю строку, когда отчёт
  превышает 10 000 строк.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Эта форма масштабируется от обновления в две строки до сотни записей в релизе, не меняя
структуры — и это настоящая проверка того, работает ли формат: читается ли он одинаково в
загруженную неделю и в спокойную.&lt;/p&gt;
&lt;h2&gt;Кто пишет changelog, и когда?&lt;/h2&gt;
&lt;p&gt;Тот, кто внёс изменение, в момент выпуска — а не технический редактор, восстанавливающий его из
тикетов неделю спустя. Тот, кто трогал код, знает, что на самом деле изменилось для пользователя;
резюме, написанное задним числом, склонно описывать тикет вместо того, что реально выпустили, а
это обычно шире или уже реального объёма. Некоторые команды добавляют шаг ревью перед тем, как
запись станет публичной, в основном чтобы поймать просочившийся внутренний язык, и это ревью
должно быть достаточно быстрым, чтобы запись вышла в тот же день.&lt;/p&gt;
&lt;h2&gt;Где место changelog?&lt;/h2&gt;
&lt;p&gt;На собственной странице, по стабильному URL, распространяемой как feed. Спрятанный в меню
настроек или в теге релиза на хостинге кода, он доходит только до тех, кто уже знал, где искать.
На публичную страницу можно сослаться из тикета поддержки, процитировать в обзоре или подписаться
на неё. Feed важен не меньше страницы: читательница, проверяющая changelog продукта раз в месяц —
редкость, подписанная на него — нет, и только feed обслуживает второй тип.&lt;/p&gt;
&lt;h2&gt;Чем он отличается от release notes?&lt;/h2&gt;
&lt;p&gt;Их постоянно путают, и они достаточно разные, чтобы смешивание давало документ, который плохо
служит обеим читательницам. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;Changelog против release notes&lt;/a&gt;
разбирает различие целиком; коротко — changelog это полная, хронологическая запись, а release
notes — отобранное подмножество, написанное так, чтобы обновление звучало достойным внимания.
Продукту обычно нужны оба, обращённые к разным моментам дня читательницы.&lt;/p&gt;
&lt;h2&gt;Что делает changelog стоящим прочтения?&lt;/h2&gt;
&lt;p&gt;Конкретность и честность о собственном охвате. «Разные исправления багов» — фраза, которая учит
читательницу больше не открывать страницу, потому что не обещает ничего проверяемого. Запись,
называющая точное изменившееся поведение, даже для мелкого фикса — та, что держит подписку
живой. Эта дисциплина касается и того, что пропускают: changelog, объявляющий только победы и
никогда — исправление того, что было сломано, читается как маркетинг под видом changelog, и
читательницы это замечают.&lt;/p&gt;
&lt;p&gt;Дисциплина версионирования тоже важна. &lt;a href=&quot;https://changeloop.dev/blog/ru/semantic-versioning-changelog/&quot;&gt;Semantic versioning и ваш changelog&lt;/a&gt;
показывает, как номер версии и запись должны соответствовать друг другу, чтобы читательница,
просматривая историю версий, получала один и тот же сигнал дважды, а не два разных.&lt;/p&gt;
&lt;h2&gt;Как генерируются changelog?&lt;/h2&gt;
&lt;p&gt;Двумя способами, и большинство реальных настроек — это смесь. Автоматизированная генерация читает
сообщения коммитов, обычно в формате &lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt;,
и превращает их в записи без чьего-либо вмешательства в результат; &lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;от conventional commits к changelog&lt;/a&gt;
разбирает этот пайплайн. Курируемая генерация означает, что кто-то пишет или редактирует каждую
запись вручную. Автоматизированный результат быстрее и никогда не пропускает смёрженный pull
request, но наследует каждое расплывчатое сообщение коммита дословно — поэтому большинство
автоматизирующих команд всё равно оставляют лёгкий проход редактуры перед публикацией, а не
показывают сырой результат.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли changelog каждому продукту?&lt;/strong&gt;
Любому продукту с пользователями, затронутыми изменениями, он нужен — будь то SaaS-приложение,
внутренний инструмент или публичное API. Форма подстраивается (changelog API читается иначе,
чем у потребительского приложения), потребность нет.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что такое changelog в терминах программного обеспечения?&lt;/strong&gt;
То же определение, что и выше: датированный, хронологический список того, что изменилось в
софте, написанный для тех, кто им пользуется, а не для тех, кто его строил.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Может ли changelog генерироваться автоматически из коммитов?&lt;/strong&gt;
Да, и многие команды делают именно это, обычно из сообщений в формате Conventional Commits.
Компромисс в том, что сгенерированная запись настолько ясна, насколько ясно сообщение коммита, из
которого она пришла, так что проход ревью перед публикацией ловит те, что нужно переформулировать.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Это то же самое, что история версий?&lt;/strong&gt;
Достаточно близко, чтобы термины использовали взаимозаменяемо. История версий иногда — просто
список номеров версий и дат без описания; changelog всегда включает, что изменилось.&lt;/p&gt;
</content:encoded></item><item><title>Changelog API: что публиковать и кто это читает</title><link>https://changeloop.dev/blog/ru/api-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/api-changelog/</guid><description>Changelog API читают те, кто решает, будет ли их код работать через месяц. Что каждая запись им должна, где ей место, и как на неё подписаться.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Changelog API — это датированная запись каждого изменения, которое может заметить вызывающая
сторона, написанная для тех, кто интегрируется с API, а не для команды, которая его выпускает.
Эта аудитория делает его другим документом, чем changelog продукта: читатель решает, будет ли его
код работать через месяц. Большинство таких changelog проваливаются одинаково, будучи
отфильтрованной копией внутреннего ленты релизов, так что удалённое поле оказывается рядом с
исправлением текста с тем же весом, и ни то ни другое не читают.&lt;/p&gt;
&lt;h2&gt;Что такое changelog API?&lt;/h2&gt;
&lt;p&gt;Это публичный, датированный журнал изменений в интерфейсе, под который другие писали код.
Полезный тест на то, место ли чему-то в нём, не имеет отношения к тому, насколько велико было
изменение внутри. Он спрашивает, мог бы правильный вызывающий код, написанный год назад и с тех
пор не тронутый, повести себя иначе из-за него. Этот тест допускает некоторые очень мелкие
изменения и исключает некоторые очень крупные.&lt;/p&gt;
&lt;p&gt;Всё ниже предполагает, что вызывающий находится вне компании и практически недосягаем иначе, чем
через этот документ. Когда вызывающий — другая команда той же компании, расчёт меняется настолько,
что заслуживает собственного разбора; &lt;a href=&quot;https://changeloop.dev/blog/ru/internal-api-changelog/&quot;&gt;внутренние changelog API&lt;/a&gt;
разбирает, что нужно этой аудитории вместо этого.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Документ&lt;/th&gt;
&lt;th&gt;Аудитория&lt;/th&gt;
&lt;th&gt;Отвечает на&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Changelog API&lt;/td&gt;
&lt;td&gt;Разработчики, вызывающие API&lt;/td&gt;
&lt;td&gt;Всё ещё работает моя интеграция?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release notes&lt;/td&gt;
&lt;td&gt;Пользователи продукта&lt;/td&gt;
&lt;td&gt;Что я теперь могу, чего не мог раньше?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Уведомление о депрекейшене&lt;/td&gt;
&lt;td&gt;Вызывающие конкретную вещь&lt;/td&gt;
&lt;td&gt;Когда это перестанет работать?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Страница статуса&lt;/td&gt;
&lt;td&gt;Все, кто сейчас затронут&lt;/td&gt;
&lt;td&gt;Сейчас всё лежит?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Руководство по миграции&lt;/td&gt;
&lt;td&gt;Вызывающие, делающие апгрейд&lt;/td&gt;
&lt;td&gt;Как перейти от A к B?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/blog/ru/api-migration-guide/&quot;&gt;Как написать гайд по миграции API&lt;/a&gt; разбирает этот последний
документ целиком; коротко говоря, это то, на что должна ссылаться запись о несовместимом
изменении, а не пытаться заменить.&lt;/p&gt;
&lt;p&gt;Эти пять — отдельные документы с отдельными жизненными циклами. Уведомление о депрекейшене —
это обещание с датой, и оно тоже относится к changelog, но запись changelog пишется один раз,
пока депрекейшен отслеживается вплоть до его sunset. Смешивание их — причина, по которой sunset
пропускают.&lt;/p&gt;
&lt;h2&gt;Что должно входить в одну запись?&lt;/h2&gt;
&lt;p&gt;Шесть вещей, и первых трёх обычно не хватает. Само изменение, сформулированное в терминах запроса
или ответа, а не внутреннего компонента. Ломает ли оно правильного вызывающего. Что должен сделать
вызывающий, включая &amp;quot;ничего&amp;quot;. Дата вступления в силу. Затронутая версия или версии. Ссылка на
руководство по миграции, если оно есть.&lt;/p&gt;
&lt;p&gt;Запись, которая говорит &amp;quot;улучшен endpoint accounts&amp;quot;, проваливается по всем шести пунктам. Запись,
которая говорит &amp;quot;поле &lt;code&gt;accounts.type&lt;/code&gt; теперь возвращает &lt;code&gt;individual&lt;/code&gt; там, где раньше возвращало
&lt;code&gt;personal&lt;/code&gt;; существующие значения не меняются для аккаунтов, созданных до 2 сентября; действие не
требуется, если вы не сравниваете строку&amp;quot;, отвечает на все шесть в одном предложении.&lt;/p&gt;
&lt;p&gt;Категоризируйте записи по последствиям, а не по отделу. Три метки несут почти всю ценность:
breaking, additive и fixed. &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt; уже точно определяет первые
две, и заимствование его определений вместо изобретения своих означает, что читатель, знающий
semver, знает и ваши метки. &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt; предлагает
более длинный набор, если хотите, и его центральное правило действует здесь сильнее, чем где-либо
ещё: журнал — для людей, а свалка заголовков коммитов — нет.&lt;/p&gt;
&lt;h2&gt;Чем changelog API отличается от release notes?&lt;/h2&gt;
&lt;p&gt;Release notes описывают, что продукт теперь умеет. Changelog API описывает, каков теперь контракт.
Одна и та же выпущенная работа часто порождает запись в обоих, сформулированную по-разному, потому
что аудиториям нужны разные вещи: новый формат экспорта — это функция для пользователя и новое
значение enum для вызывающего, переключающегося на этом поле.&lt;/p&gt;
&lt;p&gt;Практическое следствие в том, что эти два не могут быть одним и тем же потоком с разным стилем.
Вызывающий, подписанный на всё, что вы выпускаете, в конце концов отпишется и тогда пропустит
breaking change. Если публикуете один поток — фильтруйте его; если публикуете два — сделайте
поток API уже и никогда не пускайте в него маркетинговую запись. Мы сравниваем обе формы бок о бок
в &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;changelog против release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Где должен жить changelog API?&lt;/h2&gt;
&lt;p&gt;Рядом с справочной документацией, по стабильному URL, с каждой записью, адресуемой отдельно через
фрагмент или собственный путь. Вызывающие ссылаются на записи в разборах инцидентов и внутренних
тикетах, и запись, на которую нельзя сослаться, вместо этого вклеивается как скриншот.&lt;/p&gt;
&lt;p&gt;Публикуйте его также как машиночитаемый вывод, помимо страницы. JSON-поток, следующий
&lt;a href=&quot;https://www.jsonfeed.org/version/1.1/&quot;&gt;спецификации JSON Feed&lt;/a&gt;, или
&lt;a href=&quot;https://www.rssboard.org/rss-specification&quot;&gt;RSS-поток&lt;/a&gt; ничего не стоит, как только записи
становятся структурированными данными, и именно это позволяет клиенту встроить ваши изменения в
собственный процесс релизов. Это также часть, которая решает, будет ли кто-то на этом строить.
GitHub документирует свои &lt;a href=&quot;https://docs.github.com/en/rest/about-the-rest-api/api-versions&quot;&gt;версии REST API&lt;/a&gt;
прямо рядом со справочником по той же причине: политика версионирования — часть интерфейса.&lt;/p&gt;
&lt;h2&gt;Как выглядит хорошая запись на практике?&lt;/h2&gt;
&lt;p&gt;Три записи за одну неделю, в описанной выше форме:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2026-09-02  Breaking  v2
  `POST /invoices` теперь отклоняет `currency`, не совпадающую с
  валютой аккаунта клиента, возвращая 422 вместо тихого
  конвертирования. Вызывающие, полагавшиеся на конвертацию, должны
  отправлять валюту аккаунта. Затрагивает только v2; v1 не меняется
  до sunset 2027-01-15.

2026-09-02  Additive  v1, v2
  `Invoice` получает временную метку `settled_at`, null до момента
  оплаты счёта. Действие не требуется. Клиентов, отклоняющих
  неизвестные поля, следует обновить.

2026-08-31  Fixed  v2
  `GET /invoices?status=` возвращал пустую страницу вместо 400 для
  неизвестного статуса. Теперь возвращает 400 с допустимыми
  значениями. Вызывающие с опечаткой раньше видели ноль результатов,
  теперь видят ошибку.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Третья — тип, который чаще всего пропускают, потому что внутри это исправление бага. Для
вызывающего, построившего retry вокруг этой пустой страницы, это изменение поведения, и запись —
именно то, что предотвращает тикет в поддержку. Метка говорит fixed, а тело говорит, что мог бы
заметить вызывающий, и это различие держит журнал честным, не раздувая каждое исправление до
breaking change.&lt;/p&gt;
&lt;h2&gt;Как вызывающие на это подписываются?&lt;/h2&gt;
&lt;p&gt;Дайте им больше одного канала, потому что у них разные задачи. Поток для разработчика, которому
нужно всё. Email для того, кому нужны только breaking changes. Заголовки ответа для самого кода —
единственного подписчика, который никогда не забывает проверить: &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8594&quot;&gt;заголовок &lt;code&gt;Sunset&lt;/code&gt;,
определённый в RFC 8594&lt;/a&gt;, помещает дату вывода из
эксплуатации в ответ, где клиентская библиотека может её залогировать.&lt;/p&gt;
&lt;p&gt;Канал, который большинство команд пропускает, — прямой. Если вызывающий использовал на прошлой
неделе поле, которое вы меняете, вы знаете, кто это, и письмо на эти аккаунты стоит больше любой
общей рассылки. Это та же дисциплина, что и &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;закрытие петли обратной связи с клиентом&lt;/a&gt;,
применённая к изменению, которое никто не просил: затронутых оповещают индивидуально, а все
остальные получают поток. Вебхук — четвёртый
канал со своим режимом отказа, о котором стоит знать перед тем, как на него полагаться:
&lt;a href=&quot;https://changeloop.dev/blog/ru/webhook-changelog/&quot;&gt;changelog вебхуков&lt;/a&gt; разбирает, почему изменение payload там
ломается тихо, без вызывающего, способного отклонить новую форму.&lt;/p&gt;
&lt;h2&gt;Как написать запись для breaking change?&lt;/h2&gt;
&lt;p&gt;Начните с поломки, а не с причины. Вызывающий, просматривающий десять записей, должен в первой
фразе понять, будет ли эта запись стоить ему работы. Затем дата, затронутые версии, миграция и
крайний срок, если старое поведение исчезает, а не меняется.&lt;/p&gt;
&lt;p&gt;Поместите одно и то же содержание в уведомление о депрекейшене, заголовок ответа и прямое письмо,
сформулировав его согласованно, и дайте всем четырём одну и ту же дату. Расхождение между ними —
ошибка, превращающая запланированное изменение в инцидент, потому что вызывающий, прочитавший
только одно из них, действует по неверной дате. &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Что такое breaking change&lt;/a&gt;
охватывает само решение, а &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;как деприкейтить API&lt;/a&gt; охватывает
последующий график.&lt;/p&gt;
&lt;p&gt;В changeloop изменение API становится записью, когда pull request объединяется, кто-то
редактирует и утверждает черновик, и запись публикуется в &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;ленте и виджете&lt;/a&gt; в тот же
момент, когда вызывающего, чей отзыв из виджета стал GitHub issue, который закрывает этот pull
request, оповещают об этом в том же issue. Шаг проверки — именно то, что
здесь важно: changelog API — это договорной документ, и ни один черновик не должен дойти до
вызывающего без того, чтобы его прочитал человек.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Нужна ли каждому изменению API запись в changelog?&lt;/strong&gt;
Каждому изменению, которое мог бы заметить правильный вызывающий — да, включая те, что вы
считаете внутренними. Изменения без наблюдаемого эффекта на запрос или ответ — нет, и добавление
их приучает читателей проглядывать текст.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли changelog API жить в документации или на маркетинговом сайте?&lt;/strong&gt;
В документации, прямо рядом со справочником. Читатель обычно уже там, а changelog на
маркетинговом сайте склонен набирать аудиторию, для которой он не был написан.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Насколько далеко назад он должен идти?&lt;/strong&gt;
Бесконечно. На записи ссылаются годы спустя в разборах инцидентов, и обрезанный журнал ломает эти
ссылки. Используйте пагинацию, а не удаление.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли отдельный changelog для каждой версии API?&lt;/strong&gt;
Нет, один журнал с полем версии в каждой записи легче читать и искать. Фильтрация по версии —
функция страницы, а не причина разделять документ.&lt;/p&gt;
</content:encoded></item><item><title>Как сделать страницу changelog, за которой следят</title><link>https://changeloop.dev/blog/ru/changelog-page/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/changelog-page/</guid><description>Страница changelog оправдывает себя, когда люди возвращаются на неё. Где ей место, что нужно каждой записи, потоки и разметка, и куда встроить виджет.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Страницу changelog стоит делать, если люди будут на неё возвращаться. Это более высокая планка,
чем просто иметь такую страницу, и именно на ней спотыкается большинство: страница существует,
на неё есть ссылка в футере, обновляется рывками и посещается разве что во время инцидента.
Решения, разделяющие эти два случая, принимаются до того, как написано хоть слово, и в основном
касаются того, где живёт страница и что ещё генерируется из того же содержимого.&lt;/p&gt;
&lt;h2&gt;Что такое страница changelog?&lt;/h2&gt;
&lt;p&gt;Это публичный, датированный список того, что изменилось в продукте, по URL, который принадлежит
вам. Это одна из пяти поверхностей, на которых могут появляться одни и те же записи, и полезный
вопрос — не какую выбрать, а какая из них каноническая, а какие сгенерированы из неё.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Поверхность&lt;/th&gt;
&lt;th&gt;Лучше всего для&lt;/th&gt;
&lt;th&gt;Стоимость&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Хостируемая страница&lt;/td&gt;
&lt;td&gt;Поиска, ссылок, длинного журнала&lt;/td&gt;
&lt;td&gt;URL и шаблон&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Виджет в приложении&lt;/td&gt;
&lt;td&gt;Пользователей, никогда не заходящих на страницу&lt;/td&gt;
&lt;td&gt;Встраивание, и сдержанность&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Раздел документации&lt;/td&gt;
&lt;td&gt;Аудитории API и разработчиков&lt;/td&gt;
&lt;td&gt;Хранения рядом со справочником&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-поток&lt;/td&gt;
&lt;td&gt;Клиентов, строящих на ваших изменениях&lt;/td&gt;
&lt;td&gt;Структура, которая у вас уже есть&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSS-поток&lt;/td&gt;
&lt;td&gt;Разработчиков, подписывающихся один раз&lt;/td&gt;
&lt;td&gt;Почти ничего&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Выберите один канонический источник, публикуйте один раз, а остальное генерируйте. Команды,
поддерживающие страницу и виджет отдельно вручную, в итоге получают два текста, которые не
совпадают, и расхождение обнаруживает клиент.&lt;/p&gt;
&lt;h2&gt;Где должна жить страница changelog?&lt;/h2&gt;
&lt;p&gt;На вашем собственном домене, по стабильному пути, с каждой записью, адресуемой отдельно. Три
распространённых варианта — путь на основном сайте, поддомен и раздел документации. Путь на
основном сайте — выбор по умолчанию, против которого нужно аргументировать, а не за него: он
наследует авторитет сайта, не требует дополнительного сертификата или DNS, и держит страницу в
той же навигации, что и всё остальное.&lt;/p&gt;
&lt;p&gt;Поддомен — правильный ответ, когда страницу обслуживает система, отличная от маркетингового
сайта, и иначе пришлось бы делать proxy. Цена — он накапливает авторитет отдельно. Размещение
changelog в документации правильно, когда аудитория — разработчики, по причине, разобранной в
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;changelog API&lt;/a&gt;: читатель там уже обычно находится.&lt;/p&gt;
&lt;p&gt;Важнее выбора то, что на записи можно ссылаться по отдельности. Люди ссылаются на записи в
разборах инцидентов и внутренних тикетах, и запись, на которую можно сослаться только как
&amp;quot;changelog, прокрутите вниз&amp;quot;, вместо этого вклеивается скриншотом.&lt;/p&gt;
&lt;h2&gt;Что нужно странице changelog?&lt;/h2&gt;
&lt;p&gt;Пять вещей, и на первых двух проваливается большинство страниц. Датированная запись на каждое
изменение, новейшие сначала. Категория или метка на запись, чтобы можно было сканировать по
интересующему типу. Постоянная ссылка на запись. Способ подписки. Поиск или фильтр после
примерно пятидесяти записей.&lt;/p&gt;
&lt;p&gt;Остальное опционально. Скриншоты помогают и требуют поддержки. Имена авторов создают доверие в
одних продуктах и шум в других. Номера версий важны для вызывающих API и почти ни для кого
больше. &lt;a href=&quot;https://keepachangelog.com/en/1.1.0/&quot;&gt;Keep a Changelog&lt;/a&gt; — разумный выбор по умолчанию
для меток, если у вас нет причин изобретать свои, и его центральное правило стоит сохранить, даже
если отбросить остальное: журнал пишется для людей.&lt;/p&gt;
&lt;p&gt;Группируйте по дате, а не по версии, если ваш продукт релизится непрерывно. Читатель, сканирующий
&amp;quot;это было до или после нашего инцидента девятого числа&amp;quot;, ищет дату, а страница, организованная по
номеру версии, заставляет его считать.&lt;/p&gt;
&lt;h2&gt;Страница или виджет в приложении?&lt;/h2&gt;
&lt;p&gt;И то, и другое, из одного источника. Страница — это место, где живут поиск, ссылки и длинный
журнал. Виджет — способ достучаться до большинства пользователей, которые никогда не зайдут на
страницу, и он работает, потому что появляется в продукте, которым они уже пользуются.&lt;/p&gt;
&lt;p&gt;Провал виджета — это прерывание. Значок, требующий внимания на каждую запись, будет навсегда
отклонён в течение недели, что стоит вам канала для той записи, которая действительно имела
значение. Считайте непрочитанное с последнего взгляда читателя, тихо засевайте счётчик при первом
визите, чтобы никого не встречал значок с историей за год, и дайте читателю открыть его самому,
вместо того чтобы открывать за него.&lt;/p&gt;
&lt;h2&gt;Как сделать страницу changelog машиночитаемой?&lt;/h2&gt;
&lt;p&gt;Публикуйте те же записи как поток. &lt;a href=&quot;https://www.jsonfeed.org/version/1.1/&quot;&gt;JSON-поток&lt;/a&gt; — вариант с
наименьшим трением для всего, что потребляет его в коде, а &lt;a href=&quot;https://www.rssboard.org/rss-specification&quot;&gt;RSS-поток&lt;/a&gt; —
то, чего ожидает разработчик, подписавшийся в ридере. Оба обходятся дёшево, как только записи
становятся структурированными данными вместо HTML, написанного вручную, что и есть реальный
аргумент за то, чтобы держать каноническую копию структурированной.&lt;/p&gt;
&lt;p&gt;Разметьте и страницу тоже. Записи — это произведения с датой и заголовком, и
&lt;a href=&quot;https://schema.org/CreativeWork&quot;&gt;schema.org&lt;/a&gt; предоставляет словарь. Это стоит сделать по той же
причине, что и постоянные ссылки: это делает страницу пригодной для использования вещами, которые
не являются браузером, включая собственный процесс релизов клиента. Ничего
из этого не работает, если исходные записи никогда не были структурированными данными с самого
начала; &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-file-formats/&quot;&gt;форматы файлов changelog&lt;/a&gt; разбирает, сколько стоит
каждый из Markdown, JSON и YAML как источник истины, из которого этот поток и эта разметка
реально генерируются.&lt;/p&gt;
&lt;h2&gt;Помогает ли страница changelog SEO?&lt;/h2&gt;
&lt;p&gt;Косвенно и медленно. Отдельные записи редко ранжируются, потому что не нацелены ни на один запрос,
который кто-то вводит. Страница зарабатывает своё место через ссылки: записи цитируют в ответах
поддержки, на форумах и в разборах инцидентов, и эти ссылки накапливаются на URL, который
принадлежит вам. Страница, обновляемая еженедельно два года подряд, — это ещё и убедительный
сигнал свежести для продукта, которому она принадлежит.&lt;/p&gt;
&lt;p&gt;Что не работает — это относиться к записям как к контент-маркетингу. Запись, раздутая до трёх
абзацев ради длины, хуже справляется со своей настоящей работой — сказать читателю в одном
предложении, изменилось ли что-то, чем он пользуется. Если хотите, чтобы changelog поддерживал
поиск, вкладывайте усилия в постоянные ссылки, поток и внутренние ссылки на него, а записи
держите короткими. Наша собственная страница &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеров changelog&lt;/a&gt; собирает
страницы, которые верно ловят этот баланс.&lt;/p&gt;
&lt;h2&gt;Как люди подписываются?&lt;/h2&gt;
&lt;p&gt;Дайте им пути, которыми они уже пользуются: RSS- или JSON-поток для разработчиков, email для тех,
кто хочет слышать только важное, и виджет в приложении для всех, кто никогда не сделает ни того ни
другого. Спрашивайте, что они хотят слышать, а не предполагайте, потому что читатель, желающий
breaking changes и получающий исправления текста, отписывается от обоих.&lt;/p&gt;
&lt;p&gt;Путь, который стоит добавить последним, — тот, что замыкает петлю. Когда запись решает то, о чём
попросил конкретный человек, скажите ему это напрямую, вместо того чтобы надеяться, что он прочтёт
страницу. В changeloop запись публикуется сразу на &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;странице, в потоке и виджете&lt;/a&gt;, и
человека, чей отзыв из виджета стал GitHub issue, закрытым этим pull request, оповещают в этом
issue со ссылкой на запись, и он видит запись в виджете. Механизм тот же, что и у
любой подписки; разница в том, что получатель уже спросил. Это аргумент, развёрнутый в
&lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;закрытии петли обратной связи со стороны changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должна ли страница changelog быть на поддомене или на пути?&lt;/strong&gt;
По умолчанию — путь на основном сайте, потому что он наследует авторитет сайта и не требует
дополнительной инфраструктуры. Поддомен оправдан, когда страницу обслуживает другая система.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сколько записей должна показывать страница за раз?&lt;/strong&gt;
Достаточно, чтобы заполнить экран, и не больше, с пагинацией после этого. Загрузка двух лет
истории в один документ работает медленно и усложняет поиск новейшей записи.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Стоит ли когда-нибудь удалять старые записи?&lt;/strong&gt;
Нет. На них ссылаются извне вашего сайта, и ссылки ломаются. Исправляйте запись на месте с
пометкой, и держите URL живым.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должно ли каждое изменение появляться на странице?&lt;/strong&gt;
Только те, что мог бы заметить пользователь. Страница, фиксирующая внутренние рефакторинги,
приучает читателей проглядывать текст, а проглядываемая страница проваливается в тот день, когда
несёт что-то срочное.&lt;/p&gt;
</content:encoded></item><item><title>Шаблон письма об обновлении продукта, которое читают</title><link>https://changeloop.dev/blog/ru/product-update-email/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/product-update-email/</guid><description>Письмо об обновлении продукта, которое читают, ушло тому, кто его попросил. Шаблон, четыре типа писем, рабочие темы, сегментация и согласие.</description><pubDate>Wed, 02 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Письмо об обновлении продукта, которое читают, — это то, что отправлено человеку, попросившему
именно то, о чём оно сообщает. Всё остальное конкурирует с остальной почтой за интерес — гонку,
которую анонс релиза проигрывает в большинство недель. Этот единственный факт должен определять
форму письма ещё до того, как сформулировано хоть одно слово: кто его получает, и что этот
человек сделал, чтобы попасть в список.&lt;/p&gt;
&lt;h2&gt;Что такое письмо об обновлении продукта?&lt;/h2&gt;
&lt;p&gt;Это сообщение, рассказывающее существующим пользователям, что изменилось в продукте, которым они
уже пользуются. Есть четыре разных типа, и обращение с ними как с одним списком — причина падения
open rate. У каждого свой триггер, своя аудитория и своя приемлемая частота.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Тип&lt;/th&gt;
&lt;th&gt;Триггер&lt;/th&gt;
&lt;th&gt;Аудитория&lt;/th&gt;
&lt;th&gt;Частота&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Целевое уведомление&lt;/td&gt;
&lt;td&gt;Конкретный запрос кого-то выпущен&lt;/td&gt;
&lt;td&gt;Один человек&lt;/td&gt;
&lt;td&gt;Каждый раз&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Уведомление о breaking change&lt;/td&gt;
&lt;td&gt;Изменение, стоящее читателю работы&lt;/td&gt;
&lt;td&gt;Только затронутые аккаунты&lt;/td&gt;
&lt;td&gt;Каждый раз&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Дайджест&lt;/td&gt;
&lt;td&gt;Течение времени&lt;/td&gt;
&lt;td&gt;Пользователи opt-in&lt;/td&gt;
&lt;td&gt;Не чаще раза в месяц&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Анонс запуска&lt;/td&gt;
&lt;td&gt;Запуск, стоящий прерывания&lt;/td&gt;
&lt;td&gt;Сегмент или все&lt;/td&gt;
&lt;td&gt;Редко, и должно ощущаться редким&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Большинство команд строят только третий тип, рассылают его всем и делают вывод, что письма об
обновлении продукта не работают. Первые два несут почти всю ценность, потому что у читателя уже
есть причина заинтересоваться, и письмо приходит, пока эта причина ещё жива.&lt;/p&gt;
&lt;p&gt;Все эти четыре строки написаны для клиентов. Продажам, саппорту и customer success тоже нужно
знать, что вышло, обычно в форме, отличной от этих четырёх; &lt;a href=&quot;https://changeloop.dev/blog/ru/internal-release-notes/&quot;&gt;внутренние release notes&lt;/a&gt;
разбирают, что должен говорить этот документ и почему он должен выходить раньше заметки для
клиентов.&lt;/p&gt;
&lt;p&gt;Email — один из нескольких каналов, которые может использовать анонс запуска, не единственный. &lt;a href=&quot;https://changeloop.dev/blog/ru/new-feature-announcement/&quot;&gt;Как анонсировать новую функцию&lt;/a&gt; описывает остальные и как выбирать между ними в зависимости от того, насколько велика функция на самом деле.&lt;/p&gt;
&lt;h2&gt;Что входит в шаблон?&lt;/h2&gt;
&lt;p&gt;Шесть блоков в таком порядке. Первый — тот, которого обычно не хватает, и тот, что делает работу.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Тема:  &amp;lt;что изменилось, словами читателя&amp;gt;

1. Почему вы это получаете
   &amp;quot;Вы просили экспорт в CSV в марте.&amp;quot; или
   &amp;quot;Ваша интеграция вызывает /v1/invoices, который меняется
   15 января.&amp;quot;

2. Что изменилось
   Одно предложение. Что теперь возможно, или что теперь ломается.

3. Что вам нужно сделать
   Часто &amp;quot;ничего&amp;quot;. Скажите это явно, не оставляйте подразумеваемым.

4. Где это увидеть
   Ссылка на запись changelog, а не на главную страницу.

5. Когда
   Дата выпуска, или с какого момента это действует.

6. Как отписаться
   Один клик, немедленно уважаемый.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Блок 1 — разница между сообщением и общей рассылкой. Читатель, которому в первой строке говорят,
что это решение того, о чём он лично просил, читает дальше. Без него блоки 2-5 — рассылка, каким
бы хорошим ни был текст.&lt;/p&gt;
&lt;p&gt;Держите всё в пределах примерно 150 слов. Письмо — указатель на запись changelog, и именно там
место деталям. Письмо, воспроизводящее всю запись целиком, не даёт читателю причины кликнуть, а
вам — сигнала, было ли это кому-то важно.&lt;/p&gt;
&lt;h2&gt;Какие темы работают?&lt;/h2&gt;
&lt;p&gt;Называйте изменение, а не релиз. &amp;quot;Экспорт в CSV уже доступен&amp;quot; побеждает &amp;quot;обновление за сентябрь&amp;quot;,
потому что первое — факт, который читатель может оценить, а второе — контейнер. Номера версий в
теме полезны вызывающим API и шум для всех остальных, ещё одна причина разделить аудитории.&lt;/p&gt;
&lt;p&gt;Избегайте заявлений о выгоде, на которую читатель не соглашался. &amp;quot;Ваши отчёты теперь быстрее&amp;quot;
заявляет что-то о его опыте; &amp;quot;Отчёты свыше 10 000 строк теперь загружаются меньше чем за секунду&amp;quot;
сообщает об изменении и позволяет ему решить, важно ли это.&lt;/p&gt;
&lt;h2&gt;Когда его отправлять, и кому?&lt;/h2&gt;
&lt;p&gt;Отправляйте целевое уведомление в момент, когда что-то выпущено, людям, которые это просили,
индивидуально. Отправляйте уведомление о breaking change сразу, как дата станет точной, и ещё раз
ближе к ней, реально затронутым аккаунтам, а не всему списку. Отправляйте дайджест, только если у
вас достаточно изменений, чтобы читатель иначе что-то пропустил, и дайте людям подписываться
отдельно.&lt;/p&gt;
&lt;p&gt;Список, который почти никогда не стоит использовать, — &amp;quot;все пользователи&amp;quot;. Он превращает
конкретное сообщение в общее и приучает к отпискам. Сегментируйте по поведению, которое вы уже
храните: кто это просил, кто использует этот endpoint, кто на этом плане.&lt;/p&gt;
&lt;h2&gt;Нужно ли согласие на отправку?&lt;/h2&gt;
&lt;p&gt;Для существующих клиентов обновление об услуге, которой они пользуются, обычно другой юридический
вопрос, чем маркетинг потенциальному клиенту, и ответ зависит от того, где они находятся, и что вы
сказали им при регистрации. В ЕС релевантный вопрос — какое правовое основание из
&lt;a href=&quot;https://gdpr-info.eu/art-6-gdpr/&quot;&gt;статьи 6 GDPR&lt;/a&gt; применимо, а в США коммерческие сообщения несут
конкретные требования, установленные в
&lt;a href=&quot;https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business&quot;&gt;руководстве по соответствию CAN-SPAM от FTC&lt;/a&gt;.
Оба на практике требуют одного и того же: скажите, кто вы, проясните цель, и дайте людям
возможность остановить рассылку.&lt;/p&gt;
&lt;p&gt;Каким бы ни было основание, держите транзакционный и маркетинговый потоки раздельными на уровне
отправки. Уведомление о breaking change, от которого клиент отписался, потому что оно делило
список с промо-дайджестом, — это инцидент поддержки, ждущий своей даты.&lt;/p&gt;
&lt;h2&gt;Как это выглядит заполненным?&lt;/h2&gt;
&lt;p&gt;Целевое уведомление — самое ценное письмо об обновлении продукта и то, которое большинство команд
никогда не строят:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Тема: Экспорт в CSV уже доступен

Привет, Дана,

ты просила экспорт в CSV в марте.

Это стало доступно сегодня утром. У отчётов теперь есть
кнопка Export, создающая CSV текущего вида, включая фильтры.

С твоей стороны ничего делать не нужно. Уже включено на
твоём аккаунте.

  Подробности: example.com/changelog#csv-export
  Выпущено: 2 сентября 2026

Ты получаешь это, потому что просила. Отписаться от
обновлений по запросам: &amp;lt;ссылка&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Девяносто слов, и читатель в первой строке знает, почему это пришло. Сравните с тем же изменением
в месячном дайджесте, где оно появляется как один из девяти пунктов, а у Даны нет причин заметить,
что её собственный запрос вышел.&lt;/p&gt;
&lt;h2&gt;Что стоит измерять?&lt;/h2&gt;
&lt;p&gt;Не только open rate. Для целевого уведомления вопрос в том, вернулся ли попросивший человек и
воспользовался ли этим, так что число для отслеживания — клик к записи и использует ли этот
аккаунт функцию в течение недели. Для уведомления о breaking change это покрытие: какая доля
затронутых аккаунтов открыла письмо до даты, и с кем вы связались индивидуально.&lt;/p&gt;
&lt;p&gt;Дайджест — единственный из четырёх типов, где open rate что-то значит, и даже там он полезнее как
тренд относительно собственной истории, чем относительно отраслевого бенчмарка. У разных типов
писем об обновлении продукта разные задачи, так что усреднённая по всем цифра не описывает ничего,
на что можно опереться в действиях.&lt;/p&gt;
&lt;h2&gt;Чем это отличается от release notes?&lt;/h2&gt;
&lt;p&gt;Release notes — документ, который остаётся доступным. Письмо — механизм доставки, случающийся
один раз. Одно и то же изменение порождает оба, и письмо должно быть короче записи, на которую
указывает. &lt;a href=&quot;https://changeloop.dev/blog/ru/release-notes-best-practices/&quot;&gt;Лучшие практики release notes&lt;/a&gt; охватывает
документ, а &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;changelog против release notes&lt;/a&gt; охватывает,
какой из них вы пишете.&lt;/p&gt;
&lt;p&gt;Отношение, которое стоит наладить правильно: запись changelog — канонический текст, а письмо его
цитирует. Когда эти два расходятся, читатель, кликнувший по ссылке, находит другое описание
изменения и перестаёт доверять обоим. Публикация записи первой и генерация письма из неё убирает
расхождение конструктивно. changeloop со своей стороны работает так же: запись рецензируется
один раз и публикуется на &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;странице, в потоке и виджете&lt;/a&gt;, а человека, попросившего о ней
через виджет, оповещают в GitHub issue, которым стал его отзыв, и в самом виджете. Письмо changeloop
не отправляет; ваш почтовый инструмент цитирует опубликованную запись.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Как часто должно выходить письмо об обновлении продукта?&lt;/strong&gt;
Так часто, как есть что-то конкретное, что получатель хочет знать, что для целевого уведомления
означает каждый раз, когда выпускается его запрос, а для дайджеста — не чаще раза в месяц.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должно ли письмо содержать всю запись changelog целиком?&lt;/strong&gt;
Нет. Одно предложение и ссылка. Запись — каноническая версия, а полная копия в письме означает
два текста, которые нужно держать согласованными.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой open rate стоит ожидать?&lt;/strong&gt;
Сравнивайте каждый тип с самим собой, а не с бенчмарком. Целевое уведомление и месячный дайджест —
разные продукты, и их усреднение скрывает единственную цифру, за которой стоит следить.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужен ли отдельный список для breaking changes?&lt;/strong&gt;
Да, и это должен быть тот список, от которого люди не могут отписаться небрежно, не понимая
последствий, потому что это тот список, что стоит им сбоя.&lt;/p&gt;
</content:encoded></item><item><title>Как деприкейтить API, не теряя разработчиков</title><link>https://changeloop.dev/blog/ru/api-deprecation/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/api-deprecation/</guid><description>Депрекация — это обещание с датой. Расписание, шаблон уведомления, заголовки ответа, и шаг, не дающий sunset превратиться в инцидент поддержки.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Деприкейтить API означает объявить, что что-то ещё работает сегодня и перестанет работать к
объявленной дате, а затем сдержать обе половины этого обещания. Большинство депрекаций
проваливаются на второй половине: дата тихо сдвигается, или наступает, а вызывающие, никогда не
видевшие уведомления, узнают об этом из ошибки. Депрекация завершена, когда каждый затронутый
вызывающий либо мигрировал, либо был индивидуально уведомлён, что не сделал этого.&lt;/p&gt;
&lt;h2&gt;Что такое депрекация API?&lt;/h2&gt;
&lt;p&gt;Депрекация — это период между объявлением, что endpoint, поле или версия исчезнут, и их
фактическим удалением. В этот период старое поведение продолжает работать, документация говорит,
что оно уходит, и каждый ответ несёт машиночитаемое предупреждение. Удаление — это отдельное,
более позднее событие, часто называемое sunset. Эти два путают, и эта путаница — то место, где
происходит вред: «deprecated» начинает означать «возможно, уже исчезло», а вызывающие перестают
доверять обоим словам.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Термин&lt;/th&gt;
&lt;th&gt;Значение&lt;/th&gt;
&lt;th&gt;На что могут полагаться вызывающие&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;Объявлено как исчезающее, всё ещё работает&lt;/td&gt;
&lt;td&gt;Полное поведение до даты sunset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sunset&lt;/td&gt;
&lt;td&gt;Дата, когда перестаёт работать&lt;/td&gt;
&lt;td&gt;Ничего после этой даты&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retired / удалённое&lt;/td&gt;
&lt;td&gt;Исчезло; запросы падают&lt;/td&gt;
&lt;td&gt;Ошибка, в идеале называющая замену&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legacy&lt;/td&gt;
&lt;td&gt;Неопределено. Избегайте этого слова&lt;/td&gt;
&lt;td&gt;Ничего, что и есть проблема&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Сколько должен длиться период депрекации?&lt;/h2&gt;
&lt;p&gt;Достаточно долго, чтобы вызывающий узнал и выполнил работу, измеряется от момента, когда
уведомление до него дошло, а не от момента, когда вы его написали. Девяносто дней — обычный
минимум для публичного веб-API. Двенадцать месяцев нормально для всего, встроенного в софт,
который устанавливают конечные пользователи, потому что исправление также должно пройти через их
процесс релиза. Руководство Google по версионированию,
&lt;a href=&quot;https://google.aip.dev/185&quot;&gt;AIP-185&lt;/a&gt;, требует разумного переходного периода и рекомендует 180 дней
даже перед удалением бета-функциональности, а Kubernetes документирует свою
&lt;a href=&quot;https://kubernetes.io/docs/reference/using-api/deprecation-policy/&quot;&gt;политику депрекации&lt;/a&gt; в
количестве релизов, а не месяцах, что является правильной единицей, когда ваши вызывающие
обновляются по версии.&lt;/p&gt;
&lt;p&gt;Выберите период, запишите его как политику, и прекратите решать это по каждому изменению.
Опубликованная политика превращает каждую депрекацию из переговоров в применение правила.&lt;/p&gt;
&lt;p&gt;Запись политики депрекации покрывает начало окна; &lt;a href=&quot;https://changeloop.dev/blog/ru/sunsetting-api-version/&quot;&gt;закрытие версии API&lt;/a&gt;
разбирает отдельное уведомление, нужное в конце, когда период реально истекает и версия
перестаёт работать.&lt;/p&gt;
&lt;h2&gt;Расписание депрекации&lt;/h2&gt;
&lt;p&gt;Четыре даты, объявленные вместе в первый день. Каждая — отдельная запись changelog при наступлении,
поэтому история рассказывается четыре раза каждому, кто читает только changelog.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Объявите.&lt;/strong&gt; Запись говорит, что депрекируется, почему, что это заменяет, и дату sunset.
Документация старой вещи получает баннер, ведущий к миграции. Ответы получают заголовки,
описанные ниже.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Напомните, на полпути.&lt;/strong&gt; Вторая запись, и прямое сообщение каждому вызывающему, всё ещё
использующему старое поведение. Это шаг, требующий данных об использовании: если вы не можете
перечислить, кто всё ещё вызывает депрекированный endpoint, вы не можете это сделать, и это
стоит исправить до следующей депрекации.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Brownout, незадолго до даты.&lt;/strong&gt; Возвращайте ошибки для старого поведения в течение короткого
окна, час или день, затем восстановите. Вызывающие, пропустившие каждое уведомление, узнают об
этом сейчас, пока ещё есть время. GitHub использовал запланированные brownout перед
&lt;a href=&quot;https://github.blog/2020-07-30-token-authentication-requirements-for-api-and-git-operations/&quot;&gt;выводом из эксплуатации аутентификации по паролю для API&lt;/a&gt;,
и это самый эффективный отдельный шаг в этом списке.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sunset.&lt;/strong&gt; Удалите это. Ошибка, заменяющая это, называет замену и ведёт к руководству по
миграции. Держите ошибку на месте долго; 404 ничего не сообщает вызывающему.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Что должно говорить уведомление о депрекации?&lt;/h2&gt;
&lt;p&gt;Уведомление о депрекации говорит, что уходит, когда останавливается, что использовать вместо
этого, и кого затрагивает. Вот форма, заполненная:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;GET /v1/reports/daily&lt;/code&gt; депрекирован и перестаёт работать 1 марта 2027 года.&lt;/strong&gt;
Заменяется на &lt;code&gt;GET /v2/reports?granularity=day&lt;/code&gt;, который возвращает те же данные со стабильной
схемой и пагинацией. Затрагивает 214 интеграций, вызвавших endpoint v1 за последние 30 дней;
если ваша одна из них, вы также получите это уведомление по почте. Руководство по миграции:
[ссылка]. Ничего не меняется до 1 марта 2027 года. С этой даты endpoint v1 возвращает
&lt;code&gt;410 Gone&lt;/code&gt; со ссылкой на эту запись.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Каждое предложение несёт что-то, что нужно читательнице. Количество затронутых интеграций
сообщает каждой читательнице, стоит ли продолжать читать. «Ничего не меняется до» — это
предложение, позволяющее незатронутым закрыть вкладку. Страница
&lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; собирает записи от команд, последовательно пишущих эту
форму, и стоит прочитать три перед написанием своей первой.&lt;/p&gt;
&lt;h2&gt;Какие заголовки должен посылать депрекированный endpoint?&lt;/h2&gt;
&lt;p&gt;Отправляйте &lt;code&gt;Deprecation&lt;/code&gt;, &lt;code&gt;Sunset&lt;/code&gt; и &lt;code&gt;Link&lt;/code&gt; на преемника в каждом ответе от депрекированного
endpoint, с дня объявления. &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc9745&quot;&gt;Заголовок &lt;code&gt;Deprecation&lt;/code&gt;&lt;/a&gt;
несёт дату, когда депрекация вступила в силу; &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8594&quot;&gt;заголовок &lt;code&gt;Sunset&lt;/code&gt;&lt;/a&gt;
несёт дату, когда endpoint перестаёт отвечать; &lt;code&gt;Link: &amp;lt;url&amp;gt;; rel=&amp;quot;successor-version&amp;quot;&lt;/code&gt; указывает,
что использовать вместо этого.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Deprecation: @1756425600
Sunset: Mon, 01 Mar 2027 00:00:00 GMT
Link: &amp;lt;https://api.example.com/v2/reports&amp;gt;; rel=&amp;quot;successor-version&amp;quot;
Link: &amp;lt;https://example.com/changelog/daily-reports&amp;gt;; rel=&amp;quot;deprecation&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Большинство вызывающих никогда сами не прочитают заголовки. Их ценность в том, что HTTP-клиент,
шлюз или мониторинг вызывающего могут, что превращает вашу депрекацию в оповещение на их стороне
вместо страницы на вашей. SDK, которые вы поставляете, должны логировать
предупреждение, когда видят такое.&lt;/p&gt;
&lt;h2&gt;Кто был уведомлён, и откуда вы это знаете?&lt;/h2&gt;
&lt;p&gt;Это шаг, решающий, будет ли sunset тихим или станет инцидентом поддержки, и это самое сложное,
что можно сделать только с changelog. Запись changelog уведомляет каждого, кто читает changelog.
Депрекация должна достичь конкретных людей, чей код упадёт, и обычный способ их найти — те же
данные об использовании, которые нужны напоминанию на полпути: API-ключи, приложения или
аккаунты, недавно вызывавшие депрекированное поведение.&lt;/p&gt;
&lt;p&gt;Цикл, который мы выполняем: запись составляется из pull request, добавляющего депрекацию,
человек рецензирует формулировку и дату, а после публикации сама запись является уведомлением.
Каждый, чей отзыв из виджета о проблеме или запрос замены стал GitHub issue, который закрывает
этот pull request, получает в этом issue комментарий, говорящий, что это выпущено, со ссылкой на запись.
&lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;Лента и виджет&lt;/a&gt; обслуживают ту же запись всем остальным, вместе с каждой другой записью в
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;changelog API&lt;/a&gt;. Что мы не делаем — не позволяем
депрекации стать «выпущенной» до того, как человек её опубликовал; уведомление с неправильной
датой хуже, чем отсутствие уведомления.&lt;/p&gt;
&lt;p&gt;Какими бы ни были ваши инструменты, вопрос, на который вы должны уметь ответить в день sunset:
какие вызывающие всё ещё использовали это на прошлой неделе, и кому из них мы сказали напрямую?
Если ответ «мы опубликовали об этом что-то», sunset не готов.&lt;/p&gt;
&lt;h2&gt;В чём разница между депрекацией и версионированием?&lt;/h2&gt;
&lt;p&gt;Версионирование — это то, как вы сохраняете старое поведение доступным, пока существует новое;
депрекация — это то, как вы выводите старое из эксплуатации. Новая версия API без политики
депрекации для предыдущей — это обязательство работать с обеими навсегда. Депрекация без
версионирования — это &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;breaking change&lt;/a&gt; с задержкой. Вам нужны оба, и
версия — более лёгкая половина. GraphQL —
исключение, которое стоит назвать: обычно там вообще нет номера версии для повышения, и
&lt;a href=&quot;https://changeloop.dev/blog/ru/graphql-schema-deprecation/&quot;&gt;депрекация схемы GraphQL&lt;/a&gt; разбирает, как одна общая схема
выводит поле из эксплуатации директивой вместо этого.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должен ли депрекированный endpoint продолжать работать точно так же, как раньше?&lt;/strong&gt;
Да, до даты sunset. Единственные допустимые изменения — добавленные заголовки и, ближе к концу,
запланированный brownout, который вы объявили заранее.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой код статуса должен возвращать выведенный из эксплуатации endpoint?&lt;/strong&gt;
&lt;code&gt;410 Gone&lt;/code&gt;, с телом и заголовком &lt;code&gt;Link&lt;/code&gt;, указывающим на замену и запись changelog. &lt;code&gt;404&lt;/code&gt; говорит,
что URL никогда не существовал, что ложно и бесполезно.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Можно ли сократить период депрекации?&lt;/strong&gt;
Только по соображениям безопасности. Если старое поведение эксплуатируемо, скажите это, сократите
период, и уведомите каждого затронутого вызывающего напрямую, вместо того чтобы полагаться на
changelog.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужно ли мне деприкейтить поле, или только целые endpoint?&lt;/strong&gt;
Поля, параметры, значения enum, значения по умолчанию и заголовки — все нуждаются в одинаковом
обращении, потому что каждый может сломать корректного вызывающего. Удалённое поле — самая
распространённая депрекация и наиболее часто пропускаемая.&lt;/p&gt;
</content:encoded></item><item><title>Лучшие практики версионирования API, ради вызывающих</title><link>https://changeloop.dev/blog/ru/api-versioning-best-practices/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/api-versioning-best-practices/</guid><description>Версионируйте только то, что ломает совместимость, размещайте версию там, где её видят вызывающие, и держите старую до даты. Четыре схемы сравнены.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Версионирование API — это практика поддержания старого контракта работающим после того, как вы
его изменили, чтобы вызывающие могли переходить по своему собственному графику, а не вашему. Это
предложение содержит два решения, которые важны: что считается изменением контракта, и как долго
старый продолжает работать. То, где живёт номер версии, о чём большинство дебатов о
версионировании, наименее важно из трёх и легче всего сделать правильно.&lt;/p&gt;
&lt;h2&gt;Когда следует версионировать API?&lt;/h2&gt;
&lt;p&gt;Версионируйте API только когда изменение сломало бы корректного вызывающего. Аддитивные
изменения, новые поля, новые endpoint, новые опциональные параметры не нуждаются в версии;
вызывающие, написанные под старый контракт, продолжают работать, а новая возможность просто
существует. &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;Breaking change&lt;/a&gt; нуждается в ней, потому что
альтернатива — узнать об этом вызывающему из ошибки. Версионирование каждого релиза, включая
аддитивные, учит вызывающих, что версии — это шум, и они перестают читать важные уведомления.&lt;/p&gt;
&lt;p&gt;Практический тест такой же, как в статье о breaking change: если вызывающий, полагавшийся только
на документированное поведение, должен что-то изменить, чтобы продолжить работать, изменению
нужна версия. Если нет, выпустите его под текущей версией и напишите запись changelog.&lt;/p&gt;
&lt;h2&gt;Какую схему версионирования API следует использовать?&lt;/h2&gt;
&lt;p&gt;Используйте схему, которую ваши вызывающие могут легче всего видеть и устанавливать, что для
большинства публичных API — это версия в пути URL или датированный заголовок версии. Четыре общие
схемы различаются меньше в возможностях, чем в том, что они требуют от вызывающего, и это
правильная основа для выбора.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Схема&lt;/th&gt;
&lt;th&gt;Пример&lt;/th&gt;
&lt;th&gt;Что должен сделать вызывающий&lt;/th&gt;
&lt;th&gt;Кто использует&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Путь URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/v2/invoices&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Изменить URL при миграции&lt;/td&gt;
&lt;td&gt;Большинство публичных REST API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Заголовок версии&lt;/td&gt;
&lt;td&gt;&lt;code&gt;X-GitHub-Api-Version: 2022-11-28&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Отправить заголовок, или принять умолчание&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Датированная версия аккаунта&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Stripe-Version: 2026-08-26&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Закрепить дату на запрос или на аккаунт&lt;/td&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Параметр запроса&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/invoices?version=2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Добавить параметр&lt;/td&gt;
&lt;td&gt;Более старые API; редко выбирается сейчас&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Тип медиа&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Accept: application/vnd.example.v2+json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Согласовывать типы содержимого&lt;/td&gt;
&lt;td&gt;Пуристы; мало вызывающих справляются&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Путь URL&lt;/strong&gt; самый заметный и наименее гибкий. Каждый вызывающий может видеть, в какой он версии,
читая строку лога, а скачок версии — это найти-и-заменить. Цена: вся поверхность двигается сразу,
вы не можете изменить контракт одного endpoint без выпуска новой версии для всех, поэтому версии
пути, как правило, редки и велики.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Заголовок версии&lt;/strong&gt; держит URL стабильными и позволяет серверу выбрать умолчание для
вызывающих, ничего не отправляющих, так работает
&lt;a href=&quot;https://docs.github.com/en/rest/about-the-rest-api/api-versions&quot;&gt;версионирование REST API GitHub&lt;/a&gt;:
версия, названная по дате, в &lt;code&gt;X-GitHub-Api-Version&lt;/code&gt;, с самой старой поддерживаемой версией как
умолчанием, чтобы неверсионированные вызывающие не ломались. Цена: версия невидима в URL и легко
забывается в новом клиенте.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Датированная версия аккаунта&lt;/strong&gt; — это схема заголовка плюс одно дополнение: версия хранится
против аккаунта, поэтому каждый запрос получает её, ничего не отправляя.
&lt;a href=&quot;https://docs.stripe.com/api/versioning&quot;&gt;Версионирование API Stripe&lt;/a&gt; закрепляет каждый аккаунт на
версии, с которой он был создан, и позволяет запросу перезаписать это &lt;code&gt;Stripe-Version&lt;/code&gt;. Это самая
дружественная к вызывающему схема и требующая больше всего работы для эксплуатации, потому что
серверу нужно переводить между каждой поддерживаемой версией и текущей.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Параметр запроса&lt;/strong&gt; и &lt;strong&gt;тип медиа&lt;/strong&gt; оба работают и оба проваливают тест видимости по-разному:
параметр запроса легко теряется при построении URL, а версия типа медиа невидима почти для любого
инструмента, которым вызывающий бы отлаживал. Схема Stripe с датами является самым известным примером
подхода с датой, и &lt;a href=&quot;https://changeloop.dev/blog/ru/stripe-api-versioning/&quot;&gt;как Stripe версионирует свой API&lt;/a&gt;
разбирает её подробно.&lt;/p&gt;
&lt;h2&gt;Как версионирование API делается на практике?&lt;/h2&gt;
&lt;p&gt;На практике версия — это именованный набор поведений, и сервер отображает каждый запрос на одно
из них. Шаги одинаковы независимо от того, какая схема несёт имя.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Называйте версии по дате или целому числу, не по семантической версии.&lt;/strong&gt; Веб-API — это не
пакет. Вызывающие не могут закрепить minor версию URL, поэтому &lt;code&gt;v2&lt;/code&gt; или &lt;code&gt;2026-08-26&lt;/code&gt; говорит
всё, что нужно вызывающему, а &lt;a href=&quot;https://semver.org/&quot;&gt;семантическое версионирование&lt;/a&gt; подразумевает
обещание совместимости, которое схема не может выполнить.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Держите версию вне путей кода, которым она безразлична.&lt;/strong&gt; Версия должна выбирать слой
трансляции на границе, а не разветвлять бизнес-логику. Две полные копии кодовой базы — это как
версия оказывается неподдерживаемой.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Давайте каждой версии умолчание и документ.&lt;/strong&gt; Вызывающие, не отправляющие версию, получают
самую старую поддерживаемую, никогда не самую новую, чтобы незакреплённый клиент не сломался в
день релиза. У каждой версии есть страница, говорящая, что изменилось по сравнению с
предыдущей.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Установите окно поддержки и опубликуйте его.&lt;/strong&gt;
Руководство Google по версионированию,
&lt;a href=&quot;https://google.aip.dev/185&quot;&gt;AIP-185&lt;/a&gt;, требует разумного и заранее объявленного переходного
периода и рекомендует 180 дней даже для бета-функциональности. Выберите окно,
запишите его, и применяйте без пересогласования по каждой версии.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Выводите версии из эксплуатации так же, как выводите endpoint.&lt;/strong&gt; Версия, прошедшая своё
окно, получает то же обращение, что и любой &lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;депрекированный API&lt;/a&gt;:
объявление, заголовок &lt;code&gt;Sunset&lt;/code&gt; (&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8594&quot;&gt;RFC 8594&lt;/a&gt;) в
каждом ответе, напоминание на полпути оставшимся вызывающим, и дата удаления, которая
соблюдается.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Что такое v1 и v2 в REST API?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;v1&lt;/code&gt; и &lt;code&gt;v2&lt;/code&gt; — это имена для двух контрактов, которые один и тот же сервер поддерживает
одновременно. &lt;code&gt;v2&lt;/code&gt; существует, потому что что-то в &lt;code&gt;v1&lt;/code&gt; нельзя было изменить без разрушения его
вызывающих, поэтому изменение пошло в новый контракт, а старый продолжил работать. Номера не
подразумевают, что &lt;code&gt;v2&lt;/code&gt; завершён или что &lt;code&gt;v1&lt;/code&gt; мёртв; оба верны, только если документация так
говорит. &lt;code&gt;v3&lt;/code&gt;, появляющийся каждый квартал, — это признак того, что версионируются аддитивные
изменения, или что контракт никогда не проектировался для поглощения изменений.&lt;/p&gt;
&lt;p&gt;Это модель версионирования через путь URL, где номер версии — сегмент, который набирает
вызывающий. Сервисы gRPC обычно решают ту же проблему иначе: версия живёт в имени пакета внутри
самого файла &lt;code&gt;.proto&lt;/code&gt;. &lt;a href=&quot;https://changeloop.dev/blog/ru/grpc-protobuf-api-changes/&quot;&gt;gRPC и Protobuf&lt;/a&gt; разбирает эту
разницу и то, почему совместимость на проводе там определяется номерами полей, а не формой URL.&lt;/p&gt;
&lt;h2&gt;Что должно объявлять изменение версии?&lt;/h2&gt;
&lt;p&gt;Изменение версии должно объявлять, что ломается, кого затрагивает, как мигрировать, и как долго
предыдущая версия продолжает работать. У записи та же форма, что у любой другой записи об
изменении, ломающем совместимость, плюс строка, объявляющая окно поддержки. Вот одна для API,
версионированного заголовком:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Версия API 2026-11-01 доступна. Версия 2025-06-15 поддерживается до 1 ноября 2027 года.&lt;/strong&gt;
Новое в 2026-11-01: &lt;code&gt;GET /invoices&lt;/code&gt; возвращает &lt;code&gt;amount&lt;/code&gt; в минимальных единицах как целое число
вместо десятичной строки, а депрекированное поле &lt;code&gt;customer_name&lt;/code&gt; удаляется в пользу объекта
&lt;code&gt;customer&lt;/code&gt;. Затрагивает вызывающих на 2025-06-15, парсящих &lt;code&gt;amount&lt;/code&gt; как строку, что является
умолчанием для незакреплённых клиентов, созданных до июня 2025 года. Миграция: парсите &lt;code&gt;amount&lt;/code&gt;
как целое число и читайте имя из &lt;code&gt;customer.name&lt;/code&gt;. Закрепите &lt;code&gt;X-Api-Version: 2026-11-01&lt;/code&gt;, когда
будете готовы. Ничего не меняется для вызывающих, не закрепляющих версию.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Последнее предложение — то, что позволяет большинству читательниц перестать читать, и оно
принадлежит каждому объявлению версии. Страница &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; включает
записи от API, версионирующих таким образом, и разница между хорошими и остальными в основном в
этом последнем предложении.&lt;/p&gt;
&lt;h2&gt;Кого уведомляют, когда версия меняется?&lt;/h2&gt;
&lt;p&gt;Всех на старой версии, индивидуально, и changelog для всех остальных. Изменение версии — это
единственный случай, когда «мы опубликовали об этом что-то» гарантированно пропускает именно тех
вызывающих, которые важны: тех, кто закрепил версию два года назад и с тех пор не читал заметки
о релизе. Данные об использовании отвечают, кто они; уведомление должно достичь их там, где их
код, в заголовках ответа и в сообщении владелице аккаунта.&lt;/p&gt;
&lt;p&gt;В цикле, который мы выполняем, запись, объявляющая версию, составляется из pull request, который
её выпускает, рецензируется человеком, и публикуется на &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;ленте и виджете&lt;/a&gt;, где
версионированный клиент может прочитать её как JSON. Каждый, чей отзыв из виджета просил об
изменении или сообщал о баге, который оно решает, и стал GitHub issue, который закрывает этот pull
request, уведомляется в этом issue, как только запись выходит в эфир. Механизм тот же, что и для любой записи; скачок версии — это просто
запись с самой высокой ставкой.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должно ли каждое изменение API получать новую версию?&lt;/strong&gt;
Нет. Только изменения, ломающие совместимость. Аддитивные изменения выпускаются под текущей
версией с записью changelog. Версионирование аддитивных изменений учит вызывающих игнорировать
версии.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Лучше ли версионирование через URL, чем через заголовок?&lt;/strong&gt;
Версионирование через URL легче видеть вызывающим и сложнее вам развивать постепенно;
версионирование через заголовок наоборот. Для публичного API с множеством мелких клиентов
версионирование через URL проваливается реже. Для крупного API со слоем трансляции датированная
версия через заголовок масштабируется лучше.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сколько версий следует поддерживать одновременно?&lt;/strong&gt;
Настолько мало, насколько позволяет ваше окно поддержки, и никогда неограниченное число. Две или
три параллельные версии — это нормально; больше обычно означает, что версии не выводятся из
эксплуатации.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что должны получать невероенные запросы?&lt;/strong&gt;
Самую старую поддерживаемую версию, чтобы существующие незакреплённые клиенты продолжали
работать, с заголовком ответа, сообщающим им, какую версию они получили.&lt;/p&gt;
</content:encoded></item><item><title>Breaking changes: что считается и как выпустить</title><link>https://changeloop.dev/blog/ru/breaking-changes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/breaking-changes/</guid><description>Breaking change это изменение, которое не пережил бы корректный вызывающий. Что считается, что нет, как поймать его в CI и безопасно выпустить.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Breaking change это изменение, которое корректно написанный вызывающий не смог бы пережить.
Определение важно, потому что большинство споров о том, «считается» ли что-то, на самом деле
споры о том, кто держал это неправильно. Если вызывающий следовал вашей документации, а ваше
изменение заставило его код перестать работать, изменение было breaking. Ваши намерения
к этому не имеют никакого отношения.&lt;/p&gt;
&lt;p&gt;Это весь тест. Остальная часть этой статьи посвящена тому, что из него следует: что его не проходит, что
проходит, как поймать провал до слияния и что делать, как только вы знаете, что выпускаете такое.&lt;/p&gt;
&lt;h2&gt;Что считается breaking change?&lt;/h2&gt;
&lt;p&gt;Применяйте тест к вызывающему, а не к диффу. Изменение является breaking, когда вызывающий,
полагавшийся только на документированное поведение, должен изменить свой код, конфигурацию или
данные, чтобы продолжить работать. Удаление поля, переименование endpoint, ужесточение валидации,
изменение значения по умолчанию и изменение типа значения, всё это квалифицируется. Добавление
опционального поля, нет. Исправление бага обычно нет, с одним важным исключением ниже.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Изменение&lt;/th&gt;
&lt;th&gt;Breaking?&lt;/th&gt;
&lt;th&gt;Почему&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Удаление или переименование поля, endpoint, флага или опции&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Корректные вызывающие ссылаются на это&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Добавление опционального поля или нового endpoint&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Существующие вызовы не меняются&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Превращение опциональной входной величины в обязательную&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Вызовы, опускавшие её, теперь падают&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ужесточение ранее принимавшейся валидации&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Входные данные, которые работали, теперь отклоняются&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение значения по умолчанию&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Вызывающие, не установившие его, получают новое поведение&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение типа (строка в число, единичное значение в массив)&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Парсеры, написанные под документированный тип, падают&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение порядка ключей объекта&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Если только вы не документировали порядок&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Исправление бага, на который полагались вызывающие&lt;/td&gt;
&lt;td&gt;На практике да&lt;/td&gt;
&lt;td&gt;См. раздел о случайных контрактах&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Повышение лимита частоты или размера&lt;/td&gt;
&lt;td&gt;Нет&lt;/td&gt;
&lt;td&gt;Ничто из работавшего не перестаёт работать&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Понижение лимита частоты или размера&lt;/td&gt;
&lt;td&gt;Да&lt;/td&gt;
&lt;td&gt;Трафик, который был в порядке, теперь ограничивается&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Изменение формулировки сообщения об ошибке&lt;/td&gt;
&lt;td&gt;Зависит&lt;/td&gt;
&lt;td&gt;Breaking, если вы это документировали или вызывающие сопоставляют с ним&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что не является breaking change?&lt;/h2&gt;
&lt;p&gt;Изменение не breaking, когда каждый вызов, который работал раньше, по-прежнему работает без
изменений и значит то же самое. Новый endpoint, опциональный параметр запроса, новое поле в ответе,
превращение обязательного входного значения в опциональное, повышение лимита и улучшение сообщения
об ошибке, с которым никто не сопоставляет, проходят тест. Такие аддитивные изменения можно
выпускать в минорном релизе с обычной записью в changelog.&lt;/p&gt;
&lt;p&gt;Аддитивные изменения всё же ломают вызывающих в трёх случаях. Клиент, чей десериализатор отклоняет
неизвестные поля, падает на первом же новом поле ответа, поэтому заранее документируйте, что
вызывающие должны игнорировать незнакомые поля. Новое значение enum ломает каждого вызывающего с
исчерпывающим switch (подробнее ниже). А растущий ответ может вытолкнуть вызывающего за лимит
размера, таймаут или ширину столбца, о которых ему не приходилось думать.&lt;/p&gt;
&lt;p&gt;Четыре строки таблицы заслуживают более пристального взгляда, потому что именно там возникают
разногласия.&lt;/p&gt;
&lt;h2&gt;Четыре breaking change, которые упускают команды&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Случайные контракты.&lt;/strong&gt; Если ваш API три года возвращал одно и то же недокументированное поле,
вызывающий на это опирался. &lt;a href=&quot;https://www.hyrumslaw.com/&quot;&gt;Закон Хайрума&lt;/a&gt;: короткая версия: при
достаточном числе пользователей каждое наблюдаемое поведение вашей системы будет от кого-то
зависимым. Вот почему «это было исправление бага», не защита. Исправление может быть корректным
и всё равно быть breaking. Выпустите его как таковое.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Изменения поведения без изменения схемы.&lt;/strong&gt; Поле всё ещё там, тип тот же, а значение теперь
означает что-то другое. &lt;code&gt;status&lt;/code&gt;, который был &lt;code&gt;active&lt;/code&gt; или &lt;code&gt;inactive&lt;/code&gt;, а теперь также возвращает
&lt;code&gt;suspended&lt;/code&gt;, ломает каждого вызывающего с исчерпывающим switch. Timestamp, переходящий с
локального времени на UTC, ломает всех, кто не прочитал документацию дважды. Ничто в диффе файла
OpenAPI этого не показывает.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ужесточённая валидация.&lt;/strong&gt; Вы начинаете отклонять email без TLD, или пробелы в конце, или имена
длиннее 80 символов. Каждый вызывающий, отправлявший ровно это, теперь получает 400 на запрос,
который работал на прошлой неделе. Изменения валидации чаще всего выпускаются как исправление
«усиления».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Изменённые значения по умолчанию.&lt;/strong&gt; Никто, кто установил значение явно, ничего не замечает.
Все, кто этого не сделал, а это большинство вызывающих, получают новое поведение, не меняя ни
строки. Изменённое значение по умолчанию ломает большинство ваших пользователей именно потому,
что они никогда не видели эту настройку.&lt;/p&gt;
&lt;h2&gt;Как обнаружить breaking change до выпуска?&lt;/h2&gt;
&lt;p&gt;Сравните контракт в pull request с контрактом в основной ветке, в CI, и провалите сборку при
breaking-различии. Инструменты сравнения схем есть для большинства форматов интерфейсов, и каждый
знает правила breaking для своего формата:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Интерфейс&lt;/th&gt;
&lt;th&gt;Инструмент&lt;/th&gt;
&lt;th&gt;Что сравнивает&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;REST (OpenAPI)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/oasdiff/oasdiff&quot;&gt;oasdiff&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Две спецификации OpenAPI, с отчётом о breaking changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gRPC (Protobuf)&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://buf.build/docs/breaking/&quot;&gt;buf breaking&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Файлы &lt;code&gt;.proto&lt;/code&gt;, на уровне wire или исходного кода&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/kamilkisiela/graphql-inspector&quot;&gt;GraphQL Inspector&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Две схемы, с пометкой breaking и опасных изменений&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust crates&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://github.com/obi1kenobi/cargo-semver-checks&quot;&gt;cargo-semver-checks&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Публичный API против последней опубликованной версии&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Пакеты TypeScript&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://api-extractor.com/&quot;&gt;API Extractor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Закоммиченный отчёт о публичном API пакета&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Эти инструменты надёжно ловят удалённые поля, переименованные операции и изменённые типы. Они не
видят первые два из четырёх видов выше, случайный контракт и изменение поведения, потому что ни то,
ни другое не отражается в схеме. Используйте инструмент, чтобы остановить очевидные случаи, а для
остальных вопрос на ревью: «заметит ли это корректный вызывающий?». Тот же CI-джоб, естественное
место, чтобы требовать запись в changelog, как описано в
&lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-ci-enforcement/&quot;&gt;проверке записей changelog в CI&lt;/a&gt;, а
&lt;a href=&quot;https://changeloop.dev/blog/ru/grpc-protobuf-api-changes/&quot;&gt;изменения API gRPC и Protobuf&lt;/a&gt; разбирают случаи на уровне wire.&lt;/p&gt;
&lt;h2&gt;Как пометить breaking change в коммите?&lt;/h2&gt;
&lt;p&gt;В &lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt; breaking change
помечается &lt;code&gt;!&lt;/code&gt; перед двоеточием (&lt;code&gt;feat(api)!: remove the legacy export endpoint&lt;/code&gt;) или футером,
начинающимся с &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; и описанием. Любой из вариантов соответствует major версии.
Пишите футер как первый черновик записи в changelog: кого это затрагивает и что им нужно сделать.
&lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;Conventional commits и changelog&lt;/a&gt; разбирает, как далеко
вас доводит это соглашение.&lt;/p&gt;
&lt;p&gt;То же правило действует для библиотек. Удалённая публичная функция, суженный тип параметра или
изменённое возвращаемое значение, это major версия по семантическому версионированию. Библиотеки
соблюдают его не всегда: &lt;a href=&quot;https://arxiv.org/abs/2110.07889&quot;&gt;исследование 119 879 обновлений в Maven Central&lt;/a&gt;
показало, что 16,6% нарушили семантическое версионирование, но затронули лишь 7,9% клиентских
проектов, потому что большинство этих изменений касалось кода, который ни один клиент не вызывал.
Поломку измеряют у вызывающего.&lt;/p&gt;
&lt;h2&gt;Как выпускается breaking change?&lt;/h2&gt;
&lt;p&gt;Вы выпускаете его открыто, с датой, с путём. Шаги ниже в порядке, и последний, тот, который
пропускает большинство команд: сказать людям, кого это затронуло, что то, чего они ждали, теперь
произошло.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Решите, является ли это им.&lt;/strong&gt; Используйте тест выше, а не дифф. Если два инженера не
согласны, это breaking; несогласие, доказательство того, что вызывающий мог разумно
полагаться на старое поведение.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Версионируйте это.&lt;/strong&gt; По &lt;a href=&quot;https://semver.org/&quot;&gt;семантическому версионированию&lt;/a&gt; breaking
change, это major версия. Если вы работаете с датированным или версионированным API, это
идёт в новую версию, а старая продолжает работать до объявленной даты. Если вы не можете
версионировать, вы не выпускаете breaking change, вы выпускаете сбой с записью в changelog.
Какая схема несёт версию, тема
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-versioning-best-practices/&quot;&gt;лучших практик версионирования API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Напишите запись до объединения кода.&lt;/strong&gt; У записи фиксированная форма: что меняется, кого
затрагивает, что им нужно сделать, и до когда. Если вы не можете заполнить все четыре,
изменение не готово. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;Шаблон release notes&lt;/a&gt; ставит эти записи первыми,
с датой вместо номера версии, именно поэтому.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Дайте дедлайн, а не номер релиза.&lt;/strong&gt; «Удалено в v5» ничего не значит для того, кто не следит
за вашими релизами. «Перестаёт работать 1 ноября 2026 года» значит одно и то же для всех.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Предоставьте миграцию.&lt;/strong&gt; Пример кода старого вызова рядом с новым. Если изменение
переименование, назовите оба имени в одном предложении. Если это удалённое поле, скажите, куда
делись данные.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Объявите везде, где было документировано старое поведение.&lt;/strong&gt; Changelog, страницу
документации, описывающую endpoint, release notes SDK, и заголовок депрекации в ответе, если
он у вас есть. Объявленное в одном месте объявлено людям, которые случайно туда посмотрели.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Замкните петлю.&lt;/strong&gt; Если клиентка попросила изменение, или сообщила о баге, который к нему
привёл, скажите ей, когда оно выпущено. Это шаг, превращающий это из чего-то, сделанного с
вашими пользователями, в что-то, сделанное вместе с ними.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Как выглядит хорошая запись о breaking change?&lt;/h2&gt;
&lt;p&gt;Хорошая запись называет затронутого вызывающего в первой строке, объявляет дату, и включает
исправление. Вот одна для случая ужесточённой валидации, в форме, которую мы используем:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Адреса электронной почты без домена отклоняются с 1 ноября 2026 года.&lt;/strong&gt;
&lt;code&gt;POST /users&lt;/code&gt; и &lt;code&gt;PATCH /users/:id&lt;/code&gt; в настоящее время принимают значения &lt;code&gt;email&lt;/code&gt; вроде
&lt;code&gt;alice@localhost&lt;/code&gt;. С 1 ноября они возвращают &lt;code&gt;400 invalid_email&lt;/code&gt;. Затрагивает любую интеграцию,
создающую пользователей из внутренних каталогов. Миграция: отправьте полностью
квалифицированный адрес, или опустите поле и установите его позже. Никаких изменений не
требуется, если ваши адреса уже имеют домен, что верно для 99,4% аккаунтов, созданных в этом
году.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Где место этому уведомлению, и что ещё должно быть рядом с ним, разбирает
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-changelog/&quot;&gt;changelog API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Процент в конце, не украшение. Он говорит читательнице, стоит ли ей беспокоиться, что и есть
вопрос, с которым она открыла запись.&lt;/p&gt;
&lt;h2&gt;Почему бы просто не избегать их?&lt;/h2&gt;
&lt;p&gt;Потому что альтернатива хуже. API, который никогда ничего не ломает, накапливает каждую ошибку,
которую когда-либо совершил: неправильно названное поле, неверное значение по умолчанию, timestamp
в локальном времени. Каждая из них, налог на каждого нового вызывающего навсегда, чтобы защитить
вызывающих, которые могли бы мигрировать за один вечер. Команды с лучшей репутацией стабильности
ломают вещи редко, по расписанию, с путём миграции и предупреждением, дошедшим до людей, для кого
оно предназначалось.&lt;/p&gt;
&lt;p&gt;Механика этого предупреждения, тема сопутствующей статьи о
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;депрекации API&lt;/a&gt;. Запись, объявляющая это, составляется так же, как
любая другая запись в &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;ленте changelog&lt;/a&gt;: из объединённого pull request, удержанная для
человека, затем опубликованная там, где затронутые вызывающие уже читают.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;В чём разница между breaking и non-breaking изменением?&lt;/strong&gt;
Breaking change заставляет корректного вызывающего менять код, конфигурацию или данные, чтобы
продолжить работать. Non-breaking оставляет каждый существующий вызов рабочим с тем же значением,
поэтому добавления обычно безопасны, а удаления, переименования и ужесточённые правила обычно нет.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Считается ли добавление обязательного поля?&lt;/strong&gt;
Да. Каждый существующий вызов его опускает, поэтому каждый существующий вызов теперь падает.
Добавьте его как опциональное с разумным значением по умолчанию, или версионируйте endpoint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Считается ли исправление бага?&lt;/strong&gt;
Может быть. Если вызывающие полагались на ошибочное поведение, исправление его ломает их,
независимо от того, что говорила документация. Относитесь к любому исправлению, меняющему
наблюдаемый вывод, как к breaking, если только вы не можете показать, что никто на него не
полагался.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Применяется ли семантическое версионирование к веб-API?&lt;/strong&gt;
Правило да: breaking change получают новую major версию, а старая продолжает работать в течение
объявленного периода. Номер часто живёт в URL или заголовке даты, а не в версии пакета.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сколько предупреждения достаточно?&lt;/strong&gt;
Достаточно, чтобы вызывающий нашёл уведомление и выполнил работу. Девяносто дней, обычный
минимум для публичных API; дольше для всего, используемого в коде, отправляемом конечным
пользователям и не обновляемом удалённо.&lt;/p&gt;
</content:encoded></item><item><title>Замыкание петли обратной связи со стороны changelog</title><link>https://changeloop.dev/blog/ru/customer-feedback-loop/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/customer-feedback-loop/</guid><description>Петля обратной связи замыкается, когда запросивший знает: выпущено. Петля в четырёх шагах, где рвётся, и почему changelog — верное место для замыкания.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Петля обратной связи клиента замкнута, когда человеку, давшему обратную связь, сообщают, что с
ней произошло. Не когда она зарегистрирована. Не когда приоритизирована. Даже не когда выпущена.
Когда ему говорят. Большинство команд хорошо выполняют первые три шага и совсем не выполняют
последний, а потом удивляются, почему люди, отправляющие обратную связь, перестают её отправлять.&lt;/p&gt;
&lt;p&gt;Эта статья о том последнем шаге, и о конкретном утверждении: changelog — верное место для
замыкания петли, потому что это единственный артефакт, уже существующий именно в тот момент,
когда петлю можно замкнуть.&lt;/p&gt;
&lt;h2&gt;Что такое петля обратной связи клиента?&lt;/h2&gt;
&lt;p&gt;Петля обратной связи клиента — это путь от пользователя, говорящего вам что-то, до этого
пользователя, узнающего, что вы с этим сделали. У неё четыре шага: сбор обратной связи, решение,
что с ней делать, выпуск результата, и уведомление запросившего. Петля открыта, пока не произойдёт
четвёртый шаг. У команды, собирающей обратную связь и выпускающей исправления, но никогда никого
не уведомляющей, есть почтовый ящик, а не петля.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Шаг&lt;/th&gt;
&lt;th&gt;Что происходит&lt;/th&gt;
&lt;th&gt;Где обычно рвётся&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Сбор&lt;/td&gt;
&lt;td&gt;Обратная связь приходит: виджет, поддержка, продажи, интервью&lt;/td&gt;
&lt;td&gt;Ничего; каждая команда это делает&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Решение&lt;/td&gt;
&lt;td&gt;Триаж, объединение с дубликатами, принятие или отклонение&lt;/td&gt;
&lt;td&gt;Отклонения никогда не сообщаются&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Выпуск&lt;/td&gt;
&lt;td&gt;Кто-то это строит, и это выходит в эфир&lt;/td&gt;
&lt;td&gt;Ссылка на запрос теряется при merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Уведомление&lt;/td&gt;
&lt;td&gt;Запросивший узнаёт, что выпущено&lt;/td&gt;
&lt;td&gt;Пропускается, или делается только для самого громкого запросившего&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Четвёртая строка — то, о чём эта статья. Она рвётся по структурной причине, а не культурной: к
моменту выпуска функции запрос, вызвавший её, живёт в другой системе, чем выпущенная вещь, и
соединение их — не чья-то обязанность. Петля начинается раньше, с того, как запрос вообще
запрашивается; формулировки и время описаны в статье
&lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-ask-for-customer-feedback/&quot;&gt;как попросить обратную связь у клиентов&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Почему петли обратной связи остаются открытыми?&lt;/h2&gt;
&lt;p&gt;Петли обратной связи остаются открытыми, потому что запрос и выпущенное изменение живут в разных
местах, а связь между ними устанавливается вручную, если вообще устанавливается. Запрос в
инструменте обратной связи, ящике поддержки или таблице. Изменение в pull request. Объявление в
changelog или письме. Три системы, три владельца, и ссылка от третьей обратно к первой — это
человек, вспоминающий месяцы спустя, кто спрашивал.&lt;/p&gt;
&lt;p&gt;Есть вторая причина. Шаг уведомления обычно оформляется как маркетинговая задача («объявить
функцию») вместо задачи поддержки («ответить человеку»). Объявления идут всем и не достигают
никого конкретно. Человек, попросивший функцию в марте, читает объявление в июне, если вообще
читает, как новость, а не как ответ. Петля замыкается, только если сообщение адресовано ему.&lt;/p&gt;
&lt;h2&gt;Почему замыкать петлю со стороны changelog?&lt;/h2&gt;
&lt;p&gt;Потому что запись changelog — единственный артефакт, существующий именно в правильный момент,
содержащий именно правильные слова, и написанный именно правильным человеком. Она существует,
когда изменение в эфире, и не раньше. Она говорит, что изменилось, словами читательницы, что и
есть сообщение, в котором нуждается запросивший. И написана кем-то, кто только что прочитал pull
request, что является единственным моментом, когда ссылка на исходный запрос всё ещё видна.&lt;/p&gt;
&lt;p&gt;Сравните альтернативы. Замыкание петли из инструмента обратной связи означает, что инструменту
обратной связи нужно знать, когда функция выпущена, что означает, что кто-то вручную обновляет
статус. Замыкание её из pull request означает уведомление клиентки при merge, до того как
изменение в эфире, нарушенное обещание с временной меткой, как только развёртывание задерживается.
Замыкание её из маркетингового объявления означает ожидание такового, а большинство выпущенных
изменений его никогда не получают.&lt;/p&gt;
&lt;p&gt;Changelog находится посередине: после merge, в момент релиза, с готовой формулировкой.&lt;/p&gt;
&lt;h2&gt;Как замыкается петля, шаг за шагом&lt;/h2&gt;
&lt;p&gt;Это механизм, который мы выполняем. Он описан здесь как спецификация, а не как тур по продукту,
потому что каждый шаг можно выполнить вручную или другими инструментами; важен порядок.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Обратная связь становится issue в репозитории, который её исправит.&lt;/strong&gt; Отправка через виджет
регистрируется как помеченный issue на GitHub (&lt;code&gt;feature-request&lt;/code&gt; или &lt;code&gt;bug&lt;/code&gt;, приоритет, и
&lt;code&gt;from-widget&lt;/code&gt;), причём адрес электронной почты отправителя в тело issue не попадает. Issue живёт
рядом с кодом, чтобы шаг три мог его найти. Issue, созданный вручную, например по
&lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-template/&quot;&gt;шаблону запроса функции&lt;/a&gt;, находится вне этого пути: шаг пять
его не комментирует, так что эту петлю замыкайте сами.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Исправление ссылается на issue.&lt;/strong&gt; Pull request говорит &lt;code&gt;Fixes #142&lt;/code&gt;, собственное ключевое
слово закрытия GitHub. Ничего нового учить не нужно, и это то же предложение, которое
разработчицы уже пишут.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Запись changelog составляется из объединённого pull request и несёт ссылку.&lt;/strong&gt; При merge
черновик создаётся, а &lt;code&gt;#142&lt;/code&gt; читается из тела PR и прикрепляется к черновику. Ссылка создаётся,
пока ещё дёшево, машиной, из данных, которые уже там есть.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Человек рецензирует запись.&lt;/strong&gt; Формулировку, аудиторию, стоит ли вообще публиковать.
Выброшенный черновик ничего не замыкает, что верно: внутренний рефакторинг, случайно
сославшийся на issue, — не новость.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;При одобрении запросивший уведомляется.&lt;/strong&gt; Комментарий публикуется в issue, которым стал его
отзыв, «Shipped —» затем заголовок записи и ссылка на опубликованную запись, а виджет показывает
отправителю ту же выпущенную запись. Один раз, никогда дважды,
и только после того, как человек опубликовал запись. Та же запись выходит через
&lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;ленту и виджет&lt;/a&gt; всем, кто не спрашивал.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Порядок в пятом шаге — весь дизайн. Уведомление запросившего при merge было бы раньше и легче, и
было бы неверным примерно так же часто, как задерживаются развёртывания. Feature flag ломает даже
этот порядок, потому что одобрено и опубликовано может произойти, пока функция всё ещё невидима
для аккаунта запросившего; &lt;a href=&quot;https://changeloop.dev/blog/ru/feature-flags-feature-requests/&quot;&gt;feature flag и запросы на функции&lt;/a&gt;
разбирает дополнительную проверку, которая нужна этому шагу, как только задействован флаг.&lt;/p&gt;
&lt;h2&gt;Как выглядит замкнутая петля для клиентки?&lt;/h2&gt;
&lt;p&gt;Она выглядит как ответ. Клиентка отправила запрос через виджет, и однажды виджет показывает его
выпущенным, со ссылкой на запись, описывающую это её словами; на GitHub issue получает ту же
новость в виде комментария. Она не подписалась на рассылку, не проверяла roadmap, не искала в changelog. Ей
сказали.&lt;/p&gt;
&lt;p&gt;Это опыт, заставляющий случиться следующий кусок обратной связи. Люди отправляют обратную связь
продуктам, которые отвечают. Страница &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; включает записи от
команд, чьи пользователи явно продолжают возвращаться с запросами, и общая нить не в
инструменте; она в том, что записи читаются как ответы.&lt;/p&gt;
&lt;h2&gt;Как измерить петлю обратной связи?&lt;/h2&gt;
&lt;p&gt;Измеряйте долю выпущенных изменений, уведомивших хотя бы одного запросившего, и время от выпуска
до уведомления. Два числа, оба лёгкие, как только ссылка существует, и невозможные до этого.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Коэффициент замыкания&lt;/strong&gt;: из записей changelog, опубликованных в этом месяце, сколько связаны
хотя бы с одним запросом, и из них, сколько уведомили запросившего. Если второе число намного
ниже первого, уведомления проваливаются; если первое низкое, запросы не связываются из pull
request, и исправление — это одно предложение в шаблоне PR.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Время от выпуска до уведомления&lt;/strong&gt;: сколько времени между выходом записи в эфир и уведомлением
запросившего. С механизмом выше это секунды. Вручную это обычно недели, или никогда, и
«никогда» — число, которое важно.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Не измеряйте петлю по объёму собранной обратной связи. Сбор — лёгкий шаг, и команда, которая его
измеряет, будет его оптимизировать, что производит больше открытых петель.&lt;/p&gt;
&lt;h2&gt;Где вписывается roadmap?&lt;/h2&gt;
&lt;p&gt;Публичная roadmap — это способ замкнуть петлю раньше: она говорит запросившим, что их запрос
услышан, до его выпуска. Она полезна, и не заменяет последний шаг. «Запланировано» — это обещание
о будущем; «Выпущено» — это факт о настоящем. Ведите
&lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;публичную roadmap&lt;/a&gt; из тех же issue, с одной меткой на колонку, чтобы
один и тот же запрос переходил от запланированного к выпущенному без повторного ввода где-либо. Перевод в
выпущенное делается сменой метки (&lt;code&gt;roadmap:shipped&lt;/code&gt;), которую никто не сделает за вас при одобрении
записи, так что делайте это в том же ревью.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Каковы четыре шага петли обратной связи клиента?&lt;/strong&gt;
Сбор, решение, выпуск, уведомление. Петля открыта, пока не произойдёт четвёртый шаг. Большинство
фреймворков добавляют шаги анализа и приоритизации в середине; это уточнения «решения», и ни один
из них ничего не замыкает.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Следует ли уведомлять клиентов, когда запрос отклонён?&lt;/strong&gt;
Да, и это самое пренебрегаемое сообщение в петле. Чёткое «мы не будем это делать, и вот почему»
заканчивает ожидание. Молчание оставляет петлю открытой навсегда, а клиентку — проверяющей.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Чем замыкание петли отличается от объявления функции?&lt;/strong&gt;
Объявление идёт всем. Замыкание петли — это ответ людям, которые спрашивали, по каналу, через
который они спрашивали. Делайте оба; это разные сообщения для разных читательниц.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;А если запросившего нет на GitHub?&lt;/strong&gt;
Большинства там нет, и это нормально. Виджет продолжает показывать им статус того, что они
отправили, включая выпущенную запись и её ссылку, так что им не нужно ничего, кроме страницы, с
которой они писали. Комментарий в issue предназначен для тех, кто видит репозиторий.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Работает ли эта петля с GitLab или Bitbucket вместо GitHub?&lt;/strong&gt;
Виджет и changelog работают; автоматический комментарий на шаге пять пока нет. Команда на GitLab
или Bitbucket всё равно получает каждую заявку, всё равно заводит её как issue и всё равно
показывает запросившему статус в виджете, но замыкание именно этой петли обратно на сам issue
приходится делать вручную, пока такая интеграция не появится.&lt;/p&gt;
</content:encoded></item><item><title>Шаблон запроса функции, становящийся changelog</title><link>https://changeloop.dev/blog/ru/feature-request-template/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/feature-request-template/</guid><description>Запрос функции полезен только тогда, когда его можно найти при выпуске. Шаблон, метки, которые его направляют, и поля, которые потом читает changelog.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Шаблон запроса функции — это форма с четырьмя вопросами: что пытается сделать человек, что его
останавливает, что он попробовал вместо этого, и как он хочет быть уведомлён, когда это будет
готово. Всё остальное, что обычно появляется на такой форме, селекторы приоритета, оценки усилий,
баллы бизнес-ценности, предназначено для команды, получающей запрос, и неправильно заполняется
отправителем.&lt;/p&gt;
&lt;p&gt;Аккуратные запросы — неправильный тест для шаблона. Правильный: шесть месяцев спустя, когда
функция выпущена, может ли кто-то найти запрос, понять его, и уведомить человека, который его
написал? Большинство шаблонов спроектированы для приёма. Этот спроектирован для дня, когда петля
замыкается.&lt;/p&gt;
&lt;h2&gt;Что должен включать шаблон запроса функции?&lt;/h2&gt;
&lt;p&gt;Он должен включать цель, блокер, обходной путь, и путь обратно к запросившему. Четыре поля, в
этом порядке, каждое отвечает на вопрос, который команда задаст позже.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Поле&lt;/th&gt;
&lt;th&gt;Вопрос, на который отвечает позже&lt;/th&gt;
&lt;th&gt;Почему оно в форме&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Что вы пытаетесь сделать?&lt;/td&gt;
&lt;td&gt;Была ли построенная функция той, что нужна?&lt;/td&gt;
&lt;td&gt;Цель переживает любое конкретное предложение&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Что вас останавливает сегодня?&lt;/td&gt;
&lt;td&gt;Как выглядит «готово»?&lt;/td&gt;
&lt;td&gt;Называет пробел, не предписывая исправление&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Что вы делаете вместо этого?&lt;/td&gt;
&lt;td&gt;Насколько это на самом деле срочно?&lt;/td&gt;
&lt;td&gt;Болезненный обходной путь — более сильный сигнал, чем селектор приоритета&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Как нам вас уведомить?&lt;/td&gt;
&lt;td&gt;Кто получает сообщение «выпущено»?&lt;/td&gt;
&lt;td&gt;Поле, которое чаще всего пропускают шаблоны&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Что намеренно отсутствует: предложенное решение как обязательное поле (желанное в комментарии,
неверное как рамка), селектор приоритета (каждый отправитель выбирает высокий), и любая оценка
усилий или ценности (работа команды, после триажа). Шаблон, просящий решение, получает запросы на
кнопки; шаблон, просящий цель, получает запросы на результаты, и о результатах пишется запись
changelog.&lt;/p&gt;
&lt;h2&gt;Шаблон&lt;/h2&gt;
&lt;p&gt;Это шаблон issue GitHub, который мы используем, в виде формы. Вставьте его в
&lt;code&gt;.github/ISSUE_TEMPLATE/feature_request.yml&lt;/code&gt;, и он отрендерится как структурированная форма на
странице нового issue. Запросы, поданные через него, попадают как issue с теми же полями, что и
поданные через виджет обратной связи, что важно для следующего раздела.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Feature request
description: What you are trying to do, and what stops you.
labels: [&amp;quot;feature-request&amp;quot;]
body:
  - type: textarea
    id: goal
    attributes:
      label: What are you trying to do?
      description: &amp;gt;-
        The outcome, not the button. &amp;quot;Export a month of invoices as one
        PDF&amp;quot; beats &amp;quot;add a PDF export&amp;quot;.
    validations:
      required: true
  - type: textarea
    id: blocker
    attributes:
      label: What stops you today?
      description: &amp;gt;-
        Where the product runs out. An error, a missing option, a limit.
    validations:
      required: true
  - type: textarea
    id: workaround
    attributes:
      label: What do you do instead?
      description: &amp;gt;-
        The spreadsheet, the script, the manual step. &amp;quot;Nothing, I gave
        up&amp;quot; is a valid answer.
  - type: input
    id: contact
    attributes:
      label: How should we tell you when it ships?
      description: &amp;gt;-
        An email address, or leave blank to be notified only on this
        issue.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Две детали выполняют работу. &lt;code&gt;labels: [&amp;quot;feature-request&amp;quot;]&lt;/code&gt; означает, что запрос классифицируется
при создании, вместо того чтобы ждать, пока кто-то его триажирует. А последнее поле существует,
потому что «мы дадим вам знать» — это обещание, а обещанию нужен адрес.&lt;/p&gt;
&lt;h2&gt;Какие метки должен нести запрос функции?&lt;/h2&gt;
&lt;p&gt;Запрос функции должен нести одну метку для того, что он есть, одну для того, насколько он
срочен, и одну для того, откуда он пришёл. Три метки, три оси, и каждую читает другая
читательница.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Метка&lt;/th&gt;
&lt;th&gt;Значения&lt;/th&gt;
&lt;th&gt;Кто читает&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Тип&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature-request&lt;/code&gt;, &lt;code&gt;bug&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Кто решает, в какую очередь он попадает&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Приоритет&lt;/td&gt;
&lt;td&gt;&lt;code&gt;priority:low&lt;/code&gt;, &lt;code&gt;priority:medium&lt;/code&gt;, &lt;code&gt;priority:high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Кто планирует следующий цикл&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Источник&lt;/td&gt;
&lt;td&gt;&lt;code&gt;from-widget&lt;/code&gt;, &lt;code&gt;from-form&lt;/code&gt;, &lt;code&gt;from-support&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Кто измеряет, откуда приходят запросы&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Виджет применяет первые две оси и &lt;code&gt;from-widget&lt;/code&gt;, когда подаёт отправку как issue; &lt;code&gt;from-form&lt;/code&gt; и
&lt;code&gt;from-support&lt;/code&gt; предлагаются для запросов, приходящих другими путями. Метки виджета такие:
тип (&lt;code&gt;bug&lt;/code&gt; или &lt;code&gt;feature-request&lt;/code&gt;, решаемый классификатором только по сообщению),
приоритет (спокойный, конкретный отчёт о сбое высокий; дубликат чего-то уже спрошенного низкий;
всё, что даже намекает на проблему безопасности, — &lt;code&gt;bug&lt;/code&gt; и высокий, независимо от формулировки),
и &lt;code&gt;from-widget&lt;/code&gt;. Те же три оси работают для запросов, приходящих вручную через шаблон выше, и в
этом суть: запрос — это запрос, независимо от того, откуда он вошёл.&lt;/p&gt;
&lt;p&gt;Ещё одна конвенция: виджет удаляет адрес электронной почты отправителя из тела issue перед
подачей, потому что issue живёт в репозитории, который может быть публичным, и заменяет его
ссылкой на отправку. Адрес в issue не попадает; отправитель следит за результатом в самом виджете. Делайте то же самое с полем
контакта, если ваш трекер виден людям вне команды.&lt;/p&gt;
&lt;h2&gt;Как запрос функции становится записью changelog?&lt;/h2&gt;
&lt;p&gt;Запрос функции становится записью changelog, когда pull request закрывает issue, а запись,
составленная из этого pull request, связывается обратно. Механизм — собственные ключевые слова
закрытия GitHub: PR, чьё описание говорит &lt;code&gt;Fixes #142&lt;/code&gt;, закрывает issue 142 при merge. Если ваши
записи changelog составляются из объединённых pull request, черновик может нести номер issue с
собой, и запись знает, кто спрашивал.&lt;/p&gt;
&lt;p&gt;Вот почему шаблон просит цель вместо решения. Когда запись пишется, цель — это предложение,
нужное автору: «Теперь вы можете экспортировать месяц счетов как один PDF» — это запись changelog.
«Добавлен экспорт PDF» — это сообщение коммита. &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;Инструменты для changelog&lt;/a&gt;,
составляющие записи из pull request, могут выполнить сбор и связь; формулировка всё ещё нуждается
в человеке, и человеку нужна цель.&lt;/p&gt;
&lt;h2&gt;Что происходит, когда это выпущено?&lt;/h2&gt;
&lt;p&gt;Запросивший уведомляется со ссылкой на запись. В нашей настройке это происходит автоматически для
запросов, пришедших через виджет: комментарий, говорящий «Shipped — &amp;lt;заголовок записи&amp;gt;» со ссылкой
на опубликованную запись, размещённый на issue, как только человек одобряет запись, а виджет
показывает отправителю ту же запись. Issue, поданный вручную по этому шаблону, автоматического
комментария не получает; замыкайте эту петлю сами, по тому же правилу. Комментарий намеренно размещается
при одобрении, а не при merge: комментарий, говорящий, что что-то в эфире до того, как это так,
— это нарушенное обещание с временной меткой. Каждый запрос уведомляется не более одного раза;
второе одобрение той же записи не создаёт второй комментарий.&lt;/p&gt;
&lt;p&gt;Если вы делаете это вручную, применяется то же правило. Не замыкайте петлю из pull request.
Замыкайте её из опубликованной записи, и замыкайте один раз. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;Лента и виджет&lt;/a&gt; несут ту же
запись всем, кто не спрашивал, что большинство; комментарий для тех, кто спрашивал.&lt;/p&gt;
&lt;h2&gt;Почему большинство шаблонов запросов функций проваливаются&lt;/h2&gt;
&lt;p&gt;Они спроектированы, чтобы облегчить триаж, и им это удаётся, ценой единственного момента, важного
для запросившего. Шаблон с двенадцатью полями получает меньше запросов, а те, что получает,
приходят от людей с терпением заполнить двенадцать полей, что не та же популяция, что нуждается
в функции. Шаблон с четырьмя полями, одно из которых «как с вами связаться», получает больше
запросов и может почтить каждый из них.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должен ли шаблон запроса функции спрашивать о приоритете?&lt;/strong&gt;
Нет. Спрашивайте вместо этого об обходном пути. «Я экспортирую в таблицу и перепечатываю каждую
пятницу» говорит о приоритете больше, чем выпадающий список, который отправитель поставил на
высокий.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли запросившие предлагать решение?&lt;/strong&gt;
Могут, в свободном тексте. Не делайте это рамкой. Запросы, написанные как решения, труднее
объединять друг с другом и труднее превращать в запись changelog.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли запросы функций появляться в публичной roadmap?&lt;/strong&gt;
После планирования да: метка на том же issue помещает его в колонку запланировано, и запросивший
может видеть, как он движется. Статья &lt;a href=&quot;https://changeloop.dev/blog/ru/public-roadmap/&quot;&gt;публичная roadmap&lt;/a&gt; — это
механизм.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как обрабатывать дубликаты?&lt;/strong&gt;
Свяжите новый запрос с существующим issue и пометьте его низким приоритетом; не закрывайте его.
Каждый дубликат — ещё один человек для уведомления при выпуске. С автоматическим комментарием
Changeloop этот человек уведомляется, только если pull request называет и его issue
(&lt;code&gt;Fixes #142, fixes #187&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Где должен жить шаблон?&lt;/strong&gt;
В репозитории, который получит pull request, чтобы работало ключевое слово закрытия. Запрос в
отдельном трекере должен связываться вручную при merge, и именно этот шаг пропускается.&lt;/p&gt;
</content:encoded></item><item><title>Публичная roadmap из вашего issue-трекера, три колонки</title><link>https://changeloop.dev/blog/ru/public-roadmap/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/public-roadmap/</guid><description>Публичная roadmap это обещание о будущем. Держите её маленькой, питайте из уже отслеживаемых issue и перемещайте каждый элемент меткой на его issue.</description><pubDate>Sat, 29 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Публичная roadmap — это список того, что вы намерены построить, опубликованный там, где клиенты
могут его увидеть. Слово, выполняющее работу, — &lt;em&gt;намерены&lt;/em&gt;: roadmap — это набор обещаний о
будущем, и каждый элемент в ней — тот, который вы либо сдержите, либо станет видно, что не
сдержали. Это причина публиковать её, и это также причина, по которой большинство публичных
roadmap устаревают за квартал. Версия, которая выживает, маленькая, выведена из данных, которые
вы уже поддерживаете, и связана на другом конце с changelog, чтобы обещание становилось фактом
без того, чтобы кто-то его повторно вводил.&lt;/p&gt;
&lt;h2&gt;Для чего нужна публичная roadmap?&lt;/h2&gt;
&lt;p&gt;Публичная roadmap говорит клиентке с запросом, что её запрос услышан, до его выпуска. Это ранняя
половина замыкания петли: «Запланировано» отвечает на вопрос «прочитал ли это кто-то», а
«В разработке» отвечает на «действительно ли это происходит». Ни одно из них не заменяет
последний шаг, уведомление запросившей при выпуске, но оба уменьшают число людей, спрашивающих
тем временем.&lt;/p&gt;
&lt;p&gt;Это также делает кое-что для команды: заставляет публичное обязательство, что является самым
дешёвым известным лекарством против backlog, тихо хранящего четыреста элементов, которые никто
не построит.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Колонка&lt;/th&gt;
&lt;th&gt;Обещание, которое она даёт&lt;/th&gt;
&lt;th&gt;Что перемещает элемент в неё&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Запланировано&lt;/td&gt;
&lt;td&gt;Мы намерены это построить&lt;/td&gt;
&lt;td&gt;Решение, зафиксированное как метка на issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;В разработке&lt;/td&gt;
&lt;td&gt;Кто-то работает над этим сейчас&lt;/td&gt;
&lt;td&gt;Метка &lt;code&gt;roadmap:building&lt;/code&gt; на issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Выпущено&lt;/td&gt;
&lt;td&gt;Это в эфире&lt;/td&gt;
&lt;td&gt;Метка &lt;code&gt;roadmap:shipped&lt;/code&gt;, или закрытие issue, пока она на нём стоит&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Трёх колонок в фиксированном порядке достаточно. Четвёртая колонка («рассматривается», «на
рецензии», «backlog») — место, где благие намерения становятся музеем, и это первая, которую
клиенты учатся игнорировать.&lt;/p&gt;
&lt;h2&gt;Должна ли ваша roadmap быть публичной?&lt;/h2&gt;
&lt;p&gt;Сделайте её публичной, если вы можете держать её маленькой и честной; держите её приватной, если
альтернатива — длинный список возможно. Цена публичной roadmap не имеет ничего общего с её
публикацией: каждый элемент на ней теперь вопрос, который кто-то задаст, в поддержке, в звонках
продаж и в разговорах о продлении. Десять элементов, которые вы построите, — это актив.
Шестьдесят элементов, которые вы, возможно, построите, — это шестьдесят будущих разговоров о том,
почему нет.&lt;/p&gt;
&lt;p&gt;Две честные причины не публиковать: ваши планы меняются быстрее квартала, или ваши конкуренты
читают вашу roadmap внимательнее ваших клиентов. Обе реальны, и обе решаются публикацией меньшего
вместо ничего: только «в разработке», с «запланировано», держимым внутренним, всё равно говорит
запросившей, что её issue движется.&lt;/p&gt;
&lt;h2&gt;Как построить публичную roadmap из issue GitHub?&lt;/h2&gt;
&lt;p&gt;Поместите одну метку на колонку на issue, которые вы уже отслеживаете, и отрендерите помеченные
issue как roadmap. Ничто не вводится повторно, roadmap не может отклониться от работы, и один и
тот же issue, начавшийся как запрос клиента, движется через колонки, не меняя идентичность.&lt;/p&gt;
&lt;p&gt;Механизм, как мы его выполняем:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Одна метка на колонку, с фиксированным префиксом&lt;/strong&gt;: &lt;code&gt;roadmap:planned&lt;/code&gt;, &lt;code&gt;roadmap:building&lt;/code&gt;,
&lt;code&gt;roadmap:shipped&lt;/code&gt;. Любой issue в подключённом репозитории, несущий одну из них, появляется в
этой колонке. Issue без ни одной из них не на roadmap, что верно для большинства issue, что
правильно.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Колонки — это упорядоченный массив, всегда в одном порядке.&lt;/strong&gt; Запланировано, в разработке,
выпущено. Не карта, индексированная по имени, чтобы читательнице (или виджету) никогда не
пришлось угадывать последовательность.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Если issue несёт две метки, побеждает наиболее продвинутая.&lt;/strong&gt; Кто-то добавит
&lt;code&gt;roadmap:shipped&lt;/code&gt; до удаления &lt;code&gt;roadmap:planned&lt;/code&gt;; конечный автомат, руководимый «какой webhook
пришёл последним», поместил бы элемент в разные колонки в зависимости от порядка доставки.
Решение только из набора меток делает ответ одинаковым независимо от того, как приходят
события.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Выпущено это такое же состояние метки, как и остальные.&lt;/strong&gt; Карточка перемещается, когда issue
получает &lt;code&gt;roadmap:shipped&lt;/code&gt; или закрывается, пока эта метка на нём стоит. Сама карточка не
ссылается на запись changelog; подробности живут в записи, составленной из pull request,
закрывшего issue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Подавайте её как данные.&lt;/strong&gt; Roadmap — это документ JSON с этими тремя колонками,
опубликованный рядом с лентой changelog с теми же заголовками кэша, чтобы сайт документации,
виджет или страница статуса могли отрендерить её без второй интеграции. &lt;a href=&quot;https://changeloop.dev/docs&quot;&gt;Документация ленты&lt;/a&gt;
имеет точную форму.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Метка — это немного, о чём просить мейнтейнера, и это вся интеграция. Никакой доски для
поддержания синхронизации, никакого отдельного инструмента для входа, и запрос, поданный
клиенткой, является элементом на roadmap; при выпуске это тот же элемент.&lt;/p&gt;
&lt;h2&gt;Что публичная roadmap не должна содержать?&lt;/h2&gt;
&lt;p&gt;Она не должна содержать даты, оценки, или что-либо, о чём вам было бы стыдно, если бы спросили
через девять месяцев. Даты — классическая ошибка: квартал на roadmap становится обязательством в
презентации продаж становится тикетом под названием «вы сказали Q3». Колонки говорят достаточно.
«В разработке» уже означает «достаточно скоро, что кто-то этим занимается».&lt;/p&gt;
&lt;p&gt;Она также не должна содержать внутренний backlog. Roadmap с тремястами элементов — это проблема
поиска, не обещание, и клиентка, находящая свой запрос на позиции 212, узнала кое-что, что вы не
хотели ей говорить.&lt;/p&gt;
&lt;h2&gt;Как roadmap связывается с changelog?&lt;/h2&gt;
&lt;p&gt;Roadmap и changelog описывают одни и те же issue с двух сторон, одна для будущего, другая для
прошлого. Никто не двигает карточку на отдельной доске. Мейнтейнер меняет метку на issue, с
которым уже работал, запись составляется из pull request, а когда человек одобряет запись,
запросившая, чей отзыв из виджета стал этим issue, уведомляется на нём. Перевод карточки в выпущено остаётся отдельным шагом,
меткой &lt;code&gt;roadmap:shipped&lt;/code&gt;, так что сделайте его частью того же ревью; одобрение записи не делает
этого за вас.&lt;/p&gt;
&lt;p&gt;Это та же петля, которую &lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;статья о петле обратной связи&lt;/a&gt;
описывает со стороны changelog; roadmap — это то, что клиентка видит посередине этого. Обзор
&lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;инструменты для changelog&lt;/a&gt; охватывает, какие продукты предлагают представление
roadmap, а какие относятся к ней как к отдельной доске, что и есть разница, решающая, остаётся ли
она точной.&lt;/p&gt;
&lt;h2&gt;Как выглядит хорошая публичная roadmap?&lt;/h2&gt;
&lt;p&gt;Она выглядит короткой, и каждый элемент на ней — это issue, который может открыть любой. Тест —
может ли клиентка перейти от элемента к обсуждению за ним, и от выпущенного элемента к записи,
описывающей, что на самом деле изменилось. Roadmap, являющаяся списком названий функций без
входа, — это брошюра.&lt;/p&gt;
&lt;p&gt;Проработанный пример, как JSON, который получил бы виджет:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;columns&amp;quot;: [
    { &amp;quot;column&amp;quot;: &amp;quot;planned&amp;quot;, &amp;quot;hasMore&amp;quot;: false, &amp;quot;items&amp;quot;: [
      { &amp;quot;id&amp;quot;: &amp;quot;6b0c1f...&amp;quot;, &amp;quot;column&amp;quot;: &amp;quot;planned&amp;quot;,
        &amp;quot;publicTitle&amp;quot;: &amp;quot;Saved views on the inbox&amp;quot;,
        &amp;quot;publicDescription&amp;quot;: &amp;quot;Keep a filter you use often and come back to it.&amp;quot;,
        &amp;quot;publishedAt&amp;quot;: &amp;quot;2026-09-16T10:04:11.000Z&amp;quot; }
    ]},
    { &amp;quot;column&amp;quot;: &amp;quot;building&amp;quot;, &amp;quot;hasMore&amp;quot;: false, &amp;quot;items&amp;quot;: [
      { &amp;quot;id&amp;quot;: &amp;quot;71a4e2...&amp;quot;, &amp;quot;column&amp;quot;: &amp;quot;building&amp;quot;,
        &amp;quot;publicTitle&amp;quot;: &amp;quot;Roadmap column in the widget&amp;quot;,
        &amp;quot;publicDescription&amp;quot;: &amp;quot;See what is coming without leaving the page.&amp;quot;,
        &amp;quot;publishedAt&amp;quot;: &amp;quot;2026-09-12T08:20:02.000Z&amp;quot; }
    ]},
    { &amp;quot;column&amp;quot;: &amp;quot;shipped&amp;quot;, &amp;quot;hasMore&amp;quot;: false, &amp;quot;items&amp;quot;: [
      { &amp;quot;id&amp;quot;: &amp;quot;5c9d70...&amp;quot;, &amp;quot;column&amp;quot;: &amp;quot;shipped&amp;quot;,
        &amp;quot;publicTitle&amp;quot;: &amp;quot;Feedback filed as labelled issues&amp;quot;,
        &amp;quot;publicDescription&amp;quot;: &amp;quot;Widget submissions arrive as issues your triage already handles.&amp;quot;,
        &amp;quot;publishedAt&amp;quot;: &amp;quot;2026-09-02T15:41:37.000Z&amp;quot; }
    ]}
  ],
  &amp;quot;enabled&amp;quot;: true,
  &amp;quot;language&amp;quot;: &amp;quot;en&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Три элемента в трёх колонках — это вполне достаточная публичная roadmap. Она говорит, что
грядёт, что происходит, и что произошло, и каждая строка проверяема. Ещё пять форматов, от
Now/Next/Later до roadmap по результатам, показаны на примерах пунктов в статье
&lt;a href=&quot;https://changeloop.dev/blog/ru/product-roadmap-examples/&quot;&gt;примеры product roadmap&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Сколько элементов должна иметь публичная roadmap?&lt;/strong&gt;
Настолько мало, насколько вы можете защитить. Меньше десяти в общей сложности нормально для
маленького продукта; больше тридцати в «запланировано» обычно backlog, замаскированный под
roadmap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должна ли публичная roadmap иметь даты?&lt;/strong&gt;
Нет. Колонки сообщают последовательность, не создавая дедлайн. Если клиентке нужна дата, это
разговор, а не элемент roadmap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли клиенты голосовать за элементы roadmap?&lt;/strong&gt;
Голоса измеряют, кто пришёл, а не что важно. Комментарий на issue, объясняющий обходной путь,
который они используют сегодня, стоит больше пятидесяти голосов, и стоит что-то голосующему, что
и есть суть.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что происходит с отменённым элементом roadmap?&lt;/strong&gt;
Удалите метку и скажите почему на issue. Публичное «мы не будем это делать» — часть петли, и это
сообщение, которое большинство команд никогда не отправляют.&lt;/p&gt;
</content:encoded></item><item><title>Автоматизация changelog и её пределы</title><link>https://changeloop.dev/blog/ru/changelog-automation/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/changelog-automation/</guid><description>Автоматизируйте сбор, форматирование и публикацию. Не автоматизируйте отбор или формулировку. Где граница и что происходит, когда она сдвигается.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Автоматизация changelog работает, когда она автоматизирует сбор, классификацию и публикацию, и
останавливается на отборе и формулировке. Автоматизируйте всё — и вы доставляете отформатированный
git log; не автоматизируйте ничего — и changelog пишется рывками, по памяти, перед релизами.
Полезный вопрос в том, какие части автоматизировать, а не сколько.&lt;/p&gt;
&lt;p&gt;Проекты автоматизации changelog проваливаются в одном из двух направлений, и оба предсказуемы уже
с первой встречи по дизайну. Автоматизируйте слишком мало, и changelog становится документом,
который кто-то должен обновлять, что означает, что он обновляется рывками, кем бы ни выпала
короткая соломинка. Автоматизируйте слишком много, и он превращается в отформатированный git log:
полный, точный, и никем не читаемый.&lt;/p&gt;
&lt;h2&gt;Какие части changelog следует автоматизировать?&lt;/h2&gt;
&lt;p&gt;Три из четырёх шагов. Сбор и публикацию полностью; классификацию как первый проход с
человеческим переопределением; отбор и формулировку никогда.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Шаг&lt;/th&gt;
&lt;th&gt;Автоматизировать?&lt;/th&gt;
&lt;th&gt;Почему&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Сбор: изменения из коммитов, PR, тикетов в список&lt;/td&gt;
&lt;td&gt;Полностью&lt;/td&gt;
&lt;td&gt;Утомительно, пропускается под дедлайном, машины делают это идеально&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Классификация: Added, Fixed, Changed, Deprecated, Removed, Security&lt;/td&gt;
&lt;td&gt;Первый проход, человеческое переопределение&lt;/td&gt;
&lt;td&gt;Около 80% верно только из метаданных; неверные 20% — это записи, которые важны&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Отбор и формулировка: что сказать читателю, и как&lt;/td&gt;
&lt;td&gt;Никогда&lt;/td&gt;
&lt;td&gt;Это вся ценность артефакта&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Публикация: страница, лента, письмо, виджет, Slack&lt;/td&gt;
&lt;td&gt;Полностью, из одного источника&lt;/td&gt;
&lt;td&gt;Куда на самом деле уходит большая часть ручных усилий&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Сбор.&lt;/strong&gt; Извлечение изменений из места, где они происходят (коммиты, PR, тикеты), и помещение их
в список. Автоматизируйте это полностью. Люди плохи в этом, это утомительно, и это шаг, который
пропускается под дедлайном. &lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;Conventional commits&lt;/a&gt; или
метки PR — обычное сырьё.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Классификация.&lt;/strong&gt; Решение, является ли что-то Added, Fixed, Changed, Deprecated, Removed или
Security. Автоматизируйте первый проход из типа коммита или метки PR, и позвольте человеку
переопределить. Точность здесь около восьмидесяти процентов только из метаданных, а неверные
двадцать процентов концентрируются именно на записях, которые важны, потому что двусмысленность
коррелирует со значимостью.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Отбор и формулировка.&lt;/strong&gt; Решение о том, что должен узнать читатель, и как это сказать. &lt;strong&gt;Не
автоматизируйте это.&lt;/strong&gt; Это вся ценность артефакта. Всё остальное — логистика.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Публикация.&lt;/strong&gt; Доставка готовых записей на страницу, в ленту, письмо, in-app виджет, канал
Slack. Автоматизируйте полностью, и из одного источника. Сюда на самом деле уходит большая часть
ручных усилий, и почти никто это не считает. Это также шаг, который может сообщить человеку,
попросившему изменение, что оно выпущено, что и есть вся суть
&lt;a href=&quot;https://changeloop.dev/blog/ru/customer-feedback-loop/&quot;&gt;замыкания петли обратной связи со стороны changelog&lt;/a&gt;. У почтовой
половины этого шага своя форма, в &lt;a href=&quot;https://changeloop.dev/blog/ru/product-update-email/&quot;&gt;шаблоне письма об обновлении продукта&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Последний пункт стоит обдумать. Команды склонны видеть changelog как проблему письма, а затем
тратят большую часть времени на распространение: копирование записей в инструмент почты,
переформатирование для in-app, вставку в Slack, обновление страницы документации. Написание
занимает час. Копирование занимает час на каждый релиз, навсегда, и это часть, которую должна
иметь машина.&lt;/p&gt;
&lt;h2&gt;Что происходит, когда граница сдвигается?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Сдвиньте её вверх, и получите дамп git.&lt;/strong&gt; Полная автоматизация из коммитов производит
&lt;code&gt;bump deps&lt;/code&gt;, &lt;code&gt;fix flaky test&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt; и &lt;code&gt;address review comments&lt;/code&gt; перед клиентами. Каждая команда,
сделавшая это, потом добавила фильтр, и фильтр — это шаг отбора, повторно введённый под другим
именем, с худшей эргономикой.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сдвиньте её вниз, и получите рывки.&lt;/strong&gt; Полностью ручной сбор означает, что записи пишутся по
памяти в момент релиза. Это тот режим, о котором предупреждает
&lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt; с самого начала, и он тихо ухудшается:
changelog выглядит поддерживаемым вплоть до той самой недели, когда ни у кого не было времени.&lt;/p&gt;
&lt;h2&gt;Как выглядит pipeline автоматизации changelog?&lt;/h2&gt;
&lt;p&gt;Четыре шага, с ровно одними человеческими воротами, размещёнными там, где черновик становится
публичным.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;При merge выводите черновик записи из PR: тип из метки или префикса коммита, заголовок как
первый черновик, ссылка обратно на PR, зафиксированный автор. Поместите его в неопубликованную
корзину.&lt;/li&gt;
&lt;li&gt;Любой может редактировать любой черновик в любой момент, и редактирование дёшево. Большинство
получает одну переписанную строку.&lt;/li&gt;
&lt;li&gt;Выпуск релиза требует, чтобы каждая запись в корзине была либо отредактирована, либо явно
помечена как внутренняя. Эти ворота — весь дизайн. Без них черновики выпускаются
неотредактированными в загруженную неделю.&lt;/li&gt;
&lt;li&gt;Публикация — это разветвление из выпущенного набора: публичная страница, лента, письмо,
виджет, пост в Slack. Один источник, несколько отображений, без копирования.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Шаг 3 — единственное место, где нужен человек, и он занимает около десяти минут на релиз, как
только черновики приличные. Там, где вовлечён запрос клиента, черновик также несёт issue, который
он закрывает, что позволяет шагу 4 уведомить попросившего;
&lt;a href=&quot;https://changeloop.dev/blog/ru/feature-request-template/&quot;&gt;шаблон запроса функции&lt;/a&gt; спроектирован так, чтобы эта ссылка
пережила процесс. Где этот шаг стоит в общем потоке релиза, рассказывает статья
&lt;a href=&quot;https://changeloop.dev/blog/ru/release-management-process/&quot;&gt;процесс управления релизами&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Что автоматизация требует от ваших данных?&lt;/h2&gt;
&lt;p&gt;Ничего из вышеперечисленного не работает, если changelog — это файл Markdown, потому что файл не
может быть отображён на пяти поверхностях без повторного парсинга, а парсинг прозы — это как вы
заканчиваете с виджетом, показывающим половину заголовка.&lt;/p&gt;
&lt;p&gt;Записи должны быть структурированы: тип, дата, версия или идентификатор релиза, аудитория, тело и
ссылка. Тогда файл, страница, лента и письмо — все представления. Этот структурный момент —
единственное, что стоит сделать правильно перед выбором инструмента, потому что это то, что
нельзя дёшево добавить позже. Ничто
из этого не работает, если запись на самом деле не создаётся для каждого изменения, которому она
нужна; &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-ci-enforcement/&quot;&gt;обязательная запись в changelog в CI&lt;/a&gt; разбирает, как
заставить pipeline отклонять merge без записи, вместо того чтобы оставлять этот шаг на память.&lt;/p&gt;
&lt;p&gt;Мы строим &lt;a href=&quot;https://changeloop.dev/&quot;&gt;changeloop&lt;/a&gt;, где changelog сначала лента, а потом уже страница, так что читайте это
как заинтересованность, а не беспристрастную рекомендацию; &lt;a href=&quot;https://changeloop.dev/pricing&quot;&gt;цены&lt;/a&gt; — это один бесплатный
репозиторий без карты, достаточный, чтобы увидеть форму.
&lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;Инструменты для changelog&lt;/a&gt; — наш обзор того, что ещё существует, включая
продукты, с которыми мы конкурируем, а &lt;a href=&quot;https://changeloop.dev/changelog-generator&quot;&gt;генератор changelog&lt;/a&gt; выполняет шаги
сбора и классификации в браузере, если вы хотите увидеть вывод перед тем, как обязаться на
pipeline.&lt;/p&gt;
&lt;h2&gt;Тест&lt;/h2&gt;
&lt;p&gt;Посчитайте минуты между объединённым изменением и видимостью этого изменения для клиентки, которая
не читает ваш репо. Если большинство этих минут — это кто-то, копирующий текст между
инструментами, автоматизация, которая вам нужна, находится в публикации, а не в написании.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Может ли ИИ написать changelog?&lt;/strong&gt;
Он может составить черновик. Модель, которой дан объединённый pull request, чаще всего производит
пригодный первый черновик заголовка и тела, что и есть сбор и классификация, сделанные лучше.
Отбор — стоит ли вообще что-то говорить читателю, и финальная формулировка всё ещё нуждаются в
человеке, знающем аудиторию, и pipeline, публикующий черновики без этих ворот, автоматизировал не
тот шаг.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;В чём разница между генератором changelog и автоматизацией changelog?&lt;/strong&gt;
Генератор превращает коммиты в отформатированный список один раз, по запросу. Автоматизация
работает при каждом merge, поддерживает неопубликованную корзину, обусловливает релиз человеческим
ревью, и публикует на каждую поверхность из одного источника. Генератор — это первый шаг pipeline,
выполняемый вручную.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Следует ли автоматизировать changelog из коммитов или из pull request?&lt;/strong&gt;
Из pull request, где единицей изменения является PR: заголовок и описание пишутся один раз, для
всего изменения, и PR связывает issue, который закрывает. Вывод на основе коммитов работает,
когда коммит является единицей и следует конвенции.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как предотвратить публикацию внутренних изменений автоматизацией?&lt;/strong&gt;
Классифицируйте &lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;ci&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt; и обновления зависимостей как внутренние по
умолчанию, и сделайте продвижение к публичности осознанным актом. Обратный по умолчанию, публичное
если только кто-то не скроет, — это как &lt;code&gt;bump deps&lt;/code&gt; достигает клиентов.&lt;/p&gt;
</content:encoded></item><item><title>Changelog vs release notes: в чём разница?</title><link>https://changeloop.dev/blog/ru/changelog-vs-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/changelog-vs-release-notes/</guid><description>Changelog — это непрерывный реестр для того, кто что-то ищет. Release notes — это отобранное сообщение для того, кто решает, важно ли это ему.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Changelog — это непрерывный, накопительный реестр всего, что изменилось, написанный для того, кто
что-то ищет. Release notes — это отобранное сообщение об одном релизе, написанное для того, кто
решает, важно ли ему это. Разница в аудитории, а не в форматировании, и большинству команд нужны
оба: один как справочник, другой как анонс, выведенные из одних и тех же записей.&lt;/p&gt;
&lt;p&gt;Большинство команд заканчивают с одним из них случайно, а с другим — по запросу. Вы начинаете с
changelog, потому что разработчица хочет реестр того, что было выпущено. Месяцами позже кто-то из
поддержки спрашивает, почему клиенты не знали о функции, которая живёт с апреля, и теперь вам
нужны release notes.&lt;/p&gt;
&lt;h2&gt;Changelog vs release notes, рядом друг с другом&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Changelog&lt;/th&gt;
&lt;th&gt;Release notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Читатель&lt;/td&gt;
&lt;td&gt;Тот, кто что-то ищет&lt;/td&gt;
&lt;td&gt;Тот, кто решает, важно ли это ему&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Охват&lt;/td&gt;
&lt;td&gt;Всё, что изменилось&lt;/td&gt;
&lt;td&gt;То, что стоит сказать об этом релизе&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Периодичность&lt;/td&gt;
&lt;td&gt;Непрерывная, при каждом merge или релизе&lt;/td&gt;
&lt;td&gt;При релизе, и только тех, что стоит анонсировать&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Тон&lt;/td&gt;
&lt;td&gt;Краткий, фактический, часто повелительный&lt;/td&gt;
&lt;td&gt;Объясняющий, иногда убеждающий&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Срок жизни&lt;/td&gt;
&lt;td&gt;Постоянный, читается и годы спустя&lt;/td&gt;
&lt;td&gt;Читается первую неделю, потом архивируется&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Живёт в&lt;/td&gt;
&lt;td&gt;Репо, сайте документации, странице &lt;code&gt;/changelog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Письме, in-app, посте блога, странице релиза&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Терпит неудачу из-за&lt;/td&gt;
&lt;td&gt;Неполноты&lt;/td&gt;
&lt;td&gt;Скучности, или слишком позднего появления&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Что такое changelog?&lt;/h2&gt;
&lt;p&gt;Changelog — это хронологический, почти полный реестр того, что изменилось, самое новое первым, с
каждой записью, типизированной (added, changed, deprecated, removed, fixed, security) и
датированной. Его читатель уже решил, что ему важно. Он что-то ищет: когда изменилось поведение,
исправлен ли баг, какая версия ввела флаг. Полнота — вся ценность, поэтому конвенция
&lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt; тратит большую часть своей единственной
страницы на структуру и почти ничего на прозу.&lt;/p&gt;
&lt;h2&gt;Что такое release notes?&lt;/h2&gt;
&lt;p&gt;Release notes — это избирательное сообщение, написанное прозой, об одном релизе. Его читатель ещё
ничего не решил. Он решает, важен ли ему этот релиз, и нужно ли ему что-то с этим делать. Отбор —
вся ценность: release note, перечисляющая всё, — это changelog с абзацами, и она подводит
читателя так же, как changelog, пропускающий что-то, подводит своего. &lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;Как писать release notes&lt;/a&gt;
о том, как отбирать и формулировать.&lt;/p&gt;
&lt;h2&gt;Нужен ли вам и changelog, и release notes?&lt;/h2&gt;
&lt;p&gt;Вам нужны оба, как только ваши две аудитории начинают хотеть разного; до этого один артефакт,
выполняющий обе работы, — правильно. Маленькие команды публикуют одну страницу &lt;code&gt;/changelog&lt;/code&gt; с
коротким абзацем в начале каждой записи, и какое-то время это одинаково хорошо служит и
разработчице, ищущей исправление, и клиентке, просматривающей новости. Разделение слишком рано
даёт вам два дела для поддержки, и одно из них сгниёт.&lt;/p&gt;
&lt;p&gt;Разделение оказывается стоящим, когда начинает происходить это:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ваши записи changelog обросли объясняющими абзацами, которые разработчики пропускают.&lt;/li&gt;
&lt;li&gt;Или наоборот: ваши анонсы релизов начали перечислять обновления зависимостей.&lt;/li&gt;
&lt;li&gt;Поддержка копирует записи в письма и переписывает их по пути.&lt;/li&gt;
&lt;li&gt;Кто-то просит «только breaking change», а вы не можете их отфильтровать.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Последнее — настоящий признак. Если никто не может ответить «что изменилось, что касается меня»,
не прочитав всё, у вас один артефакт, плохо выполняющий две работы.&lt;/p&gt;
&lt;h2&gt;Один источник, два представления&lt;/h2&gt;
&lt;p&gt;Ошибка — относиться к ним как к двум документам. Это два представления одного и того же набора
изменений.&lt;/p&gt;
&lt;p&gt;Пишите changelog по ходу дела, одна запись на значимое изменение, каждая помечена тем, что она
есть: fixed, added, changed, removed, deprecated, security. Держите записи достаточно короткими,
чтобы написание одной не было решением. Затем, в момент релиза, release notes — это отбор и
переписывание: возьмите записи, важные для человека, сгруппируйте их по тому, что они позволяют
кому-то сделать, и поставьте причину сверху.&lt;/p&gt;
&lt;p&gt;У этого есть практическое следствие. Если changelog — это источник, он должен быть структурированными
данными, а не страницей, поддерживаемой вручную. Записи нужен тип, дата, версия и способ сказать,
для кого она. Как только это есть, публичная страница, in-app виджет и лента RSS или JSON —
это три отображения одной вещи, и никто ничего не переписывает по пути к клиенту. Письмо с
release notes может цитировать ту же запись, из любого инструмента, которым вы отправляете почту.
&lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;Автоматизация changelog&lt;/a&gt; — о том, какой из этих шагов должен
принадлежать машине. Это весь аргумент в пользу того, чтобы относиться к changelog как к ленте, а
не как к странице. Это также, с полной прозрачностью, то, что мы строим, так что читайте это как
интерес, а не беспристрастный опрос.&lt;/p&gt;
&lt;h2&gt;Если у вас есть время только на одно&lt;/h2&gt;
&lt;p&gt;Пишите changelog. Он дешевле на запись, полезен в день, когда вы его пишете, и release notes
можно потом вывести из него. Обратное неверно: вы не можете восстановить год изменений из
двенадцати писем с анонсами, а люди попросят вас об этом.&lt;/p&gt;
&lt;p&gt;Держите его в фиксированном формате, чтобы вывод оставался возможным. Наша страница
&lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; собирает записи от команд, делающих это хорошо, а
&lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;шаблон release notes&lt;/a&gt; — это форма, которую мы используем, превращая
набор записей во что-то, что стоит отправить.&lt;/p&gt;
&lt;h2&gt;Заметка об именовании&lt;/h2&gt;
&lt;p&gt;Ничто из этого не стандартизировано, и вы найдёте «release notes», используемое для непрерывного
списка, и «changelog», используемый для квартального анонса. Спорить о словах не стоит.
Решите, какую из двух работ выполняет каждый из ваших артефактов, называйте это так, как уже
называет ваша команда, и убедитесь, что ни один из них молча не делает оба.&lt;/p&gt;
&lt;p&gt;На какой поверхности окажется результат — отдельное решение, разобранное в
&lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-page/&quot;&gt;как сделать страницу changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Одно ли и то же changelog и release notes?&lt;/strong&gt;
Нет. Changelog — это полный реестр, читаемый теми, кто что-то ищет; release notes — это
отобранный анонс, читаемый теми, кто решает, важно ли это им. Одно и то же изменение появляется
в обоих, сформулированное по-разному для каждого читателя.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Можно ли сгенерировать release notes из changelog?&lt;/strong&gt;
Да, и это правильное направление. Отберите записи, важные для человека, сгруппируйте по
результату, перепишите заголовок. Обратное, восстановление changelog из анонсов, теряет всё, что
анонсы опустили.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Где должен жить changelog?&lt;/strong&gt;
Где-то постоянном и ссылаемом, куда читатель может добраться без репозитория: странице
&lt;code&gt;/changelog&lt;/code&gt;, сайте документации, или ленте, отображаемой в нескольких местах. Один
&lt;code&gt;CHANGELOG.md&lt;/code&gt; достигает контрибьюторов, но не клиентов.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли changelog включать внутренние изменения?&lt;/strong&gt;
Да, внизу, по одной строке каждое. Changelog — это полный реестр. Release notes тоже могут
их содержать, в короткой последней секции, если изменения, которые читатель заметит, идут первыми.&lt;/p&gt;
</content:encoded></item><item><title>От conventional commits к changelog</title><link>https://changeloop.dev/blog/ru/conventional-commits-changelog/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/conventional-commits-changelog/</guid><description>Conventional commits делают changelog выводимым из истории, но не делают его читаемым. Что даёт эта конвенция, где она заканчивается и как закрыть разрыв.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Conventional commits бесплатно дают changelog три вещи: тип каждого изменения, часть системы,
которую оно затронуло, и ломает ли оно что-то. Больше они не дают ничего. Формулировка,
группировка и отбор, которые и есть changelog, остаются полностью открытыми, и pipeline,
притворяющийся иначе, доставляет отформатированный git log.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;feat(exports): add CSV column selection
fix(auth): reject expired refresh tokens
chore(deps): bump node-pg to 8.11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Три коммита в формате &lt;a href=&quot;https://www.conventionalcommits.org/&quot;&gt;Conventional Commits&lt;/a&gt;. Из них
машина может сказать вам, что один — это функция, один — исправление, один — уборка, и какую
часть системы затронул каждый. Это по-настоящему полезно, и это всё обещание конвенции: история
коммитов, которую может прочитать что-то помимо человека. Ошибка — думать, что это даёт вам
changelog. Это даёт вам сырьё.&lt;/p&gt;
&lt;h2&gt;Что определяет конвенция?&lt;/h2&gt;
&lt;p&gt;Тип, необязательный scope, и описание: &lt;code&gt;type(scope): description&lt;/code&gt;. Типы условно &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;,
&lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;docs&lt;/code&gt;, &lt;code&gt;refactor&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;perf&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;ci&lt;/code&gt;. Две вещи помечают breaking change: &lt;code&gt;!&lt;/code&gt;
перед двоеточием, или футер &lt;code&gt;BREAKING CHANGE:&lt;/code&gt;. Инструменты ориентируются на &lt;code&gt;feat&lt;/code&gt; и &lt;code&gt;fix&lt;/code&gt; для
minor и patch версий, и на маркер breaking для major.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Коммит даёт вам&lt;/th&gt;
&lt;th&gt;Changelog нуждается в&lt;/th&gt;
&lt;th&gt;Кто заполняет разрыв&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;feat&lt;/code&gt; / &lt;code&gt;fix&lt;/code&gt; / &lt;code&gt;chore&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Added / Fixed / внутреннее&lt;/td&gt;
&lt;td&gt;Отображение, автоматическое&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;(scope)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Группировку, которую узнаёт читатель&lt;/td&gt;
&lt;td&gt;Человек, раз на scope&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!&lt;/code&gt; или &lt;code&gt;BREAKING CHANGE:&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Кто ломается, до когда, и что делать&lt;/td&gt;
&lt;td&gt;Человек, каждый раз&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Описание, написанное для ревьюера&lt;/td&gt;
&lt;td&gt;Результат, написанный для клиентки&lt;/td&gt;
&lt;td&gt;Человек, каждая запись&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Один коммит&lt;/td&gt;
&lt;td&gt;Одно изменение, которое может быть многими коммитами&lt;/td&gt;
&lt;td&gt;Правила squash, или человек&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Маркер сообщает это инструменту; он не сообщает это вызывающей стороне, что является темой
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;как деприкейтить API&lt;/a&gt; и
&lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;что такое breaking change&lt;/a&gt;. Это маленькая спецификация, и её стоит
соблюдать, даже если вы никогда ничего из неё не генерируете, потому что она заставляет принять
одно решение на коммит: видят ли пользователи это изменение, или нет.&lt;/p&gt;
&lt;h2&gt;Где останавливаются conventional commits?&lt;/h2&gt;
&lt;p&gt;Они останавливаются на предложении. Всё, что захватывает конвенция, — это метаданные об
изменении; само изменение всё ещё описано словарём ревьюера.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сообщения коммитов написаны для ревьюеров.&lt;/strong&gt; &lt;code&gt;fix(auth): reject expired refresh tokens&lt;/code&gt;
корректно и ничего не говорит клиентке. Читательница changelog хочет «вас выйдут из системы,
когда сессия действительно истечёт, вместо периодических 401».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope внутренние.&lt;/strong&gt; &lt;code&gt;exports&lt;/code&gt;, &lt;code&gt;auth&lt;/code&gt;, &lt;code&gt;ingest&lt;/code&gt; — это названия модулей. Они стабильны, что
делает их хорошими для группировки, и бессмысленны для тех, кто вне кодовой базы.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Одно изменение часто — это много коммитов.&lt;/strong&gt; Функция, объединённая через одиннадцать коммитов,
создаёт одиннадцать записей, десять из которых шум, а сжатие их для сокрытия этого теряет историю
ревью.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;chore&lt;/code&gt; — это мусорка, а не категория.&lt;/strong&gt; Обновления зависимостей, изменения CI и переименования
попадают туда все, и некоторые важны для пользователей, пока большинство нет.&lt;/p&gt;
&lt;p&gt;Итак: конвенция бесплатно даёт вам тип, scope и статус breaking, и оставляет формулировку,
группировку и отбор полностью открытыми. Эти три — и есть changelog.
&lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-entry-ownership/&quot;&gt;Кто на самом деле отвечает за запись в changelog&lt;/a&gt; разбирает,
кто должен заниматься этой формулировкой, группировкой и отбором, поскольку сама конвенция не
имеет на этот счёт мнения.&lt;/p&gt;
&lt;h2&gt;Как генерируется changelog из conventional commits?&lt;/h2&gt;
&lt;p&gt;В двух слоях, и второй должен быть обязательным.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Слой первый, автоматический.&lt;/strong&gt; При merge выводите черновик записи из коммита: тип отображён на
тип changelog (&lt;code&gt;feat&lt;/code&gt; на Added, &lt;code&gt;fix&lt;/code&gt; на Fixed, маркер breaking на Changed плюс флаг), scope
сохранён как метаданные, а не текст, ссылка на PR. Поместите его в раздел Unreleased, который
требует &lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Слой второй, человеческий, и необходимый.&lt;/strong&gt; Прежде чем выйдет релиз, каждая черновая запись
либо получает однострочное переписывание словарём пользователя, либо помечается как внутренняя и
убирается из публичного вида. Это шаг, который люди пытаются пропустить, и его пропуск создаёт
changelog, читающиеся как диф.&lt;/p&gt;
&lt;p&gt;Важная деталь дизайна в том, что второй слой не опционален в pipeline. Если релиз можно выпустить
с неотредактированными черновиками, это случится, в неделю, когда все заняты. Какие шаги
принадлежат машине, а какие человеку — вся суть &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;автоматизации changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Вырезка релиза — это и момент, когда git-тег, релиз и эта запись changelog либо совпадают, либо
начинают расходиться; &lt;a href=&quot;https://changeloop.dev/blog/ru/git-tags-releases-changelog/&quot;&gt;git-теги, релизы и ваш changelog&lt;/a&gt;
разбирает, как держать эти три вещи синхронизированными.&lt;/p&gt;
&lt;h2&gt;Три ловушки&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Squash merge съедает футеры.&lt;/strong&gt; Если ваша платформа сжимает с заголовком PR как сообщением,
футер &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; коммита внутри этой ветки исчезает, и ваши инструменты молча перестают
видеть breaking change. Проверьте, что на самом деле сохраняет ваш шаблон squash.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Коммиты revert создают призрачные записи.&lt;/strong&gt; &lt;code&gt;fix&lt;/code&gt;, который откатывается на следующий день,
создаёт запись для того, что никогда не было выпущено, если только вывод не примиряет revert-ы.
Большинство инструментов этого не делают.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Повышение версии и changelog рассинхронизируются.&lt;/strong&gt; Если версия вычисляется из коммитов, а
changelog пишется вручную после, они расходятся примерно за два релиза. Вычисляйте оба за один
проход или примите, что один из них неверен.&lt;/p&gt;
&lt;h2&gt;Если вам нужна механическая часть без pipeline&lt;/h2&gt;
&lt;p&gt;Наш &lt;a href=&quot;https://changeloop.dev/changelog-generator&quot;&gt;генератор changelog&lt;/a&gt; выполняет шаг вывода в браузере: вставьте
коммиты, получите сгруппированные, типизированные записи. Он намеренно детерминирован и
полностью клиентский, поэтому вставляемые вами коммиты никогда не покидают вашу машину, что
важно, когда сообщения из приватного репозитория. Он честно выполняет половину сбора и не
пытается сделать второй слой, потому что второй слой — это суждение, а инструмент, притворяющийся
им, создаёт именно тот changelog, против которого выступает эта статья.&lt;/p&gt;
&lt;p&gt;Для версии pipeline, &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;инструменты для changelog&lt;/a&gt; охватывает, что существует.&lt;/p&gt;
&lt;h2&gt;Резюме&lt;/h2&gt;
&lt;p&gt;Conventional commits надёжно и дёшево отвечают на «какого рода это изменение». Они не отвечают
на «что мы должны сказать людям», и никакое количество инструментов поверх сообщения коммита
этого не сделает, потому что информация никогда не была в сообщении коммита. Бюджетируйте на
переписывание.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Генерируют ли conventional commits changelog автоматически?&lt;/strong&gt;
Они автоматически генерируют черновик: типизированные, со scope, связанные записи. Формулировка
для клиентки, группировка и решение о том, что опустить, всё ещё нуждаются в человеке, и
pipeline, пропускающий этот шаг, публикует сообщения коммитов.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какие типы conventional commit появляются в changelog?&lt;/strong&gt;
&lt;code&gt;feat&lt;/code&gt; и &lt;code&gt;fix&lt;/code&gt; всегда, как Added и Fixed. &lt;code&gt;perf&lt;/code&gt; обычно, как Changed. &lt;code&gt;chore&lt;/code&gt;, &lt;code&gt;docs&lt;/code&gt;,
&lt;code&gt;refactor&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt; и &lt;code&gt;ci&lt;/code&gt; по умолчанию внутренние и появляются только если человек
продвигает один из них.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как conventional commits помечают breaking change?&lt;/strong&gt;
&lt;code&gt;!&lt;/code&gt; после типа или scope (&lt;code&gt;feat(api)!: ...&lt;/code&gt;), или футер &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; в теле коммита. Оба
теряются, если squash merge сохраняет только заголовок PR.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Нужны ли conventional commits для автоматизации changelog?&lt;/strong&gt;
Нет. Метки PR, шаблоны PR и ссылки на issue несут те же метаданные для команд, которые
объединяют через pull request. Conventional commits — самый дешёвый вариант, когда единицей
изменения является коммит.&lt;/p&gt;
</content:encoded></item><item><title>Как писать release notes, которые реально читают</title><link>https://changeloop.dev/blog/ru/how-to-write-release-notes/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/how-to-write-release-notes/</guid><description>«Исправления багов и улучшения производительности» — это не release note. Вопрос, на который должна отвечать каждая запись, и переписанный реальный пример.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Чтобы писать release notes, которые читают, отвечайте на один вопрос в каждой записи: что читатель
теперь может сделать, чего не мог раньше, и что ему нужно для этого сделать. Ставьте всё с
дедлайном первым, называйте, кого это касается, пишите «действий не требуется», когда это правда,
и пропускайте релизы, которым нечего сказать. Всё остальное на этой странице — применение этого
правила.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Исправления багов и улучшения производительности.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Каждый продукт когда-нибудь публиковал это. Причина редко в лени: так получается, когда release
notes пишутся изнутри, кем-то, кто провёл две недели в диффе и уже не видит, какие части заинтересуют
постороннего. Лучший тон это не исправит; ответ на вопрос — да.&lt;/p&gt;
&lt;h2&gt;Что должны включать release notes?&lt;/h2&gt;
&lt;p&gt;Release notes должны включать для каждого изменения, заслуживающего упоминания: что читатель
теперь может сделать, кого это касается, что ему нужно сделать (включая «ничего»), и когда вступает
в силу то, у чего есть дедлайн. Они не должны включать номера внутренних тикетов, названия
компонентов, которые использует только команда, или номер версии как единственный заголовок.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Включить&lt;/th&gt;
&lt;th&gt;Опустить&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Результат, словами читателя&lt;/td&gt;
&lt;td&gt;Реализацию, словами команды&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Кого касается, по плану, роли или версии API&lt;/td&gt;
&lt;td&gt;«Некоторые пользователи»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Требуемое действие, или «действий не требуется»&lt;/td&gt;
&lt;td&gt;Тишину, которую читатель заполняет худшим сценарием&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Дату для всего, у чего есть дедлайн&lt;/td&gt;
&lt;td&gt;Номер версии вместо даты&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ссылку на документацию с объяснением&lt;/td&gt;
&lt;td&gt;Ссылку на pull request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Баги, о которых сообщили люди, и поднятый лимит&lt;/td&gt;
&lt;td&gt;Внутренние id тикетов&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Скучный раздел, по одной строке, внизу&lt;/td&gt;
&lt;td&gt;Скучный раздел, смешанный с новостями&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Разделение между release note и &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;записью changelog&lt;/a&gt; — это
то, что делает возможным этот список: changelog хранит всё, поэтому заметки могут что-то опускать.
Размеченные примеры каждого вида записи собраны в статье
&lt;a href=&quot;https://changeloop.dev/blog/ru/release-notes-examples/&quot;&gt;примеры release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Вопрос, на который отвечает каждая запись&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Что читатель теперь может сделать, чего не мог раньше, и что ему нужно для этого сделать?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Если запись не может на это ответить, она принадлежит changelog, а не release notes. Обе половины
важны. Первая половина — это ценность. Вторая половина — та, которую забывают команды, и именно
она порождает тикеты в поддержку, когда её нет.&lt;/p&gt;
&lt;p&gt;Два примера второй половины, выполняющей реальную работу:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;«Существующие вебхуки продолжат работать до 1 ноября. После этой даты неподписанные payload
будут отклоняться.»&lt;/li&gt;
&lt;li&gt;«Действий не требуется. Существующие экспорты автоматически перекодируются при следующем
открытии.»&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Второй пример явно говорит «действий не требуется». Эту фразу стоит писать каждый раз, потому что
читатель, который её не находит, предполагает худшее.&lt;/p&gt;
&lt;h2&gt;Как следует упорядочивать release notes?&lt;/h2&gt;
&lt;p&gt;Упорядочивайте их по последствиям для читателя, никогда — по части системы, которая изменилась.
Группировка по API, панели, мобильному приложению и инфраструктуре — это ваша организационная
схема, а не проблема читателя.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Breaking change и всё, у чего есть дедлайн.&lt;/strong&gt; Всегда первым, даже если это мелочь. Если
читатель перестаёт читать после одной строки, это должна быть та строка, которую он должен был
прочитать. Если дедлайн — это sunset, запись должна звучать как
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;уведомление об устаревании&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Что нового и чего они хотели.&lt;/strong&gt; По одному на абзац, с результатом в первом предложении.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Что улучшилось.&lt;/strong&gt; Баги, о которых сообщили, лимиты, которые подняли, что было медленным.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Всё остальное, списком.&lt;/strong&gt; Обновления зависимостей, внутренние рефакторинги, мелкие тексты. По
одной строке каждое. Никто не читает этот раздел, и всё же он должен быть, потому что тот, кто
его ищет, действительно в нём нуждается.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Переписывание&lt;/h2&gt;
&lt;p&gt;До:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;v4.2.0&lt;/strong&gt; Исправлена проблема, из-за которой endpoint &lt;code&gt;POST /exports&lt;/code&gt; периодически возвращал
500 под нагрузкой. Рефакторинг воркера экспорта. Обновлён &lt;code&gt;node-pg&lt;/code&gt; до 8.11. Улучшена обработка
ошибок в сериализаторе CSV.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;После:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Экспорты больше не падают на больших аккаунтах.&lt;/strong&gt;
Аккаунты с более чем примерно 50 000 строк могли получить 500 при запуске экспорта, чаще в
конце месяца. Это исправлено, и теперь экспорты любого размера сами повторяют попытку вместо
того, чтобы падать. Действий не требуется, и любой экспорт, упавший на прошлой неделе, можно
просто запустить заново.&lt;/p&gt;
&lt;p&gt;Также в 4.2.0: &lt;code&gt;node-pg&lt;/code&gt; 8.11, более понятные ошибки в сериализаторе CSV.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Тот же релиз. Второй вариант называет затронутый аккаунт, момент, когда было хуже всего, что
изменилось, и что делать. Обновление зависимости не исчезло, оно просто перестало быть
заголовком. Статья &lt;a href=&quot;https://changeloop.dev/blog/ru/release-notes-best-practices/&quot;&gt;лучшие практики release notes&lt;/a&gt;
содержит остальные правила, которым следует это переписывание, каждое с ценой пропуска.&lt;/p&gt;
&lt;h2&gt;Что стоит удалить&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;«Мы рады объявить.»&lt;/strong&gt; Читатель ещё не рад. Заслужите это в следующем предложении.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Внутренние номера тикетов.&lt;/strong&gt; &lt;code&gt;PROJ-4471&lt;/code&gt; ничего не значит вне вашего трекера. Если записи
нужна ссылка, дайте ссылку на страницу документации.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Названия компонентов, которые использует только ваша команда.&lt;/strong&gt; Если вы переименовали
«пайплайн приёма данных», скажите «импорты».&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Номер версии как единственный заголовок.&lt;/strong&gt; &lt;code&gt;v4.2.0&lt;/code&gt; — это ярлык для архива, а не резюме.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Скриншоты страницы настроек, которую никто не посещал.&lt;/strong&gt; Покажите то, что изменилось, в
действии.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Как часто следует публиковать release notes?&lt;/h2&gt;
&lt;p&gt;Публикуйте, когда что-то произошло, а не по расписанию. Заметки, приходящие с каждым релизом,
приучают всех их игнорировать. Заметки, приходящие, когда что-то произошло, открывают. Это
нормально, и обычно правильно, выпустить релиз вообще без заметок и перенести его записи в
следующий набор, у которого есть заголовок, достойный прочтения.&lt;/p&gt;
&lt;p&gt;Changelog продолжает фиксировать всё. Таково разделение труда: changelog полон, заметки
избирательны. Если вы поддерживаете changelog структурированным по ходу дела, написание заметок
становится отбором и переписыванием, а не археологией.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;Шаблон release notes&lt;/a&gt; — это форма, которую мы используем для этапа
отбора, а &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; собирает записи от команд, чей changelog
достаточно хорош, чтобы выводить из него заметки.&lt;/p&gt;
&lt;p&gt;Всё это предполагает страницу, которую вы полностью контролируете, без ограничения длины и с
работающими ссылками. &lt;a href=&quot;https://changeloop.dev/blog/ru/mobile-app-release-notes/&quot;&gt;Release notes для мобильных приложений&lt;/a&gt;
разбирает, что меняется, когда поверхность — это листинг App Store или Play Store.
&lt;a href=&quot;https://changeloop.dev/blog/ru/emergency-release-notes/&quot;&gt;Экстренные release notes&lt;/a&gt; разбирают другое исключение: что
меняется, когда не остаётся времени вообще следовать обычному процессу написания.&lt;/p&gt;
&lt;h2&gt;Один тест перед публикацией&lt;/h2&gt;
&lt;p&gt;Прочитайте заметки как человек, который был в отпуске две недели и у которого есть 40 секунд.
Если за это время он не может понять, требуется ли от него что-то, заметки не готовы, какими бы
точными они ни были.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Насколько длинными должны быть release notes?&lt;/strong&gt;
Такими длинными, каких требуют значимые изменения, и ни строкой больше. Релиз с одним breaking
change и двумя улучшениями — это три абзаца. Наполнение тихого релиза, чтобы он казался
значительным — это как читатели учатся пропускать заметки.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Кто должен писать release notes?&lt;/strong&gt;
Человек, понимающий изменение, отредактированный кем-то, кто его не понимает. Инженерка знает,
что изменилось; редакторка знает, что посторонний поймёт неправильно. Написание записи в момент
merge, пока инженерка ещё помнит, — это практика, которая делает это дешёвым.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли release notes включать исправления багов?&lt;/strong&gt;
Да, те, о которых кто-то сообщил или с которыми столкнулся. Укажите симптом, который видел
читатель, а не причину. «Экспорты более 50 000 строк падали» — это исправление, которое читатель
узнаёт; «исправлена гонка в воркере экспорта» — это сообщение коммита.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;В чём разница между release notes и changelog?&lt;/strong&gt;
Changelog — это полный, непрерывный реестр; release notes — это отобранное сообщение об одном
релизе, написанное для людей, которые ещё не решили, интересует ли их это. Более длинный ответ —
в &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;changelog vs release notes&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Keep a Changelog, реально внедрённый</title><link>https://changeloop.dev/blog/ru/keep-a-changelog-implemented/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/keep-a-changelog-implemented/</guid><description>Спецификация Keep a Changelog занимает одну страницу, но команды сбиваются при внедрении. Что она требует, что оставляет на ваше усмотрение и где подводит.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Keep a Changelog — это конвенция на одну страницу для &lt;code&gt;CHANGELOG.md&lt;/code&gt;: самая новая версия первая,
один раздел на версию с номером и датой ISO, записи, сгруппированные под шестью типами (Added,
Changed, Deprecated, Removed, Fixed, Security), и раздел Unreleased сверху для записей между
релизами. Большинство команд, ссылающихся на неё, внедряют около двух третей, а треть, которую
они оставляют, — это та треть, что защищает их пользователей.&lt;/p&gt;
&lt;p&gt;Оливье Лакан опубликовал &lt;a href=&quot;https://keepachangelog.com/&quot;&gt;Keep a Changelog&lt;/a&gt; в 2014 году с фразой,
которая состарилась лучше большинства прозы о софте: &lt;em&gt;don&amp;#39;t let your friends dump git logs into
changelogs&lt;/em&gt;. Десять лет спустя это ближайшее к стандарту, что есть в этом уголке софта. Стоит
прочитать источник, а не пересказ; этот текст о частях, которые оставляют в стороне.&lt;/p&gt;
&lt;h2&gt;Что требует Keep a Changelog?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt; в корне репо, самая новая версия первая, с одним разделом на версию. Каждая версия
несёт номер и дату ISO, и группирует свои записи под шестью типами:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Тип&lt;/th&gt;
&lt;th&gt;Для&lt;/th&gt;
&lt;th&gt;Цена его оставления в стороне&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Added&lt;/td&gt;
&lt;td&gt;Новые функции&lt;/td&gt;
&lt;td&gt;Ничего; никто это не оставляет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changed&lt;/td&gt;
&lt;td&gt;Изменения в существующем поведении&lt;/td&gt;
&lt;td&gt;Читатели узнают об изменении поведения из ошибки&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;Функции на пути к удалению&lt;/td&gt;
&lt;td&gt;Удаление становится инцидентом вместо запланированного события&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Removed&lt;/td&gt;
&lt;td&gt;Функции, удалённые в этом релизе&lt;/td&gt;
&lt;td&gt;Никто не отличает удаление от бага&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixed&lt;/td&gt;
&lt;td&gt;Исправления багов&lt;/td&gt;
&lt;td&gt;Ничего; никто это тоже не оставляет&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Уязвимости&lt;/td&gt;
&lt;td&gt;Единственная читательница, искавшая это, не находит&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Плюс раздел &lt;code&gt;Unreleased&lt;/code&gt; сверху, чтобы было место для записи в момент её merge, и чтобы каждый
мог увидеть, что грядёт.&lt;/p&gt;
&lt;p&gt;Это почти всё. Остальное — обоснование: записи для людей, одна запись на изменение, и файл —
документ, а не лог.&lt;/p&gt;
&lt;h2&gt;Какие части Keep a Changelog оставляют в стороне?&lt;/h2&gt;
&lt;p&gt;Раздел Unreleased, затем четыре из шести типов, Security в их числе, в этом порядке.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Unreleased&lt;/code&gt; исчезает первым.&lt;/strong&gt; Это раздел без дедлайна, поэтому его поддержка прекращается
первой, и как только он исчезает, записи пишутся в момент релиза из истории коммитов. Это именно
тот сброс git-лога, о котором спецификация предупреждает с самого начала, достигнутый постепенно.
&lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-automation/&quot;&gt;Автоматизация changelog&lt;/a&gt; в основном о том, как поддерживать этот
раздел живым без того, чтобы кто-то должен был помнить об этом.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Шесть типов схлопываются в два.&lt;/strong&gt; Большинство реальных changelog заканчиваются с Added и Fixed,
потому что Changed и Deprecated требуют суждения о том, на что кто-то полагался. Это суждение —
ценная часть. Deprecated в частности — единственный тип, являющийся обещанием о будущем, и его
пропуск — это как удаление превращается в инцидент; механика соблюдения этого обещания — в
&lt;a href=&quot;https://changeloop.dev/blog/ru/api-deprecation/&quot;&gt;как деприкейтить API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Security перестаёт быть отдельным.&lt;/strong&gt; Исправление безопасности, помещённое под Fixed, невидимо
для единственной читательницы, искавшей его. Держите его отдельно, даже когда исправление
тривиально, и особенно когда вы предпочли бы не привлекать к нему внимание.&lt;/p&gt;
&lt;h2&gt;На что не отвечает спецификация?&lt;/h2&gt;
&lt;p&gt;Это формат файла. Он ничего не говорит о вопросах, с которыми вы сталкиваетесь сразу после её
принятия:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Как кто-то узнаёт?&lt;/strong&gt; Файл в репо достигает контрибьюторов. Он не достигает клиентку, которая
никогда не открывала GitHub.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;А продукты без версий?&lt;/strong&gt; Непрерывно развёртываемый сервис не имеет v4.2.0, по которой можно
группировать. Большинство команд заменяют это датами, что работает, и спецификация это ни
благословляет, ни запрещает.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Кто пишет запись?&lt;/strong&gt; Спецификация предполагает, что это делает человек. Она не говорит когда.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;А множество аудиторий?&lt;/strong&gt; Один файл обслуживает разработчиков. Он не обслуживает тем же
содержимым нетехническую администраторку, и ручное переформатирование для неё — то, откуда
начинается дублирование. &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;Changelog vs release notes&lt;/a&gt; —
это разделение, которое спецификация оставляет вам сделать самостоятельно.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://common-changelog.org/&quot;&gt;Common Changelog&lt;/a&gt;, более строгий форк идеи, ужесточает часть
этого: запрещает определённые формулировки записей, требует ссылку на изменение, и имеет чёткое
мнение о том, кто читатель. Стоит прочитать, если свободные части Keep a Changelog — это то, о
чём ваша команда постоянно спорит.&lt;/p&gt;
&lt;h2&gt;Можно ли автоматизировать Keep a Changelog без сброса git-логов?&lt;/h2&gt;
&lt;p&gt;Да: выводите черновик из структурированных коммитов, помещайте его в Unreleased с
предзаполненным типом, и требуйте, чтобы человек редактировал формулировку перед выпуском релиза.
Предупреждение спецификации о результате, а не об инструменте. Выведение черновика из коммитов
— это нормально. Публикация этого черновика без редактирования — то, против чего она возражает.&lt;/p&gt;
&lt;p&gt;Машина занимается сбором и форматированием, в чём она хороша. Человек занимается отбором и
формулировкой, в чём она не хороша. &lt;a href=&quot;https://changeloop.dev/blog/ru/conventional-commits-changelog/&quot;&gt;Conventional commits&lt;/a&gt;
описывают то разделение на два уровня, на которое это опирается, и то, какие типы коммитов
соответствуют каким из шести категорий выше. Наш обзор &lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;инструменты для changelog&lt;/a&gt;
охватывает, что существует для половины сбора.&lt;/p&gt;
&lt;h2&gt;Где Keep a Changelog перестаёт быть достаточным?&lt;/h2&gt;
&lt;p&gt;Он останавливается на распространении. Keep a Changelog — хороший ответ на «как должен выглядеть
этот файл». Это не ответ на «как наши пользователи узнают, что изменилось», потому что файл
Markdown в репо — это стратегия распространения, работающая только если ваши пользователи —
контрибьюторы.&lt;/p&gt;
&lt;p&gt;Это препятствие, с которым большинство команд сталкивается вторым: файл в порядке, и никто вне
команды его не читает. Решение этого означает, что записи должны стать данными, которые можно
отобразить в другом месте, что является другой проблемой, чем форматирование файла, и причиной,
по которой &lt;a href=&quot;https://changeloop.dev/changelog-examples&quot;&gt;примеры changelog&lt;/a&gt; собирает публичные страницы changelog, а не
файлы репозитория. Как превратить эти записи в то, к чему люди возвращаются, разбирает
&lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-page/&quot;&gt;как сделать страницу changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Всё равно примите спецификацию. Она стоит вечера, делает вторую проблему решаемой, и всё ещё
лучшая страница, когда-либо написанная об этом.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Является ли Keep a Changelog стандартом?&lt;/strong&gt;
Это широко принятая конвенция, а не спецификация органа стандартизации. Инструменты (скрипты
релиза, линтеры, парсеры) достаточно часто предполагают её форму, чтобы её следование покупало
совместимость.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Что попадает в раздел Unreleased?&lt;/strong&gt;
Каждая запись для изменения, которое было объединено, но ещё не выпущено в пронумерованном
релизе. Когда релиз выпускается, раздел переименовывается в версию и дату, а новый, пустой
раздел Unreleased идёт над ним.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должен ли changelog использовать семантическое версионирование?&lt;/strong&gt;
Keep a Changelog рекомендует это и не требует. Библиотеки и API от этого выигрывают; непрерывно
развёртываемый сервис обычно заменяет это датами, что формат допускает.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли исправления безопасности быть в changelog до того, как они публичны?&lt;/strong&gt;
Добавьте запись, когда исправление выпущено, с достаточной детализацией, чтобы оператор мог
действовать, и не более. Отложить запись до даты скоординированного раскрытия нормально;
опустить её — нет.&lt;/p&gt;
</content:encoded></item><item><title>Лучшие практики release notes, которые важны</title><link>https://changeloop.dev/blog/ru/release-notes-best-practices/</link><guid isPermaLink="true">https://changeloop.dev/blog/ru/release-notes-best-practices/</guid><description>Большинство списков лучших практик — это советы по стилю. Эти меняют поведение читателя, плюс три популярных, которые оказываются карго-культом.</description><pubDate>Fri, 28 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Важные лучшие практики release notes — это те, к которым прилагается последствие: пишите запись в
момент merge, называйте, кого это касается, указывайте требуемое действие даже когда его нет,
датируйте breaking change, ведите одну постоянную запись на изменение, группируйте по результату
и сохраняйте скучный раздел. Каждая меняет поведение читателя. Большинство остальных советов на
эту тему меняют то, как заметки выглядят.&lt;/p&gt;
&lt;p&gt;Поищите лучшие практики release notes, и получите советы по стилю: будьте ясны, будьте кратки,
используйте простой язык, добавляйте скриншоты. Ничто из этого не неверно, и ничто из этого ничего
не меняет, потому что ни одна команда никогда не садилась с намерением быть неясной. Практики ниже
идут вместе с ценой их пропуска, потому что практика без прикреплённого режима отказа — это просто
предпочтение.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Практика&lt;/th&gt;
&lt;th&gt;Цена пропуска&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Писать запись при merge, а не при релизе&lt;/td&gt;
&lt;td&gt;Восстановленные позже записи говорят «различные улучшения»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Называть, кого касается&lt;/td&gt;
&lt;td&gt;Каждый читатель решает, что это не про него&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Указывать требуемое действие, включая «никакого»&lt;/td&gt;
&lt;td&gt;Сорок одинаковых тикетов в поддержку, и читатели, предполагающие худшее&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Датировать breaking change, а не версионировать&lt;/td&gt;
&lt;td&gt;Дедлайн обнаруживают после того, как он прошёл&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Одна постоянная, ссылаемая запись на изменение&lt;/td&gt;
&lt;td&gt;Никто не может ответить «когда это изменилось»&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Группировать по результату, а не по системе&lt;/td&gt;
&lt;td&gt;Читателям нужна ваша архитектура, чтобы найти свой раздел&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Сохранять скучный раздел&lt;/td&gt;
&lt;td&gt;Служба безопасности, проверяющий соответствие и отлаживающий несовпадение версий теряют свой источник&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Какие лучшие практики для release notes?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Пишите запись, когда делаете merge, а не когда выпускаете релиз.&lt;/strong&gt;
Цена пропуска: человек, восстанавливающий релиз из истории коммитов, — не тот, кто внёс изменение,
и он угадает намерение. Записи, написанные две недели спустя, — это те, что говорят «различные
улучшения».&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Называйте, кого касается, по имени.&lt;/strong&gt;
«Команды на плане Business», «любой, кто использует API экспорта v1», «self-hosted установки на
Postgres 14». Цена пропуска: каждому читателю приходится выяснять, касается ли это его, и
большинство решит, что нет.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Указывайте требуемое действие, включая случаи, когда его нет.&lt;/strong&gt;
Цена пропуска: поддержка отвечает на один и тот же вопрос сорок раз, а читатели, не спросившие,
предполагают, что что-то требуется, и откладывают это.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Давайте breaking change дату, а не номер релиза.&lt;/strong&gt;
«Удалено в v5» ничего не значит для того, кто не следит за вашими релизами. «Перестаёт работать 1
ноября» значит одно и то же для всех. Цена пропуска: дедлайн обнаруживают после того, как он
прошёл. Что считается таковым, и чек-лист для выпуска, — в &lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;что такое breaking change&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ведите одну постоянную, ссылаемую запись на изменение.&lt;/strong&gt;
Письмо — не архив, а сообщение в Slack — не ссылка. Цена пропуска: никто не может ответить «когда
это изменилось» через шесть месяцев, включая вас. У письма всё же есть своя задача, разобранная в
&lt;a href=&quot;https://changeloop.dev/blog/ru/product-update-email/&quot;&gt;шаблоне письма об обновлении продукта&lt;/a&gt;; оно указывает на запись,
а не заменяет её.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Группируйте по результату, а не по системе.&lt;/strong&gt;
Цена пропуска: читателю приходится держать вашу архитектуру в голове, чтобы понять, какой раздел
относится к нему. Порядок, следующий из этого, — в
&lt;a href=&quot;https://changeloop.dev/blog/ru/how-to-write-release-notes/&quot;&gt;как писать release notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Сохраняйте скучный раздел.&lt;/strong&gt;
Обновления зависимостей и внутренние изменения остаются внизу, по одной строке каждое. Цена
пропуска: команда безопасности, проверяющий соответствие и отлаживающий несовпадение версий
теряют свой единственный источник. Чаще всего ошибаются в исправлениях;
&lt;a href=&quot;https://changeloop.dev/blog/ru/bug-fix-release-notes/&quot;&gt;release notes об исправлении багов&lt;/a&gt; показывает, как их писать,
чтобы читатель понимал, нужно ли ему действовать.&lt;/p&gt;
&lt;h2&gt;Какие лучшие практики changelog, и чем они отличаются?&lt;/h2&gt;
&lt;p&gt;Changelog — это справочник, поэтому его практики касаются полноты и структуры, а не убеждения.
Четыре важные:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Один фиксированный тип записи на строку.&lt;/strong&gt; Added, Changed, Deprecated, Removed, Fixed,
Security. Это не домашний стиль, а фильтр: именно он позволяет запросить «только breaking
change». Конвенция &lt;a href=&quot;https://changeloop.dev/blog/ru/keep-a-changelog-implemented/&quot;&gt;Keep a Changelog&lt;/a&gt; — обычный
источник.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Раздел неопубликованного.&lt;/strong&gt; Место, где записи живут между merge и релизом. Его отсутствие —
причина, по которой команды пишут записи поздно.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Даты ISO.&lt;/strong&gt; &lt;code&gt;2026-08-28&lt;/code&gt;, а не &lt;code&gt;28/08/26&lt;/code&gt;, что означает два разных дня в зависимости от
читателя.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Одна запись на изменение, а не на коммит.&lt;/strong&gt; Три коммита, исправляющие один баг, — это одна
запись.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Оба артефакта подробно сравниваются в &lt;a href=&quot;https://changeloop.dev/blog/ru/changelog-vs-release-notes/&quot;&gt;changelog vs release notes&lt;/a&gt;;
короткая версия — практики changelog защищают полноту, а практики release notes защищают
внимание.
&lt;a href=&quot;https://changeloop.dev/blog/ru/private-release-notes-enterprise/&quot;&gt;Приватные release notes для enterprise-клиентов&lt;/a&gt;
разбирает версию этого, возникающую, только когда ваши клиенты больше не все на одной сборке: те
же цели полноты и внимания, но откалиброванные по аккаунту вместо рассылки всем сразу.&lt;/p&gt;
&lt;h2&gt;Три, оказывающиеся чистым карго-культом&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Эмодзи как типы записей.&lt;/strong&gt; Ракета и гаечный ключ — это не таксономия. Они выглядят аккуратно и
не могут быть отфильтрованы, отсортированы или полезно прочитаны программой чтения с экрана.
Используйте слова, а если хотите эмодзи, ставьте его после слова.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Семантические номера версий как заголовки для размещённого продукта.&lt;/strong&gt; Semver — это обещание о
совместимости API. Для продукта SaaS, где никто не выбирает свою версию, номер версии в заголовке
— это внутренний архив, замаскированный под новость. Держите semver в changelog и вне анонса.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Публикация по расписанию независимо от содержания.&lt;/strong&gt; Ежемесячные заметки без содержания учат
людей, что ваши заметки — это шум. Публикуйте, когда есть что сказать. Changelog покрывает
остальное.&lt;/p&gt;
&lt;h2&gt;Та, что действительно сложна&lt;/h2&gt;
&lt;p&gt;Поддержание changelog и анонса в согласии, без написания всего дважды.&lt;/p&gt;
&lt;p&gt;Большинство команд начинают с одной страницы, разделяют её, когда аудитории расходятся, а затем
тихо позволяют одной из двух сгнить, обычно changelog, потому что у него нет прикреплённого
дедлайна. Выход структурный, а не дисциплинарный: храните записи как данные с типом, датой и
аудиторией, и относитесь к обеим поверхностям как к отображениям этого. Наш обзор
&lt;a href=&quot;https://changeloop.dev/changelog-tools&quot;&gt;инструменты для changelog&lt;/a&gt; охватывает, что доступно для этого, включая
инструменты, с которыми мы конкурируем, а страница &lt;a href=&quot;https://changeloop.dev/beamer-alternative&quot;&gt;альтернатива Beamer&lt;/a&gt; —
честное сравнение с виджетом, с которого начинает большинство команд.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;Шаблон release notes&lt;/a&gt; — это место, где живёт этап отбора, как только
записи существуют.&lt;/p&gt;
&lt;h2&gt;Если вы внедряете только одно&lt;/h2&gt;
&lt;p&gt;Пишите запись в момент merge, в фиксированном формате, с типом. Каждая другая практика на этой
странице становится проще, как только эта на месте, и ни одна не выживает без неё.&lt;/p&gt;
&lt;h2&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Должны ли release notes иметь скриншоты?&lt;/strong&gt;
Только того, что изменилось, в действии. Скриншот страницы настроек, которую никто не посещал,
добавляет прокрутку, а не информацию. Текст, называющий результат и затронутого читателя,
побеждает изображение, не показывающее ни того, ни другого.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Как писать release notes для breaking change?&lt;/strong&gt;
Сначала дата, потом затронутые вызывающие стороны, потом требуемое действие, потом миграция.
Никогда не начинайте с номера версии. Полная форма с примером записи — в
&lt;a href=&quot;https://changeloop.dev/blog/ru/breaking-changes/&quot;&gt;что такое breaking change&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Должны ли release notes писаться инженерией или маркетингом?&lt;/strong&gt;
Составлены инженером, внёсшим изменение, в момент merge, и отредактированы кем-то, кто читает их
как посторонний. Ни то ни другое само по себе не создаёт заметки, на основе которых клиент может
действовать.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Какой идеальный формат для release notes?&lt;/strong&gt;
Сначала элементы с дедлайном, потом новые возможности, потом улучшения, потом список по одной
строке для остального. &lt;a href=&quot;https://changeloop.dev/release-notes-template&quot;&gt;Шаблон release notes&lt;/a&gt; — это формат в виде
страницы для заполнения.&lt;/p&gt;
</content:encoded></item></channel></rss>