Author here. Happy to take any feedback about this post.
I learned to write design docs at Microsoft and Google, and I thought they both had good culture around docs that hasn't percolated out as well as other engineering practices at those orgs. I haven't seen a thorough explanation of how to write design docs, so this is my attempt to externalize what I've learned about writing them.
This is good guidance, but what do you have to say about convincing your team of developers to live it out?
I've found that developers usually like writing code and avoid contributing to documentation. For some, it's actually scary because (edit: for them,) high quality writing is harder than high quality coding, and it can be avoided quite a bit.
On the project side, it's rare for the implementation and verification stages to not consume all the budget and more, and delivery creeping past the original optimistic date. So there's no time or money to spend on documentation.
The combination is that even with your great advice in hand, it's hard to navigate to really solid and comprehensive design documentation underpinning the products.
The documentation became the bible, and although I tried to keep the design goals at the conceptual/logical level the following would happen the moment the implementation started:
1. This is ambigous the docs need updating, please refactor your design
2. This doesn't work as the doc stated why did you get this wrong
3. The requirements have changed you need to update it
The burden to get "everything right" was absolutely lumbered of me, and the document became an easy finger pointing exercise, even if blame wasn't intended by those launching the critique the burden of "owning" the doc and the consequences of the doc was real.
Now there's a good chance that I am just a shit documentation writer, I can accept that, but honestly I feel like for the vast majority of organisations this just falls into another step of the waterfall pattern, which just doesn't work.
What you're describing sounds like toxic team dynamics rather than something specific to design docs. Do you work effectively with your teammates outside of design docs, or is there similar tension/hostility everywhere?
What you're describing sounds like the design process working as intended (modulo the finger-pointing). The design doc should be unambiguous, and the implementation should match it.
Assuming this isn't just symptoms of a sick team, my other explanation is that your teammates find your deviations from the design doc unexpected. It sounds like you're running into situations where you can't implement the design doc as written, so you're proactively making your own design choices and showing your teammates the implementation. Could you loop your teammates in earlier on before you've implemented the code? Like, "The design docs says we're supposed to use SQLite, but I realized that SQLite doesn't support types the way we expected, so I think we should switch to Postgres for X, Y, and Z reasons."
Thanks for taking the time to reply, please take my response as earnest attempts to better myself :)
So, I think I didn't elaborate on the process enough to get the answers I was looking for. Here's what happened.
1. I would uncover a requirement from the business
2. The conceptual design would be written, high level understanding of the feature etc that was trying to be written
3. Conceptual design would be signed off
4. Logical design would take place ( I think this is basically everything from the Constraints section down in your model )
5. Logical design would get reviewed and signed off.
Now technically everyone could and was encouraged to sign off the logical design, but in reality maybe one other person in the team would, I don't really know the reasons why.
Then implementation start, this was usually NOT me but another team member tasked with the design, and this is where the process really started to fall down with the onus being put squarely back on me as to why the design didn't work :)
I also actually tried the other approach, implement as much as possible ( because AI fast ) and then reverse engineer the design, but then that very much felt like, what the hell is the point now? I might as well just use the standard code review process.
It's hard to say without knowing what things are like at the company/team you work for, but I can say the things you're describing sound unusual to me.
Most significantly, it's strange for the person writing the design doc not to be the person implementing the code. This is asking for trouble because there's a principal-agent problem[0], and also there's bound to be signal lost in the handoff between designer and implementer. It's not so unusual for the design doc author to work with a team on implementation, but they'd still be actively involved in implementation, which sounds different from what you're describing.
I've also never heard of this separation between a conceptual design doc and a logical design doc. I've been on teams where the product manager writes a UX-focused spec, and then the dev writes a technical-focused spec, but I've never heard of a conceptual vs. logical spec.
Does the org have a strong engineering culture in other ways? Like automated tests, automated deploys, automated monitoring/alerting, useful code reviews? Because the easiest answer is that you're in an org with poor software engineering practices, or at least weak documentation culture, and the design review process you're experiencing is there for historical or political reasons rather than engineering reasons.
Good read, although the document would be very lengthy if I am to write all the sections in the articles. I sometimes break down the design doc into multiple design docs.
- Manager doc : Summary(Background + Objective), User Story (Scenarios), High level architecture, open questions, task break down + timeline including other teams' tasks
- Engineering Architecture doc: Summary, Glossary, Goal (Functional + Non-functional + Non-goals), More detailed architecture & components between, open questions, tasks break down + timeline
- Engineering API / Database design doc: Similar summary + link to architecture doc. More detail information on API (eg: input params, output params, example client code) + database design (eg: database type + fields), open questions
Each doc is to be read within a single meeting. The shorter doc helps narrowing down the discussion scope.
Disclosure: I worked at Amazon where there typically a 1 hour meeting session where people spend 15-30 minutes reading the doc first. It's probably why I make my doc short enough for the duration. It feels redundant sometimes to have multiple docs with the same summary, but it beats telling people "Today, we'll read section 1,2,3,5,8 of the doc"
Really nice read. I'll add that it's effective to scope design docs up and down as needed, both in terms of how big your project is and how big your company is. A 50-person startup doesn't need a full design doc with multiple approvers. But a one-pager explaining what you're doing and having some documentation is really helpful even with an engineering team of 5. I'll also still write design docs for code changes that only touch a handful of files, if I feel it's important enough. The process of writing in a concise and precise way for other people to consume also has the positive side effect of making things more clear for yourself, too.
> Interfaces section
Only real criticism I have here, is I would not include any code in a design doc, unless it is really really vitally important. I've seen a lot of design docs (especially in the LLM age, written by more junior staff) which are effectively just an English summary of code. The point of a design doc is (generally) not to explain that you're going to have a WidgetManager and WidgetFactory class and what specific properties and methods they have, it's to explain how the widget creation workflow works and maybe you have the WidgetManager/WidgetFactory in an architecture diagram. As a general rule, if you're starting to include actual code, you've gone too low-level, IMO.
> Not all design decisions are equally important. Some choices are more permanent than others.
At AWS one of the corporate culture memes was calling a decision either a "one-way door" or "two-way door". Just asking yourself the question, if we had to walk this back, is it truly irreversible or just an inconvenience? Turns out most day-to-day decisions are two-way doors, particularly engineering ones. Even if the choice made is wrong and a bunch of work needs to be done to switch back, it's still preferable to what a lot of companies end up in, which is decision paralysis where every change needs approval from multiple committees, resulting in months or years before work can start. Note that this doesn't meaningfully increase the odds the decisions made are the right ones; it just delays the implementation and diffuses responsibility if the wrong decision was made.
> A from-scratch rewrite would never work, and even if you manage to write new code in Rails, you’re still maintaining code in two wildly different languages.
Orthogonal to the article, but this line of thinking (including the link to the classic 2000 "Things You Should Never Do, Part I" article[0]) may be worth reviewing in the post-LLM world; for all their flaws, LLMs are spectacular at language-to-language translation, and we already have one major project released[1] that shows porting a relatively large and mature project from one language to another is possible. Not to say that it's the best use of your time, or that you shouldn't do your due diligence and pick the right language up front, or even that the original 2000 article was about a language-to-language rewrite (the Netscape rewrite was an architectural redesign).
Thanks for reading and for the thoughtful feedback!
> Only real criticism I have here, is I would not include any code in a design doc, unless it is really really vitally important.;
Yeah, that's fair. If I were setting guidelines for a large org, I'd maybe discourage code snippets in design docs, as it's hard to know when is too much. At my last company, the dev team was just 3-4 people, and I found it helpful to have little snippets in design docs especially when we're talking about semantics of a new library or how to migrate existing code to a new system.
> Orthogonal to the article, but this line of thinking (including the link to the classic 2000 "Things You Should Never Do, Part I" article[0]) may be worth reviewing in the post-LLM world; for all their flaws, LLMs are spectacular at language-to-language translation, and we already have one major project released[1] that shows porting a relatively large and mature project from one language to another is possible.
Yeah, I agree this could change with LLMs, but I think Joel is still correct up to today. Bun is an interesting case because it's friendliest possible conditions for an LLM rewrite (self-contained inputs and outputs, easy to test old implementation and new implementation side by side, huge test corpus w/ third-party tests). I haven't followed it closely, but it seems like the jury's still kind of out as to whether the rewrite was a good idea.
I have worked on DO-178C (aerospace) and IEC 62304 (medical device) software design documents and they are much narrower in scope.
OP's design document is comprehensive enough to cover much of ground of the full documentation package for regulated software submissions. Basically all that's left is tracing requirements to design to verification method to verification result.
It certainly feels like this is an intrinsic friction point in a world where more and more of the actual code is written by AI. I know in my workflows, reading a design doc of any length is a big tradeoff of time that could be spent building. Which isn't a new problem to have, of course, but as the time from plan->code->review->deploy keeps racing downward, "reading design docs" feels like it's ripe for disruption as far as how much time and attention it takes.
I think getting people to read design documentation was always the challenge; this is not a new thing.
I've both produced documentation and consumed it. When I consume documentation, I don't expect much. And to be honest, I don't like the low signal to noise ratio in typical design documentation. That was always a problem. Any sufficiently complex thing is just hard into a power point friendly diagram. And anything involving boxes and arrows where the number of boxes is 5 at best, is probably not that interesting to think about.
Start with a single reviewer who is invested in the topic has been helpful for me. Occasionally it is hard to even find one person with how scatter brained everyone seems to have become lately, but depends on who you work with I guess...
Claude, write a skill to create design docs as per this blog post /s
In all seriousness a big chunk of my work is reviewing docs and 100% of the design docs I read these days are generated and there is a lot of slop. I have to parse them with AI to make sense of them, contributing to the problem. I wish people would follow a sensible set of rules like this one.
Did anyone have any solution to this dread? Or cracked the code on how to write docs that have other agents as their primary audience?
I’d say don’t bother trying to parse it alone. Have a meeting where the person that created it presents it, and drill into anything weird.
If you can back them into a corner and force them to admit they don’t even understand something they supposedly wrote, use that as an opportunity to remind people it’s not acceptable to generate design documents that you don’t understand and then push them off onto other people.
No feedback on the design doc, except to say it's a good template and very helpful for someone who hasn't worked in a world where design docs have been critical. But can I say we use tinybeans and have a similar complaint (and others), and we would happily jump ship if there was an alternative like that laid out in your example.
I've never experienced a situation where a software design document meaningfully improved the overall process. At best, it helps to keep the business in sync at the expense of a much longer delivery timetable. Even high level software delivery contracts never seem to stay on rails for very long.
It is often faster to just build the damn thing and see where it lands. Software is not like a nuclear power plant or offshore oil platform. You do not need to prove a whole lot of things in advance of construction. No one actually has to give you permission to do anything. You can email a link of a vertical slice prototype to the business whenever you feel like it. That can be the "design document".
I'll admit a lot of bias because I think design docs are extremely useful, but I find that when people hate design docs, it's almost always for one of two reasons:
1. The developer has worked on teams where design docs are viewed as a pointless ritual, so authors treat them as a pointless requirement and write bad docs and their teammates view them as pointless so they don't bother giving useful feedback, reinforcing everyone's belief that they're a pointless ritual.
2. The developer does not like other people questioning their engineering choices, and they know that it's harder for their teammates to push back on finished code than a design doc. Investing in the implementation before design changes the calculus to bias in favor of whatever's already implemented rather than what would have been the ideal implementation. Plus, it's harder for the team to review design decisions of 10k LOC than a 5-page design doc.
YES - and 3 the the assumption that it needs to be a certain length before it can be considered a design document.
Esp. in the age of AI a little guidance to brainstorm on before a random project prompt goes a long way. (Not saying people that don't use design docs just code away thoughtlessly) - experience goes a long way too that's why there's success stories with and without design docs.
I think your framing is fair here. But I'd like to offer an even more complicated/nuanced take:
Designing in a group can be very difficult, and doing it well is a skill set that most people don't naturally have.
I think this explains your point 1. Why do people view designed docs as pointless? Because they really don't have a vision or model for what and effective and healthy collaborative design process would look like.
> Designing in a group can be very difficult, and doing it well is a skill set that most people don't naturally have
Not only is it a skill every participant needs to have, they also all need to have a similar amount of competence and knowledge about the domain as well as the current implementation, otherwise it's mostly pointless ime.
But if all ven diagram circles overlap ... It is nice.
I can count the times this materialized (in my professional life) on one hand. So I'm generally more towards the "make a prototype, then explain it to the others. Either it's the baseline for the discussion or the illuminating event that clears up wherever this approach works with that team.
Num. 2 especially relatable.
A good mark of high quality professional is if he presents his plan before execution to hear feedback and comments - even if they are totally against his original idea, and he can then take this feedback and incorporate effectively in a re-design.
100%. I find it's generally used as a waterfall practice - i.e. BDUF first with a design document, then implement instead of "implement following conservative assumptions, revisit and refactor aggressively".
The latter being vastly more effective at honing good design because more decisions are made in retrospect.
I find that a spike or a spike PR to demonstrate a new approach (if a software design decision is controversial) is 10x as valuable.
> implement following conservative assumptions, revisit and refactor aggressively
> The latter being vastly more effective at honing good design because more decisions are made in retrospect.
Only if people actually do that.
I've joined a project where a design doc should've been written before the first line of code (as per the agreed upon dev process). Developers disregarded that and yolo'd their way to a first prototype. No documentation whatsoever. Then someone else was tasked with writing a design doc for that big ball of mud. You can imagine how that went.
I've joined the project only much later. At every corner I'm dumbfounded by the "design decisions". Refactoring now is a herculean task and kept to the minimum required.
I'm certainly not advocating for waterfall-like "make a plan and stick to it no matter the cost". But looking at the requirements and drafting a coarse design from those goes a long way. At least you can get idea if whatever you have though up is in agreement with the requirements.
Treat the design document as a living document. Do a coarse draft first. Implement. Refine the doc with stuff you've found out, ditch the stuff that didn't work. As a bonus you get a relatively neat on-boarding doc for people joining later.
yoloing your way to a first prototype and aggressively refactoring along the way does make a lot of people very uncomfortable but it still produces better architectures than BDUF or even a scaled down BDUF (LDUF?).
it's really not generally appreciated just how much better architectural decisions made in the context of refactoring are. if you have a time budget for architecture it will always be better spent on refactoring than writing documents in advance, no matter how minimal they are.
Have you never encountered code that you thought was designed fundamentally incorrectly, but was too entrenched to change? That's what design review is for.
> t best, it helps to keep the business in sync at the expense of a much longer delivery timetable.
If you're writing a software design document that slows down your delivery timetable, you're doing it wrong. (Or, more charitably, your business is doing it wrong.) If your design document is to keep the business in sync, you're doing it wrong. That's not what a design document is for. It's for keeping you in sync.
> It is often faster to just build the damn thing and see where it lands.
What are you building? If you don't know, then sure, it's really hard to write a design document. At that point, you're doing exploration, research, not development.
But even when it's an exploration project... once you've found something worth doing, take a day or two and document what you're doing and how you're doing it. Think through all the places in the code you're going to have to touch, all the other things it has to interface with. Make sure you're not going to leave a gaping hole in functionality or, worse, in security.
> Software is not like a nuclear power plant or offshore oil platform.
As others have said, sometimes software is a nuclear power plant or offshore oil platform or airplane or medical device, or even just medical informatics. If you mess up people can die. Sometimes it trades financial instruments, and if you mess up it can destroy the company.
> No one actually has to give you permission to do anything.
On your own time, sure. If you own the company, sure. Otherwise, you need their permission to spend their time on things that they're willing to pay for.
Now, look, it's true that many places go too far overboard on "process". But YOLOing and cowboying isn't the answer either. They aren't even the answer if your single goal is to go as fast as possible. You go faster by spending the appropriate amount of time thinking through what you're building, how you're building it, and making sure you're not missing any of the big things that often trip projects up.
Instead of thinking through all the places in the code the AI is going to have to touch, why not kick off three parallel agents implementing the thing and finding out what they did and the tradeoffs they found?
Planning is essential but it doesn't survive contact with reality. However, AI makes contact with reality cheap! Why not use it to improve designs, by writing the design after a few implementations have already been made?
I'm looking for the places that need to be touched, but that wouldn't occur to me (and maybe not to an AI either) while I'm knee-deep in the code. Seeing where the AI touched isn't going to solve that.
If the feature works, and passes AI auditor agents with various hats (thinking of auth and security in particular), did that code you're not thinking of need to be touched? What effect did it have that cannot be captured in side effects, tests or audits?
If what you said doesn't make the AI think of changing that code, why is it going to make the AI auditor think of testing that code? That's what a gap looks like: Nobody changed it, nobody tested it, but some business constraint is now left in an inconsistent state because some piece got updated and another piece did not.
Here's an example. You updated the code that interfaced with the database. But you forgot to update the stored procedures within the database. As a result, the database is now being put in an inconsistent state with every transaction that uses your new code. That is the kind of thing that a software design doc can help you remember, because it is supposed to make you think through all the stuff.
And if you're going to say "Your business stuff shouldn't be able to get into an inconsistent state", well, there's a lot of businesses that have potential landmines laying around. You can say they shouldn't. You're right, in an ideal world. But in this world, they do, and you have to live and work in the world that we have.
Now, in fairness, a good AI check might turn up that the database was left in an inconsistent state... if it understood the constraints well enough. If. I wouldn't want to gamble my production database on the AI's understanding and testing of all the constraints, though.
When I've worked with systems that had these kinds of characteristics, we had checklists. A long list of "have you thought of X". You can't rely on someone writing a design to think of these things either! You need to have a process, and the process applies whether you dive into the code, dive into the spec, or have an AI dive into either.
Well, yes, I'd expect a checklist to be used as part of creating the design document. If there's a separate auditing tool that also knows about the checklist, yes, that's useful.
But if you're doing a spike, no, don't do a design document for it. How can you? You don't know what the design needs to be yet!
It's been quite helpful when your project needs expertise from other people, and you want them to vet your approach and find gaps. Doing the up-front work of explaining the context and structuring the project in an easy to understand way makes it more likely for busy people to engage with it and help you out. Of course, it's helpful as a rubber-duck exercise on its own, so I would err on creating one, even if just for myself, for anything high-risk or hard to change later.
> It is often faster to just build the damn thing and see where it lands.
Part of documentation is figuring out if you're building the RIGHT thing. It give the opportunity to get feedback from more than one party.
The usability of most modern (complex) application is deplorable. I see things that a paper prototype with 5 people on the street should have stop dead in its tracks being rolled out with banners and trumpets.
And then no one ever wants to remove an unused or unprofitable feature. There is no bonus for it, no one puts that on their resume. But the feature you launched that really did enshitify the product gets put on there with 3 gold stars.
It's mixed for me because there are certain things that I clearly think are needed. For example I'm building a custom network architecture and it's to the point where I'm using frontier models to reverse engineer game clients (while battling against the cyber safety system) for the sole purpose of validating that the network architecture I'm making is, if not "useful" (cause there's the game itself), at least different and superior. And to me the designs out there clearly are evidence of things not designed well and thought through ahead of time and instead a patchwork of hacks.
But then there are aspects I'm missing because while I've thought about the network protocol deeply, I'm not, say, a game developer who's ever gone through the whole game dev lifecycle. There's common patterns with software dev but it ain't it. There are probably so many things I have not thought about w.r.t. the whole deployment process that I'm not sure if letting AI vibe design+code it out is good or if I need to sit down and deeply work out the things I don't even know I don't know.
> I've never experienced a situation where a software design document meaningfully improved the overall process.
If you don't have a document, then how do you make sure that internal team A and internal team B and internal team C and external vendor D and external vendor E all create the correct things so the entire system actually works?
I cowboyed a lot of projects, then 2 years later a feature is not working as expected. It is.
Good docs, signed off by stake holders is essential. It basically covers you the dev, and confirms everyone involved agrees on what the software will do in certain situations.
Have you never built a large piece of software that had tradeoffs? What if your teammate just goes immediately into implementation with an AI and the AI decides to use library Foo which is disallowed for certain customers and API Bar which uses a legacy IAM platform that your company is in the process of moving away from? What if there are privacy, security, or legal requirements? It's more important than ever to discuss these things with humans who know the system because an agent will blindly go off and find something that someone once made work and will use it as evidence for why that's the way things should be done.
I've written bad/poorly designed code and made decisions I regret and have had coworkers use that bad code to defend their design choices because the agent said it was the best available option.
Design documents also let the engineering team who will be reviewing your code get a high level understanding of all the pieces you're sending them. If you've ever worked at a large company or codebase it's insane to say these docs aren't helpful.
When you need buy-in from others outside your team, you probably need a design doc. Even when you don't, if the design is not trivial then a design doc will help your successors understand what you were up to.
I mostly work on solo projects and the reason I create design docs is so that I can sit and think through cases quietly, although AI does most of the coding, writing the doc in as detail as possible is what makes me feel I am still in control
I disagree. Having a design doc would have saved me some time having to rewrite certain parts of a CRM system I am working on in Obsidian[0]. Not having a plan on handling certain aspects up from can make more work.
It reads more like a CONOPS or a software architecture document, but its not detailed enough from a high level perspective, and too detailed at a low level perspective (ie. it has implementation details in a few places you would expect in a higher level design doc).
In that light, I'm not sure who the audience would be in a corporate environment. Is it for architects, other developers, or yourself?
Some items in your doc seem more like non-functional requirements that I would expect to see in a specification, not a design document: e.g., security, privacy, legal.
Some of the items in your document seem more like non-functional requirements that I would expect to find in a specification, not a design document,e.g., security, privacy, legal.
Isn't much of this made redundant by being part of an existing system? Also, this level of detail is a recipe for being outdated once the issues, compromises and compromises starts coming in
> Isn't much of this made redundant by being part of an existing system?
I haven't found that to be true in my work. If you're only making a minor change to an existing system, then you may not need a design doc, but a significant change to an existing system has as much, if not more, complexity and ambiguity than greenfield development.
> Also, this level of detail is a recipe for being outdated once the issues, compromises and compromises starts coming in
I think this is what people typically get wrong about design docs.
I don't think design docs are a good medium for being the perpetual, living description of the system. I think design docs should capture the design at the time of implementation. You should modify the design docs while you implement the work called for in the design document, but once you're done with that work, you freeze the document and preserve it for posterity only.
The design doc is about a specific change to the system. If you need a doc to describe the high-level architecture of the system as it evolves, that should be a different doc.
I’m curious how you handle design docs when requirements change significantly during implementation. At some point, updates and corrections can start describing a somewhat different project from the one that originally went through review.
Is there a rule of thumb for when it’s enough to update the existing document, and when the design has changed enough to justify a new design doc and another review?
My rule of thumb is to ask myself, "Is there a chance my reviewers would not have signed off had this been in the design doc they reviewed?" If the answer is yes, I send it out for a follow-up and explain why I had to change the design.
In my experience, the response from my reviewers is generally, "Yeah, that's fine." It's a combination of (1) the practical limitations that it's hard for them to get the whole design back into mental context to argue about it and (2) they trust that I'm taking the design seriously and have thought this through. I think occasionally, I've sent a post-approval change out and someone points out something
It's common to encounter a curveball nobody anticipated at design time, but if you just go rogue and unilaterally make design decisions, it degrades trust and undermines the review process, so I want my reviewers to know that I'm taking their feedback seriously.
Lot of this is outdated. Including stuff that made a lot of sense in the past like diataxis and the google guidance.
I've started to build docs structured as a skill. Since every model/harness is trained to handle skills well today. The entire docs of a project or modeled as a skill.
I also have additional frontmatter on the md files. Specifically 2 keys -> when should you read, when you should not read this doc. This with a simple cli to help parse this has made the docs experience much quicker and nicer.
You can also generate svgs, mermaids etc on the fly now when you are really stuck on something.
I think they're valuable, both because they get you to think through the actual functionality (and underlying implementation) of the software, and the make sure that you and the [person you're developing for] are roughly on the same page. Plus, every edge case or design issue you catch while writing the spec saves you a ton of time.
That said, I think a big weakness of specs is that it's just not possible to write a perfect spec that doesn't have any blind spots and covers all the edge cases and issues you'll run into when actually developing. This makes it more difficult to hold the customer accountable to the spec, since you (the designer and devs) can't really be accountable to the spec unless you want to deliver some overly literal, not-actually-helpful product.
Fun piece of trivia, Joel published one of his functional specs.[0]
As a huge fan of Joel's writing and engineering ideas, I was actually underwhelmed by his spec. It wasn't bad but it also felt like he missed a lot of opportunities to articulate design decisions to the reader more quickly or clearly.
One obvious mistake is that there's over a page (in a 20-page spec) just dedicated to coding conventions and what prefixes variable names will have. I think Joel later conceded that it was a mistake to cover naming conventions in a spec, though I can't find a link now.
I definitely agree that it's not perfect. I think he's a great starting point though, because when trying to get engineers to document stuff (something typically approached with similar enthusiasm to having their teeth removed with a hammer) it really helps if the "how to write a spec" doc is somewhat fun to read.
Unrelated - I really dig your "my [x]th year as a bootstraped founder" series.
I've never been much for design docs. But I have some projects that are on again/off again and I can lose my train of thought. It seems like having one of these could help a lot with that.
I answered this in another comment,[0] and I don't think there's widespread agreement on this, but I think design docs should be a short-term doc that lives until the design implementation is complete. I don't think design docs are the right format for a document that has to evolve alongside the code forever.
Don't know about efficient, but there is at least two ways which seem to work OK-ish (although not all that efficient, I gahter):
* Do regular certifications. Before certification, check if the document is up to date. If not, update it.
* Share the documents to answer teammates' questions. Like with a WIKI it may turn out that the important stuff is actually missing/undocumented/outdated. This is then a good opportunity to fix the document.
I used to work in medical devices where it's all about documentation and even there nobody took the time or had time allocated by management to work on documentation. And most people aren't good at writing so the documents were terrible.
I've found the design doc itself is relatively useless once it has been created, but that the act of creating the design doc is an indispensable part of the process. Spending time and getting your thoughts organized before diving into the team, the management and the editor makes a huge difference.
I think the design doc still has some value after it has been created. For me it almost acts like a checklist of things to be completed, and it's nice to have it in one place in bite-sized bits. My design docs will also have links to external resources and it's nice to have them in one place so I don't have to track them down later.
But I 100% agree that the majority of the value is gained in the writing of the design doc, and the decisions/tradeoffs that have to be thought through during that process. Which is why I strongly push back against suggestions of using AI to write design docs. Since delegating the writing to AI causes over half the value of the design doc to be lost.
> A good design doc can save you years of development time
Brainstorm with your agent in a new session, ask a thousand questions, at the end ask for a detailed prompt.md to develop an app then tell it to comply
I think specs are incredibly valuable for who's writing/developing the software as a thought exercise, and pretty much useless for anyone else, especially after you ship it as it'll always get outdated very quickly.
1) Add a section called "Potential Changes". This is broader than "missing features", and can include other items too, such as new hardware that might become avaliable, customer requirement changes you might anticipate, possible new technology (e.g. a new database or cloud service that might be useful), multilingual support, etc. Listing some of these often causes reviewers to think of others as well.
Ensuring the design is modular around such changes means implementing any of them will be far easier than if assumptions are hard-coded throughout the codebase.
2) Security and privacy are two aspects of a more general category of "compliance assurance". Those two are worthy of their own categories, but you should have a section covering any other legal, regulatory, or corporate requirements. The plan for auditing these compliances should be listed too.
Often, of course, there are none beyond security and privacy.
> A good design doc can save you years of development time.
I only have a few years of experience in this business, but I have seen numerous cases where none of any of this matters. Your perfectly drafted plan could easily be derailed by technical limitations, customer request or company reorg. You are better off use that planning time for something else.
I would argue that the technical limitations should be considered during the creation of the design doc. In my experience, writing design docs can help me simplify the implementation because I've through through a lot of the headaches ahead of time.
But I will say I've seen many projects get ended by customer request or reorg. I think it's a cost-benefit analysis where you should consider the size of the project (and how long it will take to implement) vs. how long it will take to write the design doc. If it's a 2 day task, that is easy to change after the fact, then no need to write a design doc. But if it's a 2 month project that will have public endpoints that other teams or products will use, it likely is worth a 2-3 day design doc.
Coming from an optics/electronics background, it's fascinating to see how much debate there is here around whether a design document is useful or not. I don't think any engineer outside software would start a project without writing at least a few paragraphs to make sure everyone agrees on what needs to be built, and that there's no major blocker.
I blame the low cost of iteration in the software world (even lower now with LLMs).
88 comments
[ 2.4 ms ] story [ 32.7 ms ] threadI learned to write design docs at Microsoft and Google, and I thought they both had good culture around docs that hasn't percolated out as well as other engineering practices at those orgs. I haven't seen a thorough explanation of how to write design docs, so this is my attempt to externalize what I've learned about writing them.
I've found that developers usually like writing code and avoid contributing to documentation. For some, it's actually scary because (edit: for them,) high quality writing is harder than high quality coding, and it can be avoided quite a bit.
On the project side, it's rare for the implementation and verification stages to not consume all the budget and more, and delivery creeping past the original optimistic date. So there's no time or money to spend on documentation.
The combination is that even with your great advice in hand, it's hard to navigate to really solid and comprehensive design documentation underpinning the products.
The documentation became the bible, and although I tried to keep the design goals at the conceptual/logical level the following would happen the moment the implementation started:
1. This is ambigous the docs need updating, please refactor your design 2. This doesn't work as the doc stated why did you get this wrong 3. The requirements have changed you need to update it
The burden to get "everything right" was absolutely lumbered of me, and the document became an easy finger pointing exercise, even if blame wasn't intended by those launching the critique the burden of "owning" the doc and the consequences of the doc was real.
Now there's a good chance that I am just a shit documentation writer, I can accept that, but honestly I feel like for the vast majority of organisations this just falls into another step of the waterfall pattern, which just doesn't work.
How do you handle this? What did I miss?
What you're describing sounds like toxic team dynamics rather than something specific to design docs. Do you work effectively with your teammates outside of design docs, or is there similar tension/hostility everywhere?
What you're describing sounds like the design process working as intended (modulo the finger-pointing). The design doc should be unambiguous, and the implementation should match it.
Assuming this isn't just symptoms of a sick team, my other explanation is that your teammates find your deviations from the design doc unexpected. It sounds like you're running into situations where you can't implement the design doc as written, so you're proactively making your own design choices and showing your teammates the implementation. Could you loop your teammates in earlier on before you've implemented the code? Like, "The design docs says we're supposed to use SQLite, but I realized that SQLite doesn't support types the way we expected, so I think we should switch to Postgres for X, Y, and Z reasons."
So, I think I didn't elaborate on the process enough to get the answers I was looking for. Here's what happened.
1. I would uncover a requirement from the business 2. The conceptual design would be written, high level understanding of the feature etc that was trying to be written 3. Conceptual design would be signed off 4. Logical design would take place ( I think this is basically everything from the Constraints section down in your model ) 5. Logical design would get reviewed and signed off.
Now technically everyone could and was encouraged to sign off the logical design, but in reality maybe one other person in the team would, I don't really know the reasons why.
Then implementation start, this was usually NOT me but another team member tasked with the design, and this is where the process really started to fall down with the onus being put squarely back on me as to why the design didn't work :)
I also actually tried the other approach, implement as much as possible ( because AI fast ) and then reverse engineer the design, but then that very much felt like, what the hell is the point now? I might as well just use the standard code review process.
Does that make sense? Sound familiar?
Most significantly, it's strange for the person writing the design doc not to be the person implementing the code. This is asking for trouble because there's a principal-agent problem[0], and also there's bound to be signal lost in the handoff between designer and implementer. It's not so unusual for the design doc author to work with a team on implementation, but they'd still be actively involved in implementation, which sounds different from what you're describing.
I've also never heard of this separation between a conceptual design doc and a logical design doc. I've been on teams where the product manager writes a UX-focused spec, and then the dev writes a technical-focused spec, but I've never heard of a conceptual vs. logical spec.
Does the org have a strong engineering culture in other ways? Like automated tests, automated deploys, automated monitoring/alerting, useful code reviews? Because the easiest answer is that you're in an org with poor software engineering practices, or at least weak documentation culture, and the design review process you're experiencing is there for historical or political reasons rather than engineering reasons.
[0] https://en.wikipedia.org/wiki/Principal%E2%80%93agent_proble...
- Manager doc : Summary(Background + Objective), User Story (Scenarios), High level architecture, open questions, task break down + timeline including other teams' tasks
- Engineering Architecture doc: Summary, Glossary, Goal (Functional + Non-functional + Non-goals), More detailed architecture & components between, open questions, tasks break down + timeline
- Engineering API / Database design doc: Similar summary + link to architecture doc. More detail information on API (eg: input params, output params, example client code) + database design (eg: database type + fields), open questions
Each doc is to be read within a single meeting. The shorter doc helps narrowing down the discussion scope.
Disclosure: I worked at Amazon where there typically a 1 hour meeting session where people spend 15-30 minutes reading the doc first. It's probably why I make my doc short enough for the duration. It feels redundant sometimes to have multiple docs with the same summary, but it beats telling people "Today, we'll read section 1,2,3,5,8 of the doc"
> Interfaces section
Only real criticism I have here, is I would not include any code in a design doc, unless it is really really vitally important. I've seen a lot of design docs (especially in the LLM age, written by more junior staff) which are effectively just an English summary of code. The point of a design doc is (generally) not to explain that you're going to have a WidgetManager and WidgetFactory class and what specific properties and methods they have, it's to explain how the widget creation workflow works and maybe you have the WidgetManager/WidgetFactory in an architecture diagram. As a general rule, if you're starting to include actual code, you've gone too low-level, IMO.
> Not all design decisions are equally important. Some choices are more permanent than others.
At AWS one of the corporate culture memes was calling a decision either a "one-way door" or "two-way door". Just asking yourself the question, if we had to walk this back, is it truly irreversible or just an inconvenience? Turns out most day-to-day decisions are two-way doors, particularly engineering ones. Even if the choice made is wrong and a bunch of work needs to be done to switch back, it's still preferable to what a lot of companies end up in, which is decision paralysis where every change needs approval from multiple committees, resulting in months or years before work can start. Note that this doesn't meaningfully increase the odds the decisions made are the right ones; it just delays the implementation and diffuses responsibility if the wrong decision was made.
> A from-scratch rewrite would never work, and even if you manage to write new code in Rails, you’re still maintaining code in two wildly different languages.
Orthogonal to the article, but this line of thinking (including the link to the classic 2000 "Things You Should Never Do, Part I" article[0]) may be worth reviewing in the post-LLM world; for all their flaws, LLMs are spectacular at language-to-language translation, and we already have one major project released[1] that shows porting a relatively large and mature project from one language to another is possible. Not to say that it's the best use of your time, or that you shouldn't do your due diligence and pick the right language up front, or even that the original 2000 article was about a language-to-language rewrite (the Netscape rewrite was an architectural redesign).
[0] https://www.joelonsoftware.com/2000/04/06/things-you-should-...
[1] https://bun.com/blog/bun-in-rust
Thanks for reading and for the thoughtful feedback!
> Only real criticism I have here, is I would not include any code in a design doc, unless it is really really vitally important.;
Yeah, that's fair. If I were setting guidelines for a large org, I'd maybe discourage code snippets in design docs, as it's hard to know when is too much. At my last company, the dev team was just 3-4 people, and I found it helpful to have little snippets in design docs especially when we're talking about semantics of a new library or how to migrate existing code to a new system.
> Orthogonal to the article, but this line of thinking (including the link to the classic 2000 "Things You Should Never Do, Part I" article[0]) may be worth reviewing in the post-LLM world; for all their flaws, LLMs are spectacular at language-to-language translation, and we already have one major project released[1] that shows porting a relatively large and mature project from one language to another is possible.
Yeah, I agree this could change with LLMs, but I think Joel is still correct up to today. Bun is an interesting case because it's friendliest possible conditions for an LLM rewrite (self-contained inputs and outputs, easy to test old implementation and new implementation side by side, huge test corpus w/ third-party tests). I haven't followed it closely, but it seems like the jury's still kind of out as to whether the rewrite was a good idea.
OP's design document is comprehensive enough to cover much of ground of the full documentation package for regulated software submissions. Basically all that's left is tracing requirements to design to verification method to verification result.
I've both produced documentation and consumed it. When I consume documentation, I don't expect much. And to be honest, I don't like the low signal to noise ratio in typical design documentation. That was always a problem. Any sufficiently complex thing is just hard into a power point friendly diagram. And anything involving boxes and arrows where the number of boxes is 5 at best, is probably not that interesting to think about.
Start with a single reviewer who is invested in the topic has been helpful for me. Occasionally it is hard to even find one person with how scatter brained everyone seems to have become lately, but depends on who you work with I guess...
In all seriousness a big chunk of my work is reviewing docs and 100% of the design docs I read these days are generated and there is a lot of slop. I have to parse them with AI to make sense of them, contributing to the problem. I wish people would follow a sensible set of rules like this one.
Did anyone have any solution to this dread? Or cracked the code on how to write docs that have other agents as their primary audience?
Yes. Don’t “write” your design docs with AI. If you can’t personally enforce that, get your manager to.
If you can back them into a corner and force them to admit they don’t even understand something they supposedly wrote, use that as an opportunity to remind people it’s not acceptable to generate design documents that you don’t understand and then push them off onto other people.
It is often faster to just build the damn thing and see where it lands. Software is not like a nuclear power plant or offshore oil platform. You do not need to prove a whole lot of things in advance of construction. No one actually has to give you permission to do anything. You can email a link of a vertical slice prototype to the business whenever you feel like it. That can be the "design document".
I'll admit a lot of bias because I think design docs are extremely useful, but I find that when people hate design docs, it's almost always for one of two reasons:
1. The developer has worked on teams where design docs are viewed as a pointless ritual, so authors treat them as a pointless requirement and write bad docs and their teammates view them as pointless so they don't bother giving useful feedback, reinforcing everyone's belief that they're a pointless ritual.
2. The developer does not like other people questioning their engineering choices, and they know that it's harder for their teammates to push back on finished code than a design doc. Investing in the implementation before design changes the calculus to bias in favor of whatever's already implemented rather than what would have been the ideal implementation. Plus, it's harder for the team to review design decisions of 10k LOC than a 5-page design doc.
Designing in a group can be very difficult, and doing it well is a skill set that most people don't naturally have.
I think this explains your point 1. Why do people view designed docs as pointless? Because they really don't have a vision or model for what and effective and healthy collaborative design process would look like.
Not only is it a skill every participant needs to have, they also all need to have a similar amount of competence and knowledge about the domain as well as the current implementation, otherwise it's mostly pointless ime.
But if all ven diagram circles overlap ... It is nice. I can count the times this materialized (in my professional life) on one hand. So I'm generally more towards the "make a prototype, then explain it to the others. Either it's the baseline for the discussion or the illuminating event that clears up wherever this approach works with that team.
Often, the group members presented to, do not have the required knowledge to critique the design document.
I have seen people proposing (demanding even) changes based on vague feelings and their need to be seen as contributing.
Once they say something, it is out there, now it is the poor presenter who has to refute it or accept modifications to the design.
The latter being vastly more effective at honing good design because more decisions are made in retrospect.
I find that a spike or a spike PR to demonstrate a new approach (if a software design decision is controversial) is 10x as valuable.
Only if people actually do that.
I've joined a project where a design doc should've been written before the first line of code (as per the agreed upon dev process). Developers disregarded that and yolo'd their way to a first prototype. No documentation whatsoever. Then someone else was tasked with writing a design doc for that big ball of mud. You can imagine how that went.
I've joined the project only much later. At every corner I'm dumbfounded by the "design decisions". Refactoring now is a herculean task and kept to the minimum required.
I'm certainly not advocating for waterfall-like "make a plan and stick to it no matter the cost". But looking at the requirements and drafting a coarse design from those goes a long way. At least you can get idea if whatever you have though up is in agreement with the requirements.
Treat the design document as a living document. Do a coarse draft first. Implement. Refine the doc with stuff you've found out, ditch the stuff that didn't work. As a bonus you get a relatively neat on-boarding doc for people joining later.
it's really not generally appreciated just how much better architectural decisions made in the context of refactoring are. if you have a time budget for architecture it will always be better spent on refactoring than writing documents in advance, no matter how minimal they are.
Throw the document away, it doesn't have any value.
But thinking through what you are going to do, in some detail, is valuable.
If you're writing a software design document that slows down your delivery timetable, you're doing it wrong. (Or, more charitably, your business is doing it wrong.) If your design document is to keep the business in sync, you're doing it wrong. That's not what a design document is for. It's for keeping you in sync.
> It is often faster to just build the damn thing and see where it lands.
What are you building? If you don't know, then sure, it's really hard to write a design document. At that point, you're doing exploration, research, not development.
But even when it's an exploration project... once you've found something worth doing, take a day or two and document what you're doing and how you're doing it. Think through all the places in the code you're going to have to touch, all the other things it has to interface with. Make sure you're not going to leave a gaping hole in functionality or, worse, in security.
> Software is not like a nuclear power plant or offshore oil platform.
As others have said, sometimes software is a nuclear power plant or offshore oil platform or airplane or medical device, or even just medical informatics. If you mess up people can die. Sometimes it trades financial instruments, and if you mess up it can destroy the company.
> No one actually has to give you permission to do anything.
On your own time, sure. If you own the company, sure. Otherwise, you need their permission to spend their time on things that they're willing to pay for.
Now, look, it's true that many places go too far overboard on "process". But YOLOing and cowboying isn't the answer either. They aren't even the answer if your single goal is to go as fast as possible. You go faster by spending the appropriate amount of time thinking through what you're building, how you're building it, and making sure you're not missing any of the big things that often trip projects up.
Planning is essential but it doesn't survive contact with reality. However, AI makes contact with reality cheap! Why not use it to improve designs, by writing the design after a few implementations have already been made?
Only slightly tongue in cheek.
Here's an example. You updated the code that interfaced with the database. But you forgot to update the stored procedures within the database. As a result, the database is now being put in an inconsistent state with every transaction that uses your new code. That is the kind of thing that a software design doc can help you remember, because it is supposed to make you think through all the stuff.
And if you're going to say "Your business stuff shouldn't be able to get into an inconsistent state", well, there's a lot of businesses that have potential landmines laying around. You can say they shouldn't. You're right, in an ideal world. But in this world, they do, and you have to live and work in the world that we have.
Now, in fairness, a good AI check might turn up that the database was left in an inconsistent state... if it understood the constraints well enough. If. I wouldn't want to gamble my production database on the AI's understanding and testing of all the constraints, though.
It's orthogonal.
But if you're doing a spike, no, don't do a design document for it. How can you? You don't know what the design needs to be yet!
Part of documentation is figuring out if you're building the RIGHT thing. It give the opportunity to get feedback from more than one party.
The usability of most modern (complex) application is deplorable. I see things that a paper prototype with 5 people on the street should have stop dead in its tracks being rolled out with banners and trumpets.
And then no one ever wants to remove an unused or unprofitable feature. There is no bonus for it, no one puts that on their resume. But the feature you launched that really did enshitify the product gets put on there with 3 gold stars.
But then there are aspects I'm missing because while I've thought about the network protocol deeply, I'm not, say, a game developer who's ever gone through the whole game dev lifecycle. There's common patterns with software dev but it ain't it. There are probably so many things I have not thought about w.r.t. the whole deployment process that I'm not sure if letting AI vibe design+code it out is good or if I need to sit down and deeply work out the things I don't even know I don't know.
It's always a set of tradeoffs between things.
If you don't have a document, then how do you make sure that internal team A and internal team B and internal team C and external vendor D and external vendor E all create the correct things so the entire system actually works?
- interfaces lists, with attached commitment levels
- interface contracts where interface commitment levels do not otherwise allow teams A, B, and C to use each other's interfaces.
That's much better than design docs.
Good docs, signed off by stake holders is essential. It basically covers you the dev, and confirms everyone involved agrees on what the software will do in certain situations.
I've written bad/poorly designed code and made decisions I regret and have had coworkers use that bad code to defend their design choices because the agent said it was the best available option.
Design documents also let the engineering team who will be reviewing your code get a high level understanding of all the pieces you're sending them. If you've ever worked at a large company or codebase it's insane to say these docs aren't helpful.
[0]: https://www.scottrlarson.com/blog/article-crm-obsidian/
I think this is a good idea. Thanks to the author.
It reads more like a CONOPS or a software architecture document, but its not detailed enough from a high level perspective, and too detailed at a low level perspective (ie. it has implementation details in a few places you would expect in a higher level design doc).
In that light, I'm not sure who the audience would be in a corporate environment. Is it for architects, other developers, or yourself?
> Isn't much of this made redundant by being part of an existing system?
I haven't found that to be true in my work. If you're only making a minor change to an existing system, then you may not need a design doc, but a significant change to an existing system has as much, if not more, complexity and ambiguity than greenfield development.
> Also, this level of detail is a recipe for being outdated once the issues, compromises and compromises starts coming in
I think this is what people typically get wrong about design docs.
I don't think design docs are a good medium for being the perpetual, living description of the system. I think design docs should capture the design at the time of implementation. You should modify the design docs while you implement the work called for in the design document, but once you're done with that work, you freeze the document and preserve it for posterity only.
The design doc is about a specific change to the system. If you need a doc to describe the high-level architecture of the system as it evolves, that should be a different doc.
Is there a rule of thumb for when it’s enough to update the existing document, and when the design has changed enough to justify a new design doc and another review?
My rule of thumb is to ask myself, "Is there a chance my reviewers would not have signed off had this been in the design doc they reviewed?" If the answer is yes, I send it out for a follow-up and explain why I had to change the design.
In my experience, the response from my reviewers is generally, "Yeah, that's fine." It's a combination of (1) the practical limitations that it's hard for them to get the whole design back into mental context to argue about it and (2) they trust that I'm taking the design seriously and have thought this through. I think occasionally, I've sent a post-approval change out and someone points out something
It's common to encounter a curveball nobody anticipated at design time, but if you just go rogue and unilaterally make design decisions, it degrades trust and undermines the review process, so I want my reviewers to know that I'm taking their feedback seriously.
I've started to build docs structured as a skill. Since every model/harness is trained to handle skills well today. The entire docs of a project or modeled as a skill.
I also have additional frontmatter on the md files. Specifically 2 keys -> when should you read, when you should not read this doc. This with a simple cli to help parse this has made the docs experience much quicker and nicer.
You can also generate svgs, mermaids etc on the fly now when you are really stuck on something.
I think they're valuable, both because they get you to think through the actual functionality (and underlying implementation) of the software, and the make sure that you and the [person you're developing for] are roughly on the same page. Plus, every edge case or design issue you catch while writing the spec saves you a ton of time.
That said, I think a big weakness of specs is that it's just not possible to write a perfect spec that doesn't have any blind spots and covers all the edge cases and issues you'll run into when actually developing. This makes it more difficult to hold the customer accountable to the spec, since you (the designer and devs) can't really be accountable to the spec unless you want to deliver some overly literal, not-actually-helpful product.
As a huge fan of Joel's writing and engineering ideas, I was actually underwhelmed by his spec. It wasn't bad but it also felt like he missed a lot of opportunities to articulate design decisions to the reader more quickly or clearly.
One obvious mistake is that there's over a page (in a 20-page spec) just dedicated to coding conventions and what prefixes variable names will have. I think Joel later conceded that it was a mistake to cover naming conventions in a spec, though I can't find a link now.
[0] https://web.archive.org/web/20051028171624/https://www.joelo...
Unrelated - I really dig your "my [x]th year as a bootstraped founder" series.
[0] https://news.ycombinator.com/item?id=49698580
* Do regular certifications. Before certification, check if the document is up to date. If not, update it.
* Share the documents to answer teammates' questions. Like with a WIKI it may turn out that the important stuff is actually missing/undocumented/outdated. This is then a good opportunity to fix the document.
But I 100% agree that the majority of the value is gained in the writing of the design doc, and the decisions/tradeoffs that have to be thought through during that process. Which is why I strongly push back against suggestions of using AI to write design docs. Since delegating the writing to AI causes over half the value of the design doc to be lost.
Brainstorm with your agent in a new session, ask a thousand questions, at the end ask for a detailed prompt.md to develop an app then tell it to comply
There, saved years of development time in AI era
1) Add a section called "Potential Changes". This is broader than "missing features", and can include other items too, such as new hardware that might become avaliable, customer requirement changes you might anticipate, possible new technology (e.g. a new database or cloud service that might be useful), multilingual support, etc. Listing some of these often causes reviewers to think of others as well.
Ensuring the design is modular around such changes means implementing any of them will be far easier than if assumptions are hard-coded throughout the codebase.
2) Security and privacy are two aspects of a more general category of "compliance assurance". Those two are worthy of their own categories, but you should have a section covering any other legal, regulatory, or corporate requirements. The plan for auditing these compliances should be listed too.
Often, of course, there are none beyond security and privacy.
I only have a few years of experience in this business, but I have seen numerous cases where none of any of this matters. Your perfectly drafted plan could easily be derailed by technical limitations, customer request or company reorg. You are better off use that planning time for something else.
But I will say I've seen many projects get ended by customer request or reorg. I think it's a cost-benefit analysis where you should consider the size of the project (and how long it will take to implement) vs. how long it will take to write the design doc. If it's a 2 day task, that is easy to change after the fact, then no need to write a design doc. But if it's a 2 month project that will have public endpoints that other teams or products will use, it likely is worth a 2-3 day design doc.
I blame the low cost of iteration in the software world (even lower now with LLMs).