3 ms·
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 y
by jbooth 10y ago
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.
- sitkack 10y agoIf 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 https://en.wikipedia.org/wiki/Bidirectional_transformation
- gnaritas 10y agoIf 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.
- TeMPOraL 10y ago> 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.
- gnaritas 10y agoGood 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.
- jbooth 10y agoLike 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.
- gnaritas 10y agoYou 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.
- jbooth 10y agoAgree with all of that. My hatred of extreme DRY is due to having been burned by premature/poor abstraction so many times. Also, there are even exceptions to that rule.. I've seen a number of cases, let's say you've got a bunch of command line utilities that launch different jobs, there's some code that's duplicated across like 10 of them. Be careful with deduplicating that, you can wind up forcing very different things to pretend they're the same. To put it another way -- it doesn't make a whole lot of sense to abstract some "forNtimes(closure, N)" function instead of just writing a for loop. There's a limit.. that example is laughable but I've seen a lot of abstractions that actually increase the amount of code in my day.
- gnaritas 10y agoWe're probably in close agreement then. However I'll disagree with your last statement as that's actually often a standard abstraction and the clearer less error prone way to write an n times loop. I'd rather see 20.timesRepeat(() => doStuff()); than for(var x = 0; x<20; x++){ doStuff(); } for and foreach loops are virtually always in need of some cleaner functional abstractions that are already standard parts of virtually every collections library and are far more amenable to chaining. Abstracting loops is not premature abstraction, they're already abstracted in your collections lib.
- TeMPOraL 10y agoWhat 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.
- jbooth 10y agoIt'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.
- TeMPOraL 10y agoI think the problem here is with inheritance, which I personally consider a code smell. There are few specific places when you need it, and by using inheritance there you're strongly signalling a particular abstraction happening - one of the "is-a" type. It definitely should not be used for just code deduplication.