Professional English for Developers Module 5 – Emails and chat
Team chat etiquette, threads and shorthand
Ask the question in your first chat message, keep replies in threads, decode LGTM, PTAL and WIP, and share code and logs as text, never as screenshots.
What you will learn
- Start a chat with the question itself, not a bare hello, and keep replies in threads
- Use and decode chat shorthand such as LGTM, PTAL, WIP, FYI and OOO
- Format code, logs and errors as text in code blocks, not as screenshots
- Choose between chat, email, a ticket and a call for a given message
Before you start
What you’ll learn · Before you start
What you will learn
- Start a chat with the question itself, not a bare hello, and keep replies in threads
- Use and decode chat shorthand such as LGTM, PTAL, WIP, FYI and OOO
- Format code, logs and errors as text in code blocks, not as screenshots
- Choose between chat, email, a ticket and a call for a given message
Before you start
On this page
Six chat messages asked one colleague for help: “hi”, “r u there?”, three fragments and a screenshot of the error. The question arrived in message 5, and the error never arrived as text. Sent as one message, the same request holds the question in its first line and the error in a code block: Text marked as code, in chat or Markdown usually with three backticks on the lines before and after it, and shown in a fixed-width font exactly as typed., and gets its answer the first time the colleague looks.
Good team chat etiquette comes down to three habits. Put the greeting and the question in one message, and keep the replies in a thread (in chat): A chain of replies attached to one chat message, which keeps a discussion together and out of the main flow of the channel.. Use shorthand such as LGTM, PTAL and WIP only with readers who know it, and give a time instead of ASAP. Share code, logs and errors as text, never as pictures of text.
Put the question in the first message, and the replies in a thread
A message that says only “hi” makes the reader answer a greeting before they learn what you need. The page nohello.net compares it to calling someone on the phone, saying hello, and then putting them on hold. Its advice is short: “Just ask the question!” You can still be friendly, in the same message. Step through one morning in Pune, first the slow way, then in one message:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- A bare "hi". 09:02 IST. The nightly build has failed, and Kavya writes "hi" to Arjun, then waits for him to answer before she asks anything.
- Arjun answers the greeting. 09:41 IST. Arjun comes out of a review, sees "hi" and answers "hi, what's up?". He has nothing to work on yet.
- The question, an hour late. 10:01 IST. Kavya is back from her stand-up and writes "the build is failing, can someone check pls". The question reaches Arjun 59 minutes after her first message.
- A screenshot of the error. Arjun asks which error. Kavya sends a screenshot of the log. He cannot copy the text to search for it, so he asks for the log as text, and the next question waits again.
- One message instead. Back to 09:02 IST. This time Kavya sends one message: the greeting, what failed and when, the question with a time and its zone, and the error as text in a code block.
- Answered at the first look. 09:41 IST. Arjun comes out of the review, reads the question and the error, and knows the fix. The answer arrives the first time he looks, with no greeting to answer first.
The question reached Arjun 59 minutes after the first “hi”, and even then the error was a picture he could not search. Asked in one message, it was answered at 09:41, the first time he looked. Chat is asynchronous communication: Communication in which the reader answers when they can, not at once, as in email and most team chat. A message that holds the whole question lets them answer in one go.: the reader answers when they can, so the message has to hold everything they need when they arrive. The program checks the six messages and the one that replaced them:
// One request for help in a team chat, sent two ways, checked for this lesson's habits: no bare greeting waiting for an
// answer, the question in the first message, logs as text in a code block instead of a screenshot, a time with its
// zone, no mass mention and no text-message spelling. It also counts the messages a reader has to read before
// learning what is asked.
const FENCE = '`'.repeat(3);
const MESSY = [
'hi',
'r u there?',
'the build is failing',
'[screenshot: build-error.png]',
'can someone check pls',
'@channel URGENT',
];
const CLEAN = [
`Hi Arjun, the nightly build of payments-api failed at the migration step at 02:00 IST. Could you look at it before the 11:00 IST release check? Here is the error:\n${FENCE}\nERROR migrate: relation "refund_audit" already exists\n${FENCE}`,
];
const ASKS = /\?|\bcould you\b|\bcan (?:you|someone)\b/i;
function check(messages) {
const flags = [];
const askAt = messages.findIndex((m) => ASKS.test(m) && !/^r u there\?$/i.test(m));
messages.forEach((m, i) => {
if (/^(?:hi|hello|hey)[!. ]*$/i.test(m)) flags.push(`message ${i + 1} is a bare greeting: the reader waits for the question`);
if (/^\[screenshot/i.test(m)) flags.push(`message ${i + 1} is a screenshot of text: nobody can copy or search it`);
if (/@(?:channel|here|everyone)\b/i.test(m)) flags.push(`message ${i + 1} notifies everyone: mention only who must act`);
for (const w of m.match(/\b(?:r u|pls|plz|u)\b/gi) ?? []) flags.push(`message ${i + 1}: "${w}" is text-message spelling`);
});
const all = messages.join('\n');
if (!all.includes(FENCE)) flags.push('no code block: the error is not there as text');
if (!/\b\d{1,2}:\d{2}\s?(?:IST|UTC)\b/.test(all)) flags.push('no time with a zone: the reader cannot tell how urgent it is');
return { flags, askAt };
}
for (const [name, messages] of [['Messy', MESSY], ['Clean', CLEAN]]) {
const { flags, askAt } = check(messages);
console.log(`${name}: ${messages.length} message${messages.length === 1 ? '' : 's'}, the ask in message ${askAt + 1}, ${flags.length} flags`);
for (const f of flags) console.log(` - ${f}`);
}
console.log('\nThe clean message as the reader sees it:\n');
console.log(CLEAN[0]); Output
Messy: 6 messages, the ask in message 5, 7 flags - message 1 is a bare greeting: the reader waits for the question - message 2: "r u" is text-message spelling - message 4 is a screenshot of text: nobody can copy or search it - message 5: "pls" is text-message spelling - message 6 notifies everyone: mention only who must act - no code block: the error is not there as text - no time with a zone: the reader cannot tell how urgent it is Clean: 1 message, the ask in message 1, 0 flags The clean message as the reader sees it: Hi Arjun, the nightly build of payments-api failed at the migration step at 02:00 IST. Could you look at it before the 11:00 IST release check? Here is the error: ``` ERROR migrate: relation "refund_audit" already exists ```
Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node messy_clean.mjs
Runs on this device, in your browser. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs.
Your run, in this browser
Once the question is out, keep the answers together. Slack’s help centre puts it plainly: “Threads help you to create organised discussions around specific messages”, without clutter in the channel. Reply in the thread of the message you answer, and @mention: A person's name tagged with @ in a chat message, which notifies that person. A mention of the whole channel notifies everyone in it. only the people who must act; a mention of the whole channel wakes everyone. Across time zones, schedule a message for the reader’s morning instead of sending it into their night: chat tools such as Slack can schedule a message to send later.
Key idea
Put the greeting, the question, the details and a time with its zone in one message, then keep every reply in its thread.
Checkpoint
Check: The question in the first message, replies in threads
Shorthand saves typing only when the reader knows it
Team chats are full of shorthand, and each piece stands for a whole sentence. Review threads are where it is densest:
| Shorthand | Means |
|---|---|
| LGTM | looks good to me: the reviewer approves the change |
| PTAL | please take a look, or another look after changes |
| WIP | work in progress: not ready for review yet |
| nit | a minor point, worth fixing but not blocking |
| FYI | for your information: no action needed |
| OOO | out of office |
Google’s engineering practices define LGTM as what a code reviewer says when approving a change, and a nit as “a minor thing”. The Kubernetes contributor guide uses PTAL to ask a reviewer to take another look, and asks for WIP in the title of a pull request that is not ready for review. FYI is in the IETF’s glossary of internet terms.
Shorthand is a shared code, so it works only for readers who share it. Google’s style guide says not to use internet slang abbreviations such as tl;dr in documentation; chat is more relaxed, but a newcomer or a colleague who reads English as a second language may not know them, so expand them for those readers. And give a time instead of ASAP or EOD: “by 17:00 IST” means the same moment to everyone.
Not every message belongs in a chat at all: some go better in an email, a ticket or a call. And a reply of one word, or a lone emoji, can read as curt or mean different things to a colleague who does not know you.
Checkpoint
Check: Shorthand and the readers who know it
A shorthand decoder, with when to avoid each one, run on a review message Pro: opens with a Pro, Premium or Ultimate pass
Knowing what shorthand means is half the skill; knowing when to write the words out is the other half. This part gives a decoder with a rule for each term, and runs it on a real-sized review message and its rewrite for a newcomer.
In this part:
- A decoder with a rule for each term
- A review message decoded, then rewritten for a newcomer
1 runnable example (JavaScript) · about 3 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Code and logs as text: a curly-quote failure, reproduced with real Git Pro: opens with a Pro, Premium or Ultimate pass
A picture of code cannot be copied, searched or read aloud, and text pasted from the wrong place can break the command it shows. This part reproduces one such break with real Git and shows the two habits that prevent it.
In this part:
- Text, not pictures of text
- A curly quote that breaks a command
2 runnable examples (Python) · about 4 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Choosing the channel, and replies that do not read as curt Pro: opens with a Pro, Premium or Ultimate pass
The same message can be right in a chat thread and wrong in an email, or the other way round. This part lets you choose the channel for a message of your own, and shows how short replies and reactions read to colleagues abroad.
In this part:
- Chat, email, a ticket or a call
- Short replies and reactions, read from abroad
- Three rules to keep from the parts on shorthand, code and channels
about 7 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
Practise: five fragments, one message
The exercise holds the five fragments a developer sent to a new colleague about a flaky test. Rewrite them as one message until the sample tests pass:
Exercise · Easy · JavaScript
Turn five chat fragments into one message
Kavya needs help from Lena, a QA engineer who joined the team last week. The test "pays with a saved card" in checkout.spec.ts has failed in about one run in five on CI since PR #640 was merged yesterday, with this error:
TimeoutError: waiting for selector "#pay-button" failed: timeout 5000ms exceeded
Kavya would like Lena to look at it before the release check at 16:00 UTC, and she can pair with her at 14:00 UTC. messages.mjs holds the five fragments Kavya first sent. Rewrite them as one message, inside the list:
- the first line holds the question: what you need, with Could you …?;
- it names the test file, checkout.spec.ts;
- the error is text in a code block: three backticks on a line of their own, the error line, then three backticks again (write each line break as
\n); - every time has a zone;
- no bare greeting, screenshot,
@channelor@here, text-message spelling such as pls or r u, and, because Lena is new, no shorthand such as ASAP, EOD, PTAL or WIP.
Starter code · messages.mjs
// Rewrite Kavya's five chat fragments as one message that Lena can act on. Keep the list: one string per message, with
// \n for each line break inside a message.
export const messages = [
'hi Lena',
'r u around?',
'checkout test flaky again',
'[screenshot: ci-failure.png]',
'pls check ASAP',
]; The sample tests · messages.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { messages } from './messages.mjs';
// The habits of the lesson, as its chat checker reads them.
const FENCE = '`'.repeat(3);
const message = messages.join('\n');
const firstLine = (messages[0] ?? '').split('\n')[0] ?? '';
test('one message, not five', () => {
assert.equal(messages.length, 1, `${messages.length} messages: put everything in one`);
});
test('the first line holds the question', () => {
assert.ok(/\?/.test(firstLine) && /\b(?:could|can|would) you\b/i.test(firstLine), `ask in the first line, with "Could you …?": "${firstLine}"`);
assert.ok(!/^(?:hi|hello|hey)\b[^?]*$/i.test(firstLine), 'a greeting alone makes the reader wait; add the question to it');
});
test('it names the test and gives the error as text in a code block', () => {
assert.ok(message.includes('checkout.spec.ts'), 'name the test file: checkout.spec.ts');
const lines = message.split('\n');
const open = lines.indexOf(FENCE);
const close = lines.indexOf(FENCE, open + 1);
assert.ok(open >= 0 && close > open, 'put the error between two lines of three backticks');
assert.ok(lines.slice(open + 1, close).some((l) => l.includes('TimeoutError')), 'the code block holds the error line, as text');
assert.ok(!/\[screenshot/i.test(message), 'no screenshot: the error goes in as text');
});
test('every time has a zone', () => {
const times = message.match(/\b\d{1,2}:\d{2}\b(?:\s?(?:UTC|IST|CET))?/g) ?? [];
assert.ok(times.length > 0, 'say by when: the release check is at 16:00 UTC');
for (const t of times) assert.ok(/(?:UTC|IST|CET)$/.test(t), `give "${t}" its zone`);
});
test('no mass mentions, text-message spelling or shorthand', () => {
assert.ok(!/@(?:channel|here|everyone)\b/i.test(message), 'mention only who must act: Lena');
const speak = message.match(/\b(?:r u|pls|plz|u)\b/i);
assert.ok(!speak, `"${speak?.[0]}": write the words out`);
const short = message.match(/\b(?:ASAP|EOD|EOW|PTAL|WIP|IMO|OOO|LGTM|TL;DR)\b/);
assert.ok(!short, `"${short?.[0]}": Lena is new, so write it out`);
}); A hint
Start with the greeting and the question on one line: "Hi Lena, could you look at a flaky test in checkout.spec.ts before the 16:00 UTC release check?" Then the facts, then the error between two lines of three backticks.
Results of the sample tests
| Test | Result | Details |
|---|
What your code printed
The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.
Then try the questions on first messages, threads and shorthand:
Practice that adapts to you
Practise this lesson
7 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up (fresher to mid-level): Why is “hi” on its own a weak first message in a work chat?
Because the reader has to answer a greeting before learning what you need, and if either of you is busy the question arrives an hour later. Chat is asynchronous, so the first message should hold the greeting, the question, the details and a time with its zone. Then the reader can answer the first time they look.
Three longer questions of this module’s bank build on this lesson:
-
Fresher to mid
A teammate keeps posting screenshots of stack traces in the team channel, and nobody can search or copy them. How do you ask them to change, and what do you show them?
-
Mid to senior
A production bug needs a decision from a client, your lead and the QA team today. Which channels do you use for what, in which order, and what does each message say?
-
Mid to senior
Your team's chat is full of shorthand such as PTAL, WIP and nit, and two new hires say they feel lost. What do you change, and how do you get the team to keep the change?
Key takeaways
- Team chat etiquette starts with one message: the greeting and the question together, with the details and a time with its zone, so the reader can answer the first time they look.
- Reply in threads and mention only the people who must act.
- Use shorthand only with readers who know it, and give a time instead of ASAP or EOD.
Terms in this lesson
- @mention
- A person's name tagged with @ in a chat message, which notifies that person. A mention of the whole channel notifies everyone in it.
- asynchronous communication
- Communication in which the reader answers when they can, not at once, as in email and most team chat. A message that holds the whole question lets them answer in one go.
- code block
- Text marked as code, in chat or Markdown usually with three backticks on the lines before and after it, and shown in a fixed-width font exactly as typed.
- smart quotes
- Curly quotation marks, such as “ ” and ‘ ’, which word processors can put in place of the straight marks " and ' as you type.
- thread (in chat)
- A chain of replies attached to one chat message, which keeps a discussion together and out of the main flow of the channel.
References
- No hello (nohello.net)
- Use threads to organise discussions (Slack Help Center) (Slack)
- Send and read messages (Slack Help Center) (Slack)
- Format your messages in Slack with markup (Slack Help Center) (Slack)
- Use emoji and reactions (Slack Help Center) (Slack)
- Notify a channel or workspace (Slack Help Center) (Slack)
- Abbreviations (Google developer documentation style guide) (Google for Developers)
- Images (Google developer documentation style guide) (Google for Developers)
- Google Engineering Practices Documentation (Google)
- Pull request process (Kubernetes contributor guide) (Kubernetes)
- RFC 1983: Internet Users' Glossary (IETF)
- CommonMark Spec 0.31.2: fenced code blocks (CommonMark)
- git-commit documentation (Git)
- Shell Command Language: quoting (POSIX.1-2024) (The Open Group)
- Smart quotes in Word and PowerPoint (Microsoft)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress