Live data from Hacker News

Prefer duplication over the wrong abstraction

sandimetz.com

41–50 of 101 posts

Re: Prefer duplication over the wrong abstraction

#41
post #32
post #3

How do you know that the abstraction is wrong (and how) if you don't create it? It seems to me like the article is saying - don't ever make mistakes, they are costly.

In some sense, yes, it's what article is saying. But yet I agree with it absolutely: it's basically the same thing I try to convey to some my colleagues for years. Because the problem is that many programmers — almost all novices and even some pretty experienced ones — don't admit to themselves the simple fact, that they might be wrong in the what they are thinking right now, at the moment. Sure, they won't deny that…

I think we can agree that the abstraction that has more lines of code than the original duplication is probably wrong. But that's something very different. I don't think abstracting duplicated code precludes sticking to YAGNI.

Re: Prefer duplication over the wrong abstraction

#42
post #39

It seems to me that it would be better to address step 6, where programmer B adds cruft to the abstraction rather than re-working it. I appreciate that pragmatics sometimes dictates that duplication is the right option, but instead of mostly giving up and advocating an emphasis on duplication, I'd rather encourage better design of abstractions in the first place, and more willingness to genuinely improve abstractions…

This is the correct answer. It sounds like in that case the initial abstraction was either poorly designed, or the behavior being added doesn't fit the abstraction.

Re: Prefer duplication over the wrong abstraction

#43
post #13

Earlier quoted context omitted.

I think such conservative approach can be justified when working on existing code, which has been somewhat proven to work. But I don't think it's justified when you're building the code. I simply don't think you can always get the good abstraction right. But if you don't attempt it, you will never get it right. What you're advocating is not attempting it.

If it's new code, and you are unsure what abstraction is needed, build the simplest abstraction possible. YAGNI That way, as the code develops, and it becomes more clear what is needed, then you can easily build it at that time. If you have code that needs to be duplicated, throw it into a function, a lightweight and powerful abstraction.

That's what I am advocating in this thread. ;-)

Re: Prefer duplication over the wrong abstraction

#44
post #21

I see the author's point, but it overlooks code maintenance. At step 4, where "Time passes" it should read, Programmer A fixes bugs, optimizes, adds features, etc. Repeat. If the code is duplicated, the maintenance effort is also duplicated or the duplicates diverge significantly making them more difficult to understand in relation to each other. Why does methodA do this, but methodB does that? Tools can help prevent…

Agreed. I think this is actually dangerous advice. While I agree that the wrong abstraction can cause lots of pain, the repetition of a bug through duplicate code is arguably a worse issue. One example might be not using an abstraction for accessing filesystem resources in a web based service. You might end up duplicating a ton of code that improperly takes a string from a request without sanitizing it and then have…

This would not be a candidate for duplication tho, because the underlying intent is also logically the same. Author is talking about things that coincidentally happen to have similar code at the moment, but are fundamentally and logically unrelated, having a high likelihood of diverging in the near future.

Re: Prefer duplication over the wrong abstraction

#45
post #21

I see the author's point, but it overlooks code maintenance. At step 4, where "Time passes" it should read, Programmer A fixes bugs, optimizes, adds features, etc. Repeat. If the code is duplicated, the maintenance effort is also duplicated or the duplicates diverge significantly making them more difficult to understand in relation to each other. Why does methodA do this, but methodB does that? Tools can help prevent…

Programmer A replaced the duplication with a new abstraction at step 3, so maintenance activities can be performed once on the abstraction definition instead of once per copy. It wasn't until the functionality diverged (thereby invalidating the abstraction) that the author advises replacing the abstraction.

Re: Prefer duplication over the wrong abstraction

#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.

Re: Prefer duplication over the wrong abstraction

#47
I think this is especially pertinent for the current SOA/microservices trend that many companies are adopting nowadays. Build small, simple, highly focussed services that specialize at one thing. Services do one thing, and do it well, at the cost of flexibility and the ability to generalize over different use cases. I think this something that is perfectly ok and shouldn't make programmers squirm, even if it leads to code duplication.

In some of the more popular microservice frameworks for instance, I see some attempts to build abstractions for things like data persistence -(what if we want to swap out Postgres for Mongo, etc?) But I think that's a good example of a needless abstraction. In fact by building an abstraction like that, you lose many of the features that perhaps made that specific database so great in the first place.

It seems to be easier to mentally justify logic duplication in the hardware world. An FPGA is an abstraction of logic. In general, it trades off performance for more flexibility. An ASIC is specifically designed from the ground up to do one task very well, but deviate from that task and it's borderline useless. I think that for microservices, code should be treated more like ASICs. One off, application specific code that we won't be afraid to throwaway and rewrite from scratch if we need to.

Re: Prefer duplication over the wrong abstraction

#48
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 easier to refactor and combine than it is to deconstruct (more often than not, code that is too complex to get deconstructed just gets rewritten).

Side point: Write code that is easily ripped out and replaced (I.e modular). Personally, I think this is one of the most important principles in continually evolving software. Make shit easy to replace.

Also it's not true that duplication is untrackable. Comments, find/replace, or just construct your code in such a way that it is easy to find (helper methods, wtc.)

Re: Prefer duplication over the wrong abstraction

#49
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, bugs.

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. You'll be done before your next break, and nothing that happens anywhere else will cause it to break in the future.

[0] The one exception are situations where all you are doing is configuring an existing view class in code and/or adding behavior in places that were _specifically_ anticipated by the class in question. For example, setting up the options on an existing table view class, and responding to row selections using a method meant to be overridden by subclasses.

But if your table view is actually different than the class you've got now—for example, it does something strange in responses to selections—you're much better off finding an open source replacement for the table view (if it's vendor-provided, like UITableView in iOS), copying it, renaming, and modifying it to do exactly what you need to it do.

Re: Prefer duplication over the wrong abstraction

#50
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 refactorings were described as bidirectional ST (syntax-tree) transformations we would automatically get the defactoring and the refactoring.

I could definitely use "inline method" or "name mangle method and special case".

https://en.wikipedia.org/wiki/Bidirectional_transformation

Post reply on HN