I had the opposite experience; I found it easy to scan through comments explaining what the code does, and hard to read the code itself. So I would comment every single thing to explain it in English so that I didn't have to resort to code. Of course I could drop into code mode and rely on logical axioms and learned patterns, but it wasn't as intellectually satisfying as "getting it" with pure intuition.
Something similar still serves me well as a general mental framework for approaching programming and debugging at a very local (procedure) level:
1. Make sure that the English language description of the algorithm is logically correct.
2. Make sure the code actually corresponds to the English description.
You can take this a little further by separating your comments into two groups:
1. An english language description of what the function (or code block) does as a black box (forget the internals as they are subject to change). What you put in and what you get out, or section headings to structure how you read the code.
2. Comments in the code block to tell you why a given decision was made.
What this gives you is the framework you are describing but it further cements it into three layers:
1. Function and block documentation describe contract and what the code is expected to do from outside. If the code does not implement the contract the code is wrong.
2. When reading through the code as contract-implementation you can understand why certain decisions were made.
Something similar still serves me well as a general mental framework for approaching programming and debugging at a very local (procedure) level:
1. Make sure that the English language description of the algorithm is logically correct.
2. Make sure the code actually corresponds to the English description.