This blog post has some genuinely good advice:

Every line of code written comes at a price: maintenance. To avoid paying for a lot of code, we build reusable software. The problem with code re-use is that it gets in the way of changing your mind later on.

We’re always super eager to DRY up our code. The truth is, not all code needs to be DRY. I think in my career I’ve developed a few different philosophies for how I interact with a codebase depending on the situation that I’m in.

I think the separation between library and concrete application and the separation between long-lived and frequently-changing code are the two most impactful in my engineering style.

If I’m writing a library I’m going to be aggressive about providing consumers of the library levers to pull to make it do what they want. If I’m writing an application, I’d prefer to repeat some code or a pattern a few times before promoting it to an abstraction of its own.

If I’m writing long-lived code, I’d prefer to sit and think it through intentionally. Choose good names, think about the relationships between the moving parts. If I’m writing something that’s probably going to change next week I (for better or worse) will likely concern myself less with those things.

That’s kind of the tradeoff I think. It’s inevitable, right? Either way, this article was thought provoking for me about how I write code. Hopefully it’ll do the same for you.