Задачи и баг-репорты: как описать, чтобы поняли с первого раза
Есть один измеримый критерий хорошего тикета, и он не про грамматику: исполнитель может начать работу, не задав ни одного вопроса. Всё остальное — стиль, артикли, выбор между behaviour и behavior — второстепенно по отношению к этому. Тикет, после которого прилетело «Could you clarify what exactly you did?», не выполнил свою функцию, даже если написан безупречным английским. Тикет с тремя грамматическими ошибками, по которому человек за две минуты воспроизвёл баг, свою функцию выполнил.
Это соотношение стоит держать в голове всю главу, потому что оно снимает главный страх: писать в трекер на плохом английском не стыдно, писать неинформативно — дорого. Плохой английский стоит читателю секунд. Отсутствующие шаги воспроизведения стоят ему круга уточнений: в распределённой команде это от двенадцати часов до двух суток календарного времени на один вопрос. Английский в тикете — инструмент сжатия: чем точнее формулировка, тем меньше кругов.
Второе, что важно понять до всех правил: ваш читатель, скорее всего, тоже не носитель. В типичной международной команде английский — второй язык для большинства участников. Это меняет требования. Идиомы, сарказм, разговорные сокращения и длинные условные конструкции работают против вас. Простые времена, короткие предложения, термины из репозитория и цифры — работают. Инженерный английский в трекере ближе к языку авиационных чеклистов, чем к языку эссе; почему это не бедность, а инженерное решение, разбирается отдельно в главе Ясность.
Эта глава — про механику текста в трекере. Она не про процесс работы с багами (это тестирование и поддержка), не про формулировку требований (это системный анализ) и не про приоритизацию бэклога (это Scrum). Здесь — что именно написать буквами, как это прочитает получатель и как переписать.
Кто читает ваш тикет и в каком режиме
Тикет читают минимум три разных человека в трёх разных режимах, и они предъявляют к тексту несовместимые требования. Пока эта модель не в голове, непонятно, почему «и так же всё написано» не работает.
Триажер просматривает список из сорока новых issue. На каждый у него пять-десять секунд, и он видит только заголовок и ярлыки — тело не открывает. Его задача: решить, это баг или вопрос, кому это принадлежит, срочно ли. Всё, что не поместилось в первые ~60 символов заголовка, для него не существует.
Исполнитель открыл тикет и пытается воспроизвести. Ему нужны шаги, окружение, версия, точный текст ошибки и разница между ожидаемым и фактическим. Его блокирует любая дырка: неизвестная версия, «в некоторых случаях», скриншот вместо текста ошибки.
Археолог — вы сами через восемь месяцев, или новый человек в команде, который через год ищет, почему код выглядит вот так. Он придёт через поиск по словам и через ссылку из коммита. Ему нужно, чтобы в тексте были те слова, по которым ищут: имя эндпоинта, код ошибки, имя компонента.
за 5 секунд?"} B -->|нет| B1["Ярлык needs-info,
тикет уходит в конец очереди"] B -->|да| C{"Есть шаги, версия,
текст ошибки?"} C -->|нет| C1["Круг уточнений:
+1 сутки календаря"] C1 --> A C -->|да| D{"Отделено наблюдение
от догадки?"} D -->|нет| D1["Исполнитель проверяет
чужую гипотезу вместо симптома"] D -->|да| E["Работа начинается
в первый же час"] D1 --> C1 classDef bad fill:#c25f5f22,stroke:#c25f5f,color:#8a8f98 classDef good fill:#4f9d6922,stroke:#4f9d69,color:#8a8f98 class B1,C1,D1 bad class E good
Отсюда практический вывод, который определяет всю структуру текста: заголовок — это интерфейс, тело — реализация. Заголовок пишется для того, кто не откроет тикет. Тело — для того, кто откроет и будет по нему работать. Это два разных текста с разными правилами, и путать их — самая частая структурная ошибка.
Сколько стоит один недостающий факт
Арифметика простая и неприятная. Команда распределена по часовым поясам с разницей 6–9 часов. Вы отправили неполный репорт в 18:00 по своему времени. Исполнитель увидел его в свой рабочий день, задал вопрос, вы уже спите. Вы ответили следующим утром, он спит. Один недостающий факт — примерно сутки календаря; два вопроса подряд, заданные последовательно, — двое суток.
которые помещались в первое сообщение
Никакого исследования тут нет — есть арифметика асинхронности, проверяемая на собственном трекере за пять минут. Вывод: полнота репорта важнее языковой чистоты ровно настолько, насколько сутки дороже секунд. Отсюда правило: сомневаетесь, включать ли факт, — включайте; лишняя строчка стоит читателю секунду, недостающая — сутки. Про асинхронный режим целиком — глава Асинхронная переписка.
Заголовок: одна строка, которую прочитают все
У заголовка своя грамматика, отличная от грамматики обычного предложения. Она называется телеграфным стилем и устроена так: подлежащее-система, глагол наблюдаемого
поведения, условие. Артикли в начале допустимо опускать (Export fails…, а не The export fails…), точка в конце не ставится, восклицательные знаки не ставятся никогда.
Глагол решает больше, чем всё остальное
Самая частая формулировка русскоязычного инженера — doesn't work — не содержит информации. Сравните, что сообщают глаголы, каждый из которых означает свой класс проблемы:
| Глагол | Что он сообщает читателю | Куда он направит первый взгляд |
|---|---|---|
fails |
операция завершилась неуспехом, есть явный отказ | код возврата, обработчик ошибки |
returns 500 |
ответ пришёл, но неуспешный | логи сервера, стектрейс |
returns stale data |
ответ успешный, но содержимое неверное | кэш, репликация, инвалидация |
times out |
ответа не было в отведённое время | таймауты, блокировки, медленный запрос |
hangs |
процесс не завершается и не отдаёт ошибку | дедлок, бесконечный цикл, ожидание ресурса |
crashes |
процесс аварийно завершился | дамп, сигнал, паника |
throws NullPointerException |
конкретное исключение | точное место в коде |
leaks memory |
потребление растёт без возврата | профилирование |
Это не список полезных фраз для заучивания — это карта диагнозов. Выбирая глагол, вы уже делаете половину триажа: times out и crashes попадут к разным людям. Именно поэтому
doesn't work бесполезно: оно не сужает поиск ни на шаг.
Время глагола сообщает воспроизводимость
Здесь есть тонкость, которую почти никто не проговаривает, а носитель считывает автоматически:
- Present simple —
Export times out for ranges longer than 31 days— читается как «это свойство системы, воспроизводится». Это норма для баг-репорта. - Past simple —
Export timed out during the release on 14 March— читается как «был единичный случай в прошлом». Это норма для инцидента и постмортема, но в обычном баг-репорте создаёт впечатление, что проблема уже неактуальна. - Present continuous —
Export is timing out— читается как «прямо сейчас, возможно временно». Уместно в чате во время инцидента, неуместно в заголовке issue: через неделю непонятно, о чём речь.
Ошибка «написал past simple про воспроизводимый баг» приводит к предсказуемому итогу: тикет закрывают как not reproducible, потому что читатель понял, что речь про разовое
событие. Про язык инцидентов и то, чем он отличается, — SRE: реагирование на инциденты.
Разбор реальных заголовков
Ниже — формулировки, которые действительно приходят в трекеры, и то, как они читаются на той стороне.
1. Bug in export → «здесь что-то есть, разбирайтесь сами». Слово bug в заголовке избыточно: тикет уже лежит в трекере багов и имеет ярлык. Родственный случай —
Export doesn't work correctly: correctly сообщает, что вы знаете, как правильно, но не говорите, а проверить «правильность» читатель не может. Переписываем:
CSV export writes the header twice when the report has more than 1000 rows.
2. URGENT!!! Production is down!!! → капслок и восклицательные знаки не ускоряют реакцию, а расходуют доверие: если следующий тикет действительно про падение, ему уже не
поверят. Кроме того, для инцидентов в норме есть отдельный канал, а не трекер. Переписываем: Checkout API returns 503 for all requests since 14:20 UTC. Факт со временем
работает быстрее любых знаков препинания.
3. Can't login → чей логин, какой метод, какая ошибка? Заголовок из двух слов вынуждает открыть тело — а триажер тело не открывает. Переписываем: SSO login fails with "invalid_grant" for users whose email was changed in the last 24 hours. Длинно, но это ровно та строка, которую через полгода найдут поиском.
4. Fix the retry logic → это не описание проблемы, а готовое решение. Заголовок-решение опасен тем, что закрывает обсуждение: если ваш диагноз неверен, никто уже не
проверит симптом. Переписываем: Payment retries fire three times within one second, which triggers rate limiting. Решение — в теле, отдельным абзацем.
Полезная проверка на английский: если заголовок можно поставить в предложение We reproduced that ______, и получится осмысленная фраза — заголовок описывает наблюдаемое
поведение. We reproduced that export times out for large ranges — работает. We reproduced that fix the retry logic — очевидно нет.
Тело: четыре блока и четыре вопроса
Канонический скелет баг-репорта существует не одно десятилетие и почти не менялся: он есть в руководстве Mozilla по написанию багов, в правилах Chromium и в классическом эссе Саймона Тэтхэма «How to Report Bugs Effectively», написанном ещё в 1999 году и не устаревшем ни на строчку. Четыре обязательных блока отвечают на четыре вопроса читателя — «как повторить», «чего вы ждали», «что получилось», «где это было»; пятый, Notes, существует для гипотез.
## Summary
Report export times out for date ranges longer than 31 days.
## Steps to reproduce
1. Sign in as a user with the `analyst` role.
2. Open **Reports → Sales**.
3. Set the date range to 01 Jan – 15 Feb.
4. Click **Export to CSV**.
## Expected
The browser downloads a CSV file within 30 seconds.
## Actual
The request to `POST /v1/reports/export` returns 504 after 60 seconds.
Response body: `{"error":"gateway_timeout","request_id":"8f21ac"}`
Reproduced 5 out of 5 times.
## Environment
App 4.2.1 (build 3921), Chrome 126, macOS 14.5, tenant `acme-eu`, region `eu-central-1`.
## Notes
Ranges of 30 days or less finish in about 4 seconds, so the boundary looks like the
31-day mark. I have not checked whether the timeout is in the gateway or in the worker.
Разберём язык каждого блока — здесь есть несколько неочевидных вещей.
Steps to reproduce — императив, по одному действию на строку. Правильно: Open the settings page. Неправильно: We should open the settings page (это не инструкция, а
предложение обсудить), I opened the settings page and then I clicked… (рассказ от первого лица, читателю приходится вылавливать действия из повествования) и You need to open settings (лишняя модальность). Императив в английском не звучит грубо в инструкциях — это стандартный жанровый регистр, тот же, что в документации; Google developer
documentation style guide прямо предписывает императив для процедур. Одно действие на строку — чтобы читатель мог сказать
«у меня получилось до шага 3».
Expected и Actual — оба в present simple, оба про наблюдаемое. Частая ошибка: The system must return 200. Глагол must в техническом английском занят: он означает
нормативное требование в смысле RFC 2119 — об этом подробно в главе Стандарты и RFC. В
баг-репорте вы не выдвигаете требование, вы описываете расхождение, поэтому: Expected: the endpoint returns 200 with the updated record. Если хочется сослаться на источник
ожидания — это отдельное предложение: The API reference says this endpoint returns 200 on success.
Actual — это цитата, а не пересказ. It shows an error бесполезно. Нужен точный текст: код статуса, тело ответа, идентификатор запроса, первая строка стектрейса. Текстом,
а не скриншотом: по скриншоту нельзя искать, нельзя скопировать в grep и его не прочитает человек со скринридером. Про то, как читать и цитировать чужие ошибки и логи, — глава
Сообщения об ошибках и логи.
Environment — цифры, а не прилагательные. Latest version — худший ответ на вопрос о версии: «последняя» у вас и у читателя это разные сборки, и через месяц строка станет
ложью. Здесь же классический ложный друг: actual version по-русски значит «актуальная», а по-английски читается «фактическая» и никак не означает «текущая». Нужное слово —
current. Окружение проще не описывать словами, а собирать командой:
# Собрать окружение одной командой и приложить вывод к тикету:
# так исключаются опечатки в номерах версий и споры про «последнюю» сборку
{
echo "app: $(myapp --version)"
echo "os: $(uname -srm)"
echo "runtime: $(node --version 2>/dev/null || echo 'n/a')"
echo "commit: $(git rev-parse --short HEAD)"
} | tee environment.txt
Notes — место для гипотез, и только там. Всё, чего вы не проверили, живёт в этом блоке и помечено как непроверенное. Почему это отдельная дисциплина — ниже.
Отделять наблюдение от догадки
Это самое ценное умение в баг-репорте и одновременно то, что хуже всего переносится из русского. В русском гипотезу часто маркируют интонацией и вводными словами («да там
наверняка кэш»), а при переводе интонация теряется, и остаётся голое утверждение: This is a caching problem. Читатель принимает его за факт, идёт проверять кэш, теряет полдня
и возвращается недовольным.
Английский маркирует степень уверенности модальностью и структурой предложения, и делает это жёстче русского. Работают три средства.
Модальные глаголы. may, might, could понижают уверенность примерно до «возможно»; should в предположении означает «по идее должно» и часто звучит как претензия;
must — уже разобранный случай нормативного требования. Практическая разница: This might be a caching issue — гипотеза, This should be a caching issue — странно, This is a caching issue — утверждение факта, за которое вы отвечаете.
Глаголы восприятия. seems, appears, looks like переводят фразу из режима факта в режим наблюдения: The response appears to come from cache — «выглядит так, что».
Носитель прочитает это как «я вижу признаки, но не доказал». Это честнее, чем is, и мягче, чем ничего не говорить.
Прямое признание границы проверки. Самая сильная и самая недооценённая конструкция — просто сказать, чего вы не делали: I have not checked whether…,
I could not reproduce this on staging, I only tested with the EU tenant. Никакой модальности не нужно, граница знания названа явно. Русскоязычные инженеры часто
избегают таких фраз, опасаясь выглядеть некомпетентно; эффект ровно обратный — читатель видит человека, который различает, что он знает и что предполагает.
Опасен левый верхний квадрант — уверенное утверждение без проверки. Правый нижний тоже стоит денег: если вы проверили, но написали maybe, читатель перепроверит за вами. Хедж
должен быть пропорционален незнанию, а не вежливости.
Задача — это не баг
Для задачи (feature, task, chore) структура другая, потому что другой вопрос у читателя. У бага вопрос «что сломано»; у задачи — «что должно стать правдой, когда всё готово». Отсюда правило формулировки: задача описывает результат, а не действие.
Refactor the payment module— действие. Непонятно, когда закончится и как проверить.Payment retries are capped at three attempts per minute— результат. Проверяемо, спорить можно по существу.
Заголовок задачи в английском обычно пишут либо повелительным наклонением как команду репозиторию (Add rate limiting to payment retries — тот же стиль, что в сообщениях
коммитов, см. Коммиты и pull request), либо декларацией результата в present simple. Смешивать в одном трекере не стоит: список
выглядит неряшливо и хуже сканируется.
Критерии приёмки на английском чаще всего пишут в форме Gherkin, и это редкий случай, когда грамматика действительно важна — потому что фразы парсятся инструментами и читаются вслух на груминге:
Feature: Access token refresh
# Given — состояние до действия: артикль "a" вводит нового участника,
# дальше по тексту этот же участник идёт с "the"
Scenario: Refreshing a token that has already expired
Given a user with a refresh token that expired 10 minutes ago
When the client sends POST /v1/auth/refresh
Then the API responds with 401
And the response body contains the code "token_expired"
Три языковые вещи, которые здесь стоит заметить. Первое: Given — это состояние, поэтому глагол в прошедшем или в форме причастия (a token that expired), а не
последовательность действий. Второе: When — ровно одно действие, present simple, третье лицо (sends, не send). Третье: Then — наблюдаемый результат, тоже present
simple; распространённая калька Then the API should respond with 401 формально принята во многих командах, но should снова тащит за собой оттенок требования — декларативное
responds точнее. Содержательная сторона критериев приёмки — в главе Критерии приёмки, а форматы user story — в
Анализ в Agile.
Отдельно про шаблон As a <role>, I want <feature> so that <benefit>. Он полезен, когда роль и польза действительно неочевидны. Он звучит фальшиво и раздражает, когда им
оборачивают техническую задачу: As a developer, I want to upgrade the library so that the library is upgraded — реальная строчка из реального бэклога, и таких много. Если
польза не формулируется без тавтологии — шаблон не нужен, пишите задачу декларацией результата.
Жизненный цикл: что означают слова на кнопках
Статусы и резолюции трекера — это готовые английские формулировки, которые вы будете и читать, и писать. У каждой есть точное значение и социальный вес, который русскоязычные инженеры часто недооценивают.
duplicate — нейтрально, но требует ссылки: Closing as a duplicate of #482 — the root cause is the same. Без ссылки читается как «отстань». То же с автоматическим
stale: закрытие по таймауту допустимо только с оговоркой This is not a judgement on the report — please comment and it will be reopened.
wontfix — самая резкая из резолюций: буквально «не будем чинить», и без объяснения она портит отношения с внешним репортёром. Принято сопровождать причиной и оговоркой:
Closing as wontfix for now — the workaround in #514 covers the reported case, and the fix would require breaking the public API. Happy to revisit if more users hit this.
Здесь работают for now и happy to revisit: они превращают отказ из окончательного в пересматриваемый, ничего при этом не обещая.
not reproducible / cannot reproduce — тут важно не написать так, будто вы обвиняете репортёра во лжи. Разница между I cannot reproduce this и
This does not happen огромна: первое — про вас и вашу попытку, второе — про мир и звучит как «вы выдумали». Рабочая формулировка называет, что именно вы пробовали:
I could not reproduce this on 4.2.1 with a clean profile, 10 attempts. Could you check whether it still happens on the current build and share the request id?
works as intended (WAI) — уместно, только если поведение действительно задокументировано. Если оно нигде не описано, WAI читается как «нам лень», и по существу это баг
документации: The behaviour is intentional, but it was not documented — I opened #620 to fix the docs.
Как просить недостающую информацию
Отдельный навык — попросить факты так, чтобы человек их прислал, а не обиделся и ушёл. Три приёма, каждый со своей причиной:
- Спрашивать конкретное, а не «подробности».
Could you add more details?перекладывает работу обратно и почти всегда получает такой же расплывчатый ответ. Работает список:Two things would help: the exact error text and the app version from Settings → About. - Называть, зачем.
I need the request id to find the trace on our side— человек понимает, что его не гоняют по кругу, и находит id охотнее. - Не начинать с обвинения.
You did not provide the steps(вы не предоставили) — обвинительная конструкция во втором лице.The steps are missingилиI could not tell from the description how to get to that screenописывают ситуацию, а не проступок. Механика «сказать про работу, а не про человека» подробно разобрана в главе Обратная связь, а её применение к ревью — в следующей главе трека.
Срочность: как эскалировать по-английски
ASAP, urgent, please fix quickly не ускоряют ничего. Причина не в вежливости: эти слова не содержат информации, по которой можно принять решение о приоритете.
Приоритет считается из трёх вещей — что не работает, у скольких, до какого момента это терпит. Формулируйте их, и срочность возникнет сама:
This blocks the 4.2 release: QA cannot sign off on checkout until it is fixed. Code freeze is on Thursday.All EU tenants are affected — about 2 300 accounts. Users can still pay through the old flow, so there is a workaround.This is a regression: it worked in 4.1.7 and broke in 4.2.0.
Слово regression — одно из немногих, которое действительно поднимает приоритет само по себе, потому что означает «мы это уже умели и сломали». Так же работает
blocker в его процессном смысле: «дальше нельзя двигаться». Оба слова стоит употреблять точно: если вы называете блокером то, что блокером не является, в следующий
раз вам не поверят — а других способов сказать «правда очень срочно» у вас нет.
Кальки и ложные друзья, которые встречаются в тикетах чаще всего
Ниже — не словарь, а разбор конкретных строк, которые действительно приходят в трекеры от русскоязычных инженеров. У каждой: что написано, как это читает получатель, как переписать.
| Написано | Как читается | Как надо |
|---|---|---|
actual version 4.2 |
«фактическая версия» — читатель ищет, чему она противопоставлена | current version 4.2 |
I will realize this feature |
«я осознаю эту функциональность» | I will implement this feature |
We need to decide this problem |
«принять решение по проблеме» вместо «решить» | We need to solve this problem |
Please control the queue length |
control = управлять, а не наблюдать |
Please monitor the queue length |
incorrect work of the service |
work не значит «функционирование» |
the service returns wrong totals |
The bug reproduces on staging |
reproduce в английском переходный: баг сам себя не воспроизводит |
The bug is reproducible on staging / I can reproduce it on staging |
on production |
предлог не тот, идиома фиксированная | in production |
Sorry for my bad English |
привлекает внимание к языку вместо содержания и снижает вес сообщения | ничего не писать |
informations, feedbacks, advices |
эти существительные неисчисляемые, множественное число невозможно | information, feedback, advice |
It is not working normally |
normally = «в обычном режиме», а не «нормально» |
It fails with a 500 on every second request |
How I can reproduce it? |
порядок слов утвердительный в вопросе | How can I reproduce it? |
We must fix it (в описании бага) |
must = нормативное требование по RFC 2119 |
This needs to be fixed before the release |
Please, fix it asap |
запятая после Please — русская пунктуация, asap — давление без информации |
This blocks the release on Thursday |
Про артикли отдельно и честно. В тикетах они ломают смысл редко — и именно поэтому не стоит тратить на них основные силы. Практический минимум, который закрывает большинство
случаев: первое упоминание объекта — a/an, все последующие — the (I created a report; the report was empty); единственные в системе сущности — всегда the (the database, the API, the main branch); имена собственные и продукты — без артикля (Postgres, Kafka, Chrome); неисчисляемые — без артикля (traffic, latency, data,
memory). Одно место, где артикль действительно меняет смысл и стоит проверки: I checked the log (тот самый, о котором речь) против
I checked a log (какой-то один из многих) — во втором случае читатель обязан спросить, какой именно. Систематический разбор ошибок русскоязычных инженеров — в главе
Типичные ошибки.
Шаблон, который делает часть работы за вас
Шаблон не научит писать, но он делает пропуск факта заметным. В GitHub для этого есть issue forms — YAML-описание формы с обязательными полями; в отличие от markdown-шаблонов, поля нельзя молча стереть. Документация — Configuring issue templates.
# .github/ISSUE_TEMPLATE/bug_report.yml
name: Bug report
description: Report a reproducible defect
title: "bug: " # префикс подставится в заголовок автоматически
labels: ["bug", "needs-triage"]
body:
- type: input
id: version
attributes:
label: Version
description: Exact build you observed this on, not "latest"
placeholder: "4.2.1 (build 3921)"
validations:
required: true # без версии форму не отправить
- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: One action per line, starting from a known state
value: |
1.
2.
3.
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual result
description: Paste the exact error text or status code, not a screenshot
validations:
required: true
- type: dropdown
id: frequency
attributes:
label: How often does it happen?
options: # частота отвечает на вопрос «стоит ли ловить гонку»
- Every time
- Occasionally
- Once, could not reproduce again
validations:
required: true
Шаблон закрывает пропуски, но не качество формулировок. Перед отправкой проще прогнать текст по пяти вопросам:
- Первые 60 символов заголовка содержат компонент и наблюдаемый глагол?
- Может ли человек, впервые видящий систему, дойти по шагам от известного состояния до поломки?
- Текст ошибки приведён текстом, а не картинкой, и версия указана числом, а не словом
latest? - Каждая догадка помечена как догадка (
might,appears,I have not checked)? - Если тикет закрывают вопросом — какой это вопрос? Ответьте на него заранее.
Особые случаи, где обычные правила не работают
Уязвимость не публикуют в трекере. Публичный issue с воспроизведением уязвимости — это раздача эксплойта. Английский тут ритуализирован: ищется SECURITY.md, приватный
advisory или адрес вида security@, а первое сообщение короткое и без деталей: I would like to report a possible security issue in the authentication flow. Could you confirm the right private channel? Контекст — трек Безопасность.
Инцидент — не баг. Во время инцидента пишут в канал коротко, в present continuous, с временными метками и без гипотез: Checkout is returning 503 for all regions since 14:20 UTC. Investigating. Баг заводится потом, из постмортема, и в нём уже past simple. Разница жанров разобрана в Постмортемах.
Баг в чужой опенсорс-библиотеке. Вы просите об одолжении у человека, который делает это бесплатно: никаких сроков и требований. Обязателен минимальный воспроизводимый
пример (в английском его устойчиво зовут MCVE — minimal complete verifiable example): не проект целиком, а двадцать строк, которые падают. Нормы таких обращений разобрал Эрик
Реймонд в «How To Ask Questions The Smart Way»; плюс строчка, сразу поднимающая ваш статус в глазах мейнтейнера:
Searched the existing issues and did not find this.
Баг, который вы не можете воспроизвести. Соблазн — не заводить вовсе. Правильнее завести и честно сказать об этом в заголовке и теле: Intermittent 502 on checkout — could not reproduce reliably (3 occurrences in 2 weeks). Слово intermittent — точный отраслевой термин для «плавает», а числа в скобках превращают «иногда» в данные. Плюс всё, что
есть: время каждого случая, request id, любые совпадения. Такой тикет полезен: следующий человек с тем же симптомом найдёт его поиском и добавит свои три случая.
Мини-итог
- Критерий качества тикета один: исполнитель начинает работу, не задав ни одного вопроса. Грамматика вторична, полнота — нет.
- Заголовок и тело — два разных текста. Заголовок пишется для триажера, который не откроет тикет: компонент, наблюдаемый глагол, условие, всё в первых 60 символах.
- Глагол в заголовке — это уже диагноз:
times out,crashes,returns stale dataнаправляют разных людей в разные места.doesn't workне направляет никуда. - Present simple означает «воспроизводится», past simple — «был единичный случай». Перепутанное время меняет судьбу тикета.
- Steps — императив, по одному действию на строку; Expected/Actual — present simple, без
must: оно занято нормативным смыслом из RFC 2119. Actual — точная цитата ошибки текстом, а не скриншот; версия — числом,latestне является версией. - Догадка помечается модальностью (
might,appears to) или прямым признанием границы (I have not checked…): уверенное утверждение без проверки — самая дорогая ошибка. - Задача описывает результат, а не действие.
As a…, I want…не обязателен и вреден там, где польза формулируется тавтологией. - Резолюции — это слова с весом:
wontfixбез объяснения ломает отношения,cannot reproduceформулируется про себя (I could not reproduce), а не про репортёра. - Срочность выражается фактами — что сломано, у скольких, до какого срока, — а не словами
urgentиASAP.regressionиblockerработают, пока употребляются точно.
Материалы
- Simon Tatham. How to Report Bugs Effectively — эссе 1999 года, до сих пор лучший короткий текст на тему.
- Mozilla. Bug writing guidelines и Chromium. Bug reporting guidelines — каноническая структура репорта в двух больших проектах.
- Eric S. Raymond. How To Ask Questions The Smart Way — нормы общения в опенсорс-сообществах; Joel Spolsky. Painless Bug Tracking — про минимальный набор полей и почему больше не нужно.
- Google. Developer documentation style guide — императив, времена, тон; применимо к тикетам почти целиком.
- Gherkin Reference — синтаксис Given/When/Then, и ISTQB Glossary — точные значения
error,defect,failure: их путают чаще всего. - plainlanguage.gov guidelines — правила простого английского, написанные для госдокументов и отлично работающие в трекере.
Что дальше
Тикет вы написали — дальше начинается разговор о коде, и там язык устроен ещё жёстче: одна неудачно выбранная конструкция в комментарии на ревью превращает техническое замечание в личную претензию, причём вы об этом не узнаете. Как формулировать возражения, требовать изменений и отклонять чужой подход, оставаясь в рабочих отношениях, — в следующей главе.