Posted by var0xyz 22 hours ago
Of course, this is not to imply that it's necessarily possible to know every requirement perfectly before you begin - I find that I frequently don't really understand the requirements until I've built the damn thing and it's made first contact with the real world.
So I usually toss that first version out, and build the second one. And that one is usually good enough that I don't immediately want to throw it out the window.
And by the time I get through the third version, usually a fair bit after the second is done, it's pretty damn good.
Because now I understand the problem and the requirements so much better than I did at the start, and I better understand what the system needs to be to solve that problem.
Will it be perfect? Never, except in a static and unchanging universe. But we can approach optimality for a given moment in time, which is functionally the same thing.
For me it's been a complete lack of requirements. Absolutely no one in the company seeming to want to make a firm decision on what we're building right at the moment. Every decision coming with a hedge "but maybe we might want to do this sometime later so we should keep our options open"
So any time there was a tradeoff we would take the option that leaves our options open, which takes way more time and effort to get right
Is it though? Engineering is providing the cheapest solution that corresponds to what your customer asked. As it goes: anyone can build a bridge with infinite budget, only an engineer can do it for cheap.
A system that's un-necessarily complex for what it does is over built, and under engineered.
I think it's important beyond semantics, because sometimes you have to propose designs that wouldn't be in books, yet they're the cheap and fit with all requirements, and are thus well engineered.
Now the difficulty is to figure the requirements that are not being expressed. "Allowing an occasional resurfacing" and "don't explode when there's icing" are obvious ones; the hard one for our job are "allow for adding another lane" or "allow support for trains as well"... because you know these might come.
Is there always a unique solution? If constraints A is tightened and then determines the outcome, could that not also happen with a tightened constraint B that determines a different outcome?
Spend too much time thinking into perfection, trying to achieve it and you will get a convoluted system with lava-layer patterns full of complexity astronauts.
My biggest problem comes from:
> Every constraint on the table. Tighten those enough and something interesting happens, you end up with only one possible solution. And that solution is, somewhat ironically, the perfect one.
Constraints are not rigid and unchangable [1] but flexible things which can bend to solve the problem at hand. Constraints can be: deadlines you impose, frameworks you are working within, the shape of the output schema, performance characteristics etc. And because they trade off against each other, tightening them leaves you with several solutions, each fitting a different trade-off.
Constraints also change over time as you and your team's collective understanding of the problem, the environment or priority of the problem change. This needs to be considered when building the initial system too: baking in some flexibility means giving up some of today's "perfection" to deal with future variance.
Understanding what constraints matter, which can be shaped and trading them off against each other is, to a very large degree, the job of software engineering. So no, I don't think you enumerate the constraints and find the only solution which fits; this is a very simplistic take on the complexities of building software.
[1] unless you work in a dictatorial company in which case my condolences!
Maybe this sentiment stems from being software engineers, but at least for hardware it becomes abundantly clear that "good enough" is a desirable state unless you want to spend years in development. The only direct comparison I can find in software is computer graphics, where the endeavor often halts as soon as the average person can't perceive a difference anymore.
And frankly, they change on a regular basis. By the time you figure them out that perfectly, they're invalidated. A new feature is suddenly needed by the customer, a bottleneck that wasn't there before appears now, scale changes, consumer preferences change, new hardware and software come out, everything changes.
IMO, the best engineering is 80/20. Get 80% of the result you want for relatively little effort and complexity, and don't sweat the remaining 20%. Embrace the imperfection. Get it done in the simplest, most obvious way - even if you know it has limitations, edge cases, and some things missing.
Knowing how to get that 80% is extremely hard (and how to do it without causing lots of problems down the road), but I think senior engineers get pretty good at it. And if you absolutely need to, get another 80% of that remaining 20%.
Picking serverless as the leading example to show off perfection.
The author ruins their entire argument with this one claim.
If "we picked this tool because we know it best" is a legitimate requirement, then every tool choice is justified as a "perfect" choice because it's what the architect was most comfortable with. If your emotions and current knowledge levels are considered reasonable justifications for a "perfect" solution, then all solutions are perfect solutions; they simply haven't had enough emotional justification yet. If all solutions are perfect solutions, then none are.
There are, ultimately, two kinds of software - those that need to ship by a deadline, and those that don't. A deadline forces you to eject dead weight that you don't need - requirements have a habit of getting clarified real fast when you need to build to a deadline. If you had time to over-engineer despite a deadline, you should consider working for a more productive organization. Meanwhile, the concept of "over-engineering" is a little vague for software that doesn't have a deadline. If you don't have a deadline, you don't have to compromise on quality. "Over-engineering" is then just a value judgement that you made poor use of your infinite timescale and built the wrong things with it. But who is making that judgement? Not the person who built it, not the person who funded it (i.e. usually self-funded as a hobby project), and not the person who uses it (since over-engineering is an implementation detail, rather than a product choice), so who cares?
edit: to clarify: "pick a stack you know already since we don't have time to learn a new one" is a totally valid requirement. But I disagree that it means that you built a "perfect" solution with it. I also disagree that you usually need to build perfect software - getting comfortable with adequate is how most people ship most software.