I have three posts on Variables, Functions, and Classes if it interests you. In these posts, I talk about using the context and content of the code to create solid names. Going through the exercise of naming and re-naming code as it evolves is the foundation of self documenting code.
Docunent anything that you would need to retain if you were to attempt a rewrite. That is, if the structure of the code changes, what would need to stay the same for the application to be successful?
For a CRUD application, this means documenting individual validation and transformation rules. For a game, this might mean the list of actions a player can make.
Let namespacing take care of the fact that a module is a sub-module of a parent. Dependencies should not have to be explicitly called out to achieve self documenting code.
Complex operations are better documented and reimagined than not documented and rediscovered. Deadlines and incomplete domain understanding sometimes means that it's better to write a comment about what the code is supposed to represent, rather than leaving the comment off and letting the code misrepresent itself.
Don't be scared of writing comments. Be aware that when you run across a comment, it may be a candidate for refactoring.
- Name code appropriately
- Document the right stuff
- Use comments when the circumstance calls for it