DRY. Don’t Repeat Yourself. It’s a programmer’s mantra. And it’s a great
rule of thumb. In general we should work to avoid duplicate code, refactor
to functions, and maintain a single set of logic.
And I don’t want to argue against that – within a single codebase. If
you maintain and control all the code, you should strive to stay DRY.
The biggest way that this goes overboard is when people try to
overgeneralize across projects. Then we end up with tiny “utility” packages
for trivial functionality or sprawling frameworks.
It’s tempting to reach for one of these packages – at either end of the
spectrum. It saves a little code, and it’s just a go get away. But we
should pause and consider what happens when we go get a package.
First, are the license terms acceptable? Is it using a standard FOSS
license or is it something “weird” that you don’t really understand. If
you’re pulling this into a corporate codebase, you may need to get extra
special approval for “weird” licenses.
Is the package currently maintained? Is it active? Is it mature? Are there
dozens (or hundreds) of open issues? You need to try to predict if you’re
going to find bugs, and if so, if the maintainer is going to fix them – or
even accept patches.
Are the docs good? Is there an active tag on stack overflow for questions?
Other avenues to get answers if there’s any chance you’re going to have
trouble with the package?
Maybe the package is under-maintained. That might be ok … is the code
clear enough that you’d consider vendoring it and maintaining it yourself
(even just for your own use)?
Does the package expose you to any security risks? Will a critical bug in
the package cause you downtime? How are you going to monitor for new
releases – or at least for security fixes? Even without security fixes are
you going to plan to take upgrades periodically. (Upgrades aren’t
necessarily “free” – there may be API or behavior changes that affect your
Another class of risks is an over-dependence on a framework. This can be
true even if the framework is your own!
I have done it to myself and I have seen it at multiple employers. A
pattern emerges across projects, and then that pattern is refactored into a
library that is used by all of those projects. Future projects come along,
and they are a little different but you contort the project, or add some
options to the library, or (likely) both.
Over time – sometimes even very rapidly – this reduces the quality of the
projects, or of the library, or (likely) both. When you’re lucky, this
happens right away – you realize during refactoring that project A and B
are not actually that similar and the pattern only exists in spirit. A few
hours (days?) of work is lost but the integrity of the projects are
So it’s important to realize: if there is some code that you need to copy
from an existing project, IT IS OK if you copy it! It’s also ok if you
feel bad about copying it. That small bit of shame and doubt that you
experience will keep you honest for all the times that you really should
Don’t get me wrong. I use plenty of other packages in my projects. But I
try to make a conscious decision about what I’m pulling in, and the quality
and risks of that dependency versus the quality, time, and risk of doing it
On Friday we’ll look at how to add pagination to our app with Gin.
I saw this Go blog post shortly after I drafted this article, but it
wasn’t coincidental. Both were likely inspired by the latest in a series
of npm supply chain incidents. The title of this article was loosely
inspired by the same Go proverb mentioned in that blog post: “a little
copying is better than a little