loading...
Cover image for  When Code Duplication is the Right Answer w/ Sandi Metz

When Code Duplication is the Right Answer w/ Sandi Metz

niko profile image Niko 👩🏾‍💻 ・1 min read

This talk blew my mind and I thought it would benefit the DEV community.

Main Argument

Sandi equates trying to fix a problem by increasing the complexity of the wrong abstraction, with chasing a beach ball on the outgoing tide. She urges us to prefer duplication over abstraction in our code. DRY isn’t bad and duplication isn’t good. But, if your choice is between duplication and the wrong abstraction, the right choice is duplication.

Let’s Discuss

Sandi offers this quote, “Make the change easy, this might be hard, then make the easy change”, as guidance. She advises us not to get lost trying to get to the future with our code, but instead to aim for code that can adapt for the future when it arrives (with the idea of making small objects that have single responsibility at it’s core). What are your thoughts about this?

Posted on Aug 31 '17 by:

niko profile

Niko 👩🏾‍💻

@niko

Dev Rel & Live Coding Streamer. Obsessed with using code, inclusion, & design thinking to bring big ideas to life and tell digital stories worth sharing.

Discussion

markdown guide
 

In Soap/Micro service architecture I have an empirical rule:

0) Duplication within the same codebase is bad unless it serves purpose of better readability.
1) Duplicating the same utility/stateless code twice is not a crime in separate projects.
2) Making some piece of code to be generic to fit only 2 usages in different micro services/projects is over engineering and usually a bad idea
3) Duplicating 3 times (across diff projects) is still not bad but probably It's time to reconcile why this is happening and mark it as a refactoring candidate.

 

Thanks for sharing, that makes a lot of sense! I'm going to add this to my jr dev notebook. I'm just now coming to terms that duplication isn't always the bad guy as I was taught in school.

 

I struggle with this as I like DRY concepts, but at work, I develop over the top of an already established platform with fairly strict constraints.

While they do a pretty good job in making inheritance easy, sometimes things don't quite fit the bill. This occasionally results in me having to pinch a bit of code outside the scope of what I'm doing, but not available to call independently.

I agree it's best to have a balancing act. Copying and pasting within the same OOP file is clearly not good practice. However, if re-using something that isn't easy to access, and doesn't really fit with what I need, sometimes copying a little code is the lesser of two evils.

 

I think she is a great developer and right to the point.
I think that all principles (like DRY and SOLID) are guidelines not rules, you choose the best approach for each problem, if there are more pro reasons to break a principle so be it.
I think that those 2-3 LOC from the example are ok to duplicate, then coming down to business rules if you try to put them in methods, the next dev will enlarge those methods with the extra conditions, and complica them.

Another approach will be composition and/or FP, you put the +/- operations in very small reusable functions and combine them for each business rule (in a FP manner).

 

This talk is a masterful walkthrough on how to translate a functional definition into good, extensible code. I found the bit about identifying the GildedRose class as a Factory particularly enlightening.

Not quite sure where the DRY/duplication dicotomy comes into place here, though. I think that transforming a flawed, confusing method into classes that inherit a single API should not be regarded as "repeating yourself". In python you may be tempted to think of it as so, as you have to add lines of code that look the same. But in fact you are just implementing a contract, and for that there's a few things that must be repeated.

This is one of the things that Java does well: in Java you would create an Item interface, and define the different classes that implement it. An interface just defines a contract, a type, with the signature of the methods the subtypes will have. You then must implement each and every method in each of the subclasses. But it doesn't feel as code duplicaton, as the compiler will fail if you don't implement these methods, thus "hiding away" the repeated parts from the things you feel guilty about in your code, as they are not your responsibility.

This brings to mind that thing you hear in talks all the time: patterns are the solutions you use when the language doesn't have the right tool for the problem at hand. I know python has inheritance and types and all the flying colors. But I don't think it is helping the developer get to a good solution if it makes them think that inheritance and contracts are code duplication.

 

I love the squint test concept. It's something I often share with others.

 

I loved it too. I never thought of using shape and color to give context to how clean code is :D.

 

In short, duplication is bad, unnecessary complexity is bad. If you need to choose between the two choice depends on amount of extra complexity vs probability of change of duplicated functionality.