Hacker News new | ask | show | jobs
by rsj_hn 1653 days ago
For the same reason, I'm not so absolutist about DRY. Having the most elegant codebase also often means the codebase that's hardest to work on, and it's often better to clean things up afterwards once you know how things will be structured.
3 comments

This question determines if you need to be DRY or not:

"If [some fact] in the code base needs to change, how many places would we have to change it in?"

If the answer is > 1, you have a very good DRY case. Otherwise, when [some fact] changes, it will probably not be changed in one of the places, and the system will be broken.

This often coincides with having an "elegant codebase", but that's not the most important part.

A younger self used to be very strict about DRY.

For a living codebase, nowadays my general rule of thumb is to consciusly duplicate code until it covers 3 different cases, and only then refactor (unless the DRY way is as fast and obvious).

It takes more than that to yield spaghetti and a lot of time is saved on premature generalization. Plus the generalization is often way more straightforward once the explicit cases are already implemented.

https://en.wikipedia.org/wiki/Rule_of_three_(computer_progra...

I follow this too for "style" refactorings.

The original formulation of DRY was "Every piece of knowledge must have a single, unambiguous, authoritative representation within a system," which in import winds up pretty close to what you have here.
Recently (last month basically), i rewrote my code (i'm leaving soon and i want my coworkers/successors to have success improving on what i've done).

I followed every principle of good code, except one, DRY. I tried to make generic parts to connectors, because they do have similarities. But this is a work of at least a year, and the price to make it generic was increasingly more complex configuration files (Just the pagination alone added 3 variables for two different APIs, and the number of app i am supposed to interact with should grow to ~40). I decided after a few days of reflexion that the idea was not that dumb in principle, but unworkable in my case, and decided that one connector for one API, even with a lot of repetition.

Yeah, I had a few connectors (API clients to different APIs with some business logic wrappers to handle low level stuff) and decided that they should share code with a generic connector interface, and then when one of them changed it was pretty painful untangling it. There is a tradeoff between getting stuff done and abstraction engineering, and there are costs to premature abstraction engineering.
See also: the wrong abstraction is worse than no abstraction at all.

https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction