Warning, the following post is heavily opinion based, but I feel this can morever so help a beginner from engaging in some very bad practices (and, you know, these opinions where formed through my own practice).
I would suggest using a "manager" or "controller": Essentially, a singleton (an object you instantiate only once) that will handle all of the operations that are relevant to all of your bullets. While these actions will still be governed by the bullet themselves, the logic will feel more intuitive, and the performance will be much better as well.
While I personally would say that something like a bullet-manager is reasonable, specially for a beginner project, there is NO reason ever for it to be a singleton. Does he need access to the bullet manager throughout his entire game? Probably not. Should there every be only one bullett manager? To be fair, he might probably only ever need one, but that does not mean that instantiating a second one hurts, and the unnecessary global access kills it all. I just had to write this, because not only is singleton the one pattern that gets told to each and every beginner that there is (seriously, name one person that did not come across it as one of their first patterns they heard of). Also its just misused almost always, like in this case. Specially for someone who quote unquote states that he "hates" his own code, won't lead to any good. So, don't do singleton, never ever, this will help in keeping your code at least halfway clean.
Keep it simple
If you need a feature once, write it the simplest way possible. If it turns out that you need that feature over and over, only then should you refactor it into a generic solution.
I also got a slight problem with this, because out of my own experience, beginners code faults doesn't really come from overengineering. I can probably only speak for myself beacuse thats where I've seen it, but my first code didn't suck because I tried to add too many things or wanted to be clever by designing it in all weird ways, but because I simply didn't know how to write good code. So K.I.S.S. is probably rather a thing to recommend to an intermediate, if a beginner tries to account for it, it might even reduce in worse code, because that beginner might be thinking to himself: "Am I overcomplicating it by making a seperate class for it? Isn't it overkill to add this as a private method instead of just granting public global access?".
As for some direct advice for the OP. Partice, by trial and error. Dont' be afraid to refactor, as others have said, and also don't be afraid to start over. Once you've gotten the hang of programming per se, also don't be afraid to try out different kind of coding styles and patterns. You are not part of some game company and therefore not under any pressure or deadline whatsoever. As long as you work alone, its a safe playfield for you to test whathever you want, and see what works, and what doesn't. Always have a straight goal in mind you are working on - e.g. "I want to get enemy patroling going", and design your code around that goal. Also, if you have any specific questions about your code design, feel free to ask them here on the forums, there is enough people to be willing to help you.