Writing clean code is a skill that you never stop developing, and your approach will change over time. One year, you'll feel good about your code, the next you might hate it. Just like any art.
I'd split the areas that matter for both clean code and clean docs in three categories:
Organization — How you name things, where you put things, how you structure your code, etc. Everything should have a logical purpose and not be overburdened with other responsibilities.
Presentation — How you style your code, how consistent you are, and whether you're following existing style guidelines that may be applicable (for instance, if you're writing Python, you probably should be striving to look like most PEP-8-compliant code — https://www.python.org/dev/peps/pep-0008/).
Communication — How do you communicate what your code is doing to others or to your future self? You should be able to hand your code to someone new and they should be able to follow along. This has elements of a. and b., and also involves documenting your code and documenting it well.
Make sure code is readable, not just writable. Don't be too clever. If there's an obviously-readable version of code and a "you have to get the trick" version of code, choose the former.
When you're in the body of a function, think of blocks of code like paragraphs. What is this paragraph of code doing? If you have two loops back-to-back, are they part of the same paragraph, or different ones? This can help you to figure out where to, say, separate things out with blank lines, and where you might want to add comments to document that paragraph.
Document your code. Don't repeat what the code itself is saying (you should let your code speak for itself), but explain the details, the why, the how. You may have a loop that's calculating a score based on items in an inventory, with some conditional in there. That'd be a good place to put a comment describing, at a higher-level, what you're doing.
As above, thinking in paragraphs can help you to figure out where comments can do the most good.
You also may want to think of your comments in terms of summaries vs. descriptions, depending on what you'r documenting.
A good method here is, describe the code out-loud to somebody, or to something (a rubber duck is a common approach). If the code is so obvious that you're effectively just repeating the line of code in your explanation, don't bother. If, however, by saying it out-loud you're able to convey the intent of the code better than the code itself does, you're probably best putting that in a comment.
You should aim to comment:
1. Classes — Describe the purpose of the class, what it's responsible for — make this a contract, so if the class's description is starting to sound like a jack-of-all-trades, you may want to consider your organization/architecture of that code.
2. Functions — Describe the purpose of the function (a good approach is a very short summary and a more detailed description), the arguments it takes in, the results you can expect (return values, exceptions that can be raised).
3. "Paragraphs" of code.
4. As your code grows, modules of code, to give high-level descriptions, point people in the right direction.
In Python, you have comments, but you also have "docstrings" which are used for the class, function, and module-level docs. There is no standard for how to structure these. For my Review Board product, though, we've developed a standard we use that works *very* well: [Writing Codebase Documentation](<https://reviewboard.notion.site/Writing-Codebase-Documentation-e16312b5f061437cb73cbfa369ac3cb5>).
A classic example in Python is an if
statement checking for truthiness (for values other than booleans). For example, if you have an object, and you want to check if it's None
or not None
, it's common to want to do:
```python
if obj:
...
```
Instead of:
```python
if obj is not None:
...
```
Seems to make sense. If it's `None`, it's considered `False`. *However*, in Python, objects can define how they evaluate to true/false, so your implicit check might not behave the way you expect for some type of value. It's better to explicitly check for what you're expecting. Not only will you avoid unexpected behavior, but you'll do a better job of communicating your intent to others on the code.
I think a good base approach is to have smaller bits of code that do one thing than larger blocks that do many things. Again, this can be aided through documentation. If you have a class and you're saying "This class does A and B and C and D and ....", then maybe you need to consider whether it really should do all those things.
Each class should be able to say "My job is this." Maybe that job is representing state for something and performing related actions (an item in an RPG). Maybe it's managing other objects under it, orchestrating them (an Inventory or a Player). But it should have a clear purpose.
Same with modules, same with functions.
Good rule of thumb: You should always be able to fit the thing you're working on fully in your head. If the class/module is too big to fit in your head, rethink the design.
On the subject of presentation, you want all your code to feel like it's written by the same person at the same moment in time. That means sticking to a style. This governs things like:
When do you add blank lines between things. How many?
Spaces or tabs? How far do you indent?
How do you break up long lines? Long strings? Long conditionals?
How do you name functions? Variables? Classes?
etc.
Everyone has their own style preferences, but consistency is key. If a language has a de-facto standard, start with that (Python has PEP-8, linked above). Build upon that. That'll help others contribute down the road, help keep you consistent, and help you leverage code checking tools that understand the base standard.
If you're working with other people, document that standard. Here's ours: Python Coding Style Guide
When you're using such a tool, you're taking a series of changes made to your tree and turning them into commits to the repository. When doing this:
While that's not code organization per se, it really is an important part of the development process, and learning best practices there as you start is key. Also, points a. and b. can help a lot with your mental process while working on some code. "What am I focusing on right now?" There should be a clear answer to that.
It's effectively another way of documenting your work. Not lines of code, but a history of the distinct changes you made to your project