In the course of development you will certainly come across code where you notice an abstraction can be made. Two code paths look so similar, there is a generalization to be made, the code can be more dry. So you make the abstraction because it feels good!
The problem often is you may not have considered the impact and coincidence of time. You may have based the decision to dry up the code solely on the fact that you can right now.
The real picture is that the components or units of code that are "wet" have been separate up to this one point in time, and perhaps only now, in this one moment, do they look similar enough that a clean abstraction can be made. However, the influences that have driven their "reasons to change" (S in SOLID) up to this point remain and will remain separate.
Had you not made this abstraction today, maybe two days from now, the units of code would appear so different you would never have considered abstracting them in the first place.
If you did go ahead with the abstraction, you are now forcing separate units of code to "reuse" some common "abstraction" even though they are begging to be separated again. Maybe they never had that much in common to begin with. This is because the "commoness" of code is not driven by syntax or a temporary coincidence of common requirements. Common code is determined by code which has the exact same reasons to change.
Now the question becomes, what is a "reason to change". I believe there is a common misconception about the "responsibility" of units of code. The common belief seems to be a unit of code should be responsible for one thing, it should do one thing well. While that is true, consider this, computers do what humans tell them and programs are created by humans (directly or indirectly). The only "reason" a program would change is because a person has new requirements for that unit of code. A unit of code's "reason to change" is not the details of its implementation, but rather the person, or group of people, that influence its scope of requirements. A unit of code should only be responsible "to" a single entity.
So, DRY up your code when you have multiple code paths doing similar things and they have the same reasons to change. If the units of code have the exact same reasons to change, it is much less likely they will want to diverge in their implementation in the next five minutes (or year). When you notice a common unit of code which used to have the same reason to change, now has multiple reasons to change, break it up until each piece has a single reason to change once again. Reasons to change come from people, not implementation details. So another way to look at this is, abstract common code when the requirements for those units of code are defined by one person (or group). Break code apart if you notice multiple people (or groups of people) have competing requirements for a shared unit of code.