Many software developers would say that designing a software system is like designing a building. You have to decide where the support beams go, where the plumbing runs and how the wiring works. I believe, though, that designing software is much more like teaching somebody to speak your language when you don't know theirs. You need to start with primitive concepts and teach them the words for those. From there, you have to build up their vocabulary using words they already know. In a software system, the methods that already exist in the system are the vocabulary you start with. To build up the vocabulary, you define new methods. Then you find that if you have the right vocabulary, the way to express the solution to your problem is trivial. If you have a hard time expressing the solution, though, it's likely that you don't have enough vocabulary.
Download