Using ASCII art to document data structures in code
/ 4 min read
Sometimes there is a requirement to add a complex data structure to software, for example directed acyclic graphs (DAGs). Letβs just assume there is no other way, and it has to be done.
I had to implement a DAG-like data structure for a feature request and there was no suitable thirdparty library. So all functions, like checks for circular dependencies and adding a new relationship had to implemented by myself. Extensive testing and documentation was essential in order to let my future self and others understand what was going on. I even felt the urge to add (Javadoc-like1) comments to many tests and several fixture methods.
Useless Javadoc?
Usually I do not rely much on Javadoc or comments to describe what a single method does, especially if they are internal. In the following simple example, the methodβs signature and its name almost tell everything that needs to be known. It makes the Javadoc seem redundantβthe only additional information there, is how negative input values are handled.
Useful Javadoc?
I changed my mind about this, when I had to deal with complex data structures: adding comments at the methodsβ signatures was a major relief in documenting what was going on. The challenge was to explain the relationships between entities without writing a novel. Thatβs where ASCII art (I was using asciiflow as tool) came to play. I mostly used it to annotate tests and fixture methods, especially for those related to the method that was checking for circular dependencies.
It is not easy to keep track of the test setup. Take the following example, and try to understand the test setup without Javadoc. Those three comments are supposed to help a bit, because it is difficult to understand random code examples without any context.
Click to expand the test without Javadoc
Click to expand the test annotated with Javadoc
Now imagine, having to understand more complex setups, containing several additional entities and having even more relationships with each other! ASCII art illustrations allow the reader to comprehend the setup without much effort.
Lessons learnt
Implementing this, taught me a few things. Most are not directly related to this blog post, I am going to document those here nevertheless:
- Annotate methods with illustrations made from ASCII art, instead of adding plain text comments only
- This reduces the cognitive load
- I used asciiflow, which did not cause me any problems
- Extensive testing is your best friend
- Incrementally increase the complexity of the tests cases
- Avoid deleting simpler tests, even if those are covered by more complex examples. Usually, I would remove test cases that are already covered as part of the refactoring, but in the given scenario the simpler tests proved useful to help readers understand the code better.
- Consider helper methods or convenience methods (fixtures) to make the test setup more readable. It also reduces the risk of a faulty test setup (see below).
- Double-check the test setup
- Watch out, to not prepare faulty data structures that differ from what is documented! Debugging such a case is tricky.
Footnotes
-
I did not use Javadoc or multiline comments (opening with
/**
or/*
) for the ASCII art illustrations, because IntelliJ IDEAβs code formatter destroyed the commentβs structure. Commenting out each line separately with//
prevented this. The examples above are Javadoc nonetheless. β©