This post is reproduced from its original home on blog.e2.gg, where Evan and I share our thoughts on engineering, management, and remote work.
As I have (somewhat unexpectedly) been drawn into the world of management, one of my favourite parts of the job has been mentoring and uplifting then engineers in my organization. One of the most critical parts of that process is the fitting of incrementally more ambitious and open-ended projects to devs at each step of their learning curve, and the most important part of that, in terms of ensuring their success, is act of writing effective design documents for their projects.
This isn’t a post about why design docs are fundamentally critical to the design of good software (Joel Spolsky articulated that more effectively than I ever will, as have, honestly, many, many others) but it is worth noting that single most common root cause of failure that I’ve seen hamstring projects, particularly those run by more junior engineers, has been inadequately thorough design documents. This is the singular moment during which more senior engineers can scrutinize each element of the design, particularly the nasty and easy to miss failure cases, in the context of the whole (other than, of course, after the project launches and things start breaking). However, the exercise of communicating technical intent, complete and unambiguous, is a new and foreign challenge of its own – and even just getting started can be a daunting task to someone writing their first design doc.
So instead this is a post about what you need to get started writing your first (or your hundredth) design doc, in as brief and functional terms as is possible. With the following, I hope to provide all the structure and tooling you need to create something comprehensive for review from your peers, as well as offering a few tips and tricks to keep in mind as you fill out the format along the way.
Structure
There’s nothing more intimidating, as a writer, than a blank sheet of paper – where do I even start? To that end, for any informative documents I’m required to produce, I start with all the sections and headers I can identify, and turn the problem from “filling out the page” into (as much as is possible) “filling in the blanks.” Although the following may not quite be universal – you shouldn’t shy away from altering it to fit your domain – I find that generally starting with this format gives me enough structure to start breaking down the document into smaller problems to digest.
- Overview
- Stakeholders/key personnel – Start off with who are you (author), who owns the thing you’re building (teams), and who cares about it (key stakeholders). Although this may be unnecessary in some smaller docs, for a broader audience it really helps the folks asking questions if they know who they’re talking to.
- Background – This is where you start the narrative. It’s always important to think about how the content of your document flows from section to section, each conveying unique information that supports the conclusions that follow, and this is where you can lay your groundwork for your readers’ comprehension of that narrative. Keep it short, this isn’t the time to justify all the specifics of your solution, but set the stage with the impetus for the feature, and any requisite technological context.
- Essential terminology – Although there’s a good chance you can skip this section, take a moment and consider – are there any terms that are specific to this domain that your readers are unlikely to know, or are you introducing novel terminology for the purposes of your solution? I’ve seen countless technical discussions spiral into frustration because speaking unambiguously in english is actually really hard, and anything you can do to preempt potential confusion will save you effort down the line.
- Objectives
- Goals – What are you going to accomplish?
- Non-goals – What are you not trying to accomplish? Don’t put world peace. Many projects have intuitable extensions, or adjacent problem domains that you may be pushed towards rolling into scope. Push back – be clear regarding your boundaries (in documentation as in life).
- Technical Summary
- General Overview – Explain the logic and flow of your solution in two to three paragraphs, or if you’re feeling ambitious, five or six bullet points.
- System Diagrams – At least a broad system overview, with diagrams for key subsystems as necessary, with complimentary notes providing context as necessary.
- Key Components – Using a new AWS offering? Have a really complicated class heirarchy that’s central to the solution? Offering a new API to internal clients? Enumerate them here.
- Technical Flows – This is a chance to explain how what you’re building will be used. Whether it’s a library, an API, or elsewise, understanding it through its flows rather than it’s atomic points of interaction is a much more informative lens for critiquing the design. Sequence diagrams are immensely useful here, and I’d strongly recommend getting familiar with them for anyone who writes client-facing code (more on them later).
- Contracts/API – Okay, so now that we understand the flows, what exactly are our points of contact? The prior segment should have had most of these listed by name, and now that the reader understands how they’ll be used you can step through and give more detail on specific arguments, return values, and encapsulated business logic.
- Persistence – Are you storing data? Great, now let’s get into the details. How is that data modelled? How is it indexed? Is it scalable, and is it flexible enough to support future use cases? Bad modelling at the persistence level often causes problems down the road – particularly for the second version of a feature as you expand beyond the tightly scoped initial problem domain, so making sure the constraints of your design are well understood at the outset can be enormously valuable.
- Observability
- Metrics – What are you counting?
- Monitors – What are you analyzing?
- Alerts – What do you want to respond to?
- Risks and Risk Mitigation – Where could this project go off the rails? What business outcomes or technology constraints might result in failure cases? What might extend the timeline beyond your current estimates for delivery?
- Deployment/Rollout Strategy – “Turning it on” is another common point of failure for new features. Particularly if your project is a new/alternative flow or resource, ensuring that that any ramp up is smooth and well monitored is essential. How to manage deployments is the subject of another post, but at a minimum cover timelines, rollback plans, backwards compatibility, monitors to track during deployment, and metrics to be used as success criteria.
- Appendix – At this point you’ve covered your bases! Long form references, or content that isn’t strictly necessary to the pitch but may be useful to a curious reader can be plugged into an appendix, making it clear that this isn’t part of the body of the proposal. You can drop basically anything in here, but a few likely entries follow:
- Alternatives – Are there other strategies that are still worth considering, or that you want to justify in their exclusion?
- Required Sign-offs – In some cases explicit sign off from a set of technical partners (for inter-service contributions, for example) may be useful to have on paper. Drop it in here!
- Follow-on projects – Where are you taking this project post-MVP?
- Specific scope exclusions – Any potential expansions on the non-Goals as listed above.
- Dependencies – Projects being executed in parallel, requirements of non technical partners, really anything that may block the project from proceeding.
Tools
Of course, not everything you’ll be sticking in that doc will raw text – it’s helpful to have diagrams and tables to present specific structured information, and so I’ve highlighted a few of the most lightweight and useful tools I’ve come to appreciate in my time producing design docs.
Authorship
Where do you actually write the doc? Honestly, “wherever you’re most comfortable” is a good place to start, and the first few hours should mostly be spent dumping as many ideas as possible out of your head and into their respective sections in preparation for organization and editing. That said, once you’ve got a semi-mature draft I strongly recommend finding a buddy, copying the content into a collaborative editor like google docs, and soliciting feedback as early as possible. You don’t have to have every potential question answered and every spelling eror fixed before you start getting criticism, and it’ll save you having to make larger changes when your document is more complete. Is this obvious? Sure. Have most people put off reaching out to peers in favour of adding a little more polish first, to their net detriment? Absolutely.
System diagrams
A high level system overview is near essential for any system describing more than one client and one server. Although you can get by with just Google Draw (or, for that matter, MS Paint), there are better solutions out there. Diagrams.net is free, easy to use (many of the tools in this space are far more complicated than necessary for the general case), and produces diagrams that aren’t an eyesore. If you don’t want to think about what to use here (and you shouldn’t, generally, that’s not the problem you’re trying to solve), just use this. Technically this site addresses almost every use case listed here, but due to my preference for text-based diagramming tools (over wysiwyg), I’ll include more specialized tools in the following sections.
Sequence diagrams
These are the bees knees, and criminally underused. Many technical specifications are most usefully understood through the the flow of data and the sequence of their use, but it can be hard to express these things in raw text without being so verbose as to obfuscate the key information. Sequence diagrams offer a flexible and fun way to render these flows, and in many cases can replace hundreds of words of text with a few easily understood images. I’ve been using websequencediagrams.com for years, and would strongly recommend them for their simplicity and clarity.
Entity Relationship Diagrams
Got a bunch of models, and those models are related to each other? Just like they hammered home in CS101, entity relationship diagrams are your friend. They’re simple and easy to read, so although they can be skipped over in more simply modelled domains, they’re an extremely efficient utility to have in your toolkit when necessary. Diagram.codes has a bevy of diagramming options, is well designed, and it’s ER syntax is particularly clear and simple.
API definitions
For long term documentation I think that APIs should almost always have their docs written inline with their method signatures and docs should be generated from there. However, before the API exists in code, tooling for expressing the contract you’ll be putting in place is a lot more sparse. Most popular options, like Swagger, are a little heavyweight for the brief and high-level definitions that might exist in a design doc, and I haven’t found any solutions that I’ve really loved. As such, I basically just copy and paste a rich-text version of this snippet, and now you can make your own too!
+--------------------+-----------------------------------------------------------------+
| Endpoint Name/Path |
+--------------------+-----------------------------------------------------------------+
| Description | A little about the endpoint, how it operates, and why it exists |
| Arguments: | |Parameter| Type | Description | |
| | | ------- | ---- | --------------------------------- | |
| | | id | int | the uuid of the referenced object | |
| Response: | Serialized response object |
+--------------------+-----------------------------------------------------------------+
Techniques
So now you have a structure, a general sense of content, and a few handy tools for mocking up the diagrams that you may want to include – you’re pretty much good to go! Before you rush off though, I’d like to offer a few more points to consider as you draft your first (or fiftieth) design doc.
- Good headers help set expectations for readers and break up your document into easily parsable components. Good formatting seems like a nicety that many developers see as unnecessary frivolity, but self explanatory headers with good visual distinction between h1/h2/h3/etc. make a huge difference for reader comprehension.
- Don’t just cover the happy path. Failure modes are an essential component of a design doc, and warrant equal emphasis along with the success cases.
- The design doc should not be a product doc. Linking to the product doc near the top is a great idea, but retreading product/business outcomes, unless the project is strictly technical (and even then you could pull those out into another doc), is often counterproductive because it invites debate on a tangential subject, rather than focusing attention on the technical design.
- Emphasize complex elements, and unique/novel (within your context) elements, leave explanations of common infrastructure out or note them only briefly.
- This is a long doc structure. It can feel unduly burdensome for smaller projects, and even for larger projects it’s easy for this to feel like busywork once the author feels they’ve fully internalized the solution. Again, I don’t want to litigate that these docs are valuable (they are), but if you do feel like this is too much – do less. Something is better than nothing. Skipping some sections in the name of velocity or flexibility or just in the name of saving your sanity after a long week, can be totally fine so long as the doc still covers the core design elements of your solution. Edit the format to fit your needs and your patience, but remember the more thorough the doc, the more detailed feedback you’ll get from your peers, and the more value it will return to the project.
Finally, one last note before you go – this guide is intended to inform a formal proposal of a solution, which may be several docs deep in the design process already. You might write out a complete list of approaches to be debated, early on after identifying a problem space; you might throw together a one-pager outlining your preferred solution when you’re first seeking approval from your peers or boss to explore the direction; those are good an important, but should not be as exhaustive as the document outlined above. A design doc should assume an opinionated position regarding the correct solution, and justify that opinion through its thorough treatment of the problem space. If you’re not ready to tackle the design doc yet, that’s okay! Seek advice from peers or mentors, do a lightweight comparison of alternative solutions, and make clear to your stakeholders that you need a little more time – this is a big commitment! But when you are ready, I hope this guide helps make your experience of writing your design doc just a little bit easier.