There are certainly multiple ways to design a software system. Some designs are better than others, and some may be equally good. Also, software systems grow and evolve, meaning that a design that is good today may not be so good tomorrow, when a new feature must be added.
Nevertheless there are tried and tested principles and practices that help you to figure out how to decompose your problem into classes, objects, algorithms, patterns, etc. Remember, writing software is an iterative process, just like writing a book. You never get it right on the first try. Instead, you start with a rough draft, and keep refining it. The two main concepts are cohesion and coupling. You want your modules to have high cohesion, epitomized by the single responsibility principle, and low coupling. You also want your design to make sense to other people, so that it can be easily understood, implemented, or augmented.
One good approach is to draw a high-level diagram of your system, e. g. using UML. If it looks like a mess, or if parts of it do not make sense, you probably want to refactor. It may also help to explain your system to somebody else. First, you will likely see design flaws yourself as you talk. Second if other people find your design hard to follow, you should probably fix it. Another way is to explain your design in writing. Then read it. Does it make sense to you? Then give it to other people to read. Does it make sense to them?
Designing software does get easier with experience. You develop a sense for code smells, which point you to potential design flaws. However, even if you have been writing code for decades, it is still a good idea to explain your designs to other people and see if they can follow your code.
To be more concrete, I highly recommend the following two books: Clean Code by Robert C. Martin, and Refactoring by Martin Fowler.
subjective