I still practice DRY, but I try to not overdo it with unnecessary abstractions. More recently I've been practicing SPOT (Single Point of Truth). I interpret this in two ways. One, every piece of data should have a location that reigns over all others. It's okay to have duplicates of the data, such as caches, but any copies of that data should be treated as ephemeral and possibly inconsistent with the source of truth. Second, there is some overlap with DRY where some logic that answers a question or computes a result should not be duplicates. A specific function or class which computes something important, should probably not be duplicates, but implemented once and reused. A great example is authentication, you most likely should not duplicate code that checks whether a user is authorized to do something. In a sense, the code which computes whether a user is authorized in itself becomes a "source of truth".
There are still good reasons to DRY early on. Actions that need to be performed synchronously, rather than acquiring the same lock in several places, consolidate your code so you're so there's at most a few places you acquire and release that lock. Cache invalidation, having a single class for reading and writing some piece of data makes it much easier to keep the cache consistent.
Yup, I very much favor SPOT. SPOT often means you must not repeat yourself, but abstraction isn't always the answer.
Look at my comment upthread where I attack this differently. We have a truth: Date is in the future. That should have a single point of truth--a function that checks if the date is in the future. Perhaps one with a boolean return (if you're in a position to handle it) and a wrapper that throws if the check fails (if you're not.) Pull out that truth even if you have separate code paths for the two things.
There are still good reasons to DRY early on. Actions that need to be performed synchronously, rather than acquiring the same lock in several places, consolidate your code so you're so there's at most a few places you acquire and release that lock. Cache invalidation, having a single class for reading and writing some piece of data makes it much easier to keep the cache consistent.