Live data from Hacker News

Prefer duplication over the wrong abstraction

sandimetz.com

61–70 of 101 posts

Re: Prefer duplication over the wrong abstraction

#61

My favorite example of code you should almost always[0] duplicate are view classes (in MVC terminology). Instead, I see people subclassing views to change their behavior and dealing with absolutely mind-numbing behavioral bugs in their subclass. Furthermore, the subclass's implementation is totally dependent on the _exact_ implementation of the superclass. Change it, and you get a whole crop of new, hard to debug, bu…

> Instead, I see people subclassing views to change their behavior and dealing with absolutely mind-numbing behavioral bugs in their subclass.

Because they're breaking a rule of good design, implementations should depend on abstractions, not other implementations. Never subclass a concrete class, only abstract classes.

> Solution? When you have a view class that almost, but not quite, does what you want, copy the entire class, rename it, and make it do what you want.

Better solution, move the duplicate code into a common abstract superclass. Allow the views to differ where they're concrete and keep the common code abstract in the superclass. Then you can't ever break one implementation by changing another implementation, your core complaint.

Re: Prefer duplication over the wrong abstraction

#62
post #30

For a long time I've thought that Don't Repeat Yourself is the most important software engineering rule. I still do, but in line with this article, I've learned that some things that appear to be duplication if you just look at the literal code actually aren't. Just because you've got a chunk of ten or twenty lines that are identical right now doesn't mean that they are actually identical. It's hard to give concrete…

[deleted]

Re: Prefer duplication over the wrong abstraction

#63
post #40

This made me throw up in my mouth a little. Duplication is not inherently wrong as there is a point where you should stop abstracting and live with repetitive code, but that point tends to be way further out than most inexperienced devs would assume. If you're using duplication as a temporary tool to help find the right abstraction, fine. But don't check that code into source control. The problem with duplication is…

I disagree. Abstraction isn't the end all of every implementation. Don't get me wrong, it can simplify your code in beautiful ways; but only if it makes sense. Otherwise it creates unnecessarily complex code that is very difficult to build on top of. Imagine having to decompile a very complex thing just to add a small feature or extra parameter. Simple and transparent is always better in my experience. It is a lot ea…

I'm surprised by the number of developers who think the "right abstraction" is always attainable now. In situations with complex, shifting requirements, particularly with a new product, it is very easy for a good dev team to lock in on a set of seemingly correct abstractions that make subsequent development very difficult.

I've recently been on both sides of this fight, unwinding premature abstractions in favor of some duplication, and imposing a set clean abstractions on some horror-show code.

The premature abstractions were imposed in a situation where we were trying to map several different application-layer protocols to a common set of functions. The handling of the different application layer protocols should almost certainly have been left "unabstracted" by the original developers at this stage (where understanding is murky, time is short, and complexity is high).

On the other hand, we also had a metrics reporting framework where everyone just kind of rolled their own thing depending on how they were feeling that day. It was a massive mess, it was unreliable, it was uneditable, it was inefficient, and the only cure was to rip the whole thing out and impose a set of clean abstractions around the different reporting scopes that we need. This was a case where requirements were not likely to change, the complexity of the task was relatively low, and our understanding of what we needed to achieve was not 'murky'.

I'm definitely on the side of defensively avoiding premature abstraction in certain situations. I think it leads to healthier, more transparent, easier to change code in some situations, especially in the nascent stages of a complex machine (that nevertheless must function in production).

I'll say also that unwinding premature abstraction just feels.. ugly, politically and aesthetically. But that doesn't mean it isn't the correct decision sometimes, and it certainly doesn't mean that we wouldn't have been better off if we had just embraced the particular during a time when we didn't (and couldn't) know any better.

Re: Prefer duplication over the wrong abstraction

#65
post #46
post #40

This made me throw up in my mouth a little. Duplication is not inherently wrong as there is a point where you should stop abstracting and live with repetitive code, but that point tends to be way further out than most inexperienced devs would assume. If you're using duplication as a temporary tool to help find the right abstraction, fine. But don't check that code into source control. The problem with duplication is…

So then you make all your nice pretty abstractions, and something comes from the business where it needs to be different in some wacky pathological case. Now your abstractions suck. Duplication leaves you room for that messy business logic. Increased abstraction often means increased coupling, and that can be much harder to maintain. It's a judgment call on a case-by-case basis.

If new business rules completely invalidate your abstractions in ways that aren't easily fixable, you're doing it wrong. Those wacky pathological cases should just be new implementations that plug right into your existing stuff, even if it requires slightly reworking the abstraction it's better than giving up and duplicating everything. If you're finding duplication easier, it just means you're abstracting things poorly and need to get better at doing it. Mostly likely, you've abstracted too early before you had enough different cases to actually understand how to split the concrete from the abstract correctly.

Re: Prefer duplication over the wrong abstraction

#66
post #46
post #40

This made me throw up in my mouth a little. Duplication is not inherently wrong as there is a point where you should stop abstracting and live with repetitive code, but that point tends to be way further out than most inexperienced devs would assume. If you're using duplication as a temporary tool to help find the right abstraction, fine. But don't check that code into source control. The problem with duplication is…

So then you make all your nice pretty abstractions, and something comes from the business where it needs to be different in some wacky pathological case. Now your abstractions suck. Duplication leaves you room for that messy business logic. Increased abstraction often means increased coupling, and that can be much harder to maintain. It's a judgment call on a case-by-case basis.

What you should do, when messy business requirements break your pretty abstraction is a) find an appropriate new abstraction, and b) refactor the current code to use the new abstraction. Abstractions aren't forever, they're meant to change and be replaced as appropriate.

Now doing the Right Thing may sometimes require additional work even for a simple (but unfortunately abstraction-breaking) feature. That's why people like to duplicate and then leave things duplicated - because it's the lazy option. You can get some more technical debt in exchange for being done this afternoon. But we all know what happens when you accumulate too much of that debt.

Re: Prefer duplication over the wrong abstraction

#67
post #46

Earlier quoted context omitted.

So then you make all your nice pretty abstractions, and something comes from the business where it needs to be different in some wacky pathological case. Now your abstractions suck. Duplication leaves you room for that messy business logic. Increased abstraction often means increased coupling, and that can be much harder to maintain. It's a judgment call on a case-by-case basis.

If new business rules completely invalidate your abstractions in ways that aren't easily fixable, you're doing it wrong. Those wacky pathological cases should just be new implementations that plug right into your existing stuff, even if it requires slightly reworking the abstraction it's better than giving up and duplicating everything. If you're finding duplication easier, it just means you're abstracting things poo…

> If new business rules completely invalidate your abstractions in ways that aren't easily fixable, you're doing it wrong.

Why, you might have been doing it right all along. The abstractions were good for old business rules, but are wrong for new business rules. You need to replace your abstractions with better ones. You can't expect to predict future business requirements perfectly 100% of the time; there's no shame in having to rewrite stuff to accomodate changing reality.

Re: Prefer duplication over the wrong abstraction

#68
post #46

Earlier quoted context omitted.

So then you make all your nice pretty abstractions, and something comes from the business where it needs to be different in some wacky pathological case. Now your abstractions suck. Duplication leaves you room for that messy business logic. Increased abstraction often means increased coupling, and that can be much harder to maintain. It's a judgment call on a case-by-case basis.

What you should do, when messy business requirements break your pretty abstraction is a) find an appropriate new abstraction, and b) refactor the current code to use the new abstraction. Abstractions aren't forever, they're meant to change and be replaced as appropriate. Now doing the Right Thing may sometimes require additional work even for a simple (but unfortunately abstraction-breaking) feature. That's why peopl…

It's sometimes actually the best option. We're talking about principles in a vacuum here but I have seen so many tall class hierarchies where now in order to change one isolated feature that shouldn't affect the rest of the system, I'm creating consequences for the whole system.

Decoupling is a more important principle for maintenance than DRY. Obviously you want to factor out common bits of utility code but you absolutely do not want to force all code into the same model.

Re: Prefer duplication over the wrong abstraction

#69

Earlier quoted context omitted.

If new business rules completely invalidate your abstractions in ways that aren't easily fixable, you're doing it wrong. Those wacky pathological cases should just be new implementations that plug right into your existing stuff, even if it requires slightly reworking the abstraction it's better than giving up and duplicating everything. If you're finding duplication easier, it just means you're abstracting things poo…

> If new business rules completely invalidate your abstractions in ways that aren't easily fixable, you're doing it wrong. Why, you might have been doing it right all along. The abstractions were good for old business rules, but are wrong for new business rules. You need to replace your abstractions with better ones. You can't expect to predict future business requirements perfectly 100% of the time; there's no shame…

Good abstractions aren't about predicting, they're about being nimble so that when change does come along, it's easy, because you don't have a ton of duplication to fix in order to change the abstraction. The new business rules don't belong in the abstraction in general anyway, they belong in the concrete implementations, that's the point of having implementations.

Re: Prefer duplication over the wrong abstraction

#70
Is it just me or did the author just provide the perfect argument for pattern matching in function calls as seen in Elixir? One can easily split/fork the functionality of the same abstraction depending on the arguments. This preserves the names (which preserves the abstraction), but extends the functionality to adapt to the new use case in parallel, without any dependencies.

Also, by "wrong abstraction", the author is arguing for abstractions to be backed by reasoning, not circumstances a coder might find themselves within code. Duplicate code is not itself reasoning, but a circumstance. Though it can be abstracted away, elimination cannot be the only reason.

This also highlights why more languages need features to help the coder who finds themselves in these situation. Circumstance is a context, and is driven by dependency. Again, dependency is the enemy. We need tools and code that fight it, not cause or encourage it.

Post reply on HN