This is another post in my series on designing software systems. Today, I want to talk about an important step in the software design process: writing design documents.

An inverted pyramid with Understand your audience at the bottom, then structure your document, then write great content on top.

I feel like I could write a book about this, but rather than try to boil the ocean, I’ll keep the post as terse as possible.

Table of Contents

What is a design document?

First, what is a design document? Well, it depends on your workplace (or open-source project, etc.), but broadly speaking:

A design document is a written document that explains the technical design of an upcoming feature/project in a way others can understand. Design documents are typically written prior to kicking off development on the feature/project, and can be used for estimating timelines, making decisions, understanding project scope, collaborating with other engineers, and communicating with stakeholders.

In some contexts, like open-source projects, a design document might be called an RFC (Request for Comments). Inside a company, it might be called a “design”, an “implementation plan”, and so on.

Don’t get too hung up on the exact names; the same principles apply to all documents of this class.

A good design document might take a few days to write (more if there is significant research or collaboration with stakeholders), but saves a lot of time for a project by bringing everyone on the same page and getting feedback on important decisions before any code is written.

The first principle of design documents

The first principle of design documents is: Understand who your audience is, and what they expect from the document. Everything else builds on this.

The challenge is that usually the audience is rather heterogeneous. Stakeholders from multiple teams will be interested in the document:

  • Your engineering team needs to understand, in detail, how the project will be implemented.
  • Other engineering teams might want a high-level understanding of what the project is for and what’ll be changing.
  • The stakeholder who requested the feature in the first place wants to know that you understand their needs and timelines.
  • Software architects may want to understand whether your design will fit into the rest of the system and align with long-term engineering goals.
  • Customer success may want to understand how much your design will increase (or, ideally, cut back on!) their support burden.
  • Security might want to know if your design is introducing new security risk.

Those are just examples. Just as each design is solving a problem in a unique context, each document will have a unique audience to address.

It might be helpful to take ten minutes and actually write a list of the different audience groups you want to reach, and what they’ll want out of your document.

Structuring your document

Once you understand your audience and what they need from the design document, you’re halfway to understanding how it needs to be structured!

The next challenge is to understand how to actually meet all the needs of a heterogeneous audience with a single document. As much as possible, avoid conflating everyone’s needs together into a jumble; that makes it hard for each stakeholder group to actually find what they care about.

Instead, the document should be broken out into sections that align with the stakeholders’ needs.

It’s precisely this calculus that could produce a “typical” design document format:

  • Abstract: relevant to people who want a high-level overview of the project, without technical detail — customer success, management, etc.
  • Background/Context: relevant to people who want to make sure that their needs are understood and will be met, and implementers who want to understand the “why” behind the project.
  • Technical design: relevant to people who want to review the technical details of the project (architects, other engineers)
  • Implementation plan/Timeline: relevant to people who want to understand how long the project will take.
  • Security risk assessment: relevant to Security team, who care about technical details, but probably don’t want to read the whole technical design section.

Again, this is just an example. A great design document shouldn’t blindly follow a standard template. Adapt for your particular audience’s needs.

Always organize the information in the document in a way that’ll be most useful for your key stakeholders.

Sometimes, it’s just not a good idea to use a single document for your whole audience.

An example: perhaps the Customer Success (CS) team wants to understand how to explain the new feature to customers, but the rest of the audience is mostly interested in a more technical design.

In that case, you might choose to write a technical design document, and a separate “new feature summary” for CS to reference.

Another example is producing a document specifically for Security that highlights any security-related updates (e.g. authn/authz-related changes) that would benefit from a risk assessment.

That said, producing too many documents is a problem in itself, because the more documents there are, the greater the risk of skew between them as the documents are updated over time.

A single “source of truth” document with different sections for each stakeholder group is an effective method to minimize skew risk and simplify feedback. Only create secondary documents if the benefit of separation overcomes the risk of skew.

Writing about the problem

Make sure to describe the problem — the context you’re solving for — in the document itself. Don’t jump right to the solution.

This is a good idea because, like as not, everyone involved will have a slightly different image of the problem in their heads. By getting the problem written down in concrete-as-possible terms, and soliciting feedback, you can reveal and address those differences before they become an issue.

It’s possible you’ve been handed a requirements doc of some kind before starting the design. Don’t think this obviates the need to describe the problem in your document as well.

In the first place, the requirements are likely from just one group of stakeholders (e.g. the Product team). But your design document has to address the full context of the problem, not just those specific stakeholders’ needs.

Some things that likely weren’t in the requirements doc, but should be in your design, are:

  1. What is the existing architecture this solution has to fit into?
  2. What are the observability requirements? (e.g. we need to know when there are elevated error rates, unusually slow processing, backed-up queues, etc.)
  3. Who will be managing the solution once it’s deployed, and what are their needs?
  4. Are there ongoing engineering initiatives that the design is related to, and how will you coordinate your changes?
  5. Are there security concerns that need to be addressed?

The list goes on. Suffice to say, the project requirements are just a small part of the design context that you need to think about.

Also, in the second place, the requirements themselves may warrant adjusting.

For example, if a seemingly tangential requirement would make the solution egregiously complicated, it’s worth calling out that tradeoff explicitly. Very likely, the “requirement” will prove itself to be not-so-required if it’ll make the project take 30% longer.

Highlight questions/decision points

A significant subset of your audience is likely only concerned with a few key decisions in the document. Also, there are likely issues that you, as the document author, aren’t fully equipped to answer on your own.

These key decisions and questions (questions are just unmade decisions, after all) benefit from being explicitly called out in an obvious place near the top of the design.

An example of a decision point is if there’s a requirement like “There must be a user-friendly wizard to walk the user through the process.”

But you’ve identified that implementing a multiple-step wizard in this part of the app would require a refactoring that would take two weeks, and a single-page dynamic form would be almost as user-friendly and only take three days.

In this case, it might still be worth doing the wizard, or maybe not.

You want feedback from Product and Customer Success about how much they care about a wizard specifically, and also your engineering team manager about the adjustment to the timeline.

So, you highlight this decision point at the top of the document to make it easier to solicit feedback from the aforementioned parties during design review.

Using research spikes

A design document encompasses a whole, nontrivial project/feature, whereas a research spike (or simply spike) is a shorter, focused document that’s typically focused on a single decision.

Depending on time constraints, it’s not bad practice for a design document to defer decisions to one or more spikes.

But, if you have time, it’s best to minimize the number of follow-up spikes and make as many decisions as possible in the design itself.

  • A design document would be appropriate for “An upcoming project to add full-text search capabilities to our app.”
  • A research spike would be appropriate for supporting a specific, focused decision, like “Should we use a managed Elasticsearch provider, or host our own?”

Perhaps the design document specifies that you’ll be using Elasticsearch for your full-text search, but you don’t want to block the project on deciding whether it will be a managed or self-hosted Elasticsearch.

So, you spin that decision into a research spike that can be done asynchronously during the early stages of the project.

In fact, that spike might be done by an entirely different team than the design document itself.

Spikes can also be used to respond to changes in requirements or to clarify ambiguities that arise after the project has started. Anytime a specific decision needs to be made with multiple stakeholders involved, a spike is a useful tool.

You might be wondering: if we’re just making a simple decision, isn’t making a whole document excessive? Just start a thread in Slack, or set up a quick sync with the stakeholders, and get that decision made! Who needs the extra process?

And that’s not a bad impulse. In fact — it’s a great impulse, as long as you write up a decision document afterwards to “formalize” what was decided and the rationale for the decision. It can be as simple as a single paragraph.

Speaking from experience, if the decision (and the reason for the decision) isn’t properly documented somewhere, it risks “decision churn” later in the project. And no, a Slack thread doesn’t count as documentation.

For example, you might identify a new stakeholder (say, you forgot to involve Customer Success in the decision) and they want to understand, “Why did we do it this way, again?” If you didn’t document the decision and the rationale, you might find yourself having to, basically, make the same decision a second time.

Or even, long after the project is completed, perhaps your team starts working on a Version Two of the feature, and they want to understand why we made the tradeoffs we did for Version One. If you didn’t document the rationale for the tradeoffs, then the folks working on Version Two might not have the institutional knowledge to make the best decisions, slowing down their project.

At Redox, we frequently use the SBAR model for structuring research spikes. SBARs are used in the healthcare space to concisely share information about a patient. But they can be very useful in any context where a decision needs to be made.

Adapted for software engineering spikes, the SBAR model looks like:

  • Situation: A brief summary of the situation that led to the spike.
  • Background: Useful context, research, and links that are relevant to the decision.
  • Assessment: A description of the key points and the options available.
  • Recommendation: Proposing the answer (choosing one of the options from the Assessment).

Then, you get the relevant stakeholders to sign off on the Recommendation — or, choose a single Decider (usually the stakeholder with the “most stake,” so to speak) and have them decide.

The SBAR is a very scalable model. Each section could be as small as a sentence, or as long as necessary.

To use the example of “Should we use a managed Elasticsearch provider, or host our own?”:

  • The Situation might be a single paragraph.
  • The Background might be 3-5 pages of research about what hosted providers there are and how complex it would be to host our own.
  • The Assessment might list the various hosting providers and self-hosted options, including the tradeoffs between them. Probably a great opportunity for a “Pro/Con” type of table.
  • Finally, the Recommendation should suggest one of the options listed in the Assessment.

Writing great content

We’ve talked about how the document should be organized “in the large” — the structure of the information. But that’s just part of making an effective document. The other major piece, of course, is actually writing great content.

Writing well is a skill that takes practice; don’t expect to be great all at once. I’m never satisfied with my own writing, either. That’s why I’m constantly trying to improve.

The most important thing about writing great content (at risk of repeating myself) is: keep your audience in mind!

Nobody wants to read a dense, five-hundred-word paragraph; you’re not J.D. Salinger. But that doesn’t mean you should just omit information. Speak to your audience — if they’re not experts, explain your jargon. Meet them where they’re at.

The core challenge: finding a way to present a litany of details in an engaging and clear way.

A few specific tips:

  • Don’t be overly verbose. Use short paragraphs and explanations that hit the key points, and then follow-up paragraphs that include more details.
  • Be as concrete as possible. Anything you gloss over in the design document becomes a potential source of issues or misunderstandings, and vague ideas are also harder for the reader to grasp. If your understanding is weak, your readers’ comprehension will be weak.
  • Highlight key facts or issues that you don’t want stakeholders to miss. Don’t be afraid to bold the important points or use callouts (like the NOTE sections in my blog posts) to break up your prose.
  • Include diagrams. I can’t emphasize this enough. Almost every document should have at least one diagram, and often more like five. Get familiar with a tool like Excalidraw, Figma, Sketch, etc. and you’ll be able to whip out great diagrams fast.
    • If you’re in a real hurry, you can use text-to-diagram tools like Mermaid, PlantUML, or Graphviz. But the diagrams generated by these tools tend to be less readable and effective than ones you make yourself. For the best quality, most useful diagrams, you should make them without using a text-to-diagram tool.
  • Don’t forget about tables, the ultimate tool for structuring information. Just like with diagrams, almost every great design document has a table in there somewhere.
  • Include links to past documents and external references. No document is written in a vacuum. Linking to prior art provides useful context for your readers.

Revise, revise, revise

When you first finish the document, don’t rest on your laurels just yet. You just finished the first draft. Now it’s time to revise.

If you write 1000 lines of code in one go, you expect that it’ll need some refactoring. Shared logic abstracted into functions, standardizing error messages, handling edge cases you glossed over — nobody would expect that those 1000 lines are perfect as-is.

It’s the same thing with a ten-page design document. You will not get it perfect the first time. Don’t hesitate to reword things, move paragraphs around, and even totally change the document structure if you need to.

Ideally, you should take a day or two and let things percolate, then come back to the document with fresh eyes, tear it apart, and rewrite it before you submit it for others to review.

Because there is often some time pressure around getting documents “submitted”, you may not have time to take a few days, but at least don’t submit the document on the same day you wrote it. Wait one night, minimum.

As a correlary, never plan to have finished writing the document at the last minute. That’s a recipe for a not-very-effective design.

If I’m hoping to get a design document finished in five days, I’ll:

  1. Do research and write an outline the first day.
  2. Write the first draft on the second day.
  3. Revise on the third day.
  4. Submit for feedback at the end of the third day.
  5. Respond to feedback and revise further on the fourth and fifth days.

Frequently, getting busy stakeholders to actually read and give useful feedback on your carefully-crafted design feels like the hardest part!

One tactic I like to use is to schedule a design review session where you get all the key stakeholders on a call for an hour and talk through the design with them.

Or, you can even schedule multiple syncs with different stakeholder groups, for example:

  • A sync with Product, Customer Success, and Design to go over the problem context and high-level proposed solution.
  • A sync with your engineering team to deep dive into the technical implementation.
  • A sync with Security to discuss the risk assessment.

Using syncs will drastically shorten the feedback loop and surface questions that likely would never be brought up from just asking stakeholders to “review the doc.”

Of course, this depends on your company culture and process. Understanding how to communicate effectively within your org is a whole ‘nother topic.

Conclusion

That’s it! Next time you’re writing a document, keep these in mind:

  1. Know your audience!
  2. Structure your document based on the audience’s needs.
  3. Put in the effort to write high-quality content.
  4. Don’t forget to revise!