I've mostly learned programming by building projects, making mistakes, and trying to improve the next one. That has helped, but I'm wondering what else I should be doing to develop better coding habits. Would reading open-source projects, getting code reviews, or contributing to collaborative projects be useful?
I often work on projects involving a new language or framework, so I'm learning the technology while also tackling something complex. I'm especially interested in understanding how things work under the hood, which sometimes becomes an excuse for letting the code stay messy. I also struggle to know what parts of a project to show someone for feedback, or how to break the code into useful sections when it lacks context.
I've recently been building an operating system, but I've barely read other people's code and now feel unqualified to contribute to larger projects. Part of me worries that reading code or working on smaller projects would take time away from learning concepts, although I'm starting to wonder whether focusing exclusively on one huge project is limiting my growth.
This was also prompted by someone saying my code was bad but not explaining what I should improve. I know my code is not perfect, but I'd like to find constructive ways to evaluate it and become better at writing clear, maintainable software.
5 Answers
Reading other people’s code is not wasted time, but read it actively rather than treating it as something to imitate blindly. Ask what problem each abstraction solves, whether the names make the intent obvious, and how the design could be changed safely. A book about coding practices can provide vocabulary and examples, but treat its advice as a set of ideas rather than strict laws. Combine that reading with real projects, testing, and reviews so it does not become purely theoretical.
There is no single definition of clean code, and you usually discover better patterns by writing something, revisiting it, and rewriting it. Keep older versions of your projects and look at them months later; code that once seemed obvious may become difficult to follow. That experience teaches you to prefer straightforward structure, useful names, and fewer clever shortcuts. Don’t wait until you feel qualified before sharing code or making small contributions—feedback is part of becoming qualified.
Regular peer review can help a lot, especially when you have to explain your decisions out loud. Defending why a function is structured a certain way or why you chose an abstraction makes the reasoning stick, and other people can point out assumptions you missed. Reading open-source code is useful too, but remember that you usually see the finished result without the history behind those decisions. Look for study groups, programming partners, or projects where constructive review is part of the process.
That sounds useful because it would teach me not just what to change, but why the change is better. I also think regular feedback would help me become less personally affected when someone criticizes my code.
Try to make your learning loop smaller. Instead of waiting for a giant operating-system project to be finished, build a few small programs or isolated components and ask for feedback on a focused question. For example, ask whether a module has a clear responsibility, whether the API is easy to use, or whether the tests are sufficient. Specific questions produce much more useful reviews than asking whether the entire project is good or bad.
Writing tests is a practical way to reveal design problems. Code that is difficult to test is often too tightly coupled or doing too much at once. Start with small functions, clear names, consistent formatting, and tests that describe the behavior you actually want. Also, criticism without any explanation is not very useful, so don’t treat an unsupported comment as a complete assessment of your ability.
I hadn’t thought of testing that way, but it makes sense. I need to spend more time writing tests and seeing what they reveal about the structure of my code.

I agree that clean code is more of a scale than a fixed category. There are also patterns and library features I simply wouldn’t think of on my own, so I should probably expose myself to more examples instead of relying only on personal trial and error.