DEV Community

Cover image for DRY & the Wrong Abstraction
Nick Taylor
Nick Taylor

Posted on

DRY & the Wrong Abstraction

I was chatting with someone in my Virtual Coffee community today, and they were talking about acronyms, because we love to create acronyms in tech. DRY came up, a.k.a. Don't Repeat Yourself, and then we got to talking about sometimes it's fine not to be DRY. I referenced Sandi Metz's great post, The Wrong Abstraction and a great talk by Sebastien Markbage (former React core team member), Minimal API Surface Area at JSConf 2014.

So with all that set up, let's hear from you, the community, on when to maybe DRY it up and maybe when not to. It'd be great to hear about real world examples to help others in their developer journey.

Photo by Jr Korpa on Unsplash

Top comments (15)

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

I agree and have been pretending I'm in support of DRY all the time, I don't always think it's good to put all your eggs in one basket abstraction. When do you stop, is this overdone? Just more problems sometimes

Collapse
 
adam_cyclones profile image
Adam Crockett πŸŒ€

ECSS covers an interesting anti dry concept because it's more decoupled and easier to remove

Collapse
 
nickytonline profile image
Nick Taylor

What’s ECSS?

Thread Thread
 
adam_cyclones profile image
Adam Crockett πŸŒ€

It's a little known and a little old theory of how to work with CSS

It's also a book and a style guide.

ecss.benfrain.com/

Even if you don't use it, it's worth a read particularly the bits about DRY and the strength of duplication

Collapse
 
fyodorio profile image
Fyodor

For a mediocre developer, it takes discipline to be dry and it takes iron balls to justify the dry (=longer) way to bosses.

For talented autistic hackers loving their craft, it takes discipline to not be dry when necessary and it takes iron balls to justify the β€œwet” way to themselves.

Dry can be different, as well as context for it. That’s why it’s definitely not something that’s cut in stone. But in general, it’s a nice practice. The smaller the team/project, the nicer it is.

Collapse
 
nickytonline profile image
Nick Taylor

Blaming folks is never really a good idea, but it sounds like it could possibly be a good teaching moment and/or improving communication with the team.

Collapse
 
abbasc52 profile image
Abbas Cyclewala

My thought process to decide to go with DRY is simple - Does applying DRY makes my code more manageable or more speghetti?

If applying DRY is making your code complex and less manageable, it is not worth it🀷

 
joelbonetr profile image
JoelBonetR πŸ₯‡

What can I say, I explained business analysts that development environment is not QA/UAT so many times that I forgot the count.

They always say sorry and that it's just in case we didn't noticed πŸ˜‚πŸ€·πŸ»β€β™€οΈ

Collapse
 
steveleve profile image
Steve Leve

DRY, like most of the guiding principles, is best though of as a guideline rather than a rule. There are always tradeoffs, good architecture practice is mostly a matter of understanding the tradeoffs and making deliberate informed decisions.

Sometimes it is better to duplicate a block of code if it cuts across multiple bounded contexts or presents difficult ownership & synchronization questions.

Database normalization somewhat parallels the DRY concept and helps illustrate the point. The early forms of normalization greatly improve the structure of the data but the highest levels of normalization will start to incurr additional database server overhead and application complexity. There is a middle ground that works best for any application but the exact balance is always a bit fuzzy, imprecise and moving.

The real value of the principles is to provide a language framework for discussing the work so we can make cooperative decisions acknowledging the tradeoffs we make for any given decision.

Collapse
 
peerreynders profile image
peerreynders • Edited

The issue is that there always is more nuance than the slogan suggests.

Point: Don't Repeat Yourself

"every piece of knowledge must have a single, unambiguous, authoritative representation within a system."

Just because there are two similar representations doesn't necessarily mean they refer to the same piece of knowledge. It's likely but in some cases the resemblance simply reflects the current incomplete understanding of the problem and its solution.

Counterpoint: Beware the Share (see also Fate-sharing).

Implementations sharing a common dependency are inherently coupled. If the implementations have slightly different requirements the common dependency absorbs complexity to accommodate that variation in order to be more "generic". When the requirements of one of the implementations change, the commonality has to adapt-often taking on complexity that doesn't benefit the other implementations, sometimes leading to a breaking change for the other implementations. So at times maintaining multiple distinct but much simpler dependencies can make maintenance simpler (Used Three Times).

Look at Bounded Context ("Beware the share. Check your context."):

  • The Customer to get work done inside the Sales context
  • The Customer to get work done inside the Support context
  • The Customer necessary for the the Support context and Sales context to communicate/collaborate.

Superficially there is repetition across the three Customers but they serve very different roles and more importantly neither context should let implementation details about the their internal handling of a Customer leak out.

 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

The ones I work with in the current project are good people, It's a bi-directional professional relationship, it must be. As tech lead/ lead dev, I try to explain them the concepts, the big picture about the architecture, the nuances of some features, what needs to be done to reach a given feature and so on.
They try to get better deadlines with that information and they try to understand whether something that is wrong in develop is due to a current development or if it's a flaw "Yes yes we know, it's develop, we don't want to bother you guys". πŸ˜†

Collapse
 
jwp profile image
John Peters

My guideline is once, sometimes twice but never three times.

Single Responsibility principal is king and applies to functional programing too.

Collapse
 
joelbonetr profile image
JoelBonetR πŸ₯‡

I was thinking about having maybe a getUserById and then a getUserByEmail, if you gonna DRY you can join both together in a getUserBySomething so you avoid repeating most of the query, but then you will have a conditional inside your function that makes the function more complex and it also breaks the Single Responsibility principle and it's worse IMHO.

Collapse
 
jwp profile image
John Peters • Edited

Single Responsibility does not mean all functions must only do one thing.

For example if we need new behavior, we simply write a new method whose name indicates that single responsibility. It then allows for parameters to change behaviors. It can contain calls to many other functions but strictly only does what the name implies.

I call this a decorator pattern because it adds functionality by use of optional parameters. Allows parts to be added at will, but never departs from what the name implies. It only does that one thing.

The decorated function prefers use of reusable SRP functions because that code is already done and bullet proof. They are closed for modification.

The Concept is so simple but often confuses pepple.

Doing more than one thing in a function composed of SRP Functions is only more fragile if tests prove it.

Collapse
 
paratron profile image
Christian Engel

Its a balance act (like most of the time). The drawback in getting DRY is that the code will have reduced flexibility. If parts of the application need to be refactored, that is much more work in a DRY application because you either need to extend the parts and need to be super careful not to affect other parts of the program. Or you need to break up again and create near-copies of some structures.

On the other hand, being DRY reduces the surface for bugs. More code = more surface for bugs, simple as that.

I think its a good rule of thumb to not trying to get into too DRY code too fast. Stay flexible until the overall architecture of some modules got settled and with refactoring and the use of unit tests it will be easier to DRY the code part by part.