One big reason for this is because we're often wrong about what problems we'll have in the future, or in what way they will manifest. Moreover, often the "bad" solution will work for far longer than we expect, and the day that we're anticipating where we'll be having problem X might never even come.
What's worse is that in the meantime each layer of abstraction adds a tax to how easy it is to fully understand and work with the code, to change things and add new things.
What you do want to do is to write code that is /open to/ being abstracted. E.g. keep things structured nicely, start with a basic function (named similarly) or a few related functions before putting in a full blown class, name things well so it's easy to find them while refactoring, etc.