Введение
В распределённой команде почти всё общение асинхронно. Ты пишешь сообщение — ответ приходит через восемь часов, когда коллега в Сан-Франциско открывает ноутбук и заваривает кофе. Отсюда единственное правило, из которого выводятся все остальные: сообщение должно быть самодостаточным. Переспросить и получить ответ через минуту не выйдет, поэтому каждый недостающий кусочек контекста стоит рабочего дня.
Разговор голосом устроен наоборот. Он итеративный: начал с «слушай, тут такое дело…», уточнил по ходу, договорились за три минуты. Перенеси эту привычку в чат — и каждый уточняющий вопрос обойдётся в сутки. Асинхронное сообщение ближе к баг-репорту из прошлой главы, чем к разговору у кофемашины.
Вторая тема главы — регистры. Одна и та же новость звучит совсем по-разному в командном чате, в письме коллегам из другой компании и в письме вендору, с которым у вас контракт. Разберём все три. Плюс сроки, часовые пояса и культурные различия — то, на чём спотыкаются, когда язык уже давно не проблема.
Правило «no hello»
Сцена, которую видел каждый. Коллега пишет Hi! и уходит ждать. Ты выныриваешь из задачи, отвечаешь Hi — и ждёшь уже ты. Настоящий вопрос прилетает минут через двадцать, когда он вернулся с кухни. Два выбитых контекста и полчаса на ровном месте — а вопрос был на одну строку. В англоязычной инженерной культуре так не делают, на эту тему есть даже сайт-мем nohello, ссылку на который в ответ иногда и присылают. Здоровайся и спрашивай в одном сообщении.
Bad (three messages, 20 minutes apart):
10:02 Hi!
10:02 Are you there?
10:21 I have a question about the deploy script
Good (one message):
10:02 Hi Marta! Quick question about the deploy script: it fails on
staging with "permission denied" on `/opt/releases`. Did the
service user change last week, or should I be using sudo there?
No rush — whenever you have a moment.
Приветствие, как видишь, на месте. Правило запрещает не здороваться, а тратить на приветствие отдельное сообщение с отдельным уведомлением. А приписка no rush в конце снимает ощущение аврала: она признаёт, что у человека есть своя работа и своя очередь задач.
Как задать вопрос, на который ответят
Три части: контекст (что делаю и зачем), что уже пробовал, конкретный вопрос. Третья часть должна быть именно вопросом, со знаком вопроса на конце. Описание проблемы вместо вопроса оставляет читателя гадать, чего от него хотят, — и он откладывает ответ на «когда будет время подумать».
Context: I'm adding the loyalty webhook to the staging environment.
Tried: I set `WEBHOOK_SECRET` in the app config and restarted the pods,
but requests still come back 401. I checked the secret matches
the one in 1Password and the logs show the header arriving.
Question: Is there a separate allowlist for staging webhooks, or should
the secret alone be enough?
На такое отвечают одной строкой и без единого уточняющего вопроса. К этому и стремимся. Блок «что пробовал» работает на два фронта: экономит собеседнику ход («не советуй проверить секрет — уже проверено») и показывает, что ты потратил своё время прежде, чем просить чужое.
Проблема XY — ловушка, в которую попадают все. Ты хочешь сделать X, решил, что для этого нужен Y, и спрашиваешь про Y. Тебе помогают с Y. Через час выясняется, что X делается совсем иначе и Y там не нужен вовсе. Час потерян у двоих. Лечение одно: называй исходную цель, даже если она кажется очевидной.
XY question:
How do I get the last 3 characters of a filename in bash?
Better (X and Y together):
I'm trying to get the file extension from a filename in bash — I was
going to take the last 3 characters, but that breaks for `.tar.gz`
and `.py`. Is there a standard way to do this?
Полезные формулы для обозначения цели: I'm trying to…, My end goal is…, The bigger picture is…, What I actually need is….
Треды, упоминания и служебные пометки
В Slack есть этикет, который никто не проговаривает вслух, а нарушения замечают все. Онбординг о нём молчит, узнают его по недовольным реакциям.
- Треды. Ответ на сообщение идёт в тред, а не в канал. Это держит контекст вместе и не будит сорок человек. Если результат обсуждения важен всем, в конце пишут в канал: Summary for the channel: we're going with option B, details in the thread.
- Упоминания.
@name— это уведомление, то есть выбитый у человека контекст. Ставь его, когда нужно действие именно от него.@hereдёргает всех, кто онлайн;@channel— вообще всех, включая тех, у кого сейчас три часа ночи. Второе — только для инцидентов, и лучше сначала спроси, принято ли так у вас. cc @name— «для сведения», действие не требуется. Пришло из email (carbon copy).FYI— for your information, просто чтобы ты знал.heads up— предупреждение о том, что скоро что-то произойдёт: Heads up: I'm restarting the staging DB in 10 minutes.for visibility— «чтобы было видно», обычно при пересылке в более широкий канал.bump— поднять старое сообщение, мягкое напоминание.
Heads up: I'm going to restart the staging database at 14:00 UTC.
It should be back in ~5 minutes. cc @qa-team
FYI, the vendor confirmed the outage on their side — no action needed
from us, I'll post an update when it's resolved.
@daniel could you take a look at the failing migration when you're back?
Not urgent, it only affects staging. Details in the thread.
Sharing here for visibility: the postmortem for yesterday's incident
is ready. Comments welcome until Friday.
Формулы: просьба, отказ, статус, напоминание
Девять десятых рабочей переписки — это несколько речевых актов, повторяющихся по кругу: попросить, отказать, отчитаться, напомнить. Выучи их готовыми блоками, как выучил for и if. Голова освободится под содержание.
Обычная просьба. Смягчение здесь работает: when you get a chance прямо говорит, что не горит, и человек может доделать своё, не чувствуя, что кого-то подводит.
Could you take a look at this when you get a chance?
Would you mind reviewing the migration before Thursday?
When you have a moment, could you check whether the staging key is still valid?
Any chance you could point me to the right person for billing questions?
Срочная просьба. Тут наоборот: срочность называется прямо, вместе с причиной и сроком. Срочность без причины читается как каприз, и человек, у которого горит своё, спокойно поставит тебя в конец очереди.
This one is blocking the release tonight — could you review it in the
next couple of hours? Happy to walk you through it on a call if that's faster.
Sorry for the short notice: the certificate expires at 18:00 UTC today.
Could you approve the renewal before then? Everything else can wait.
Отказ и перенос. Пустое «no» не отправляют никогда. Схема: короткая причина плюс встречное предложение. Если из главы стоит унести одну конструкцию, то эту — I won't be able to X, but I can Y. Она превращает отказ в переговоры, а тебя из человека, который срывает сроки, — в человека, который управляет ожиданиями.
I won't be able to finish this by Friday — the API change turned out to
touch the billing flow too. I can have the first half ready by Friday and
the rest by Tuesday. Would that work?
I'm heads-down on the migration until Wednesday, so I can't take this on
right now. @sergey knows this module well and might have capacity.
That's not something I can approve on my own. Let me check with legal and
come back to you by Thursday.
Статус. Лексика проектных статусов небольшая, но её надо знать точно: on track (идём по плану), at risk (может сорваться), slipping (срок уже уезжает), blocked on (стоим, ждём чего-то), ETA (estimated time of arrival — когда ожидать), done, in review, rolled back.
Status update on the payments migration:
- Schema changes: done, merged yesterday.
- Backfill script: in review, ETA end of day.
- Cutover: on track for Thursday.
- Blocked on: the vendor still hasn't enabled the sandbox account.
I've pinged them twice; if we don't hear back by Wednesday, the
Thursday date is at risk and we'd slip to next week.
Напоминание. Правило одно: напоминай так, чтобы это не читалось упрёком в забывчивости. Рабочие начала — Following up on…, Just bumping this…, Circling back on…, Gentle reminder….
Following up on my message from Monday about the sandbox account —
have you had a chance to look at it?
Just bumping this in case it got buried. No rush if you're swamped,
but it'd be good to know if it's on your radar.
Circling back on the contract review. We'd like to sign by the end of
the month; is there anything you need from our side to move it forward?
Извинение за задержку. Одна строка, без самобичевания, с фактом: Sorry for the slow reply — I was out last week. А можно и вовсе без sorry: Thanks for your patience, here's the update. Второй вариант в деловой переписке обычно лучше — он не начинает разговор с твоей вины.
Три регистра на одном примере
Новость одна: «мы нашли баг в вашем SDK, он ломает нам оплату». Текстов будет три, и общего в них — только факты.
1. Свой командный чат. Коротко, с сокращениями, эмодзи и без реверансов.
Found it 🎉 It's not us — the vendor SDK drops the idempotency key on
retry, so the second attempt creates a new charge. Repro is in #712.
Filing a ticket with them now. Meanwhile I'm pinning the SDK to 3.1.4,
which doesn't have the bug. Deploying in ~20 min.
2. Письмо в другую компанию — партнёру, с которым вы делаете интеграцию. Полные предложения, ровный тон, чёткая просьба. Ни сокращений, ни мемов: получатель не знает тебя настолько, чтобы правильно их прочитать.
Subject: Duplicate charges caused by dropped idempotency key (SDK 3.2.0)
Hi Laura,
We've traced a duplicate-charge issue on our side to the payments SDK.
In version 3.2.0, the idempotency key is not preserved when the client
retries after a 503, so the retried request is processed as a new charge.
We reproduced it consistently with the script attached.
We've pinned our integration to 3.1.4 for now, which is not affected.
Could you confirm whether this is a known issue, and let us know if a fix
is planned? We're happy to share more traces if that helps.
Thanks,
Dmitry
3. Письмо вендору по контракту. Ещё на ступень формальнее: номера тикета и аккаунта, ссылка на соглашение об уровне сервиса, названный срок ответа. Тон при этом остаётся ровным — жёсткость собирается из фактов и структуры, а не из интонации.
Subject: [Ticket #48120] Duplicate charges in SDK 3.2.0 — requesting an update
Hello,
I'm writing regarding ticket #48120, opened on 28 July.
Summary: in SDK version 3.2.0 the idempotency key is dropped when the
client retries a request after a 503 response. As a result, retried
payments are processed as new charges. Between 25 and 28 July this
produced 34 duplicate charges on our production account (account ID
AC-99120), which we have refunded manually.
We have mitigated the issue by pinning the SDK to 3.1.4.
Per our support agreement, issues at this severity carry a two business
day response time. Could you please provide:
1. Confirmation of the root cause.
2. A target date for a fix or an official workaround.
3. Guidance on whether accounts on 3.2.x should downgrade.
We would appreciate a response by Thursday, 6 August. Please let me know
if you need any additional information from our side.
Best regards,
Dmitry Volkov
Payments Team, Acme GmbH
Посмотри, из чего собран третий текст: номера тикета и аккаунта, даты, «34 duplicate charges» вместо «много», пронумерованный список из трёх требований, названный день ответа. И ни единого упрёка. Вот так и выглядит деловая жёсткость по-английски: не повышенный голос, а точность, на которую нечего возразить.
Структура делового письма
Пять частей, и четвёртую пропускают чаще всего.
- Subject line — конкретная тема, по которой письмо потом найдут поиском. Плохо: Question. Хорошо: [Ticket #48120] Duplicate charges in SDK 3.2.0 — requesting an update.
- Greeting — Hi Laura, (стандарт), Hello, (не знаешь имени), Dear Ms Alvarez, (очень формально, юристы и официальные инстанции).
- Тело — первое предложение сразу о деле: зачем пишешь.
- Call to action — чего именно ты ждёшь и к какому сроку. Письмо без этой части прочитают, покивают и закроют.
- Sign-off — подпись.
| Sign-off | Когда уместно |
|---|---|
Best regards, | Внешняя переписка, вендоры, клиенты, первый контакт |
Kind regards, | То же, чуть теплее; распространено в Европе |
Best, | Полуформально, коллеги из других компаний |
Thanks, | Когда о чём-то просишь; самый частый вариант внутри команды |
Cheers, | Неформально; UK, Австралия, стартапы. С юристом — не надо |
Sincerely, | Очень формально, официальные письма |
Первое предложение решает всё. Нас учили брать разбег: представиться, объяснить, откуда мы, подвести к делу. Англоязычный деловой стиль требует обратного — назвать причину письма сразу, потому что дальше первой строки в списке входящих ничего не видно.
Слабое начало:
I hope this email finds you well. My name is Dmitry and I am working
as a backend developer in the payments team at Acme, and I wanted to
reach out to you regarding a matter which...
Сильное начало:
Hi Laura — we've found a bug in SDK 3.2.0 that creates duplicate
charges. Details and a reproduction script below.
Время, сроки и часовые пояса
Самый недооценённый источник недоразумений во всей главе. Сначала — сокращения, которые встречаются каждый день:
EOD— end of day, конец рабочего дня.COB— close of business, то же самое, чаще в финансах и Британии (обычно ~17:00–18:00).EOW— end of week, конец недели (пятница).ETA— когда ожидать результат.OOO— out of office, вне офиса, в отпуске.PTO— paid time off, отпуск.ASAP— as soon as possible; см. раздел про ошибки.
Беда у всех этих сокращений общая: часового пояса в них нет. EOD в Сан-Франциско наступает на девять часов позже, чем в Берлине. А by Friday двусмысленно само по себе: до конца четверга или включая всю пятницу?
История, которая стоила команде релиза. Тимлид в Лондоне написал «we need it by Friday», разработчик в Сиэтле спокойно доделывал в пятницу днём — по своему времени. В Лондоне это была уже глубокая ночь с пятницы на субботу, релиз ушёл без его части, а в понедельник оба искренне не понимали, кто кого подвёл. Каждый был по-своему прав. Лечение одно: писать абсолютное время с зоной.
Ambiguous:
Can you finish it by Friday?
I'll send it EOD.
Let's meet at 3.
Unambiguous:
Could you finish it by Friday 17:00 CET (that's 08:00 in San Francisco)?
I'll send it by 18:00 UTC today.
Does Tuesday 15:00 UTC work for you? That's 17:00 for me and 08:00 for
Ana — if it's too early for her, I can do Wednesday instead.
Назначая созвон, предложи два-три слота, назови зону и посчитай, сколько это будет на часах у собеседника. Совещание в 8 утра по чужому времени формально возможно, но запоминается надолго. Формулы: Would any of these work for you?, Does 15:00 UTC suit you?, I'm flexible, just send me a slot that works., Let's keep it to 30 minutes.
Culture note: прямота и вежливость
Одни и те же слова в разных командах весят по-разному, и сбивает это сильнее, чем пробелы в грамматике. Несколько наблюдений, за которые я в своё время заплатил парой неловких разговоров.
Британское смягчение. Отрицание здесь маскируется до неузнаваемости. That's an interesting approach нередко значит «мне не нравится». I might suggest… — не «может быть», а «сделай так». With the greatest respect… обычно предваряет полное несогласие. Я однажды принял That's certainly one way to do it за одобрение и спокойно смерджил ветку — через день выяснилось, что коллега имел в виду «так делать не стоит», и он был искренне уверен, что выразился предельно ясно. Читай не форму, а то, что человек предлагает сделать.
Американская прямота в обёртке. Здесь в ходу «сэндвич»: похвала, замечание, поддержка. Great work on the tests! I'd love to see the error handling tightened up. Overall this is really close. Не обманывайся рамкой: I'd love to see в середине — это требование, и его надо выполнить.
Нидерланды, Германия, Скандинавия. Прямота — норма, грубостью не считается. I don't agree, this won't scale сказано про идею, а не про тебя, и обижаться тут не на что. Русскоязычному разработчику этот регистр обычно родной.
Что слышно в голом «I disagree». Резче, чем кажется неносителю: это не приглашение к спору, а закрытая позиция. Несогласие лучше строить через свою точку зрения или через цифру.
Blunt: I disagree. This approach is wrong.
Softer: I see it differently — I think the queue would give us the same
result with less code. What am I missing?
Softer: I'm not sure this scales: at 10k events per minute the retry
loop alone would saturate the worker pool. Could we look at the
numbers together?
Общий совет: в незнакомой команде начинай на полтона вежливее, чем кажется нужным, а дальше подстраивайся под то, как пишут остальные. Спуститься в неформальность легко и приятно. Отыграть репутацию после резкого старта — долго.
Кейс из реального проекта: один инцидент в трёх текстах
Ночью отвалилась интеграция с платёжным провайдером, часть платежей ушла дважды. К утру инцидент локализован. Дмитрий садится писать — и пишет три текста об одном и том же событии.
Текст 1. Сообщение в тред команды. Контекст у всех есть, нужны факты и следующий шаг.
Incident update (thread for #ops-payments):
What happened: between 02:10 and 04:35 UTC the payment SDK dropped the
idempotency key on retry. 34 charges were created twice. Affected
accounts are listed in the sheet linked below.
Now: SDK pinned to 3.1.4, deployed at 06:20 UTC. No duplicates since.
Next:
- Refunds: @lena is running the script, ETA 12:00 UTC.
- Vendor ticket #48120 opened, waiting on their reply.
- Postmortem doc is up, I'll add the timeline today. Comments welcome.
Nothing needed from anyone else right now — I'll post here if that changes.
Текст 2. Письмо вендору. Формально, с номерами и требованиями.
Subject: [Ticket #48120] Duplicate charges caused by SDK 3.2.0 retry logic
Hello,
I'm following up on ticket #48120, opened this morning.
Between 02:10 and 04:35 UTC on 1 August, 34 charges on account AC-99120
were processed twice. We traced this to SDK 3.2.0: when the client
retries after a 503, the `Idempotency-Key` header is not carried over to
the retried request, so your API treats it as a new charge. A minimal
reproduction script is attached.
We have mitigated the issue by pinning to SDK 3.1.4 and have refunded the
affected customers.
Could you please confirm:
1. Whether this is a known issue in 3.2.x.
2. A target date for a fix.
3. Whether other accounts on 3.2.x are affected, so we can advise our
partners accordingly.
Given the customer impact, we would appreciate a response by Wednesday,
6 August. Please let me know if you need anything further from our side.
Best regards,
Dmitry Volkov
Payments Team, Acme GmbH
Текст 3. Апдейт для менеджера. Заголовки HTTP тут никому не нужны. Нужны деньги, охват, риск и срок — и всё это в первых двух абзацах, потому что дальше она читать не будет.
Subject: Payment duplicates on 1 Aug — contained, refunds in progress
Hi Elena,
Short version: 34 customers were charged twice overnight. The cause was
a bug in our payment provider's SDK, not in our code. It's contained —
we rolled back to the previous SDK version at 06:20 UTC and there have
been no new duplicates since.
Impact: €4,120 in duplicate charges, all being refunded today (ETA 12:00
UTC). 34 customers affected; support has a template ready and will reach
out to each of them.
Risk: the fix is on the vendor's side. We're safe on the pinned version,
but we can't upgrade until they fix it. I've asked for a target date and
expect an answer by Wednesday.
Next steps: refunds today, postmortem by Friday, and I'd like to add a
test that catches a missing idempotency key before release.
Happy to walk through the details if useful — 15 minutes should be enough.
Thanks,
Dmitry
Событие одно, отбор фактов и тон — три разных. Команде: таймлайн и кто что делает дальше. Вендору: доказательства и пронумерованные требования со сроком. Менеджеру: сумма, охват, риск, дата и предложение созвониться на пятнадцать минут. Ничего не приукрашено и нигде не соврано — просто каждому дано то, чем он может распорядиться. Вот это умение и называется профессиональной письменной коммуникацией; английский тут, честно говоря, дело десятое.
Типичные ошибки
«Dear Sir/Madam» и канцелярит
Обороты из учебников девяностых сегодня звучат как письмо из нотариальной конторы и ставят между вами дистанцию, которая в IT ни к чему. Dear Sir or Madam, I am writing to inform you that, Please be advised, I would like to kindly ask you to, Awaiting your prompt response — всё это меняется на человеческие конструкции без потери формальности.
Как НЕ надо:
Dear Sir or Madam,
I am writing to inform you that we have encountered an issue with regard
to the aforementioned integration. Please be advised that we would like
to kindly request your assistance in this matter at your earliest
convenience. Awaiting your prompt response.
Как надо:
Hello,
We've hit a problem with the payments integration: retried requests
create duplicate charges. Details below. Could you confirm whether this
is a known issue and when a fix is planned?
Стена текста
Пятнадцать строк сплошняком в чате не читают. Дроби на абзацы, действия выноси списком, а главное — переставь вывод в начало. Правило BLUF (bottom line up front): сперва итог, потом обоснование. Русская школа учила обратному — сначала рассуждение, вывод в конце, — и переучиваться придётся сознательно. Зато читатель, у которого пять секунд, унесёт главное из первой строки.
«ASAP» без объяснения
ASAP не сообщает срока. Он сообщает твою тревогу. У получателя своя очередь задач, и сравнить твоё «как можно скорее» с чужим «как можно скорее» он не может — ему нужны время и причина.
Как НЕ надо:
Need this ASAP!!
Как надо:
Could you get this in before 16:00 UTC? The release train leaves at 17:00
and this is the last blocker. If that's not realistic, tell me and I'll
move the release to tomorrow.
Пассивная агрессия
Самая коварная ошибка: автор её не замечает вовсе. As I already mentioned…, Per my last email…, Just to remind you again…, As previously discussed… — все они читаются как «ты невнимательно читал». Носители иногда именно для этого их и берут, вполне сознательно. Ты, скорее всего, просто хотел сослаться на прошлое письмо — а получилось то, что получилось.
Как НЕ надо:
As I already mentioned in my previous email, the key expires today.
Per my last message, we still need the sandbox account.
Как надо:
Just flagging again that the key expires today at 18:00 UTC.
Following up on the sandbox account — is there anything blocking it
on your side? Happy to help if something's needed from us.
Вопрос без контекста
Does the API support pagination? заставляет собеседника угадывать: какой API, какой версии, что ты вообще пытаешься сделать. Он спросит — ты ответишь завтра. Три строки контекста сразу экономят этот день.
Как НЕ надо:
Does the API support pagination?
Как надо:
I'm exporting all orders from the v2 API for the monthly report — about
80k records. The docs mention a `limit` parameter but not a cursor. Is
there a way to page through the full result set, or should I filter by
date ranges instead?
Извинения через каждое предложение
«Sorry to bother you, sorry for the stupid question, sorry again» — та же болезнь, что и в ревью. Вежливее от этого не становится: текст длиннее, а содержание тонет под извинениями, и собеседник начинает подозревать, что дело серьёзнее, чем ты пишешь. Одна формула на сообщение — потолок. А чаще её просто меняют на благодарность: вместо Sorry for the delay — Thanks for waiting.
Итог
У асинхронной переписки один закон: сообщение должно быть самодостаточным, потому что ответ придёт через часы, а не через секунды. Всё остальное растёт отсюда — правило «no hello», вопрос из трёх частей (контекст, что пробовал, конкретный вопрос), названная вслух исходная цель, чтобы не увязнуть в проблеме XY, треды вместо шума в канале и осторожность с упоминаниями.
Речевые акты складываются из готовых блоков: просьба с when you get a chance, срочная просьба с причиной и сроком, отказ по схеме I won't be able to X, but I can Y, статус на языке on track / at risk / blocked on / ETA, напоминание через Following up on…. Регистр выбирается по адресату — командный чат, письмо в другую компанию и письмо вендору по контракту остаются тремя разными текстами, даже когда событие одно. Сроки пишутся с часовым поясом всегда: by Friday и EOD у каждого свои.
И то, ради чего писалась вся глава: жёсткость в англоязычной деловой переписке делается точностью — номерами, датами, цифрами, списком требований, — а не резкостью тона. Резкость заметят, но чинить от неё быстрее не станут.