It's hard to tell without looking at your code, but I suspect that you are stumbling in to a wall that many do. What's in your favour is that you recognise it, so you will probably be able to do something about it.

Systems grow over time. At the beginning, they are simple, which means that they are forgiving. If you make a mistake, it is easy to see and correct. As the software grows, it gets progressively more complex. Problems hide for a long time and when they present themselves it is often very difficult to see the actual problem.

What I'd like to do is challenge you to look at it a bit differently. Think about the number of lines of code in the OS, system libraries, language, libraries, frameworks, etc that actually go into your code. Even if you only write 2 lines of code, there are probably hundreds of thousands of lines that your 2 lines are sitting on top of. Why are your 2 lines easy to understand?

Obviously because there is a great separation between the complexity of the underlying systems and your code. What you need to be able to do is to provide that same separation in your own code.

As you mentioned that you don't work with others, I will recommend some other approaches. However, if they don't work, I recommend that you change to an office job where you can get the mentorship you require before you leave the field altogether. 15 years is a lot of learning to give up.

#1: Read good code. One of the biggest problems that programmers have is that they rely on their own code for examples of "good code". You are at a huge advantage because you recognise that you need to improve your code. What should you be reading? Read library code from whatever libraries you are using. As you are doing "web development", I would advise you to shy away from reading the source code of frameworks like Rails, but rather read the underlying class libraries for the languages you use. If you are not using languages that are open source, then it will make your life much more difficult, but try your best to find open source and free software on the internet to study.

#2. TDD. Every time. All the time. Not BDD (although BDD is an excellent practice in its own right). You want to do TDD. This will force you to think about your interfaces and to decompose. There are many books about TDD. Some of them are good and some of them are bad. Read Test Driven Development: By Example by Kent Beck. It is probably not the best book on TDD, but it will give you the basics without confusing you.

If you are working with legacy systems and don't know how to TDD with those legacy systems, read: Working Effectively With Legacy Code by Michael Feathers. It is a very, very difficult book. Learn it all.

You may hate TDD. Many people do, but using it will make you a better programmer. Personally, I don't think it's bad if you abandon it eventually, but master it before you do. This will simplify the process for you and break it down so that you can consider things in more manageable pieces. It will move you away from "Just Works" because it is god awfully slow (or at least it feels that way). Just pay attention to the effect it has on your code.

From where you seem to be now, to where you want to be, I estimate you've got 2-5 years of effort. Don't get discouraged if it doesn't come right away. This is a discipline where you can get orders of magnitude better over time. Try to be as patient as possible.

I hope this helps.