In pondering "systems that went wrong", I've noticed certain patterns in how they go wrong and patterns in the symptoms. I'll propose a UsefulLie dichotomy between idealistic messes and "lazy" messes.
Idealistic, GoldPlating, and MentalMasturbation messes:
Difficult to figure out what any piece of code does
Difficult to trace the impact of a change due to too many layers of indirection
Wrong abstraction used, resulting in big DiscontinuitySpikes. Some changes that fit the abstractions are quite easy, others are nearly impossible.
Unlike lazy messes, you spend more time studying code than typing code to fix it.
Inconsistent use of different paradigms or techniques.
Lots of wasted code for dead-end or unfinished concepts.
Lot's of violation of OnceAndOnlyOnce, so prepare to type a lot to change or fix.
Generally a consistent pattern
Lots of code to do relatively little
Lots of similar-looking IF statements or viney, repetitious sub-classing for endless exceptions to the rule.