Per me mi piace l'approccio che Kent Beck propone in XP (non è sicuro che sia la "sua" idea o quella di qualcun altro ma è lì che l'ho sentito per la prima volta):
È abbastanza difficile risolvere i problemi di oggi senza cercare di capire quali sono i problemi di domani e risolverli.
Gli sviluppatori possono dedicare molto tempo a soluzioni per requisiti che non esistono, casi limite che non si verificheranno mai o anche problemi reali in cui l'impatto del problema è significativamente inferiore al costo di impedirlo.
Questo è il tempo che potrebbe essere messo in cose che gli utenti vorranno e utilizzeranno veramente, cose che daranno loro benefici che supereranno in maniera massiccia anche i disagi che saranno causati nell'improbabile caso in cui una di queste cose avvenga realmente.
Al di là anche di questo risultato non ottimale per l'utente, l'impatto sullo sviluppatore dell'over engineering in questo modo tende ad essere un codice complesso che è più difficile da supportare e più difficile da migliorare.
Quindi per me se sai, o puoi essere abbastanza sicuro, che qualcosa è un requisito o che causerà un problema, allora indirizzalo, altrimenti non farlo.
Potrebbe essere necessario tornare indietro e rielaborarlo quando si scopre che c'era un requisito più ampio rispetto a quello originariamente implementato, ma in generale lo sforzo totale inserito nel progetto sarà comunque inferiore perché nella maggior parte dei casi ciò non accadere.