In this post I'd like to share a practice that has completely changed the way we work: documentation as a first-class citizen in our software development process.
Documentation facilitates understanding, which is vital to enable change and continuous improvement.
Traditionally, we aim to produce clean and maintainable code to make it more reliable, and write tests to protect it. We use good variable names, split functions that perform too much into simpler ones, and design them so that parameter names convey enough information.
However, seeing what the code does is not the same as figuring out why it does it.
Most of the design process happens informally in chat rooms, conversations, and online documents. As a result, understanding a decision that was made a long time ago can be very time consuming, as it requires scanning through chat messages, and reaching out to the people that were involved.
When we are not able to obtain enough information about these decisions, it becomes harder to effectively reason about the software, slowing down fixes and improvements.
This is why learning about past decisions should be as efficient and straightforward as possible: it will save us a lot of time and frustration down the line. Knowing the context will allow us to make informed decisions, which are better decisions.
If we are to make our software easier to understand, and thus easier to change, we should document our intent in every possible way. Think about it as a byproduct of the thought process we carry out as developers when designing a solution and writing code.
Capture any breadcrumbs that might be useful in the future to find out how things are supposed to work, helping other developers unravel the conditions and mindset that influenced the code, even when we no longer remember why.
Document as you go. No other time will be better to document than when the ideas are fresh in our mind. Memories fade over time, and what we fail to record then might be hopeless or painfully time-consuming to remember later.
The overhead of documenting on the spot is negligible, but the overall benefits are certainly not!
To get the best out of it, we should imagine we are someone else trying to understand our work. Which things will not be so obvious a few months from now? Thinking about it can help to reveal our underlying assumptions and knowledge.
Is it clear how this component interacts with other parts of the system?
By doing this mental exercise, we will be able to find simpler and more readable ways to solve a problem, allowing us to refine our designs and solutions. It has a direct positive impact in maintainability, regardless of whether someone actually reads the resulting documentation.
Our focus should be on recording intent, why and how things should happen. It's also useful to cross-reference classes and objects that interact with each other. Aim for the bigger picture, and work your way down as needed.
# Public: Abbreviation of a few words that sums up what the question is about. # Example: 'Side Effects' field :title, type: String
Inline docs are always at hand, require very low effort to add and update, and are very helpful for developers to gain insight (both during reviews and in the long run).
They should be clear and concise. Don't overstate the obvious and remove any words that feel unnecessary. Creating good documentation takes practice, it's more about writing skills and less about programming.
While it's possible to generate documentation pages from a minimal syntax, usually navigating through the source code and reading the inline docs is more convenient. Using Goto Symbol or Goto Definition on any editor does the trick.
Won't the comments become outdated really quickly? 🙀
More often than not, the core concepts in the software we write rarely change, so the documentation tends to be useful even when not entirely accurate.
Combined with source control, even when the comments are outdated, the original intention is never lost. We can navigate back through history and get the full context in which the documentation was written.
In the same way we should document our intent in methods, properties, and classes, it's also important to capture the broader purpose of changes in commits. This will enable us to look back to learn more, saving us an invaluable amount of time when trying to understand past decisions.
As a result, we can move forward with deeper undestanding and confidence, refactoring or removing code without fear of accidentally breaking the app, or going against an otherwise long-forgotten decision.
Usually in a team environment, the pull request replaces the commit as the unit of change. Besides providing a platform for code review, pull requests are great for adding rich non-text information, such as images and video, and hyperlinks to external resources.
As a result, they also have an immense potential for communication and documentation. We should leverage the description to explain substantial changes (why and what for), provide screenshots, and any content that makes it easier to follow the work.
Doing so will leave a solid trail that can help anyone grasp the full picture later on, in addition to improving the communication and quality of the reviews. Two for one!
Code is read a lot more often than it's written, which is why inline docs provide a great return for their tiny cost. Same can be said about writing a nice pull request description, describing specific decisions in comments, and providing screenshots.
We've saved a lot of time when figuring out how things work, enabled our team to refactor with confidence, prevented problems and regressions, and made entire areas of the app more approachable for other developers.
The simple practice of documenting helps junior and senior developers alike, and after you start using it, you'll be wondering why you didn't start sooner 😃