Hacker News new | ask | show | jobs
by Kamq 953 days ago
> I am terrified of WET code.

and

> I usually do create what others would call unnecessary abstractions, to stay DRY.

Seem completely incompatible with

> Because I tend to write all my code such that a complete stranger should be able to drop in and understand it.

Now, I don't know the codebase you're in. It could be that your abstractions are perfectly fine, but DRY code != maintainable. You're sacrificing a ton of locality of behavior (LoB) to get that DRYness, and introducing potential spooky action at a distance. Not to mention the cognitive overhead of the abstractions.

I'm not saying to never abstract, but abstractions really only supply a benefit when the things involved are guaranteed to vary together. Usually via some sort of physical process. If it's just business logic having them vary together in the same place, eventually some dictate comes down from management to change one of them but not the other.

When this happens, you introduce weird bugs on the other side of the system. That's how a platform gets the reputation of being unmaintainable. In the bad old days, it used to be that it was globals being referenced by many different functions as well as unrestricted gotos being used to jump into the middle of a function, but I've seen it happen quite often with abstractions, even ones that seem like a good idea at the time.

The code we're talking about was actually pretty DRY. You need something that does the same thing as the last half of this function? Just push a different return address onto the stack and jump into it to re-use the code. Why repeat yourself? But it had terrible LoB, changing one function could break a completely unrelated function halfway across the project (and one that didn't even obviously call the function if you're using some sort of computed goto).

You've also identified that structured programming brought about an end to the worst of these abuses, but I think you've got the reason wrong. It's not about reducing the number of places that you need to change something. You can write perfectly structured code (actually, it's hard to write unstructured code these days) and still need to change logic in 5/10/20 places. And local reasoning is still preserved in this case, as locally would consider each of those places by themselves, assuming the logic is all in different functions/modules/etc. Structured programming changed so much because forcing functions to have defined entry/exit points allows for easier preservation of invariants. You can't have meaningful invariant checks if someone can just jump into your function just after those checks. It's also much easier to see what in the project depends on the code you're changing.