RT-Thread Conference: The Trouble With Documentation
09-06-2022 | By Robin Mitchell
Last week, we took part in the RT-Thread conference teaching engineers the trouble with documentation and poorly written APIs. Why is well-documented code important, how can poorly written APIs present challenges, and what can engineers do to help others?
Does the engineering community have a problem with poor documentation?
Unless a project, device, or piece of software is to be used by a sole individual, it is essential that any associated documentation is well written, clearly laid out, and conforms to some set of publication standards. Some may feel that in-depth documentation is too much effort or unnecessary and thus write short descriptions of code functions, provide minimal product drawings, or use abbreviations and short-hand descriptors.
However, the sole purpose of documentation is to educate others not involved with the initial design and development. So long as the reader has the required minimal skills (such as an understanding of C code, how to design electronic circuits, or use CAD), the documentation should provide the means to fully understand the workings of a system and offer a range of examples should it be necessary.
Unfortunately, large quantities of poor documentation, confusing API names, and overly complicated examples make their way into modern designs and platforms. While this is not an issue for engineers with years of experience in a particular field, those looking to explore new fields can find themselves quickly confused, frustrated, and dissuaded from continuing a project.
The common theme between engineers and documentation is that engineers write documentation from their perspective knowledge and assume the reader has the same level of knowledge. Why this is the case is unclear; it could be due to laziness, it could be due to lack of empathy for the reader, it could be the difficulty and time faced with writing well-written documentation, or it could be a trait found in those from academic backgrounds (mathematicians are notorious for this).
Regardless of the reason, examples and documentation provided by engineers can often be poorly written, which often results in a barrier to those looking to explore advanced topics and designs.
It’s not just documentation; APIs can often be confusing as well
Documentation used to describe code functions, outline the measurements of a component, or present examples are not the only aspects of engineering that often receive little attention; code APIs can also be unusual and poorly named. To understand why having clear function names for an API is important, we first need to look back in time and understand why high-level languages came about.
The first computer systems had limited resources in processing ability and memory size. As such, every byte of memory used and every microsecond of execution time consumed had to be carefully considered. In such cases, coding in assembly language allows engineers to craft applications on the instruction level, allowing each instruction to be interrogated.
Should two bytes be used to load register A with zero, or should we use a XOR A instruction to reset the register and only use one byte? Should all strings be zero-terminated, or do we save the bytes and specifically pass string lengths to string printing functions? Should we use a register to hold a loop counter and execute a piece of code n times, or should the loop be unrolled to reduce the execution time of loop counter updates and jumping? These are but a tiny fraction of coding tricks that engineers would use to maximise the speed of applications and minimise memory usage.
However, as computer resources increased, so did the complexity of applications and trying to code complex programs in pure assembler is challenging and time-consuming. Combined with the increased system resources, high-level languages quickly became dominant in the computer engineering field with examples including C, C++, Python, and Java. These languages allow for a great deal of abstraction that hides the inner workings of a computer program while also providing advanced features such as dynamic memory management, function calling, object-oriented programming, and commonly used routines.
But above all else, high-level languages allow for code to be far more readable with the use of function names that make sense and code that is more readable. For example, a Z80 assembler for loop would use the B register and the DJNZ register to perform the loop until the B register is zero, but a C application can simply use the term “for(I = 0; I < 10; I ++)” which is far easier to understand. Function calls in C also allow variables to be named and passed without worrying about the stack or overflowing of register sizes.
So, given that high-level languages allow for easy-to-read code functions and layout, it is amazing how there are APIs being written by engineers that use poor naming conventions. For example, the term kprintf is often used to refer to printing text to the kernel debug console, but it would make far more sense if the name kernel_print was used instead. Another example is dfs_mkdr which is used to create a new directory in a virtual file system, but a better name would be dfs_createDirectory or fileSys_createDirectory.
Some would argue that the specific use of mkdr comes from older established Unix systems, but just because older computer systems have used short-hand naming conventions (due to memory limitations) does not mean that they should continue to be used.
How can engineers help others?
To truly understand what documentation and APIs should look like, one only has to turn to the Arduino platform or Blues Wireless Notecard tutorials.
The Arduino platform not only uses well-defined API wrappers whose name clearly refers to their function but online tutorials and examples come in varying degrees of complexity, with the most basic examples only using the bare minimum code needed and the most complex examples including all aspects of an API. Additionally, functions described in the online documentation don’t just show the function name and the parameters it takes. And it also provides multiple code examples to demonstrate how they work and the expected outputs that they give.
Blues Wireless are another example of excellent documentation and examples. Not only is their online documentation well laid out using modern graphics, but the website also provides clear examples that can be copied and pasted to their Notecards over a USB to Serial connection. Additionally, their site also integrates a serial terminal that can connect to the Notecard, allowing for examples in the documentation to be directly executed in-browser.
What engineers can learn from these examples is that when writing documentation, it should be done from the perspective of the reader and not the author. Furthermore, engineers writing tutorials and examples should work their way from the most abstract code to the most complex. For example, resources that teach about an RTOS should not start with describing how processes are handled by the kernel or how memory is allocated but instead should start with a trivial LED blink example that demonstrates how to include the OS, how to launch it and add a task that flashes the LED.
At the end of the day, writing clear documentation that guides the reader through a journey will be highly appreciated by others and will also help future engineers who may need to overtake a project if the original engineers leave.