I'm self taught and have the same problem. My solution was and is to keep reading. I rarely do exercises and I can't bring myself to code to no end, because of
opportunity costs, I've done some stuff here and there as I needed (scripting mostly) and just kept reading. Read textbooks, OS stuff, computer architecture, algorithms and math. The problem is that the stuff I need has been done and is at my fingertips, and though I could re-invent a wheel or re-implement a library, I learn well through reading books, and books open up new vistas and raise my ceiling. I've always thought, that when the time comes, I'll have a good enough background to go deeply into what ever I'm being paid to do.
If you are looking do it for a living, this method can if fact work. I didn't know that until recently.
I had been working in app support when started learning this stuff, after a couple of years I got access to the code base and would read it to solve bugs that hit the help desk or answer obscure questions about how things worked when we got them, at some point I felt confident to ask for some write access and a mandate to spend time working on stuff. It took a long time to get that but at some point it happened and now, guess what, I am professional programmer. I am still reading though. Now I see that the lack of practice didn't hurt me at all. Sure I had look up syntax, but the IDE either writes or reviews all that stuff for you and unless you are thick it seeps in after a while.
Learning by doing is critical but if you only learn by doing you will end up learning very little (unless you have much more time than I do). You'll get the practice when you'll need it and you'll get good quickly if you have the right background.
so if my experience speaks to anyone out there, try to get a job in support, a stones throw away from the development. As soon as you can read code, try to get read access to the code base. When you are comfortable, agitate appropriately for some write responsibilities in down time, even for no extra pay.