We strive to create designs that will last. But in doing so, we run the risk of over-engineering: building in so many abstractions at the beginning of a project that it degenerates into unmaintainable code.
What causes these risks, and what can we do about it? If there were a simple answer, everyone would be doing it already. Instead, we have to make do with a few heuristics, practices, and insights into human nature.