Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> The wisdom in WET is that it prevents the accidental complexity created by premature abstractions

Yes, but...

> while not preventing the introduction of abstractions later.

...not necessarily.

A facetious example to illustrate the point:

I am required to implement DogWidgets and CatWidgets and I have two choices - separate the Widgetness into some kind of base class, or copy-paste.

I take the latter approach. The code is initially easier to read and maintain due, as you say, to reduced cognitive load. Fast forward two years; I'm no longer on the project. Now Joe Junior Developer comes along and over a period of several months, is asked to make a series of changes only to CatWidgets; some of these pertain to Widgetness, but Joe is not experienced or familiar enough with the code to understand that, and anyway has not been told to change DogWidget, so we eventually end up with two divergent implementations of Widgetness. Then somewhat later, Jolene Developer joins the project and is asked to fix an intermittent bug in CatWidget. The bug turns out to be partly due to the original Widget implementation, and partly due to Joe's changes - now Jolene not only has to fix CatWidget, but also examine DogWidget carefully to determine if a) the bug affects DogWidget too, and how, and b) whether or not to fix it, and how (which may be different from the CatWidget fix).

Somewhat later still, the business expands into the BirdWidget market. Rolling CatWidget's and DogWidget's Widgetness back together into a base class is now a very difficult refactoring job that is determined to take twice as long as just copy-pasting DogWidget and making Bird changes; doing the right thing by the code doesn't make economic sense. Now we have three problems.

If I chose instead to implement Widget, and derive DogWidget and CatWidget, then yes, I am imposing some additional burden on future developers to learn how the code is structured. However, now every time a change is made to CatWidget, if the design is good then it should be fairly obvious whether it's a change to Widgetness, or a change to Catness. Bug fixes and improvements to Widget now automatically filter down to both (and all future) Widgets; if Widgets need a colour, then even if we only want to give it to CatWidgets at the moment, we can stub it out or provide a default value for DogWidget, and that thought process also forces us to examine our design instead of ignoring DogWidget altogether, which helps to keep the design current and relevant. Designs should evolve over time.

If one day we get sick of this code structure and wish we had taken the other route, we can quickly copy-paste and completely fork CatWidget with basically no risk of regression, and minimal effort. BirdWidget is obviously trivial to implement. New Widget safety legislation can be implemented once cleanly, instead of three times in three slightly different ways.

> Naive interpretations of DRY are renowned to needlessly cause problems due to those mistakes.

Naive anything is problematic. DRY and WET are tools to be deployed when it is appropriate, not rules to be followed dogmatically; as I said there's a line to walk. As to your initial question:

> How can you tell if what you're task to do is to duplicate a class?

As far as I know there is again no hard and fast rule - it's a heuristic that we develop over the course of our careers: "is this likely to change in the future, and in what ways?" With experience, one can learn to foresee that the business might branch out into the BirdWidget market, and with care, develop code that supports that possible future without being too tied up in abstraction right now. Of course one can go too far, although as I outlined above, I personally feel that 'a bit too far' is overall better than 'not quite far enough', at least in the long run. I've personally spent countless hours trying to untangle legacy WET code compared with much less time necessary to understand DRY code.





> (...) so we eventually end up with two divergent implementations of Widgetness.

That means they were never the same implementation to begin with.

> Then somewhat later, Jolene Developer joins the project and is asked to fix an intermittent bug in CatWidget. The bug turns out to be partly due to the original Widget implementation, and partly due to Joe's changes (...)

Irrelevant. It means you have two components that are buggy. Create two big tickets and tackle them whenever the team has capacity.

How many months or years have passed since your hypothetical initial refactoring?

That's the problem with mindless fundamentalisme involving DRY. Throwing complexity around and tightly coupling components that in practice have no relationship other than superficial similarities are mistakes that only create technical debt in the long run.

> As far as I know there is again no hard and fast rule - it's a heuristic that we develop over the course of our careers: "is this likely to change in the future, and in what ways?"

That's the mistake you're making: fooling yourself into believing that mindlessly throwing complexity around prevents issues and future proofs implementations. It doesn't. You are only increasing the burden to maintain a project without bringing in any tangible positive tradeoff. YAGNI is a battle-tested guideline, which you're violating. Even in your example the introduction of a new widget meant bugs affecting it were either only affecting it, thus lower in risk profile, or already in the original component, which means low risk as no one stopped them. Why are you choosing to make your life harder?


OK, well, all I will add is that I've been where you are on this now, and I've also been an architecture astronaut, and now I'm somewhere in the middle. This is where I've landed based on long experience. I know which code I prefer to maintain, and it's not the big ball of mud that, in my experience, inevitably results from insufficiently abstracted designs. I'm absolutely not making my life harder; I'm making life much easier for my future self, and this is borne out by actual experience on projects I've worked on.

However as I said, there's no hard and fast rules, so, you do you.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: