One of the major purposes of software design is to avoid making mistakes. You design your software so you don’t get halfway into the project and say “Oh yeah I didn’t think about that” and have to start over again or continue with a weak foundation. Unfortunatley don’t know exatly what type of mistakes you are likely to make until after you start coding. Since you don’t really know what the real problems are until after you encounter them, you are left with two options. First you can create your design to eliminate problems that you’ve experienced in other project. Second you can build a prototype to get an idea of what will be a problem then design and code the final system.
Trying to plan ahead and eliminate problems before they occur sounds like a great idea, but it often increases the complexity of the project. This isn’t a bad thing if the increased complexity solves real problems, but since you are trying to solve “imagined” problems before they actually occur, some won’t turn out to be problems at all. This means that that software is more complex than necessary.