loading...

The Demise of Reuse

rmorschel profile image Robert Morschel ・2 min read

I remember when code reuse first became a buzzword, back in the day. "Code duplication is bad!" they cried. "A maintenance burden! Error prone! Write code once, reuse, cut costs, and everybody wins!"

But imagine you embraced this mantra. You have a number of client systems reusing your very useful code, some in your team, some not in your team, and perhaps some you don't even know about… You want to make a change. How do you not break client code?

You turn your very useful code into a library or perhaps even a service (*waves dusty SOA banner), with well-defined interface contracts, usage guides and a versioning policy. And you start to keep track of your clients. And of course, you want to write tests. But since clients will reuse your code in surprising ways, you write more tests, for scenarios you haven't imagined (with your crystal ball.)

And all is good for a while.

Then client N+1 comes along and wants to change the common interface for legitimate reasons – change is to be expected and even embraced, right? Luckily we used XML or JSON (or both), so we have some extensibility. But no, the client is not satisfied. The change is more significant. The business is moving. We are agile. We need to change the interface fundamentally.

So we do, and we version it. We notify all our clients that there is a new version, and that version 1 is deprecated. They have 6 months to upgrade.

But some are too busy to do that, and we end up with two versions.

Or perhaps we decided the client's requirement is unique, so we write a special purpose adapter. We end up with two interfaces. Somewhere, a developer's soul dies.

Unless very carefully managed, shared code quickly becomes code nobody wants to touch. This is a very bad smell. Changes will be made around the edges, and a monster will be created. Nobody will want to own this code.

The very reuse of the code ironically becomes its own demise.

Discussion

pic
Editor guide
Collapse
jaroslavholan profile image
Jaroslav Holaň

I agree. I spend a lot of time modifying abstractions that turned out to be inflexible designs that are difficult to change when new requirements show their ugly heads.

The only thing that I dislike more than duplicate code is so-called reusable code that is littered with one-offs.

"I'll just put the new behavior in the base class and guard it with a boolean parameter that defaults to false so that the subclass can override the parameters to get the new behavior." - every code monkey at some point in their lives

I see this kind of attitude a lot in projects where code quality is neglected when the deadline approaches. It somewhat disgusts me when programmers do this. What's worse is that the management in a lot of places encourages it because it allows you to deliver sooner at the cost of code quality and maintainability.

Often I end up rebuilding bad abstractions from the ground up just so I can move the one-off behavior away from the abstraction. Ironically that almost always requires me to modify usages of the "reusable" code, which are spread across many files. Isn't that what we were trying to avoid?

It is my opinion that often times, duplicate code is the most maintainable solution. Not everything needs to be generic and extensible. Tools like Search & Replace All make it quite easy to identify duplicate code and modify it all in one click. But when you're faced with a bad abstraction, these tools can do nothing to help you fix the problem.

Collapse
mortoray profile image
edA‑qa mort‑ora‑y

I think generally a company is either in the business of making general purpose solutions (reusable code) or client solutions (non-reusable code). It's not really possible, probably not even recommended, to try and mix the two models within a company (or at least within a division).

Collapse
silwing profile image
Silwing

But even though you make client solutions you surely run into small scale situations where code reuse seems appropriate.
You don't want to make the same business validation rules in multiple places. Or maybe your client has multiple applications and you want a consistent user interface across the apps. That all leads to wanting to reuse code.
I feel the article has a good point though. Code which is reused a lot quickly becomes difficult to manage. Especially if you are missing automated testing to reassure you that nothing goes wrong when you refactor or change common code.

Collapse
mortoray profile image
edA‑qa mort‑ora‑y

I don't have a problem with reusing code so much as sharing code, that's when the problem starts. Each client should just get a fork of the code and then you start modifications. If a client wishes to upgrade their project you can look at merging in changes then. If they just need minor changes then you stick with the old version. That is, treat it like software with a distinct release for each client, and don't attempt to actually share one version of the code.

Collapse
rmorschel profile image
Robert Morschel Author

Reuse in a team is good, and cheap. Reuse across teams is hard. Reuse across the enterprise needs to be deliberated, and managed, and is costly.

Collapse
tra profile image
Tariq Ali

"Nobody will want to own this code."

Perhaps I'm naive, but why? It would seem to me that at least a few developers would definitely want to own this code, not just for "guaranteed job security" in maintaining legacy code, but also for the joy of successfully solving clients' problems and aiding them with their greatest challenges (assuming, of course, that the clients actually need those changes...and if they don't, well, there's bigger problems to worry about). Perhaps actually maintaining the code is a nightmare, but the prestige of ownership is definitely something to consider...at least on an abstract level. Legacy code is successful code.

That doesn't undermine your broader point though. "All problems can be solved by adding abstraction except for the problem of too much abstraction" (paraphrasing from the Fundamental Theorem of Software Engineering).

Collapse
automationtest profile image
Phạm Trình

I'm working with a more-than-ten-years-old product, and I think I should say that I totally agree to "Nobody will want to own this code".

Imagine that the code was written by a developer, who just left the company for years, will you volunteer to own that code? Especially, the code is big and so messy, but it's shared across components and quite stable.

If you're my customer, would you like to wait and pay me for refactoring the code that was stable for years?

These questions are not easy to answer man :)

Collapse
rmorschel profile image
Robert Morschel Author

This was based on a real example. Nobody wanted to own the code, until recently someone saw its long-term potential as a useful service, and volunteered. There was a happy ending.

Collapse
seymorethrottle profile image
SeymoreThrottle

This is my career right now. I work in a small dev shop that has been around for a long time, but I'm relatively new. I've worked on a number of projects and this keeps coming up. Every time I open a project and start working I find myself handcuffed by the exact scenario you describe here.

For a developer it can be brutal to work with this kind of codebase. I find myself constantly playing chess with shared code and the abstractions that have been used to spread it over too many projects (like butter scraped over too much bread). I spend way too much time implementing the simplest of features, and I often have to distract devs who have been there longer than me to ask what the "right" way to do things is.

If you have to own this code (because you like feeding your family) you might find yourself feeling less like a developer and more like an "expert at figuring out how this specific shared/abstracted code fits together". Which is not a very marketable skill.

Thanks for the article. If you feel like writing a followup on how to climb out of a mess like this I'll have my notebook ready.

Collapse
ambroselittle profile image
Ambrose Little

Ha. Nice allusion ("butter...").

Collapse
jillesvangurp profile image
Jilles van Gurp

One way to think about reuse is considering that you don't just ship the code you wrote but also everything that depends on including libraries, frameworks, the OS, tool chains, etc. Literally hundreds of millions lines of code. When you consider that, you'll realize that the vast majority of what you ship is reused code written by others. And it's not just the code you reuse but also the testing and integration effort that went into making all of that rock solid. What you create is literally just a tiny fraction of that.

The larger your own code base is the more likely it is to include bits and pieces that are effectively reinvented wheels that surely, somebody else did on some unrelated project in a remarkably similar way. If you write a lot of the same bits of code over and over again (i.e. you are repeating yourself, a lot), you are probably doing something wrong. That's fine up to a point but once you get large groups of people writing the same software in the same way, it's just a matter of time before some of them start publishing bits and pieces as reusable libraries and sharing them in order to be faster to market. There's some simple darwinian principle here where those that reuse smarter tend to build more and cheaper.

Also, the economics of developing large codebases are somewhat funny. Testing and integration effort for example scales exponentially to the amount of change. Meaning that testing a 50K delta to a 5 MLOC system is way more expensive than testing 500 deltas of 100 lines of code to the same system. Owning code is a really expensive hobby.

This is also why it is relatively expensive to develop large code bases in house that reinvent a lot of wheels. You can trivially outcompete companies that do that with smaller code bases and smaller teams that depend on e.g. oss libraries that provide the common bits and pieces. Write less with fewer people and you cut down on that exponential cost. Reuse these days is about avoiding to write code altogether by reusing pre-existing stuff instead of reinventing stuff. Focus your R&D on the stuff that actually needs inventing.

This is why the likes of Whatsapp can create companies worth billions with less than 50 people. Most of what they did was reuse preexisting stuff in a clever way. I used to work for a company (Nokia) that arguably spent way more on R&D on remarkably similar projects (yes, multiple) while ultimately failing to get the job done. And they weren't the only ones.

Collapse
jgoodman751 profile image
jgoodman75

I feel the tweet by dev.to is misleading. It says "A rant about the false promises of reuse." I agree reuse can be hard, especially with different teams using and changing the same code. But in general reuse is a fantastic thing. Think of the opensource libraries you use. How much effort would it take to recreate something like log4j? Probably thousands of teams use this library yet they have no real issues.

The benefits of reuse often far outway the maintenance cost in my experience.

Collapse
jzhang300 profile image
James Zhang

As Robert has pointed out, 100% code reusability is not good when it hinders adaptability.

The real focus should be, how adaptable can I write this code, not necessarily how reusable can I write the code.

Committing to strict reusable code creates future risk in adapting to new requirements.

Collapse
lovis profile image
Lovis

👍
"Simplicity before generality. Use before reuse" by Kevlin Henney - 97things.oreilly.com/wiki/index.ph...