Hacker News new | ask | show | jobs
by strongpigeon 457 days ago
> [...] Be wary of abstractions made for fabricated use cases.

Very well put and I would argue this applies to general software development. This is one of the biggest difference between my freshly-out-of-college self and me right now and something I try to teach engineer I'm trying to grow into "seniors".

Too many time have I seen a lot of wasted efforts on trying to build hyper flexible components ("this can do anything!") to support potential future use cases, which often never come to be. This typically results in components that don't do that much and/or are hard to use.

Design your components as simply as you need them, but no simpler. This typically gives more flexibility to grow rather than accounting for currently-not-needed use cases.

4 comments

I'm not sure, perhaps this is an issue with how our craft is taught, but I think we're missing something when we talk about the (economic) tradeoffs when making these decisions.

Keeping components simple, decoupled and with minimal dependencies allows for a high degree of optionality. When you pair this with a simple system that is easy to reason about - you're doing huge favours to your future self.

On the other hand, hanging off a bunch of unused features, especially ones that have interacting configuration - that's more like adding lead weights to your future self. It weighs you down and adds friction. And we tend to do a terrible job of predicting our future needs.

Kent Beck does a great job discussing the costs of these tradeoffs in his recent book "Tidy First". It builds upon the YAGNI principle, but adds a level of cost analysis that should allow you to sell these ideas to the managerial level.

I think some of it comes from a sense of admiration or even awe of complex systems. You’ve just been introduced to some of these tools as a college student and you really want to use them as they seem so neat.

But then as you start dealing with over-engineered system, you become intimately aware of the downsides of poorly abstracted system and you start becoming much more careful in your approach.

At least, that’s my pet theory.

Another good way I've seen it put is, the difference between underengineering and overengineering is that you can fix underengineering.
Somewhere, at a tender age, I read a paean to the Chevy Straight Six engine block. One of the most heavily modified engines of all time. Later on when I read Zen and the Art of Motorcyle Maintenance it had a similar vibe and effect.

I still sometimes use it as an allegory. As it originally shipped it had very low power density. It’s an unremarkable engine. But what it has in spades is potential. You can modify it to increase cylinder diameter, you can strap a giant header on it to improve volume and compression more. You can hang blowers and custom manifolds and more carbs off it to suck out more power. IIRC at the end of its reign they had people coaxing 3, almost 4 times the first gen OEM horsepower out of these things. They had turned it into a beast for that generation of “makers”.

The concept of Don't Repeat Yourself and the concept of You Ain't Gonna Need It are the yin and yang of software development.
I don’t think there’s an accepted set of concrete criteria for making software that can absorb major design changes later without a great deal of effort and stress. How you write code that can accept an abstraction layer at the last responsible moment.

Some people have an intuition for it, but it’s sort of an ineffable quality, buried in Best Practices in a way that is not particularly actionable.

So people having been scarred by past attempts to refactor code reach for the abstraction in fear, just in case, because they don’t know what else to do and it’s not written down anywhere, but abstractions are.

I've found that refactoring to fix a lack of abstraction is usually easier than refactoring to fix the wrong abstraction.
Definitely. Among other things, this is akin to Work Hardening.

Refactoring tries to avoid this but the slope of that line can still end up being positive and you can’t refactor forever unless you’re very careful. And “very careful” is also not yet quantified.