“ground control to Major Tom…”

To read the Portuguese version, click here.

We are launching azk v0.14.0 and as we explain elsewhere in our blog, rebuilding the azk CLI (command line interface) from the ground up is a big part of this new version.

Here we’ll talk in detail about why and how we did it.

Motivation

Today, the azk CLI is its only user interface (as of yet…). It is the operations center from which every and any task is commanded.

Performance and usability are paramount to the best possible azk experience.

Although the CLI didn’t have the same high performance of utilities such as grep or awk, the azk CLI wasn’t exactly slow. On the other hand, these very references were indications that there was room for improvement for our CLI.

Cutting off milliseconds from the execution and response time of a single command may not make a big difference, but many commands may be executed on a single use session of azk. If we’re dead serious about making azk a software development standard (and boy, we are!), it certainly will be used many times a day by any single user.

Those milliseconds eventually pile up.

We believe that the same applies to the CLI usability. That’s why we took extra care with commands formation, output stylization and help resources on the CLI.

All those things must be like a second nature to our user, as automatic for him as breathing.

That was no small challenge. In previous versions, we had decided to build our own parser for azk, which brought some performance issues and another kind of problem as we discuss below.

The Unix Standard

Although we haven’t created azk as a mere user interface for Docker, many of its features are only possible due to the use of containers on its core.

Thus, for practical reasons at the time, we just employed the same CLI behavior offered by Docker.

That meant azk would interpret the options passed on to the CLI according to their sequence in a given command. That resulted in problems like the one below:

$ azk --log=debug start

$ azk start --log=debug

Even though the commands above look similar, they wouldn’t effect the same results. The first one would work, but the second one would fail (and would inform that `--log=debug` is not a valid option to the start command).

In the Unix world, supporting any options sequence passed on to any command is the correct behavior. In our early decision to support a Docker-like CLI behavior on azk, we decided to build our own commands parser, but that only made the CLI maintenance more complicated than it needed to be.

The CLI was limited, hard to maintain and could have had better usability.

Some options had to be passed on to the commands precisely in right sequence, help could only be called in a very specific way and it became impossible to generate “Auto Complete” (which lists options that can be passed to a command as you type when you hit tab on the keyboard).

Solutions

Performance and usability will always be key priorities on azk. It is no use to make azk “magical” in its features if it is slow or not so intuitive to use.

So, before we try and solve the problems listed before, let’s first recap the requisites. The CLI must:

be “unix standard” or Posix;

be easy to use;

display very low response times;

be easily changeable (so that it can evolve well);

support easy implementation of “Auto Complete” on the terminal.

Part one: following the Unix way

After some research, we found a solution that addressed the requisites and brought a new approach to an old problem. It’s a tool that parses the options passed on to a given command based on the command help.

This tool is Docopt.

More than just an implementation of those requisites, Docopt is becoming a true standard for parsing commands on the CLI. On top of rich documentation of Unix commands options it also offers implementations for different languages, including JavaScript (which we used to implement those features on azk).

With Docopt, we found the first part of the solution we were looking for, but we still had to find out how to execute the correct actions after Docopt had parsed the options attached to each command on the CLI.

Part two: performance and modularization

As we built our own parser for azk, we ended up with a complex system of classes and inheritances. On one hand, it made load easier for commands and options supported by the parser, but it was also quite heavy and monolithic on the other hand and that made the CLI really hard to evolve.

Even as powerful and versatile as Docopt proved to be, it couldn’t direct or address the options it parsed. We needed a “routes” system that invoked the right piece of code responsible for each command based on the options extracted by Docopt.

We avoided the temptation of modifying Docopt and end up with another “monolith” and followed a common approach in web frameworks: routes and controllers.

So, in order to connect the options parsed by Docopt to the right actions, we built cli-router.

cli-router is born

cli-router is nothing more that a simple router implementation: a concept where a series of rules guide the decision of which action (controller) to call.

You can find it here.

Based on filters and rules, cli-router can look at command parameters and choose actions to call.

For example:

Explaining the routes:

help: if the command is help, if the “ --help” option exists or if the command doesn’t have any arguments, calls the “Help” controller;

version: if the command is version or if the “--version” option exists, calls the “Version” controller;

hello: since no filter was passed on, cli-router automatically creates a filter that verifies if the command is equal to the route name which in this case is “hello”.

What about the help?

help on azk is one of the many things we’re proud of.

It was flexible and dynamically built based on the options passed on to our old home built parser.

When we adopted cli-router and Docopt, we gave up that implementation and needed a new approach. Thanks to the flexibility of that new approach, building a new help system turned out to be easy and also allowed us to make improvements such as the “Auto Complete” system.

cli-router has a single controller called help, capable of making the CLI helpdynamic. For example: if you call help for a specific command, it extracts pertinent information and returns a new help.

This controller was built to be extensible. Thus it is possible to apply specific alterations and stylizations to each application. For example, with azk we inherited the help controller so that titles can have different colors.

To visualize the global help:

$ azk --help

To visualize just the agent command help:

$ azk agent --help

We’d like to point out that although the cli-router is part of azk, it is also a stand alone open source project and its use doesn’t depend on azk. Please, feel free to use it to build your own CLI tool. :)

Conclusion

The azk CLI is the only command center available to the final user (yet…). Performance and ease-of-use are key requisites for its use.

We have shown here how we think about the CLI evolution and the measures we took to implement it.

Since azk is open source software, we tried to publicly discuss the effort applied to its creation and evolution.

We know that in order to be the universal standard we hope azk becomes, it will never be finished. There will always be lots to do so that it can address that nth new scenario.

You can keep on counting on that kind of effort and evolution pace for azk coming from our core team.

As always, we look forward to the day when azk can also count on contributions from outside the team.

Don’t forget to check the links below with the many ways you can stay in touch with us and start to contribute (and not only with code).

And, please, don’t forget to give a “star” to azk on Github! ;)

https://github.com/azukiapp/azk

That’s all for today, folks! Thanks!

Time Azuki

More about azk

+ Site: http://azk.io

+ Github: https://github.com/azukiapp/azk

+ Documentation: http://docs.azk.io

+ Images directory created by the azk team: http://images.azk.io

Contribute to azk

+ Star azk on Github: https://github.com/azukiapp/azk

+ Report an issue: https://github.com/azukiapp/azk/issues/new

+ Help solving a reported issue: https://github.com/azukiapp/azk/issues

+ Check out our awesome sponsors: http://azk.io/#sponsors

Stay in touch with the azk team

+ Sign up the weekly digest: http://www.azk.io/#newsletter

+ Follow the blog: https://medium.com/azuki-news

+ Talk to our support (chat): https://gitter.im/azukiapp/azk (English) ehttps://gitter.im/azukiapp/azk/pt (Português)

+ Facebook: https://www.facebook.com/azukiapp

+ Twitter: http://twitter.com/azukiapp

+ YouTube: https://www.youtube.com/user/Azukiapp/videos