Preferring throwaway code over design docs
softwaredoug.com
softwaredoug.com
These are all inputs into the design. But a design is still needed, of the appropriate size, otherwise you're just making things up as you go. You need to define the problem your are solving and what that solution is. Sometimes that's a 1-page doc without a formal review, sometimes it's many more pages with weeks of reviews and iterations with feedback.
Don't forget: "weeks of coding can save hours of planning" ;)
The real problem is the industry's inability to throwaway first solutions, so we introduce this (IMO inefficient) 'design doc' step as a safety mechanism
The main issue to me is exactly that we do throw away the prototype implementation.
Writing rich documentation for throwaway code is tedious, and at the early stages I see a split between the people that mostly read the doc and only glance over the code, those who almost ignore the docs and focus on the code, and some rare people actually looking at both and getting confused at the discrepancies ("you say you in your doc you store values in the remote database, but this code only writes to the local one, which one will stay ?")
Perhaps I'm just not good at docs, but doing code heavy prototypes with only very light and high level doc was way more efficient.
Then when we settle on one direction, I can freeze the main points in a separate documentation and rewrite the prototype in a more serious version.
Having a separate design docs also helps when the system components are split across many area. Having the doc even when it's a compact proposition standardizes the process and you never have to ask upfront if it will be needed or not.
A draft PR with rich documentation doesn't often communicate the "whys" and the "why nots" nearly as well as a well-written design document, or the high-level goals of a piece of code. It also is much harder to share with the product and business sides of a company which may be less comfortable with the idea of reading code.
A great design doc can reduce non-obvious problems to trivial and is usually written alongside a prototype (if the thing is simple enough).
I will give you that if you are instead competing with a poorly-written design document, a very well-documented PR may be a good alternative.
A design needs to be understood, certainly, but that doesn't necessarily mean a document, or indeed any permanent artifact. And if you do need a permanent record, a PR can be as good a medium as any.
> Don't forget: "weeks of coding can save hours of planning" ;)
I've found the opposite is true far more often. People plan and plan until the plan is not merely pointless but actively destructive to productivity.
1. Have some long term goals.
2. Design a small iterative improvement or a minimum viable product that should bring you closer to your goals.
3. Build just that.
4. Reevaluate.
I.e. I thought the idea is to embrace changing the approach or even pivoting when necessary.
Prototyping and pathfinding are totally fine and mostly necessary.
*But*, Software Engineering without design docs or any kind of specification (even if succinct) is just tree-house building, *not* Engineering.
And the bigger the size and importance of the project, the sooner the problems and technical debt will start to show.
Do you feel "engineering" could cover the entire spectrum, where your "Engineering" specifies everything on one side of "has a design doc"? If not, is there a name for the whole spectrum? Does crocheting from a pattern sit anywhere on this spectrum, or is it something else, or does it mean that my spectrum-of-engineering is an illusion? Open questions here, not directed at DrNosferatu necessarily.
Other software, perhaps not so life-or-death, …but with which side of that “spectrum” would you like to run your business or project of importance?
The USAF has put these things to paper quite some time ago: reliability, repeatability, reproducible process, and quantification (even if in a statistical interval), etc.
The problem with software is that making one more unit has a marginal cost of zero. And, going from “prototype product” to “production product” is a mere file rename away. So the temptation to see one more bug as a fact of life is always there - and that makes the thin line between Engineering and a DIY hobby being usually far too thin.
As you say, weeks of coding can save hours of planning. But weeks of planning can be wasted, too. It’s easy to write things on paper which don’t make sense or are impossible, e.g. ‘We will colour the unicorn fleet semi-sad.’ Ideally, the design and the prototype would evolve in concert, each iteration of one driving the next iteration of the other, spiralling like the double-helix of DNA.
The great virtue of a bias towards building prototypes is that at the end of a round of prototyping one actually has software which can do something — at the end of a round of design one doesn’t really have anything.
Also, "weeks of planning can save hours of coding" :)
Many times I’ve confidently thought I understood a problem, started writing about it, and come away with new critical questions. These things are typically more visible from the abstract, or might not become apparent in the first few release milestones of work.
I’m reminded of a mentor in my career, who had designed an active/active setup retroactively for a payment gateway. He pulls up a Lucidchart and says “this diagram represents 6 months of my life”.
They’re not always necessary or helpful. But when they are you can save weeks of coding with a few days of planning.
And in the end a good PR has a lot of writing too and has this effect. IMO this sort of well documented draft PR serves as a better design proposal because pure writing causes you to forget important constraints you only remember when you’re in the code.
The only problem with having the draft being implementation is that maybe you'll get pressured into shipping the draft.
If you have a draft, keep it to yourself. Use it as a personal reference when writing the design, or share snippets. Other engineers will realize you have a draft, business people won’t.
I once did the draft with ncurses as a hedge against it becoming the real thing. It didn't go over especially well but it was fun.
> But we could make an additional million next quarter if we ship it now
...crowd in check is probably what you should be doing.
I'm with the people who decided to ship this. The organization will need to fund more maintenance than they would if they waited, but that has real costs. And "keep your 1mm/revenue idea to yourself" doesn't sound like a healthy engineering culture either.
An analogy is planning a road trip with a map. The way design docs most are built now, it shows the path and you start driving. Whereas my bosses whiteboard maps "over-planned" where you'd stop for fuel, attraction hours, docs required to cross border, budget $ for everything, emergency kit, Plan A, Plan B.
Super tedious, but way better than using throwaway code. Not over-planning feels lazy to me now
Sure, everyone has a plan until you get punched in the mouth; however, that saying applies to war, politics, negotiations, but not coding.
(If you think “why does MLJ.jl have so few stars?” please keep in mind that this library was written for the Julia language and not for Python. I honestly don’t think the library is the cause of low popularity. Just wrong place wrong time.)
1. Spend as much time in planning as necessary, in the context of mega projects planning is essentially free, maximize the time and value gained in planning.
2. Once you start execution of the plan, move as fast as possible to reduce likelihood of unforeseen events and also reduce costs increases due to inflation, interest paid on capital etc.
[0] https://www.goodreads.com/book/show/61327449-how-big-things-...
We've fully embraced the "Try, Learn, Repeat" philosophy.
Since I’m in the middle of trying to do something similar, would love to hear more details. What kind of goals, whats the conflict?
It was also great for brainstorming about every feature and functional aspect you can imagine for your product, and making an effort to accommodate it in your design even if it's not MVP material.
hey, the EU just introduced this new regulation is the software version of getting punched in the mouth.
That’s a bit uncharitable but following this line of thought - you also need those smart people to be confident and communicative.
There had to be something more like just that guys authority or him being majority shareholder or him being super empathetic that he knew how to handle people.
It’s not even an argument against planning. You’d be a fool to go to war without a plan. The point of the saying is that you’d be a fool not to tear up your plan and start improvising as soon as it stops working.
Plans are nothing, but planning is everything.
The process of building a plan builds the institutional knowledge you need to iterate when inevitably the original plan doesn’t work.
In my experience it applies to coding when you have any reliance on third party libraries or services and don't have an extensive amount of actual real world experience with that technology already.
Having to make a choice between "make a design document" or "do prototyping" is a false dichotomy. They're complimentary approaches.
Over-planning is impossible if you plan for it, thanks!
How was it better? I think a lot of people plan precisely because it feels virtuous, but that's true regardless of whether it's effective or not.
Certain projects have too many unknowns to overplan and you need to collect data to construct the assumptions necessary to evaluate the approach.
The biggest issue that I’ve had with prototyping, is that people consider it “ship” code, and force me to use it as final code.
I find that I’m best served with a hybrid approach, where I spend a lot of time planning and documenting, but basically, for myself, then writing ship-Quality prototype code, so that using it in the end product is OK.
However, if someone tells that design doc writer that this is something like a term paper at school that is being graded, they can actually improve their writing by quite a bit by doing some editing. So the symptom is really the same as prototyping: people write draft-quality design docs and magically hope it to be a good quality piece of writing suitable for a wider audience. What they need is a few rounds of editing, just like when they write prototype code they need a few rounds of refactoring.
You still have to read it back and triple check it, as you would your own work, but you don't need all the time it takes to extensively expand it from draft.
Also, which it is in context it's quite good at documenting what needs to be done to test it.
That's what they said—design prose!
a) are not good communicators,
b) do not respect you,
c) are afraid to admit they don't understand (even if your doc is clearly shit),
d) do not care very much about the project.
with a weird caveat …
if you don’t have an audience who is willing to read what you’ve edited, editing can be a partially pointless excercise.
last shop i was in i’d edit this stuff to glorious beauty. no-one else would ever read it. i tried presentations instead. didn’t help. i tried live sharing the doc in a meeting, no one cared.
but editing a design doc (or a big PR description or whatever) is always helpful for me as it is a process where i’m editing the problem/solution description without having to move code around.
i’ve done a few good refactors off the back of editing some text/diagrams.
lesson i learned: edit design stuff as if someone else will read it, but do the editing for myself (to learn something or clarify something about the problem/solution).
So I got approval to hack out a temporary impartial suboptimal version and we were able to take off in time.
This has allowed us to fly for a bit while others finish building out the permanent proper version of that part of the wing.
In fact, during our flight we discovered missed requirements in the original design. This has delayed that proper version's release to prod. But I've been able to add that quickly to my hack and keep us flying.
My hack doubles as a production support tool. And as an alternate route if the permanent version needs to be paused because of a bug. Yes it's a partial imperfect hack but it has benefits.
Someone has complained about the language I used since it is less common. But remember, we weren't going to be able to take flight with the existing resources and approach.
We would have needed more and/or faster developers in the favored language to meet the deadline.
If any present employee (including me) had bandwidth and was able to be as productive in the favored language as I was building my hack in the uncommon language, that employee would have been tasked to build the permanent solution on time. That option was not available.
Anyways, if you have an existing production support tool, it's also a place where prototype features can live for a while.
But here are two factors that make me faster in the uncommon language.
You know the usual debugger experience where if you keep stepping or you set a breakpoint and then later realize the interesting part is actually behind you? Which means you have to start your scenario again?
Well, the uncommon language has a recording debugger so you can visit any points in front of or behind you, and see what any variable or return value was. You're not limited by the current stack because the recorder captured every package you told it to from the beginning
Even a third party package...
This means I only have to debug once to find the bug, not n times.
And the language is expressive and pliable enough that this debugger was implemented in the language itself...
And mostly by one guy -- not me of course -- it didn't take a whole company to implement it.
And you know how in some languages like Java if your car (program) starts acting up in LA, you have to update the blueprint, send it to the car factory, build the new car, drive it back to LA, and try the same left turn to see it it still ferks?
With the uncommon language, I can stay in LA and change the car while the engine is still running, n times before the 2nd Java car arrives. The language is Clojure.
Rust and Clojure are the only languages that always come with unsolicited sales pitches. Not knocking the languages, just observing.
I was half expecting this comment to end without actually naming the language.
Sorry. I almost resisted naming the language. But what got to me was my co-worker's complaint was about the very tech that made it possible to launch + save $x mil + save some nights and weekends and holidays for a handful of other devs.
And that the complaint was: the language choice makes it less maintainable (hiring pool is smaller) -- but the two factors I mentioned above actually contribute greatly to maintainability.
My original comment could have just been: "a production support tool can be a place to prototype new features."
And _other_ teams could have used other tech to solve the problem. But for the team that had the context and the responsibility, this was the highest probability shot. After hitting the target, a complaint was not the expectation.
Down votes are interesting when applied to a comment that's an answer to a direct question. (this isn't directed at sd9)
I suspect it's because your answer was indirect and had a fairly proselytizing tone. I found the information interesting, but it was a somewhat irritating read because it was inverted to demand attention, like a story, rather than being upfront. A better-received comment might have read more like:
"I used Clojure. This was mainly because it's my favorite language, so I could work faster in it, and because it has certain features which make debugging extremely fast. et cetera."
I get it, every software engineer has strong opinions, but that’s a weak one. If you think writing a lot of code to see what sticks is the job description, you’ll be replaced by GPT in no time - it can do it faster and cheaper. The challenge is always in getting alignment on what should be built, you won’t code your way out of that.
Rectangles and dotted lines only get you so far. Being removed from actual code makes you forget the real constraints - the stuff that actually slows you down doesnt appear in google docs. “Here’s what I’m thinking (points at Draft PR)” gets you farther in my experiencre.
And yes it’s 100% an opinion. It’s a personal blog not a peer reviewed article :) I’m happy to be wrong.
When I go back to understand a component, I want to know why the decisions were made. A well written doc illustrates exactly that - here are the options considered, here is why we chose this option to be implemented. It can be quickly read and searched.
Throwaway code - even a pull request with comments - is not the same. It takes much longer to process, much longer to review, and it's easy to miss seemingly obvious things because the important bits are surrounded by a bunch of unimportant boilerplate.
Put another way: anything that could be represented by a single PR is generally not significant enough to need a design document. Anything significant enough to need a design document should be a chain of smaller PRs / commits which allow the pieces to be reviewed thoroughly by themselves and have tests to show that they each work.
That’s why I stressed it’s an opinion piece but no data. Unfortunately in this industry we have a lot of experience reports, but lack actual data on what is or isn’t more effective way to work.
If I'm clear on the requirements & everyone else is clear on what I'm delivering, this is unnecessary. Sure, jump straight to prototyping. But this is rarely true for any serious project. There are always unknown unknowns that you need to tease out from the stakeholders, and a technical analysis is a great way to do that.
That's a big 'if', and usually isn't possible without prototyping in my experience. What you're describing seems like something that would be written after a prototype is already done. Presenting a prototype (or iterating on multiple prototypes) is a better way to tease out unknowns than any document.
Presenting a prototype only really make sense for UI-centric things anyway, and even then, there's a million ways to make a UI mock-up that don't involve functioning code.
Without something tangible like code to tether conversations, discussions over abstract designs invariably devolve into "my imaginary piece of string is longer than your imaginary piece of string" arguments that lead nowhere.
At the same time, your argument that "you'll be replaced by GPT in no time" is also an opinion that you've not supported with any data; the same thing that you're accusing the OP of.
I mean If I stopped reading opinions, 99% of the HN comments would disappear.
In my experience those more subtle questions are much harder to raise once a prototype is working - "why does the team's experience matter? look how great it works! If you don't block it we could get this to production in a week by just polishing the prototype!"
We write a design doc. Then make small incremental changes in a PR to rollout the functionality. Our git histories look clean and orderly. Like a steady march of progress.
Who imagines this? Professors who teach software engineering classes?
This reminds me of people who think that you write prose (essays, stories, novels, etc) by writing an outline and then "filling it out" with prose, as if in the process you will never discover anything that requires you to rewrite or restructure the document. Nobody writes that way. First drafts are always terrible and basically all good writing has been heavily revised.
Writing code is much more like writing than it is like building a house or a bridge.
I use GitHub issues for this myself but that's functionally equivalent to using a PR - a PR is effectively a GitHub issue with an attached branch of code.
I wrote more about my process here: https://simonwillison.net/2022/Jan/12/how-i-build-a-feature/...
I think it’s healthy to treat design docs like a historical artifact - true at one point in time. It’s less likely they stay up to date to reflect reality.
THAT should live in the same repository as the code itself, and updates to it should be enforced as part of code review.
Design documentation that describes the process that got to that point should live separately from the repo in something like GitHub Issues, because it's not guaranteed to be up-to-date but can still be referenced during code archaeology sessions when trying to figure out WHY the software is the way it is.
Commit messages work too, but I prefer to have a short commit that links to an issue thread where I can find out more.
I wrote about this here: https://simonwillison.net/2022/Oct/29/the-perfect-commit/#do...
In my mind, the design document doesn't have to describe everything that got to the present point. It should describe the current working of the system, which parts talk to which, what protocol they speak, the details of any custom protocols, what the DB schema is, system architecture, why a certain index exists and why other indexes were explicitly omitted, etc. It doesn't have to contain every one of these things (perhaps the schema definition goes in the code repo) but these are the types of things I think it should have. It can certainly contain notes like "We used to do X but because of Y we now do Z instead" but that's not as necessary.
I would argue that such a design document is essential for keeping everybody on the same page. How else will you know the overall design? If you can fit all that documentation into comments in the code repo, great, but then you don't have a single point of reference to guide you; instead you have to hunt all over for comments that are stored disparately, and there is no overall narrative.
Design doc is broader. It's goal is communication.
Sometimes you need to communicate other than in code. Diagrams, images, words etc...
It’s very hard for anyone who isn’t the author, or otherwise intimately familiar with the code, to understand changes at a glance. The reader needs high level explanations and documentation to quickly build the correct mental model to understand the change in context.
If you can look at 1000 lines of diff and accurately tell what it’s doing, and much more importantly, the upstream and downstream implications… you’re either lying, or somehow work in a perfect hermetic vacuum of verifiability that I am very jealous of.
Though i feel that showing is better than telling, when new people onboard they have a easier time understanding via a design doc than code.
The mistake people make with design documents is going into too much detail on -how- you're going to solve the problem. That's where prototypes ("throwaway code") come in. The design document should just be a high-level overview.
Very small team and too many design docs, not good.
Huge team, multiple timezones, multiple squads, and few design docs, not good either.
And then you balance with all the values in between depending on your team size & culture.
Even within the same company, your approach will/should change as it grows. There's a critical point where move fast and break things approach will eventually end up with too many outages, production bugs, unpolished/confusing product, and last but not least, FTC eye watering fines.
Otherwise it's not documentation at all, it's lost to the wind.
Otherwise you'll inevitably find yourself re-litigating old decisions because you never recorded WHY you chose one approach over another.
I like the phrase “weaponize” to refer to the evolution of a PoC into a workable application.
Design discussions can be very useful though.
I agree with the blog post that doing a hacky solution is very helpful to understand the problem space better, although I think it's something that's challenging in an organization. In a lot of orgs, it might be viewed as a waste of time to work on something hacky. It could also come across as wasting people's time by engaging in too many discussions over PRs. People want shipping solutions today, not explorations that might need to be rewritten later. Asking for feedback might also come across as someone being unsure of a solution and needing "help" on it.
The dynamics of working in a team generally nudge devs to make more conservative moves and writing more up-front design docs, which will be slower and safer. I'm not arguing that's a bad thing, though. You need the documentation to communicate intent across an org and many other people will need to pick up the work, too. A PR may not provide enough space to comprehensively explain the overall design.
As an indie dev now, I find sketching some designs, followed by prototyping, then "massaging" the prototype into a working, shippable solution the ideal workflow. However, it only works because I'm solo and don't need to worry about getting an okay on potentially risky solutions or having to communicate and get buy-in on implementations. In a company that has lots of other devs and lots of paying customers, I wouldn't be able to do things that way, and for good reason.
Why not? You do the "sketching/mockup" of most of the flow (without going into too much design detail) in order for the team to understand better what you are going to build. Then, everybody can provide feedback based on their perspective, do a couple of iterations, then prototype (which if done well will be the initial version of the shippable solution) and then iterate again.
I know of, erm, one quite company, fairly well known in its big industry, where indeed no one gathers any requirements and a junior guy is told to type it all in - with the view that it's probably 90% correct and the rest can be ironed out at some stage, or at worst rewritten.
But what tends to happen is thus:
1. The first draft tends to address all the wrong problems, doesn't abstract the right things, is over and under engineered in all the wrong places. Fine, it's a draft I guess
2. But here's the kicker: unless it's really unusable, there is now pressure on users to accept the draft, because changing it, perhaps substantially, requires work, and as it it sort of kind of works, if you squint. And this thing is there and you can pretend it's a job done.
I think ploughing in to writing code works if you ha r a decent idea of what you need to achieve and what the pinch points are. Without that it can be quite an expensive and frustrating approach.
In short, doing both is the best thing you can do and you should scope your design docs correctly.
What you want is people to squint and tell you if they like the general approach, but what often happens is they tell you that you need more unit tests and you could use a ternary operator here and here. (The particular details will of course differ in each case.) The reason for that, in my opinion, is that your thing looks like a PR and therefore people default to the kind of review they do for PRs. But since this is a different beast it needs a different mindset during review.
And of course the only possible solution for that is proactice and active communication to get everyone on the same page.
PS. I like the approach. Sounds like something I read before where devs would throw away their code everyday until they were satisfied with the result.
I've realised over time that everyone else who prefers the design-doc approach refuse to do work like this. There's just a whole class of problems that are too hard without prototyping.
And its not just the companies, developers get too attached to their first solution, rather than using it as a way to discover knowledge. Companies need to reward knowledge discovery, not just "shipping to prod"
I feel design docs are a way to ensure that you indeed think through a problem as much as they are a tool for peer review. If you wen't through a fairly standard educational system, it's not unfamiliar to use writing as a way of thinking more deeply about a problem and communicating those thoughts with others (namely your teacher) -- a design doc is no different. This can fail when design docs are written as templated box-ticking exercises and address more superficial technical questions than the core problem of course; it actually needs to address the problem and that is very contextual in my experience.
However some folks are just better at solving problems with a more hands-on approach, in which case throwaway code may be more effective. If that is you then go for it, though its likely you'd need to still need to write _something_ to either document changes or communicate your decisions/trade-offs with the rest of your team.
Fundamentally just do what allows you to solve problems best and take into consideration how to best work with your team. There is no one-size-fits-all solution to _thinking_ and broadly no-one cares how you work (I believe, I mean I certainly don't) if you're efficient, communicate well and get the job done to a high standard.
I've had code I threw together in 10 minutes end up in production after putting it in a 'temporary' repo.
Code you throw away makes the most sense to me for prototyping cross-cutting features in existing systems. A lot of companies can accumulate a ton of crud in only a few years of development time, and it follows Conway's Law that the crud is shaped like the org tree. Writing a throwaway feature end-to-end helps to identify the interfaces between the teams and subsequently components of the software.
This is also why I'm a big fan of assembling project teams over having teams "own" an area. Everyone on the project team is responsible for the project working well. Otherwise every team is worried about their small domain.
A main goal of design is to identify what's not feasible through logic. So much easier than prototyping. But still "can it be done?" is a far cry from "can we do it?".
The benefit of prototyping is to show that something is possible. There the key question is integration: can persons Pn make code C on system S that meets both goal X and constraint Y - i.e., a design as product development.
Leaving aside bad-faith behaviors, the real question is socialization: 1. how to gather collective wisdom in some relatively natural and encouraging manner to encourage collective deep consideration of hard problems to avoid waste and get things done. And 2. the same for motivation: getting everyone aligned, understanding their role and the quality/schedule risks.
Given the uncertainties and costs of product development, the prototype has significant advantage of seeming "real" relative to some "ideal" solution, and thus can bias teams to the concrete, particularly when issues are contended. Prototype-driven planning likely reflects lack of organizational cohesion (and ironically kicks that can further down the road).
So generally I see prototyping as validating designs, and try to make the design discussions lean enough to engage otherwise-prototyping engineers.
Here are some things I expect to see in design documents that are unlikely to show up in a prototype code review. What is the high-level description of the problem to be solved? What are the success criteria? What are the functional and non-functional requirements? What are the edge cases and failure modes and how should the system handle them? Are there multiple possible approaches and trade-offs between them? How will this code be tested and released?
Prototypes, in contrast, are great for measuring performance of alternate approaches, validating unproven APIs and frameworks, and gaining practical experience with different interface design decisions.
See also Leslie Lamport's article, Who builds a house without drawing blueprints? https://cacm.acm.org/opinion/who-builds-a-house-without-draw...
For a math metaphor, it's like doing a complex problem in your head then making a document stating which mathematical tools you will use, THEN writing down the actual formula. Versus the "show your work" approach of trying a few things, recalibrating or re-routing, then settling on the final approach.
So the design doc approach is truly terrible and inefficient. Except...
If a Very Smart Person is making the design doc and can pump out a perfect plan quickly...
And/or if the engineers implementing the solution are too junior to understand the build/rebuild approach...
Or if they are likely to miss various integration footguns...
Or if they are likely to go far down the wrong path completely...
Or if the organization is of such size that no one has understanding of all the parts and integration parts so you need to set hard I/O requirements for clean handoffs.
There may be more reasons for design docs, but I strongly agree they should only be used when necessary and certainly not required so that management gets to feel useful. They add a hefty tax to development speed and it's management's job to understand that cost/benefit ratio.
If you're working on a very difficult math problem - say, a novel proof - you're definitely going to lay out the tools and techniques, the various steps of the proof, before you sit down and start writing it out. But for homework problem #7 of 14, just start doing it - you'll figure it out.
Similarly, if you're writing a CRUD app in a stack you've used before, you can probably just start. But if you're writing something complicated that you haven't done before, you should probably visit the whiteboard before the IDE.
> Build one to throw away (You will anyway)
(Probably first phrased "plan" by Fred Brooks)
I code fast prototypes though — throwing them out is easy. And when I kick off the 2nd iteration I have new insights going in.
(By the 3rd iteration I'm even hanging on to a few functions from the previous iterations.)
The best times I've had with writing design documentation has been when I thought about the problem enough that I could specify the properties necessary for a correct implementation. Depending on the scope of the problem I might use property tests or model checking. In any case, thinking about the problem up-front tends to prune away dead-ends before you head down them.
(Of course, you can't do much about a bad specification except try to avoid them... learning how to write good ones takes experience, wisdom, and constructive input from knowledgeable colleagues).
Update: I’m on the fence because I’ve also had a lot of success with implementing partial solutions: just get something good enough that works for some use cases and improve as you go.
Not all products need an "algorithm" per se, but if your product needs to do collaborative editing or something else CAP-adjacent, that algorithm is going to need to live somewhere (not in throwaway code).
The right algorithm (or even if such an algorithm is possible) won't be discovered via iterating on the code base.
I like the general idea behind ShapeUp: don't ask "how long will it take" but "how much time are you willing to literally throw in the bin to learn more about the problem". Committing to research is easy and HONEST. Committing to a finished product by a date is incredibly hard/impossible and a lie.
The first duty of all humans must be to truth.
* If you're B2B, your marginal clients are constantly deciding whether to sign or renew their contracts, and their money directly depends on promises you make them about when features they want will be available.
* If you have competitors, you have to evaluate how your product will match up with them over time. If there's some killer feature you could build with 3 engineers in the next quarter, you should probably do it. If there's a killer feature your competitors could build that fast, but you have some tech debt that would make it take 3 years, you'd better find a strategy to make that feature less important.
* If you have a large or growing product, you have more potential projects to do than people to do them, so you're going to have to decide which will produce the most benefits for a given unit of time investment.
If you have a small, non-contract-based project with no direct competitors? Sure, it's possible to get away with the "we'll finish when we finish" strategy. But there's not a ton of space in that niche, and unless you get quite lucky it's not where the big bucks are going to be.
I get it, you might need to do it to survive in the beginning because competitors will be doing the lying. But I'm saying you need to stop lying as soon as possible for the long term health of the relationship.
In fact more or less everything that I have found burdensome in the last decade or so of my career were things introduced to satisfy management.
Unit tests? Code coverage? For management peace of mind.
Code reviews? I'd argue, same.
Agile development (obviously).
This approach is fine but make sure your iterative prototyping is refining some sort of e2e / acceptance test, with good comments / README describing the intent.
It’s really easy for the prototype to end up being shipped and painful refactoring happening once you’re successful.
For me, a lot of the time this ends up being a question of what is known vs unknown. If you have a clear customer requirement but technical uncertainty then iterating on prototypes is usually better. If you have unclear customer requirement then shipping MVPs iteratively is usually better. If you have organizational uncertainty (eg you need to compose components from multiple teams and align roadmaps, as is common in big companies) then the design doc is often the place to start.
Not saying iterating the code is always bad, but it shouldn't be a substitute for sufficient up-front planning that would have saved programmer time.
And yes, the prototype usually ships. There is often not enough time to completely rewrite it, let alone fix all the bugs and add all the necessary features.
This feels true, and also why design docs are important for projects that involve roles beyond software development, where PRs can be among the worst forms of documentation.
A breadth-first search is useful when you don't know much about the intricacies of the problem/topic at hand, and so you need some ground work to take informed decisions.
If, instead, the solution space is narrow then by all means do a prototype/throwaway PR/... to validate the approach.
I don't think I'm personally capable of explorative coding. I get too lost in the weeds and lose sight of the problem.
If there are more unknowns than knowns imo its better to start with prototype to explore problem first and then eventually come back to planing.
Build phase happens at the compile time and at runtime.
Write short designs; Goals, constraints, options. Prevents the tech debt from building over time and signals better when to throw chunks of systems away.
Im curious because I wrote a framework for this (same name as my username) but when I talk about the idea I receive a sea of blank faces.
Yadda yadda, that may be true sometimes but that the quality of the doc would get you promoted makes no sense and is also not a good metric. I think most of these committees look at who approved it and what known people thought/wrote in response. I was told in this promo-game to try to get comments from high-level people for this reason. That is more a popularity contest, and less a competition of well articulated ideas.
I think most people here want to improve the way things are. We talk about engineering practice to improve the practice, not to please management or give career advice. Usually, at least.
This is where it happens first. A bunch of engineers (or just generally people with boots on the ground) get together and find better ways to do things. Before agile was mainstream and corrupted beyond recognition, the waterfall model was the way recognized by management and working within that model would have gotten you promoted easier. Things evolve.
Why writing it if you trow it away anyway ?
So business processes can kill either one.
Design docs should capture reasons.
Even if the code is throwaway, the reasons for the flow and process modelling for the use case don't change at the core. Some implementation details might change and the design may certainly also change accordingly, but the process is generally stable.
That's what should be captured in design docs.
Not a rhetorical question. Often the goal is the functional minimum. If that's your gig, it's hard to appreciate code quality maximization, and vice versa.
If you do maximize quality, I'll one-up the suggestion in the article. Treat your first write as throwaway code. And your second. Up until the point where the rewrite would be roughly identical.
It's basically early refactoring, but with the code at its freshest in your mind. Coding it the first couple times implicitly maps out the problem domain.
You also leave no internal technical debt on the table. A surprising amount reveals itself right after you wrote it in. It gnaws at your ability to proceed. Subconsciously, it splits your attention in two: how the code is and how it should be. With each "fail" your attention spreads out and thins out.
Finally, this habit makes you more fluid in the language. Quality-maximized code takes longer, but your actual typing rate ends up being much faster.