Reflections on DRY then and now
I was inspired to write this after I after I read a great blog post about DRY: https://gordonc.bearblog.dev/dry-most-over-rated-programming-principle/
When I started my career I learned about DRY pretty soon. The code base I worked on had very few tests and a lot of duplicated business rules that should not have been duplicated, so the principle made sense. However the code base also had a ton of reuse that was even more problematic. Stuff like reusing a view for different flows, and navigating in the flow meant some data was stuck in the view because it had so many conditions to handle. Differences had emerged over time and line by line it turned into five views acting as one.
At this point in my career a tool called JRebel was used by coworkers and it was not uncommon to hear about it’s use in forums and at conferences. The premise was that it hot reloaded java code into the running JVM so e.g. slow web servers did not have to be restarted to reflect the changes made in the code. I never really got into using it, and later on I picked up TDD and I then rarely started the web server anymore. Reflecting back, DRY and JRebel fit and did some good under the same “legacy code” conditions. One big clunky web server with no tests could make sense of JRebel and DRY. I mean probably, copying code would have been better with no tests being there. Our mentality however was to keep the code monster as small as possible and DRY meant you could change a condition in one place, and test it manually in the GUI and feel somewhat okay. With copied logic you would have to change so many unrelated places sometimes and perhaps not even know how do do the manual test.
Andy Hunt and Dave Thomas defined DRY in 1999 in their book The Pragmatic Programmer. And when I listened to a talk by Dave Thomas on youtube some time back, he says in the talk that he “mostly don’t test”. Direct link to this quote: 18:00. Now, he has amounted to more than I ever will in this industry and the talk is great too. Still, it makes me think even more, that tests are a direct enabler of feeling free to repeat yourself. The drawback you have sometimes with repeats is that a the repeated lines needs the same update in the code. It can feel a bit annoying if this needs to be discovered by searching the code base. But a feature that stands on it own legs and lets you know if you broke it by a failing tests negates most of this drawback. So really, to me DRY is overused between features and developers forget that refactoring away from duplication is often not that hard compared to refactoring away from coupling.
Further along, I now actively avoid libraries and frameworks that offers abstractions that are inviting developers to express things with single monolitic truths. One such library is hibernate. Back when JRebel and DRY coexisted in a code base, you would often find hibernate in there too. Hibernate is not a bad tool for persisting data since you often want to represent a row with a class to simplify the write. But the DRY and monolithic ORM representations that followed for selects has done practically irreparable damage in code bases I have worked on. So if I could pick one place that should directly avoid DRY, it would be when it comes to data access. Personally I left hibernate, JRebel in the dust a long time ago alongside those clunky web servers. I think many developers would be amazed over how easy it it so reason about data access when you don’t have to think about the ORM stuff. You can just do your own thing and spend your time reasoning over the cost of that access.
I will end this post with a good place to think about dry DRY. Test classes should not mindlessly start copying use of an unstable constructor for a dependency that is not at all owned by the feature. If that dependency cannot be refactored away or contained better, then access to this dependency should probably be done with a DRY abstraction. Felt weird writing that though… But in the talk I linked before, Dave Thomas goes into exactly this, that there is no universal best practice. DRY has it’s moments under the sun too, or as Obi-Wan puts it: Only a Sith deals in absolutes.