I've worked with beginning programmers before and one of the characteristics I see with the most struggling ones is that they have a tendency to repeatedly make small, almost random changes to code and run it until they get something which seems to work. Their code looks like a mess and almost always fails edge cases - when questioned on the behaviour of their solution on such, they often have no idea what it'll do, and only vaguely understand the code they wrote. I wonder if this is an example of them using the "fast thinking" path almost exclusively.
I've had success with forcing them to use pencil and paper, or a whiteboard, to design their algorithm and writing the code, before ever touching a computer to test it. This is a way to force them into the "slow thinking" mode, because there is no immediate feedback and they'll have to think more carefully about it. Put them in front of an IDE, however, and they just get tempted into writing code without thinking much about what it's doing.
Perhaps I'm just begging to be flamed, but I've noticed this quite a bit with TDD. It's easy to write a test case, jiggle around the code until it works, and then call it "ready".
In an ideal world, the jiggling around would be followed by a review of the relevant codebase and a good refactoring, but this step is pretty universally missed in my experience. Additionally, the thinking should be occurring in the "build the tests" phase, but it's not. Or rather, only the "happy path" tests are built; the corner cases and error cases are missed or outright skipped.
I noticed this in myself first, and slowing down has definitely helped. As has spelling out the test cases before touching any code.
I've hit this. Usually it's because I originally thought about it, created a generic solution to my understanding of the code/domain, hit an edge case, tweak it to handle that edge case, hit another edge case/break a test, tweak it to handle both that and the original, repeat.
I think everyone hits this; to avoid it you have to have a perfect understanding of the domain a priori. The difference I see now, compared to when I was starting out, is I recognize I'm doing it more quickly. Once I do, I will re-examine the domain from the perspective of "it includes all these edge cases", and generate a new abstraction that encompasses more (hopefully all) of them.
I've had success with forcing them to use pencil and paper, or a whiteboard, to design their algorithm and writing the code, before ever touching a computer to test it. This is a way to force them into the "slow thinking" mode, because there is no immediate feedback and they'll have to think more carefully about it. Put them in front of an IDE, however, and they just get tempted into writing code without thinking much about what it's doing.