Hacker News new | ask | show | jobs
by whatever_dude 3565 days ago
> If he has to, the level 3 programmer gonna err on the side of the level 1 code and will avoid as much as he can level 2 code. That's because level 1 code cost less to fix than level 2 code.

I've been doing this recently and had a hard time justifying it even to myself. It just felt right. And you've got it - it's easier to fix dumb code, than refactor an overengineered mess.

> Now here comes my point: a level 2 programmer read and write articles that is about how to not be a level 1 programmer.

You're making me understand the current programming "scene" much better, especially the plethora of self-aggrandizing blog posts I tend to see today.

I wish I could upvote you twice.

3 comments

http://www.willamette.edu/~fruehr/haskell/evolution.html

I disagree that level 1 programmers necessarily produce poor code. But they're stuck at such a low level of understanding of abstractions that they either abuse abstractions to hell (but not in a level 2 sense) or don't use them at all.

The good level 3 programmer understands that there are times to call a function, times to create class hierarchies, times to create generators, times to use high level abstractions. But they generally err on the side of lower abstractions, or higher abstractions only where they aid clarity, reduces true redundancy, or similar.

But the most important thing about a level 3 programmer is that they aren't dogmatic. Dogma both frees and constrains the developer. It frees them from the requirement to think, because dogma says "thou shalt" and "thou shalt not". It constrains them because when things fall outside the dogma, they want to make the heretical code conform, or they discard it and start over.

> it's easier to fix dumb code, than refactor an overengineered mess

Very True!

That depends on circumstances really. Yeah it's easy to fix dumb code... unless there's 10 tons of it

I once worked with about 1.5 million LOC worth of "naive" PHP code. It was one big e-commerce system. The SSOT principle wasn't followed, certain assumptions were scattered all over the place.

For example the fact that a product could only ever belong to a single size group. The task we were given was to remove this constraint. It took a few man-years of work, because it was hardcoded EVERYWHERE, from database scripts to frontend JS. And don't even get me started on how many bugs angry customers encountered before it got kind of stable.

It wasn't overengineered, just dumb, and a lot of it. I'd much prefer having to deal with some matryoshka OOP abstractions - they could be merged, simplified etc. In such case there are certain tricks in our disposal. Tricks that scale. If it's just a big ball of mud: not much you can do. It's pretty much a physical job, like counting grains of sand on the beach.

When you design a system, you always have a tradeoff between flexibility and simplicity. Extreme flexibility means over-engineering and complexity. Simplicity means less flexibility, because of a lot assumptions are hard-coded. The best design is the one which hits the sweet spot: As simple as possible, as flexible as necessary. That requires knowing the future, though.

If you want to increase flexibility later, like "remove the constraint that a product could only ever belong to a single size group", it inherently means to hunt down all the places where this assumption has been hard-coded.

Should you err on the side of flexibility or simplicity? Simplicity means the assumption hunt is costly, but maybe you never need it (YAGNI). Err for flexibility, you pay the constant cost of dealing with the API complexity, but you surely avoid some costly assumption hunts.

Usually, startup prefer simplicity because they will pivot anyways. In contrast, enterprise prefers flexibility, so they can plan years ahead and things stay in the budget.

> As simple as possible, as flexible as necessary. That requires knowing the future.

Knowing the future in this case should usually mean that you have requests for a feature from customers, but you don't have time to do it in this version. At least that is something I find useful as a rule of thumb. If that is not the case, you should really think twice before making it flexible rather than simple.

> As simple as possible, as flexible as necessary.

That really resonates with me.

Well said.

I was recently passed off a project from someone who didn't have a development background but had been working on C++... the amount of copy-paste, repetitive if statements and fixed length arrays makes the original code almost completely unusable and I was forced to suggest a total rewrite.

> If it's just a big ball of mud: not much you can do. It's pretty much a physical job, like counting grains of sand on the beach.

You can refactor as you go. It doesn't save you from sifting through the entire ball of mud, but at least it means you won't have to do it again in quite such a bad way.

I have had nightmares doing both. One of them ongoing.
Same here. I started applying LEAN lately and I'm more productive than ever. I just stopped creating interfaces and as-atomic-as-possible components in favor of simple but sometimes dumb classes which do the heavy lifting and can be easily replaced by more robust code when it is needed.