
Imagine you just got a request at work to add a new feature to the codebase - nothing too big. Just doing what you need to do would be easy enough, but you've seen something like this before. You recognize the patterns, and you just know (but not for sure) what'll be asked next, so to save yourself time later you decide to future-proof your code. In other words, you over-engineer the current solution in anticipation of what'll be asked down the road. Your future self (and your team's) will thank you.
Maybe. Maybe not.
I'd include "future-proofing" in a list of top phrases that make me cringe as a developer. It's natural, especially as you gain experience, to see a few steps ahead. This leads to a tendency to over-engineer solutions, creating mini-frameworks or adding just one more layer of abstraction, in order to make things easier later. Avoid that tendency any earlier than necessary.
Future-proofing can easily end up with painting yourself into a corner, because the actual future requirements will almost certainly be different than what you expected. Business goals change, time marches on, and today's code quickly becomes tomorrow's technical debt. Instead of a simple piece of code to expand upon someday, you're likely to end up with an elaborate piece of code to refactor.
I don't mean that you should never think ahead! If your next project actually is designing a new architecture or creating a framework, you certainly want to think about which technologies to use, how to lay it all out, etc. But in my personal experience, that's the exception and not the norm.
Let patterns emerge naturally instead of guessing what the future will bring, and deal with them as they do. When you see two or three similar bits of code, that's the time to refactor them into something more elegant. Perhaps the patterns that emerge will be exactly what you expected... but if they're not, you'll have a better idea how to tackle them when the time is right.