Шаблон запроса функции, становящийся changelog
5 мин чтения
Шаблон запроса функции — это форма с четырьмя вопросами: что пытается сделать человек, что его останавливает, что он попробовал вместо этого, и как он хочет быть уведомлён, когда это будет готово. Всё остальное, что обычно появляется на такой форме, селекторы приоритета, оценки усилий, баллы бизнес-ценности, предназначено для команды, получающей запрос, и неправильно заполняется отправителем.
Аккуратные запросы — неправильный тест для шаблона. Правильный: шесть месяцев спустя, когда функция выпущена, может ли кто-то найти запрос, понять его, и уведомить человека, который его написал? Большинство шаблонов спроектированы для приёма. Этот спроектирован для дня, когда петля замыкается.
Что должен включать шаблон запроса функции?
Он должен включать цель, блокер, обходной путь, и путь обратно к запросившему. Четыре поля, в этом порядке, каждое отвечает на вопрос, который команда задаст позже.
| Поле | Вопрос, на который отвечает позже | Почему оно в форме |
|---|---|---|
| Что вы пытаетесь сделать? | Была ли построенная функция той, что нужна? | Цель переживает любое конкретное предложение |
| Что вас останавливает сегодня? | Как выглядит «готово»? | Называет пробел, не предписывая исправление |
| Что вы делаете вместо этого? | Насколько это на самом деле срочно? | Болезненный обходной путь — более сильный сигнал, чем селектор приоритета |
| Как нам вас уведомить? | Кто получает сообщение «выпущено»? | Поле, которое чаще всего пропускают шаблоны |
Что намеренно отсутствует: предложенное решение как обязательное поле (желанное в комментарии, неверное как рамка), селектор приоритета (каждый отправитель выбирает высокий), и любая оценка усилий или ценности (работа команды, после триажа). Шаблон, просящий решение, получает запросы на кнопки; шаблон, просящий цель, получает запросы на результаты, и о результатах пишется запись changelog.
Шаблон
Это шаблон issue GitHub, который мы используем, в виде формы. Вставьте его в
.github/ISSUE_TEMPLATE/feature_request.yml, и он отрендерится как структурированная форма на
странице нового issue. Запросы, поданные через него, попадают как issue с теми же полями, что и
поданные через виджет обратной связи, что важно для следующего раздела.
name: Feature request
description: What you are trying to do, and what stops you.
labels: ["feature-request"]
body:
- type: textarea
id: goal
attributes:
label: What are you trying to do?
description: >-
The outcome, not the button. "Export a month of invoices as one
PDF" beats "add a PDF export".
validations:
required: true
- type: textarea
id: blocker
attributes:
label: What stops you today?
description: >-
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: >-
The spreadsheet, the script, the manual step. "Nothing, I gave
up" is a valid answer.
- type: input
id: contact
attributes:
label: How should we tell you when it ships?
description: >-
An email address, or leave blank to be notified only on this
issue.
Две детали выполняют работу. labels: ["feature-request"] означает, что запрос классифицируется
при создании, вместо того чтобы ждать, пока кто-то его триажирует. А последнее поле существует,
потому что «мы дадим вам знать» — это обещание, а обещанию нужен адрес.
Какие метки должен нести запрос функции?
Запрос функции должен нести одну метку для того, что он есть, одну для того, насколько он срочен, и одну для того, откуда он пришёл. Три метки, три оси, и каждую читает другая читательница.
| Метка | Значения | Кто читает |
|---|---|---|
| Тип | feature-request, bug | Кто решает, в какую очередь он попадает |
| Приоритет | priority:low, priority:medium, priority:high | Кто планирует следующий цикл |
| Источник | from-widget, from-form, from-support | Кто измеряет, откуда приходят запросы |
Виджет применяет первые две оси и from-widget, когда подаёт отправку как issue; from-form и
from-support предлагаются для запросов, приходящих другими путями. Метки виджета такие:
тип (bug или feature-request, решаемый классификатором только по сообщению),
приоритет (спокойный, конкретный отчёт о сбое высокий; дубликат чего-то уже спрошенного низкий;
всё, что даже намекает на проблему безопасности, — bug и высокий, независимо от формулировки),
и from-widget. Те же три оси работают для запросов, приходящих вручную через шаблон выше, и в
этом суть: запрос — это запрос, независимо от того, откуда он вошёл.
Ещё одна конвенция: виджет удаляет адрес электронной почты отправителя из тела issue перед подачей, потому что issue живёт в репозитории, который может быть публичным, и заменяет его ссылкой на отправку. Адрес в issue не попадает; отправитель следит за результатом в самом виджете. Делайте то же самое с полем контакта, если ваш трекер виден людям вне команды.
Как запрос функции становится записью changelog?
Запрос функции становится записью changelog, когда pull request закрывает issue, а запись,
составленная из этого pull request, связывается обратно. Механизм — собственные ключевые слова
закрытия GitHub: PR, чьё описание говорит Fixes #142, закрывает issue 142 при merge. Если ваши
записи changelog составляются из объединённых pull request, черновик может нести номер issue с
собой, и запись знает, кто спрашивал.
Вот почему шаблон просит цель вместо решения. Когда запись пишется, цель — это предложение, нужное автору: «Теперь вы можете экспортировать месяц счетов как один PDF» — это запись changelog. «Добавлен экспорт PDF» — это сообщение коммита. Инструменты для changelog, составляющие записи из pull request, могут выполнить сбор и связь; формулировка всё ещё нуждается в человеке, и человеку нужна цель.
Что происходит, когда это выпущено?
Запросивший уведомляется со ссылкой на запись. В нашей настройке это происходит автоматически для запросов, пришедших через виджет: комментарий, говорящий «Shipped — <заголовок записи>» со ссылкой на опубликованную запись, размещённый на issue, как только человек одобряет запись, а виджет показывает отправителю ту же запись. Issue, поданный вручную по этому шаблону, автоматического комментария не получает; замыкайте эту петлю сами, по тому же правилу. Комментарий намеренно размещается при одобрении, а не при merge: комментарий, говорящий, что что-то в эфире до того, как это так, — это нарушенное обещание с временной меткой. Каждый запрос уведомляется не более одного раза; второе одобрение той же записи не создаёт второй комментарий.
Если вы делаете это вручную, применяется то же правило. Не замыкайте петлю из pull request. Замыкайте её из опубликованной записи, и замыкайте один раз. Лента и виджет несут ту же запись всем, кто не спрашивал, что большинство; комментарий для тех, кто спрашивал.
Почему большинство шаблонов запросов функций проваливаются
Они спроектированы, чтобы облегчить триаж, и им это удаётся, ценой единственного момента, важного для запросившего. Шаблон с двенадцатью полями получает меньше запросов, а те, что получает, приходят от людей с терпением заполнить двенадцать полей, что не та же популяция, что нуждается в функции. Шаблон с четырьмя полями, одно из которых «как с вами связаться», получает больше запросов и может почтить каждый из них.
FAQ
Должен ли шаблон запроса функции спрашивать о приоритете? Нет. Спрашивайте вместо этого об обходном пути. «Я экспортирую в таблицу и перепечатываю каждую пятницу» говорит о приоритете больше, чем выпадающий список, который отправитель поставил на высокий.
Должны ли запросившие предлагать решение? Могут, в свободном тексте. Не делайте это рамкой. Запросы, написанные как решения, труднее объединять друг с другом и труднее превращать в запись changelog.
Должны ли запросы функций появляться в публичной roadmap? После планирования да: метка на том же issue помещает его в колонку запланировано, и запросивший может видеть, как он движется. Статья публичная roadmap — это механизм.
Как обрабатывать дубликаты?
Свяжите новый запрос с существующим issue и пометьте его низким приоритетом; не закрывайте его.
Каждый дубликат — ещё один человек для уведомления при выпуске. С автоматическим комментарием
Changeloop этот человек уведомляется, только если pull request называет и его issue
(Fixes #142, fixes #187).
Где должен жить шаблон? В репозитории, который получит pull request, чтобы работало ключевое слово закрытия. Запрос в отдельном трекере должен связываться вручную при merge, и именно этот шаг пропускается.
Технические утверждения в этой статье не проходили независимую проверку. Если здесь что-то не так, сообщите нам, и мы исправим.