Art of Clean Code - Documentation
When I think about documentation in code, I think about a fellow developer reading it couple of years down the line when I am not around. And that defines the test/quality criteria of documentation:
Will a developer who just understand the system domain, would be able to make sense of this code or not.
I am sure, I have short memory so I even forgot code written by me also after couple of years or earlier. Hence, I myself is a good test case for my own 'code + documentation' to see if I could make sense of that or not :).
But this is a practical parameter. As developers, we should have empathy towards product, code and the next developer who will manage the system once we are not around. Documentations shows the level of empathy and professionalism for this fact.
Now, there are various reasons for not doing or for doing the documentation. Let us discuss.
Right Naming Conventions does not eliminates the Need of Documentation
One of the thought school could be that if Naming conventions are right and code is written nicely, revealing intention clearly, then documentation can be skipped. Which is partially correct for two reasons;
- Naming convention is right in 'our context', which could be different than other users (especially if names are not based on domain) and context is built after spending lot of time in system
- There are still many aspects which names of classes, functions or variable can not reveal.
Let us take examples.
Example: Interface name is ExternalSystemDataService. When this interface was designed, there was only one external system for data. Hence, developer thought, it is good enough name to reveal intention as everyone knows in team about this fact. Couple of years later, there are 10 more systems shipping data. Now a new developer, who is fighting with a mammoth codebase to understand the system design, has no clue what this external system is as long as s/he is not checking the configurations, service registry, or run the system and watch the logs.
Context changes with time as system evolves
There are even more aspects to documentation, which if considered properly, can save lot of time. And this information is not revealed even by good names easily.
- What kind of use cases this service will cater to
- What kind of data this service will provide
- Is there any special case which user should be aware of
Interfaces are meant to extend and add the behavior in system while keeping the overall sanity of system intact. Interface Names helps a lot to reveal the intention, but these may not be able to describe everything on its own. Interfaces definitely needs good amount of documentation to clarify what is expected from implementing classes, and what should not be done. Refer Expression.java here. This interface is the basis of whole Expression Parsing logic, and will be implemented within core project and by others developers outside system also to add extensions later in future. It definitely needs a good quality documentation so users can understand the intention, and design clearly anytime in future too.
Public API always need a good documentation. There can't be a better reference for this, than Java library. It is one of the greatest examples to learn, that how APIs or implementation should be documented.
Hence, right naming convention does not eliminates the need of documentation. However, it may helps to reduce the amount of documentation, as good names also become part of documentation.
Documentation: Comments helps to decode special cases easily
Other thought could be that comments should be zero, as good code reveals its intention itself. This is a valid point, as long as code is written that beautifully, without any special case handling. But there are few caveat to this.
Example: A function is checking if specified subscriber should be billed monthly, yearly or should not be billed at all.
subscriber.getBillableInfo() == null > return false for billing // TODO: can be isBillable
subscriber.getBillableInfo().getStartDate() == null > return false for billing
return subscriber.getBillableInfo().getFrequency();
Now, what is that second check for. May be, it was some special case which had to be handled. Ideally, there should not be special cases. But there always are, as life is not ideal all the time, and so the code. Now, this demands comments / documentation, preferably with a Jira ticket, so any developer later can understand this easily without need of digging his head deep in logs or in break points. Documentation is not replacement of good code here, but it helps to reveal the intent clearly, as long code is not perfect.
Documentation: Comments helps to decode complexities quickly
Ideal is to write simple code, which anyone can understand easily. However, there could still be algorithms where even after having all right intention, we can not simplify it enough. Comments help a lot in such situation.
Example: Refer to ExpressionOasis > Compiler.java > compile and restructureTokenInRPN functions here. This is bit complex logic with few special cases. It is written by us, but even I needed to enable the logs to understand its intricacies every time I fixed any reported issue year later. I tried to simplify it many times, and did to good extent. But this algorithms still has its own natural complexity. By adding comments here to reveal flow, algorithm, cases, we can make life easy for the readers.
*Above class has good examples of over documentation too. Ex: isUnary function. The function name and parameter name is rightly telling the intention (+being private method), documentation is not required that much here.
Hence, strike a balance. Complexity is also very contextual, which changes from person to person a lot. Thumb rule could be, is your peer/reviewer able to understand it in one go. If no, either simplify the code (best if you can) or add documentation.
Best case is to explain ourselves in code so well, that it does not need comments. But if that is not happening due to any reason, have empathy and make it easy for next developer by adding comments.
Documentation: Comments are helpful for some house keeping also
Adding TODO in code are sometimes so helpful to not to forget that possibility which we are not fixing now due to any reason. Best, add a TODO with tracking ticket number. It can help the new reader, as well as the author of code to connect easily for possibilities of improvement anytime in future.
Documentation: Comments are required in non-code files too
Documentation is not only for Java/.NET etc classes, but is very important for configuration files etc also. Configuration files reveal a lot about system. If these are documented well, reader can understand many of the system intricacies, interactions and behavior easily just by reading the config
In conclusion,
- The important goal is to 'author' code which reveals its intention clearly, and can educate users for how to use it, and for what to use it. Whatever level of documentation is required to support this, that is required.
- There could be few debatable or contextual points for documentation, however, few are very clear. Ex: Public API / Interfaces, Abstract Classes, Special Cases, TODO, Warnings, Hidden consequences etc
Notice 'author' word in previous points. We are the author of code.
An author always wants its readers to feel comfortable, and interested. Hence, author does everything to make readers experience better.
Another important aspect is empathy for Product, Code and Readers. Give them a best experience by leaving your code in easy to read and easy to consume state.
As Robert C Martin said: "Truth can only be found at one place: The Code". Let truth be easy for everyone!
Happy Coding..