You have to “solve” the problem once to define it clearly and then solve it again to create a solution that works.
The finished software design should look well organized and clean, but the process used to develop the design isn’t nearly as tidy as the end result. Design is a sloppy process. You take many false steps and make many mistakes while designing software.
The purpose of design is to identify the mistakes early. It’s cheaper to find mistakes during the design phase and correct them than correct implemented code.
At the same time, until your software fails in production, you don’t really know the true requirements. So it’s a delicate balance of upfront design vs. on-demand design.
An ideal program runs instantly, takes zero storage, uses zero network bandwidth, doesn’t have any errors, and costs nothing. In the real world, there are trade-offs. A good design should try to find a balance among various competing factors.
A good design emerges from the iterative process of thinking about the program, writing the program, and rewriting it.