Hacker News new | ask | show | jobs
by mattbuilds 1035 days ago
I really disagree with the pros listed on over-engineering, specifically "future-proofing" and "reusability". I doubt you can accurately predict the future and whatever assumptions you make will likely be wrong in some way. Then you are stuck having to solve the problem that you created by trying to predict. As for reusabilty, it's similar. Start with solving what you have to, then abstract as you see it fit. Again, don't try to predict. Be thoughtful and really understand what is actually happening in your system. Don't try to follow some pattern you read online because it seems like a good fit.

Realistically you should engineer for the problem you have or can reasonably expect you are going to have pretty soon. You can solve future problems in the future. I'm also not saying to write horrible unmaintainable code, but don't try to abstract away complexity you don't actually have yet. Abstractions and where to separate things should become apparent as you build the system, but it's really hard to know them until you are actually using it and see it come together.

6 comments

> I really disagree with the pros listed on over-engineering, specifically "future-proving" and "reusability"

Yes, someone who argues that "over-engineering" leads to "future-proving" is caught by the bug.

When you future-prove something, that's called "engineering". Over-engineering is by definition failing to foresee future needs, imagining generic future needs ten steps ahead instead of the less ambitious future needs two steps ahead.

It is easier to modify early, simplistic assumptions than it is to walk back from premature generalisations over the wrong things.

Exactly. A thing so small and simple that you can rewrite it in an afternoon is more futureproof than any 8000 LOC monstrosity.
> Exactly. A thing so small and simple that you can rewrite it in an afternoon is more futureproof than any 8000 LOC monstrosity.

As I've said multiple times, here and elsewhere, it is easier to fix the problem of under-engineering that the problem of over-engineering.

I also disagree with the article's "pros" for over-engineering. There is no pro that I can think of that doesn't boil down to resume driven development.

The pros of under-engineering is (the way you say it) obvious: very little time was spent to figure out that you did it wrong.

Perfectly said, that was the exact point I was trying to make. I've seen so many bad decisions made in the name of "future proofing". The the future comes and you are fighting those decisions. I wonder if people switch jobs and projects so often they don't get to see the results of all that future proofing.
> I doubt you can accurately predict the future and whatever assumptions you make will likely be wrong in some way. Then you are stuck having to solve the problem that you created by trying to predict. As for reusabilty, it's similar. Start with solving what you have to, then abstract as you see it fit.

Kinda sorta. It's not a binary: you can "predict the future," just not too far out and not with complete certainty. The art is figuring out what the practical limits are, and not going past them.

> Realistically you should engineer for the problem you have or can reasonably expect you are going to have pretty soon. You can solve future problems in the future.

Another factor is comprehensibility. Sometimes it makes sense to solve problems you don't technically have, because solving them makes the thing complete (or a better approximation thereof) and therefore easier to reason about later.

Agreed. These feel backwards.

When I think "Under engineer", I think "keep it simple, because you can't predict the future". Simplicity is a great enabler of flexibility and tends to go hand in hand with scalability.

It's usually comparatively easy to make something that's too simple a bit more complex.

It's often much harder to make something that's too complex more simple.

It's interesting to try to fit what is often talked about as "future-proofing" and "reusability" into the development of a general-purpose CPU, since CPUs are in a sense the ultimate reusable system.

In an overly simplified textbook example of designing/building a CPU, you have an ISA you're building the CPU to support. The ISA defines a finite set of operations and their inputs, outputs, and side effects (like storing a value in a particular register). Then you build the CPU to fulfill those criteria.

In my experience, designers that want reusability usually don't have enough precision in how they want to reuse a system so an ISA-like design can't be created.

And practically, it's the rare (I might even say non-existent) day-to-day business problem that needs CPU-like flexibility. Usually a system just needs to support a handful of use cases, like integrating with different payment providers. An interface will suffice.

> Usually a system just needs to support a handful of use cases, like integrating with different payment providers.

Building EV chargers is a good dose of electrical engineering combined with talking to dozens of car models and their own particular quirky interpretations of common protocols, which is like designing websites for a market with dozens of unique browser implementations.

In spite of that, it seems half of the complexity is making sure people pay.

> I doubt you can accurately predict the future and whatever assumptions you make will likely be wrong in some way.

I doubt this for most of us. Computers have been around for a long time. Most of us are not work on new problems. We by now have a pretty good idea of what will be needed and what won't be. There are a lot of things left that haven't been done yet, but if you understand the problem at all you should have a good idea of what those things will be. You won't be 100% correct of course, and exactly when any particular thing you design for will actually get implemented is unknown, but you should already have a good idea of what things your users will want on a high enough level.

Of course if we ever get something new you will be wrong. 10 years ago I had no idea that LLM type AI would affect my program, but it is now foreseeable even though I don't really know what it can do will turn out useful vs what will just be a passing fad. Science fiction has 3d displays, holographic interfaces, teleportation, and lots of other interesting things ideas that may or may not work out.

Likewise, 20 years ago you could be forgiven for not foreseeing the effects that privacy legislation would have on your app, but you better assume it will exist now and the laws will change.

I think this is nicely captured by the concept of "cost of carrying".

Keeping code around is not free. Cost of carrying refers to the ongoing efforts of maintaining code, not to mention side effects such as increased complexity and cognitive load.

If you over-engineer a system you aren't getting value out of the extra bits, but you are still paying the cost of keeping them around.