Becoming an Effective Writer
What is and is not Business Writing?
- Is not meant to entertain or reflect; this is pleasure writing.
- Is meant to get facts straight and to the point, to inform or to persuade the reader.
Regular consistent practice is necessary. Changing habits is not easy; you have to be willing to change, know
how to change, and practice. "Practice makes perfect"
Readers |
Writers |
Scan for key points |
Be clear and simple |
Quickly decide importance |
Get to the point |
In order to succeed in business, you must be able not just to write, but to write effectively.
Principles of Business Writing
-
Analyze the reader
- What does my reader already know? Who is my audience?
-
Organize the message
-
Does your message begin with a purpose, organize the message in the best way for the reader, and look easy
to read?
-
Signal the next step
- Is there a time when a response is needed and does it contain contact information?
-
Value the reader
-
Effective business writers need to give the impression that the reader is important and not just another
number.
-
Ensure an effective message
- Decrease the need for follow-up messages.
-
Choose the right channel
- Email, Teams, Meeting, or Face to Face
The 10 C's of Business Writing
A writer has the right to expect every message to be: Complete, Concise, Clear, Conversational, Courteous,
Correct, Considerate, Concrete, and Credible.
- Complete: Is all of the information included so that follow-up questions are not necessary?
-
Concise: Use the fewest number of words possible. Including more words into your writing leads the reader to
have to wade through information that may not be relevant to the writing.
-
Clear: Have you thought about what the reader knows or doesn't know, or are you writing based on what you
know and what makes sense to you?
- Conversational: Does your writing sound as if you are writing to a human or to a robot?
-
Courteous: Is your tone pleasant? Have you shown the reader how they will benefit from your information or
policy? Does the message sound demanding or is it all about the writer's interest?
-
Correct: Is your writing accurate and professional, or does it give the impression that it was rushed and not
prepared?
- Coherent: Does your writing look jumbled or do the ideas tie together smoothly?
-
Considerate: Does your writing look inviting to read (using headings and bullets) or does it use 1 or 2 long
paragraphs?
- Concrete: Have you included specifics and examples, or are vague meaningless words used?
- Credible: Are all facts within the article given from trusted sources and cited?
Strong vs. Weak Verbs
Which of the following statements sound stronger and more concise?
(a) You will need to send your confirmation for your appointment by Friday. (b) Please confirm your appointment
by Friday.
12 words versus 6 words. Not only is (b) stronger, the message is more concise. Look for camouflaged words in
your message, verbs that have usually turned into nouns, commonly adding the -tion at the end of the word.
Conversation versus confirm.
The same principle applies for filler words.
(a) There are five people who want to attend the meeting. (b) Five people want to attend the meeting.
Make your writing more concise, cut out the fluff and get to the point.
Create a Clear Message
Understand your reader and their ability to comprehend what you're trying to tell them.
- What department do they work for?
- What is their experience within the topic you're talking about?
- What relationship do you have with the reader?
Make your message logical and easy to read for the reader. Your main idea should be at the top of the paragraph,
utilize transitional words (first, second, although), consider the connotation of the words that you use.
Example 1: "Hey John, I need you to talk about something urgent when you have time."
What would John think about in this message? What's so urgent?
Example 2: "Hey John, we need some help understanding the requirements in this ticket [link ticket here],
specifically we have questions about… [list your questions here]"
In this 2nd message John knows exactly what ticket you're referring to, the exact questions you have, and
knows to be prepared to answer these questions. Most of all, no worry about what exactly this urgent matter is.
Cut to the Question
Inspired from: https://nohello.net/en/
If you are asking a question to a co-worker, ask the question. Letting the reader know exactly that you have a
question will get an answer faster.
Example 1: Bob: Hey John: How's it going? Bob: What time is the meeting? John: Oh, 3:30 today.
This includes common opening phrases "How are you?" or "Hey want to hop in a call?". Putting
the reader on the spot dissecting a question in a call can make the recipient feel pressured to get the answer
now. If you just ask the question first, you'll get the answer faster.
Instead consider this:
Example 2: Bob: Hey, what time is the meeting? John: Hey, 3:30 today.
Straight to the point, no extra words or messages needed.
Avoid Negative Words
Negative words can lead to negative reactions.
- "No" and "Not"
- Reminders of a negative situation
- Doubtful words
How would you react if someone tells you "You can't.", "You won't be able to.",
"You failed."? Human nature is such that you immediately become defensive to language like this.
Instead, you should focus on what is and can be.
Example 1: "I won't be able to get to your review until Friday." Better: "I will get to your
review on Friday."
Example 2: "You can't reserve Room 110 on June 10th." Better: "Room 111 is already reserved
for June 10th, but is available on the 9th or the 11th."
Phrase your writing to offer alternatives to phrases that are usually negative. Be assertive on the
'when' something will happen or change.
Using positive language requires more thought, but is well worth the effort put in to better assist the reader.
Further Reading
The Theory Behind Contract Testing
Below are my notes from the first half of
Contract Testing in Action, highly
recommend this book as this is only the spark notes. Many of the fine details have been left out and are left
for the book to describe.
What contract testing is and why it matters
Contract testing is a form of testing where you test that two systems have a shared understanding of
expectations.
The contract is a JSON file containing the names of two systems interacting. It is the web interface interacting
with an API. The contract lists all possible interactions between the two systems.
There is a shared broker (the contract) which the API can access directly. The API pulls down the contract from
the shared broker and replays the expected request from the web app and then compares that all responses exist.
When there are two users of an API, for example a Mobile client and a Web App, a separate contract can be
introduced to ensure that changes within the API won’t break either of the applications.
Apart from detecting bugs missed by proper communication amongst teams, here are other reasons why contract
testing can be helpful:
- Speeds up development process and provides a faster feedback loop.
- Enables teams to deploy changes independently and safely.
- Issues are easier to debug since scope of tests with the contract is much smaller.
- Developers can run contract tests and update the contract locally.
- Promotes better code quality, removes the need to introduce unneeded requirements.
-
Ensures breaking changes will be communicated with teams and contract will always be up-to-date with these
changes.
Contracts on the Consumer Side
Usually the contract is driven from the consumer of the API. Usually the consumer will receive business
requirements for an application, thus they will create a contract for what fields that they will need.
The frontend engineer will
- Define the interaction with a mock provider.
- Runs the test against the mock provider and verifies the request is registered as an interaction.
-
If tests are successful, the contract will be generated automatically with includes the defined interaction.
The frontend engineer will then upload the contract to a shared repository.
Contracts on the Provider Side
Contracts will generally be stored in a separate project repository, one of the backend engineers is notified if
there are updates to the contract. The responsibility of the provider is to verify the contract.
The backend engineer will
- Download the contract generated by the frontend engineer.
- Verifies the expected contract will be returned from the API using a mock consumer.
- If the actual response and the expected response are matching. The verification is successful.
Contract testing is only useful when you have both a provider side contract and a consumer side contract.
How Contract Testing Fits
Contract testing is in between the layer of Integration tests and Unit tests. They provide high confidence that
API endpoints are shaped correctly and allow the developer to confidently know an endpoint will return the data
needed. Providing early feedback to find any discrepancies and misunderstandings between two teams before
deploying an application and running integration tests, mitigating compatibility issues found between E2E and
integration tests.
Contract testing does not replace any of the aforementioned tests, it compliments them.
Contract testing does not solve:
- Environment problems caused by configuration issues.
- Networking issues such as timeouts and dropped requests.
- Data integrity issues.
- How the user interacts with an application.
- Misunderstandings in business requirements.
When deciding whether to remove a integration or E2E test to a contract test, a good rule of thumb is to move
tests that can be completely duplicated at the contract level. This gives you confidence that you don't need
this as an integration or E2E test. Defining clear contracts between a consumer and a provider ensures that
developers will only deliver functionalities that align with the consumers needs.
Technical Overview of Contract Testing
What is a Consumer?
Contract testing puts more power in the hands of the consumer. In day-to-day life, a consumer in a retail
situation is a "user of a product or service". Each user may use their product slightly differently
and/or have different uses of the product.
The consumer as it relates to us is generally a web or mobile application that makes requests to a backend
service. But a consumer can also be a service that is calling another backend service.
In a consumer-driven approach to contract testing, the consumer is driving the contract. In the example of a
login, a consumer dictates when the application requests the login data. An end user does not care about the
shape or the data, they only care about whether they can log in or not. This is why the consumer is so integral
and should influence the expected data response.
What is a Provider?
A provider is "something that someone needs or wants, if somebody wants your product, you provide them with
it or make it available". In a consumer driven approach, the consumer will mock out the provider and the
provider mocks out their downstream dependencies.
The provider must add a test pointing to the consumer within the contract testing process and will automatically
get updates if they point to the latest version of the consumer contract.
What is a Contract?
A contract is “a legal document that states and explains a formal agreement between two different people or
groups”. It is important to distinguish the differences between a contract and a schema. A schema is described
as "an outline of a plain or theory". The schema provides the outline, it will be defined in the
planning phases before development starts. A contract is used after development to ensure the schema does not
change after released.
What is a Contract Broker?
A broker is “a person who talks to opposing sides, especially governments, making arrangements for them or
bringing disagreements to an end“. A contract broker is the central place that contracts are stored. Without a
broker, passing around contracts is manual and can lead to different versions of the most recent contract due to
code changes.
Implementing Consumer Driven Contract Testing (CDCT)
The Focus of a Consumer Contract
A consumer contract is only supposed to make sure that when a consumer asks for data from a provider service,
the correct data is returned as specified by the contract agreement. This does not care about the functional
details of how the provider works, instead they focused on what the consumer needs and checks if they get it.
A general rule of thumb when deciding what to include in the contract is: "If I don't include this
scenario, what bug in the consumer or what misunderstanding about how the provider responds might be missed. If
the answer is none, don't include it."
source
Building with LEGOs
It is important to understand coupling with contract testing. Think of coupling in the context of LEGO blocks.
In a highly coupled scenario, LEGO blocks are intertwined and connected with other blocks, if you remove 1, the
whole structure falls. These blocks are highly dependent on each other and depend on one block being present.
In contract testing you are able to smell a highly coupled contract if you make one small change to the provider
and the consumer contract fails. If you're not careful, contract tests can easily become very brittle and
flaky.
To combat flaky tests, Pact provides loose matchers, such as type based matchers. With type based matching, you
care about what is the type of data returned, rather than the actual data itself. Consider the code sample below
const EXPECTED_BODY = {
id: like(1),
username: like('marie'),
fullname: like('marie cruz')
}
This object represents the shape the consumer expects from the data provider. If the consumer makes a GET
request, it cares that the data exists, and the type of the data matches. Another question that Pact recommends
is "If I made this looser/tighter, what bugs would I miss/prevent?"
Example Consumer Jest test
A consumer contract test can be broken down into 5 steps
- Importing the required dependencies.
- Setting up mock provider that the consumer will use.
- Registering the expectations that the consumer will receive from the provider.
- Verifying the consumer test and generate the contract.
- Publish the contract to a broker.
const path = require("path");
const { fetchMovies } = require("./consumer");
const { PactV3, MatchersV3 } = require("@pact-foundation/pact");
const provider = new PactV3({
dir: path.resolve(process.cwd(), "pacts"),
consumer: "WebConsumer",
provider: "MoviesAPI",
});
const EXPECTED_BODY = { id: 1, name: "My movie", year: 1999 };
describe("Movies API", () => {
describe("When a GET request is made to /movies", () => {
test("it should return all movies", async () => {
provider
.uponReceiving("a request for all movies")
.withRequest({
method: "GET",
path: "/movies",
})
.willRespondWith({
status: 200,
body: MatchersV3.eachLike(EXPECTED_BODY),
});
await provider.executeTest(async (mockProvider) => {
const movies = await fetchMovies(mockProvider.url);
expect(movies[0]).toEqual(EXPECTED_BODY);
});
});
});
});
The test above generates a contract WebConsumer-MoviesAPI.json
using Pact to be uploaded to a
shared broker.
Implementing CDCTs for Providers
When developing contract tests, it is essential to keep in mind that there are two sets of tests that you need
to write, one for the consumer, the other for the providers. Provider contract tests typically demand less code
than it's counterpart.
The Focus of a Provider Contract Test
The primary focus of a provider contract test is to verify the contract that the consumer has generated.
Contract testing tools, such as Pact, provide a framework that allows data providers to pull the contract test
and replay the interactions that the consumer registers as part of the contract.
A consumer-driven contract testing approach forces the provider to only develop features that the consumer
requires. If the API introduces a breaking change that modify the type of a field, the contract should verify
this change before applying it to production. To reiterate, contract testing should NOT verify
validation, this should be a unit test.
If the provider changes the business logic of a validation, this would break a contract testing validation.
Ideally business rules should not break a contract with a consumer.
Using Provider States Effectively
Provider states allow data providers to define the state a response needs to be in to be able to verify the
interaction from the consumer contract successfully. When writing a provider contract test with provider states,
you need to make sure that the provider state is provided from the consumer.
- Set up the consumer test with a provider state.
- Define the state of the provider.
Example Provider Jest Test
A provider contract test can be broken down into 5 steps
- Importing the required dependencies.
- Running the provider service.
- Setting up the provider verifier options.
- Writing the provider contract test.
- Running the provider contract test.
const { Verifier } = require('@pact-foundation/pact');
const { importData, server } = require('./provider');
importData();
const port = '3001';
const app = server.listen(port, () => console.log(`Listening on port ${port}...`));
const options = {
provider: 'MoviesAPI',
providerBaseUrl: `http:`,
pactBrokerUrl: process.env.PACT_BROKER_BASE_URL,
pactBrokerToken: process.env.PACT_BROKER_TOKEN,
providerVersion: '1.0.0',
publishVerificationResult: true,
consumerVersionTags: ['main'],
};
const verifier = new Verifier(options);
describe('Pact Verification', () => {
test('should validate the expectations of movie-consumer', () => {
return verifier
.verifyProvider()
.then(
output => {
console.log('Pact Verification Complete!');
console.log('Result:', output);
app.close();
});
});
});