Senior devs will give me feedback around “can we make this more generic/flexible/extensible in case we need to do X in the future”
But I lean more towards YAGNI
I would rather keep it simple/dumb/readable until we actually need the extra functionality, then refactor at that point
But I admit it’s hard to find a balance
Separating out business logic by making code more generic _is_ basic good practice.
There doesn't need to be a high cost once you start to do this by default, and it leaves doors open for future changes.
My general feeling is to 'leave doors open' (or allow for flexibility) if the cost of doing so is minimal.
Simple / dumb / readable is something you can achieve no matter which route you take. Comment your code. Be more verbose if it helps legibility and necessary performance won't be impacted.
Fundamentally, the only certain thing is that change _will_ be required at some point. And unfortunately, the decision as to whether something will be needed in the future is rarely something a developer has a say in.
All you can do it make your future dev life easier by leaving doors open, not closed.
These days I try to get our junior devs to think of these comments as ETC comments, as the comment was made from an et cetera point of view, but they need to think of it from an Easier To Change point of view. The X they're asking about isn't a concrete requirement, it's just one of many possible future requirements. Putting effort into tackling X is a waste of time at this stage, but putting our code in a place where we could easily implement X, Y and/or Z will usually turn out to be time well spent (as the chances that some of them will be a requirement in the future, we just don't which ones).
In my experience trying to write an abstraction from only one instance of the concept in your code is a bad idea, you need at least two instances of the pattern you're trying to abstract to know what's the abstraction and what should be part of the instantiation.
Instead of falling into the trap of abstracting early, you'll be better off keeping your functions limited to doing "just one thing". That way, when you're asked "what if we need to do X in the future", you can reply with "we should be able to easily replace this function with an instance of whatever abstractions will work best for implementing X, Y or Z"
99% of the time YAGNI