The response for an “in case” is premature abstraction.
Unused abstraction makes reasoning about the codebase harder.
Unused abstraction makes reasoning about the codebase harder.
Meanwhile, if you can figure out small reasonable interfaces with potentially multiple implementers, then all the sudden things get a lot easier to deal with.
1. Engineering the generalized solution, then
2. Carrying the cognitive burden of this new indirection layer, and finally
3. Ripping out this premature -- and so likely wrong -- abstraction
Premature abstractions are like alcohol: fun borrowed from the future, and paid back later with interest. If unavoidable, choose the abstraction most narrowly scoped to your actual code base, not a future one. Humans suck at prediction. Ask me how I know.