Perfection is not over-engineering

var0.xyz

225 points by var0xyz 16 hours ago


__MatrixMan__ - 16 hours ago

I'm all for pushing back against "let's not make perfect the enemy of good." I hear that all the time in reference to software that is usually quite bad, and often a little evil to boot--nothing good anywhere in sight except some poor schmuck trying to find a way to make their job something worth taking pride in.

I'm not sure I agree that systems are products though. The product mindset is toxic. It means that you've got goals which are independent of the user's goals (typically to make money, which sometimes means doing something dastardly to the users on behalf of the shareholders).

All the best software is more in the "tool" category and less in the "product" category. Usually it's made by the users, only bothers with solving problems they have, and has no ulterior motives.

qsort - 16 hours ago

I wouldn't say that "over-engineering means solving the wrong problem". It's possible that the idea is basically correct, but people are directing effort towards optimizing for constraints that don't really exist or can be dealt with once a better picture is in place, whether it's the mythical PMF or just "we now understand what the users want, let's build that".

The worst clusterfuck I've ever worked on was a web application that was actually solving a real problem fairly well, but the team was spending time building an absurd Rube-Goldberg contraption of microservices when the entire platform had less MAU than my hobby website. It wasn't the wrong problem, but it certainly was over-engineered!

nickelpro - 16 hours ago

"We're not trying to build a perfect solution here" is not something said to assuage over-engineering or encourage sloppy work.

It's said to head off a specific complaint from a specific kind engineer who will object that the proposed solution won't work because it doesn't cover some obscure edge case which rarely comes up in production.

"We're not trying to build a perfect solution here" is saying "We acknowledge not everything will be covered, we're setting the requirements at the 90th percentile use case".

MantisShrimp90 - 13 hours ago

I believe perfection is a dirty word because it has a pernicious effect on the human mind.

Striving towards perfection too often leads to yes over-engineering but I think more importantly it also: leads to way too much bike shedding due to the need to be perfect and allot of even emotional baggage when we don't make that perfect things.

Even the author admits that their definition of perfect can only arise with stringent requirements and I'll take it a step further, maybe it was perfect for that problem at that time but guess what change happens all the time, and as architects we have to think about future problems as much as current ones. With that in mind I think that having something that is good in many scenarios is better than the thing that is perfect in the scenario you start in.

mlinsey - 16 hours ago

"With one big caveat: you need a very clear set of requirements"

Most new product launches are an exercise in figuring out what the product requirements should be through trial and error (really: through ongoing dialogue with your users). Even mature products can have requirements change over time as the market changes.

I think internalizing this reality is why most senior engineers who work in domains that touch the messy real world will reflexively push back against perfectionism.

titzer - 14 hours ago

I think over-complicated and over-engineered are not the same thing.

Over-complicated is adding too many features, too much mechanism, too many moving parts. Over-engineering is far exceeding the requirements in an unhelpful way. For example: build me a treehouse. Said treehouse could probably be made of wood. If you made it out of concrete and steel, it might be a heck of a lot stronger and last a heck of a lot longer, without being more complicated (just more expensive). Too strong is over-engineered. If you made a treehouse with 13 bedrooms and an elevator, glass windows, solar power, and running water, that's overcomplicated.

W-Stool - 16 hours ago

"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away

  - Antoine de Saint-Exupéry
pilgrim0 - 5 hours ago

> The shape of the solution only becomes obvious once you treat the system as a product and define the requirements honestly.

The “honest” part is the important one. It’s also the hardest. It’s so tempting to project preferences onto a new development, which tends to confuse the distinction between desire and necessity. There’s so many things we want to try. Maybe having lots of personal projects to vent the need for novelty helps one to make good choices when it’s critical that they must be right.

oooyay - 10 hours ago

> Set clearer requirements, set stricter constraints, and the solution follows. That solution is the perfect one for you, for that case.

I think this is a bit of a generous reframing of what seeking perfection is. Generally I think perfection seeking is best described as over-focusing on the details and pre-planning instead of laying a general blueprint that leaves room for pivots, future decisions, and iteration along the way. There's a whole breed of engineers that are really great thinkers but get stuck in the mud trying to pre-think the best way to do something instead of being adaptable.

teodorlu - 14 hours ago

Beautifully written! I want to live in a world where we strive towards perfection, rather than strive to destroy it.

lincoln20xx - 16 hours ago

I concur. Most of the most painfully over-engineered swamp projects I've dealt with have been a result of not understanding the requirements.

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.

charles_f - 16 hours ago

> Over-engineering is solving the wrong problem

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.

RandomLensman - 16 hours ago

> Every constraint on the table. Tighten those enough and something interesting happens, you end up with only one possible solution.

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?

qiqitori - 6 hours ago

If you want to make all developers working on a project happy about the way the project is being designed/implemented, it's best to reduce the number of developers to 1 or less.

leugim - 16 hours ago

I disagree, requirements are only a part of the engineering process. Perfection will be redefined after the product, tech, team knowledge changes, which will constantly.

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.

lalitmaganti - 16 hours ago

I agree with the actual principle I think this article is trying to put across (don't give up on technical quality too early by dismissing it as "perfection") but I strongly disagree with the framing.

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!

Night_Thastus - 6 hours ago

Knowing your constraints perfectly is impossible, and takes more and more effort the closer you get.

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%.

HPsquared - 15 hours ago

If something can be defined in rigorous mathematical terms and proven correct, that can save a lot of trouble downstream dealing with exceptions. Not all problems can be solved so neatly, but it's often worth putting in the effort to get from 99% to 100% correct if it means you never have to read or touch it again.

alasano - 10 hours ago

"Start a new project. Every language, every tool, every hosting model available. You pick serverless."

Picking serverless as the leading example to show off perfection.

solatic - 14 hours ago

> For someone else it's the wrong choice, they don't know Python

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.

epolanski - 16 hours ago

I don't share the definition of over engineering.

As engineering is the act of solving technical problems, over engineering is about putting too much engineering effort on aspects, features or products that don't have a linear payoff to the budget spent.

E.g. I worked in a company that was obsessed with unit test coverage metrics and the effort of maintaining the test suite was considerably biting in the ability to move the product. The ratio was 25% of product and 75% of unit tests.

And the payoff was small if not even negative, impacted morale, productivity and actively pushed back against refactors, because any large refactor was met with a disproportionate effort in unit test rewriting. Let alone the fact that as you were mocking external dependencies, and the mocks costed engineering effort and internals digging, it also suppressed work to keep it up to date.

I never got to convince the org to shift focus on E2E testing, which answered the real questions: does the product make money and works as expected. Uni test had to be used when writing a parser, not to validate some react scroll component as browser apis and the triggers mimicking costed days of work.

In fact we often had gigantic all green test suites for broken products.

That's to me over engineering an aspect of the engineering cycle.

4lx87 - 11 hours ago

I agree. Too many use "perfectionism" as an excuse to ship unremarkable crap that doesn't meet spec.

dondraper36 - 15 hours ago

The idea sounds related to the distinction between essential and accidental complexity.

https://ferd.ca/complexity-has-to-live-somewhere.html

I really like the article above in that complexity does have to live somewhere. If you have a hard problem to solve, there is a minimum level of complexity (essential complexity) that can't be further reduced, only moved from one place to another.

And yet we often add accidental complexity by making bad choices (thinking of you, microservices). If your choice is bad enough, you get all the disadvantages (challenges with distributed systems, complicated debugging), but without any of its advantages (a distributed monolith doesn't get you any deployment or team independence).

Telling one from the other, well, is something I'd like to learn and that seems to require both experience and some sort of intuition.

yuliyp - 16 hours ago

There is not a perfect solution. There are many bad solutions. There are a few solutions that are OK but with different tradeoffs.

0x20cowboy - 12 hours ago

> I believe a perfect solution exists.

That is incorrect when dealing in the real world with many different humans using a complex system. I’ve heard other people say this, and it always confuses me how it is not self evident. Human interaction is not a maths equation. There are too many random variables.

tombert - 10 hours ago

It's rare that I so thoroughly disagree with the thesis of a post here.

> Over-engineering is solving the wrong problem. That's the whole definition.

Wholeheartedly disagree. Over-engineering already seems pretty well defined just based on the words alone without tacking on a strange arbitrary definition to suit your blog post, but I think most people most people would define it more as "spending too much time and/or resources to solve a problem more-thoroughly than necessary".

Suppose I was given the task to convert all the JPEG images in a folder to PNG.

Solution A) I could write a highly optimized program writing custom CUDA decoders and encoders and using Open MPI for CPU-based optimization, and create an elaborate plugin framework on top of this to make this modular and cool.

Solution B) I could just run `find -name "*.jpg" | parallel magick {} {.}.png`.

Both solve the "right" problem; the ask was to convert these images, and both approaches can absolutely do that, so they didn't solve the "wrong problem", but I would argue that for most people Solution A would be "over engineered". You could argue that by building custom encoders and decoders and the like we're solving the "wrong problem" by going beyond what the problem asked for, but I feel like if you're criticizing the engineering methodology then that kind of proves my point.

We generally think someone is "over engineering" primarily when we are happy with the low-effort result.

There are times when Solution A is the right way to go about it. Maybe you want something that takes advantage of custom hardware, or maybe you can make an assumption about these images that Imagemagick can't, or maybe you really just understand image encoding significantly better than the Imagemagick people. in those cases, we generally don't consider it "over-engineering".

esher - 16 hours ago

Hang on. Let me overthink this.

prmph - 14 hours ago

It's not over-engineering if you are committed to what you are building for the long term, and know you'd very likely need stronger architecture at a certain time.

No one starts a project for perfectly objective reasons. Your choice of careers was not perfectly objective, you decided you liked a field, and it seemed you had enough aptitude for it, and then you did the work to get into it, learning as you went along and adjusting.

So it is with all kinds of decisions that go along with starting or changing a software project. Of course are your architectural and engineering acumen increases, you get a goo feel for how to choose good constraints and requirements, and then within the those constraints it is now up to you to find optimal solution for them, not the most over-engineered one.

Like I said before, sometimes going from A-B-C-D is much less efficient (and can actually be counter-productive) in the aggregate than going form A-D directly, even though YAGNI would dictate A-B-C-D. So long as you generally know that D would be needed sooner or later, A-B-C-D can be counter-productive because it causes to you to miss the forest for the trees. Even if you are not doing D immediately, some thought given to D can improve greatly your understanding of the context of A and the roadmap, leading to better design.

Note that string design instincts honed over time make this process work, not building out stuff just because of fads (e.g., microservices) or for some functionality you do not actually need. So here is my point of agreement with the article: the reason teams might waste time over-engineering is not because they are exploring a design space and objectives that is larger than what is strictly required for now; it is because they lack good architectural skill and experience and instincts. Again, considering D upfront can actually simplify the A you build now.

sandeepkd - 11 hours ago

In the absence of concrete examples its hard to say what is OP trying to optimize for. Optimism is good, however at the end of the day everything is a trade off, the cost has to be paid for all decisions. A good design is all about optimizing when, where and how you push those costs.

hakunin - 15 hours ago

Another point that goes along with this: good engineering is not premature optimization[1].

[1]: https://max.engineer/premature-optimization

donpark - 11 hours ago

Pefection is a fetish.

lo_zamoyski - 14 hours ago

Perfection is always relative to a purpose or telos. So in the case of artifacts - which are the products of engineering, arts, and techne in general - the purpose isn't inherent to the object in the manner it is in oak trees and human beings, but projected onto the thing. It lives in the mind of the designer and the user. That's why we can say that technology is an "accidental" extension of human beings by which human purposes are realized and mediated in ways that inherent human powers cannot directly accomplish.

So, yes, if you have a purpose in mind, you can build something that can be used for that purpose, more or less effectively. The more general the purpose, the less specific the implementation; the more specific the purpose, the less general the implementation. Over-engineering here is something that indeed goes beyond the purpose of something, with feature creep as an example of moving goalposts and a slippery grasp of the limit.

However, production is only one layer of concern in engineering. You can talk about ideal artifacts whose forms perfectly enable the realization of some purpose, but there is the practicality of constructing one that must also be considered. Think of diminishing returns. Does it makes sense to invest a certain amount of time and resources into producing a more perfect artifact? If not, then pursing such perfection is itself an imperfection on the part of human judgement. That is, a more perfect engineer might know the limit of perfection for an idealized artifact, but he also knows what the perfect practical limit of justifiable effort is. Perfectionism is a sign of an imperfect engineer.

Returning to feature creep, the author might argue that the moving goalposts are a sign that the purpose is being refined, but feature creep can also mean that the shifting purpose is detached from real needs. So, in that case, the purpose served is no longer the purpose that ought to be served, and in that sense, while one may realize an end perfectly in a relative sense, the end pursued is itself the result of imperfect understanding, which is effectively what the author is gesturing at when discussing requirements.

croisillon - 10 hours ago

next time just post the prompt

godelski - 15 hours ago

There is no such thing as perfect.

Anyone saying "don't make perfection the enemy of good" is using a thought terminating cliché, avoiding the conversation of what is good enough. Worse, it is often used by people to drag quality down. If you're creating the "minimum viable product" you usually create a product that isn't working.

But, perfection doesn't exist. Most solutions in the world have no global optima. There are always tradeoffs. You must choose. You must argue with your peers to figure out that tradeoff. Perfection has infinite depth in detail. You must optimize. You just learn the unknown unknowns in an every moving landscape.

But you should still chase perfection. Like you chase a utopia. Like you chase your dreams. There's always something to improve on. Chasing perfection while knowing it can't exist means you will continue to search for the flaws. It means you will continue to improve. "Over engineer", because that's just engineering. Make things actually work, while recognizing they're always broken somewhere. Don't get offended when someone points out a flaw, you already know it's not perfect, so figure out if it is a tradeoff or can be fixed. Just keep improving things, because otherwise they keep getting worse

groby_b - 9 hours ago

Sure, but did it need to be written by AI? Does that solve for the right constraint?

shevy-java - 10 hours ago

> I believe a perfect solution exists.

The article seems too focused on over-engineering.

Achieving 100% is often much much harder than, say, 95% or so. Just good enough. This is the old "Worse is better" problem. Why did Linux outcompete, say, Minix or something else? Worse is better is a more practical focus. You don't need to achieve 100% perfect per se. Momentum is often more important. You can still have a lot of efficiency if the momentum is the main driver.

https://en.wikipedia.org/wiki/Worse_is_better

Perfection is nice in theory; in practice it will be whacked into submission by the worse-is-better speedy wizards. The hobo programmers built for speed. You make fun of them. Then the top 500 supercomputers all use what they wrote ... like Gandhi they were winning.

zzzeek - 12 hours ago

great post but also the real thing they are talking about here is YAGNI

helge9210 - 15 hours ago

Perfection is not "perfectionism". Former is provable given set of constraint. Later is anxiety due to fear of criticism.

"We don't want to build the perfect solution." Can both mean "no need to cover use cases we don't care about" and "no need to deal with divizion by zero in a product, where a number is divided by the user entered number".

0xbadcafebee - 7 hours ago

Perfection is the enemy because the very notion of it assumes that something cannot be any better. Everything can always be better. That's the problem. Whatever solution you make, will eventually be "not good enough". Follow that path long enough and you will never be done with anything. So not only do you need to realize perfection is impossible, but you also need to accept "the bad" and live with it, or become Sisyphus.

JesseHowell - 12 hours ago

[flagged]

shoggi - 16 hours ago

[flagged]

m463 - 14 hours ago

[dead]

szundi - 11 hours ago

[dead]

IanCal - 16 hours ago

I disagree, you’re optimising many different things and there is not a simple way to compare them. The very concept of Pareto optimal is about this! There is not one uniquely perfect solution to a problem most of the time.

Spending too much time gathering requirements can be a bad business decision too. Those requirements are often not even accurate.

Building a perfect system may not be over engineering to solve the problem perfectly… but what if you don’t need to solve it perfectly? What if it’s better to fail on some requirements to deliver sooner or cheaper or deliver this and some other project?