Live data from Hacker News

Prefer duplication over the wrong abstraction

sandimetz.com

71–80 of 101 posts

Re: Prefer duplication over the wrong abstraction

#71
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…

Like I said, it's a judgment call on a case by case basis. Taking 'DRY' to an extreme leads to an overly self-coupled code base, taking decoupling to an extreme leads to the need to apply the same fix in multiple places.

Re: Prefer duplication over the wrong abstraction

#72
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…

I agree. I my mind, DRY really is not about similar looking lines of code. I think of it as an attempt to strive for a concept-to-implementation-ratio of 1.

Re: Prefer duplication over the wrong abstraction

#73
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…

> For a long time I've thought that Don't Repeat Yourself is the most important software engineering rule.

It's not. "Don't introduce unnecessary dependencies" and "keep dependency graph without cycles", "keep things modular" and "all operations in a unit (function, module, ...) should be from the same abstraction level" are just as important, if not more, but they're a little more high-level, and thus less actionable. DRY is just simple to enforce, that's all to it.

Re: Prefer duplication over the wrong abstraction

#75

Earlier quoted context omitted.

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 so…

These types of situations are very common in "view" and "view controller" classes.

Someone tries to DRY a complex view that handles takes in many options and parameters to address several use cases.

A redesign or requirements change happens and now you have an over complicated view class that needs to get deconstructed. Or you can try and build on top of /subclass/extend an over complicated thing. Neither is ideal.

Reading and understanding code is A LOT harder and time consuming than writing new code. So in reality, this view would just get rewritten (duplicated) anyway.

Re: Prefer duplication over the wrong abstraction

#76

Earlier quoted context omitted.

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.

I understand the intent. I still believe the advice is dangerous if improperly applied.

That's true for all advice, especially in software development.

Re: Prefer duplication over the wrong abstraction

#77

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 ent…

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

And then you suddenly find yourself having a "god object", a class that does huge amount of things and most of them are not related to anything else in the class - they just exist to facilitate code deduplication lower in the inheritance tree.

And then, one page really needs a different version of a behaviour that's common to many of them, and you're back to either duplicating or polluting the "god object" even more.

Inheritance is a bad tool for this problem. It's better to separate different pieces of functionality and then compose them in views. If your view needs a component behaving in a slightly different way, then you can just create a new component (or even subclass the old one, if you must).

Re: Prefer duplication over the wrong abstraction

#78

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 ent…

Exactly this. At Abebooks[1], they had a Servlet called "AbeServlet" that was duplicated for every new page that needed behaviour. By the time I arrived there were close to 200 different servlets all copied from the same "template". Eventually a new requirement came: we need to support i18n because of a merger with European counter-parts. French, British English, Spanish, and German.

Hundreds of servlets had to change. Took about two weeks of coding by several developers.

When I arrived, I created "AbeMetaServlet" (bad name, but good idea). All my servlets extended from it, as it contained common behaviour. To make my pages i18nized, I changed something like a dozen lines of code and was done in less than an hour--about 16 servlets, if I recall. I didn't know about the upcoming merger. I simply despise duplicating code.

There was another example at that shop where they had processes that started up, ran to completion, then paused until time for the next run. All the batch processes had been copied from a template with no thought to the future.

I was tasked with updating a batch job for associating pictures of book covers with inventory that vendors uploaded. Rather than copy/paste, I rolled my own and fixed a bug. (There wasn't any code that could be re-used, architecturally.) The bug added several hours of run time to the picture maintenance process. The first task each batch job performed was to fetch a list of 10,000 vendor names over an abysmally slow network drive. Undoubtedly this bug was copy/pasted into the other processes.

I re-wrote the code to request the vendor names from the database--and only open up directories for valid vendors. The code, which originally ran in something like 12 hours, was reduced to 8 minutes.

All the batch jobs likely suffered from this error. Including the one that took almost 24 hours to run. Anyone know what happens when a batch job needs more than 24 hours to finish?

Anyway. Had a proper design been developed at the start, one simple change would have made all the batch processes faster.

[1]: http://www.abebooks.com/

Re: Prefer duplication over the wrong abstraction

#79
post #71

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…

Like I said, it's a judgment call on a case by case basis. Taking 'DRY' to an extreme leads to an overly self-coupled code base, taking decoupling to an extreme leads to the need to apply the same fix in multiple places.

You can remove the judgement call by making it a design rule, as extreme programming did long ago. When you've duplicated something 3 times, it's time for some abstraction because you have enough examples now to see what needs abstracting and what doesn't. The problems you're describing are just symptoms of premature abstraction. Abstractions tend to fail when they come before the concrete, they tend to succeed when they were lifted out of several examples of the concrete.

Re: Prefer duplication over the wrong abstraction

#80

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…

Been bitten by this in React using ES6 where we would sub-class components and override render to provide another layout (or whatever; change behavior).

The right way to do it in React is to define a new Component and make the Component you'd like to depend on wrap around the returned JSX in render instead. Probably not a revolutionary paradigm, but it has made me better at reasoning about and structuring React components.

Post reply on HN