bendun.cc

On Output

Written , a 4 minute read

Rule of thumb: your application should always support main 4 forms of output, differentiated by form and receiver. Nice defaults are:

UnstructuredStructured
Human Colorful text output HTML
Computer Plain text output JSON

Unstructured computer output is nice for compostability with both classic Unix programs or modern AI algorithms. For example, generator for this blog (which currently don't exist, it's all hand written HTML) could output space delimited words for word counting, reading time estimation or training AI model to write posts for me.

Unstructured human output simplifies including already written text inside documents. Copying text from plain text file into LaTeX document is way simpler then from compiled PDF.

Structured human output is great for universal cross platform documentation, providing readable documents or graphical interfaces for end users.

Structured computer output is a great convention for cross program integrations. Instead of writing parsers for each programming language that you want to use or worrying oneself with integrating existing libraries into your build system.

Let's look at some examples that I have come across recently!

Document parsers

I love AsciiDoctor as an input format but the AsciiDoctor as a software has terrible options of output. Either you get pre-styled HTML or you supply CSS on your own. Pretty much nothing more that is useful.

Screenshot of this article written in AsciiDoctor
AsciiDoctor has really nice looking default, that is great for homework reports or documentation.

While AsciiDoctor is great for documentation generation, support for using it for general HTML output is not that great. It sheres this problem with other simple document formats (like Markdown), which are designed for mostly one use and specific output format.

A good markup language describes an abstract hierarchical structure of the document, and lets a separate program to adapt that structure to the desired output.

"Elements Of a Great Markup Language" by matklad

HTML output only fulfills one of the desired roles, a human structured format. However, from a things like personal websites or blogs we desire sometimes more. That's when JSON could come in (or AsciiDoctor as just a parser in nice programming language that supports tree structures like OCaml or Rust).

Most of the document formats have this issue, with some being especially bad like WYSIWYG document formats used by office suites. They are notoriously uncomposable, driving me mad everytime I need to use them. Whatever transformation you want to do, you cannot do it, unless you first transport the text to simpler document format (like plain text file), do transformations there and bring text back.

Compilers

What drives me to the Rust the most is the toolchain. From the input Rust text files, you can generate plethora of binaries and libraries as one would expect from compiler. However, Rust goes one step further with great error messages with console and integrated documentation generation tool that is used as the default documentation environment in the ecosystem.

Documentation generated with cargo
Example of documentation, generated only with cargo doc, which constructs documentation from comments in the source files.

Despite supporting all kinds of outputs, it lacks one important one - composable JSON output from Rust parsers. Primary use can be code generation, as done in Crossing the Impossible FFI Boundary, and My Gradual Descent Into Madness.

Lesson is simple: if your application has some representation of data, it should have the ability to output it. Rust gives nice structured output for humans in form of generated documentation but lacks the same output for computers (but is in progress!).

For great work on friendly compilers, see Compilers as Assistents from creator of Elm programming language.

In Terminal

Great example of application that has good support for output is systemctl. I was pleasantly surprised how useful it is, depending on your needs. The --output parameter supports over 15 types of output, most notably various text formats for text human consumption, JSON or even binary exports for backups. Gold standard.

Example

Suppose I want to check if libvirt is running. I check for anything, taht starts with libvirt. In the output mode meant for end user reading on terminal, systemd highlights the best match. If we would like to consume it with jq or in Python, we can switch output mode to JSON. There even is one to make greping simpler.

Image of using systemd default and json output modes
Using image here to show nice colors

Conclusion

Be considerate of how you can support your users as broadly as possible. You never know how your application may be used. If you have the data, share it. If you share it, make sure that both computers and humans can use it.