Fairly broad question! There are many ways to do it, more and more complex when you go to the professionnal side (UML). I can tell you i do (or try to do) it:
Draw your Data structure and Processing Blocs : identifying them is a key point: put your data in a class with simple and clear elements. Draw you data structure on a paper with lines indicating relationships with methods (processing blocks). Check again if you haven’t forgotten any bloc or line. At that point your drawing should look like an inextricable mesh (don’t be scared that’s normal!). Redo the drawing trying to make it look nice and ordered, with minimum line crossing. If you can’t do it, then that’s what your code is: inextricable! No wonder why you loose track… Try to re-organize your blocs on paper until it looks clear, add new blocs or functional lines if needed to make it clear. And once you’re happy with it, recode it! Having the map of your code on a paper drawing allows you to remove it from you brain, leaving room to focus on details, one by one.
Example: I’ve worked on this planet simulator and i got completely lost because it was so complex i was unable to do any addition or changes at some point. I have recoded completely 3 times the projec, each time simplifying, ordering to make it easier, but each time not satisfied. Now i am in the 4rth recoding… As an example, here is my 1rst drawing on the left (i use bamboo,paper app, free and easy to draw) and the 5th version of drawing on the right (at some point i switch to graphio light free app, because is is easier to reuse the previous version than with bamboo). I have not writen code between these 5 drawings, just re-done drawings. Once i was happy with the final drawing, the recoding was easy and pleasant, because i could avoid to keep everything together in my head, and concentrate on each bloc individually.

Compactness try to make ‘compact’ classes, i mean with minimum interractions between classes: that’s the interractions that become so complex that you can’t view them all at once and you don’t understand anymore what your program is doing. Group your functions in one class by functionnalities, in such a way that you can work on this bloc without impacting the other blocs: this is a key point for easy maintenance/improvement in your code.
Top-Bottom Bloc organization divide your code in small functions that are smaller than 1 page, so can view it all at once. Make sure you can write down what this bloc is doing, and do it, at the beginning of the bloc. If the description is too long, split it in two simpler blocs. In one bloc call subfunctions that do simple things, with same rules.
unit tests Test each of your blocs. It is easy to do with dependancies: create a project for your new class, create a tab for this class. In the main tab, write a few simple functions that proove you by printing their input+output that the class methods work as expected, and the class data are correctly filled. When you’ll call this project as a dependancy in your main project, the main tab will not be loaded, so you will not be bothered by it. Oh, and i forgot that one: write and run your test function each time you finish one function, not all at the end, cause then you won’t do it!
If you follow these guidelines you can probably multiply by 10 the number of code lines you’ll be able to manage(at least that works for me). Beyond that you’ll need to read books about programming methods.