One thing also needs to be mentioned, is that supportability of features also needs to be something that has to be addressed early on. The unintended consequence of continuing to support every single combination of every single option makes your support matrix, as well as your QA effort, enormous, and your code incredible unmaintainable.<p>I work at a company where they have a 5 year old product, and the mentality at the time was "Yes I know it doesn't make sense but if the user does X, then it could cause the server to crash, so let's do Y." This grew to a series of matrices that has now turned the act of adding 1 single feature into a 3 pages worth of "If A then B, otherwise C". This has made the QA effort in terms of testing incredibly complex, and even developers get confused as to what is supported and what isn't.<p>For example, there is an instance where copying a directory takes a different code path than copying a single file. Why? Because they wanted to "special case" this situation. It makes the functionality and behavior utterly unpredictable.<p>The takeaway that comes with experience is don't spend too much time trying to prevent your users from doing stupid things. If they want to do stupid things and the system crashes, it's okay to say "Don't do it, otherwise it will crash." This keeps your feature set, your code, and your QA effort much cleaner and more maintainable over the long haul.