A lot of people will recommend reading great code -- well known open-source libraries etc. That's good, but one thing I think is useful is to read your dependencies. Then you can get a better picture of what "regular" code is like. Most popular libraries are not great to read because they are often very abstract, or they use so much helper code that it's hard to see what's actually going on. But fairly small librarie…
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.