The thing that has seemed to have the most effect for me (of course, this may not necessarily be effective for everyone) is refactoring or even completely rewriting my side projects after/near finishing them. It's a little bit maddening, since I would rather move forward and build new features or start a new project, but the exercise is really helpful. It forces me to take a step back, look at everything I've done, and figure out where I could have done something better. Then, hopefully at least, when I'm in a similar spot in the future I'll be able to think ahead better. In fact, "thinking ahead" might be the most valuable skill for a programmer to have, and I don't really see how reading code can help with that. All of their design decisions have been made by the time you read the code, and it's really difficult, especially for a junior developer, to actually consider how and why those decisions were made.