I've noticed my programming knowledge increases by breaking down and reconstructing my model. A period occurs where I feel stupid and incompetent for a while just before I gain a new understanding or perspective on the field. Typically these last a few days.
Without a doubt, the largest such jump occurred when I learned Haskell. For a time, Haskell programming and day-to-day programming took up separate areas of my brain; almost like I was learning a new musical instrument of something. But then, after I had spent about 4 months with Haskell, it started to leak into my everyday programming practice. I was incompetent for at least a month, probably more like three.
But after it settled and I regained my ability to program in imperative languages, I had a new, remarkably clearer understanding of almost everything. Because Haskell forced me to be explicit about all my inputs and outputs, I suddenly saw software engineering in crystal clear terms of the strengthening and weakening of assumptions. It has slightly improved my skill to evaluate good and bad designs, but the most noticeable effect is that I can identify a lot more cases of when two designs are "essentially the same", I.e. when we're just bikeshedding.
There was a meta-lesson in the experience too, which was incredibly valuable. That is that my brain is malleable, and I may need to train it to get to the best design. The way I picture my library being used may not actually be the best way, and playing tricks to get the interface I picture may be hurting me and my users in the long run -- I should be busy trying to understand my problem domain so I can change my picture of the interface until its usage and implementation are both obvious.
If that makes sense...