It is extremely rare to write code to solve a problem and be done with it. Problems are often half formed and coding at any point in time reflects your understanding of the problem at that time. Often you should move from complexity to simplicity in the way you solve a problem. The initial set of ideas to solve a problem most likely will be complex. The code you write will look complex. It will have data models that are hard to remember and connect in your brain. You will struggle every time to fix a bug.
The sign of using a debugger to fix a bug tracing through reams of routines is an indication of the complex answer you have given to a problem. If you have thought through a simplistic model, your brain can hold it. But it is difficult to arrive at a simple model when you are exploring a problem space. The reason is your brain is not yet familiar with the new landscape, the new symbols, the new lingo, the new data model, connections, and it is a struggle to fix things in that mess.
That is when you rethink your strategy. You have to have a simplistic path way to the solution. You rethink the concepts that you have formed. When the concepts that make the solution become clear as to what they are , why they are there, their functions and their limitations, their relations between one another, that is the time to recode. Throwing away large chunks of code and rewriting that in a way your brain can easily relate to is a great relief and saves a lot of time later. You can build on it more easily than working over complex piece of code.
Often you start with some simpler models about the problem but end up drifting into complexity adding more and more functions, overloading a class with lot more functionality, being more procedural to solve everything, than constructing simpler building blocks and clearly identifiable functions with each of them. This happens with time pressures, laziness to rewrite parts and the zeal to see the output.
Coding is a continuous process of going from complexity to simplicity in your mental model about the problem. You should not worry about rewriting whenever you sense fatigue with your current code. There is always a simpler and lesser way to solve a problem and you should strive to reach that point.
In this context, being object oriented helps. Reusing and extending on functionality to build a higher order thing is a great help. This should again be considered only to represent your mental model of the concepts rather than simply declaring everything as a class to conform to OO.
If you have clearly organized your concepts in your head, then you will divide up your code based on that. If you have not done that homework, then it is better to just sit with pen and paper and work on getting that mental model right. The mental flow of what the problem is and what the concepts are to solve that problem, eliminate the unwanted pieces, have the absolutely necessary pieces.
Only when you are convinced about the understanding of the problem and the models that can represent it adequately you should sit to code. Otherwise, you will end up writing a lot of code, and in your enthusiasm to follow best practices like modularity you will end up having a lot more wrong divisions of code making it a mess.