DEV Community

Discussion on: The Fallacy of DRY

Collapse
 
courier10pt profile image
Bob van Hoove

+1 for pointing out the coupling and complexity issue that may come with 'DRY' abstraction. Some concrete examples of where you might refrain could help the discussion. Where do we draw the line?

Collapse
 
jeroendedauw profile image
Jeroen De Dauw

Do you have any suggestions for good examples?

I did describe some scenarios using words rather than code. These are quite simple ones, yet the code would take up a bunch of space. Do you think it would be better to provide code examples for those anyway?

I suppose I could add this one somewhere:

for($i=0; $i<4, ++$i) {
    doAction($i);
}

vs

doAction(1);
doAction(2);
doAction(3);
Collapse
 
courier10pt profile image
Bob van Hoove • Edited

I like your example, it's very concise. I'd definately prefer the latter version.

Now I owe you an example trying to get at 'where to draw the line'.

Let's say I have 2 types:

public class SupportFee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Active { get; set; }
}

public class HardwareFee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Active { get; set; }
}

If I were to write code to maintain these sets I would end up with for instance 2 controllers and a couple of views to support them. They'll be very similar, but it's okay. At this point it would not bother me.

But now we add a couple more types, for instance DeviceType, ConfigurationType and ImageType. They have the same properties and adhere to the following interface:

public interface IOptionType
{
    int Id { get; set; }
    string Name { get; set; }
    bool Active { get; set; }
}

The example is taken from an actual application I wrote. I has about 10 types that adhere to the IOptionType. Also, all of them are small sets. At this point it makes sense to have an abstract controller that I inject with mapping objects, providing default views. It's just cumbersome to write the same code over and over again.

Now time passes, feature requests come in... If over time any type deviates from the IOptionType or outgrows being a small set I can still decide to write dedicated code for it.

So there's an example where the fine line is around 3 or more similar types. The DRY abstraction helped me a lot.

I think that the 3 or more criterium is nice as rule of thumb.

Thread Thread
 
jeroendedauw profile image
Jeroen De Dauw

Thanks for the more verbose example.

Even with all this description I do not understand the situation well enough to say much about it, which makes me think this does not work as an illustration of how to decide if unification is desired or not.

One thing I'm wondering about is why not do something like

public class Thing
{
    int Id { get; set; }
    string Type { get; set; }
    string Name { get; set; }
    bool Active { get; set; }
}

In other words, having a field that indicated the type, and then naming the class to something meaningful in your domain. Presumably also without the mutability part, so you have a nice Value Object (assuming no domain logic belongs on the thing itself).

Generally I find it odd to have objects that just contain data have an interface for them, such objects being mutable, or interfaces containing an interface prefix or suffix.

Anyway, I will keep the lack of examples for this post in the back of my mind and hopefully come back in some time to mitigate it.

Thread Thread
 
courier10pt profile image
Bob van Hoove

I think this is a fine example where unification makes sense. The abstraction saved me a lot of work, outweighing coupling or complexity issues, whereas with only 2 OptionTypes it would've been silly to go that route.

The Thing class wouldn't help our code much. Even though they're small sets, they have discrete types and tables. And overtime some of these types did change and get extra properties. Also I prefer to have meaningful names, both in the database and the code. This also helps the guy that makes the occasional report using the database.

But that is another discussion really. Just like the I-prefix.