Improving User Experience with Shell Scripts

Earlier this year, we rewrote the architecture of this blog. It is composed of a Rails application (the blog engine) and a separate repository of Markdown files. Whenever a new commit is made to the master branch of the markdown repo, the blog engine is notified via a webhook and automatically imports the changes and publishes them.

As an author all you have to do is write a Markdown document and merge to master after getting it reviewed. You don’t need to know about the blog engine, Rails, or webhooks.

In theory.


Authors like to preview their content before shipping it. Markdown previewers, although a step in the right direction, created output that was very different from what a post would look like on production. Not only did they not match the style of our blog, but they also lacked all the other UI elements that would normally be present such as the header, tags, and authors.

The blog engine has a local preview mode that reads posts from the local file system instead of the database. Problem solved!

In solving one problem however, we’d created another. Now authors needed to install the blog engine locally, run a server, and point it to their local copy of the markdown repository. In addition, they needed to update the engine as changes were made to it as well as keep up with versions of Ruby and Rails.

Addressing the problem

We received a lot of feedback that the process of writing a blog post had become convoluted and confusing. First-time authors were frustrated with all the tools they had to set up before they could even start writing. Something needed to change.

The new approach needed to solve the following:

  • Give authors the ability to preview their work in a way that would look identical to production
  • Completely remove the need for authors to know about the blog engine
  • Not force authors to manage Ruby and Rails versions

Shell scripts to the rescue

We eventually decided to add a shell script ,bin/server, to the markdown repo that would boot a “preview server”. The process for authoring a post is now:

  1. Write Markdown document
  2. Run bin/server and preview post in browser
  3. Open pull request

All of the complexity that was previously so frustrating is now hidden behind the bin/server command. This script tries to clone or update the latest version of the blog engine into a temporary directory. It configures the engine to run in local mode and points it to the local markdown repo. It will also automatically install the correct Ruby version. Finally, it boots up a server.

Adding a small shell script vastly improved the experience of authoring a blog post. This was particularly true for our designers. They don’t spend their entire day in the shell and thus have a lower tolerance for arcane processes that require running a lot of different shell commands.

As someone who was not only an author, but also worked on developing the blog engine, I had gotten used to all the hoops I needed to jump through. Once we introduced bin/server, I was surprised at how much pain I had previously considered acceptable.

Cleaning things up

Iterating on the script idea, we found that authors thought the output bin/server command was both overwhelming and a little confusing. Most of it is not necessary unless you are debugging. It was time for a second round of UX. We redirected most of the output into a server.log file where it was out of the way yet still available if we needed to debug. We added better error messaging and colorized important lines in the output to emphasize function.

server output

Bonus points

Authors sometimes encounter small bugs in the blog engine. Once we push fixes to the repo, all authors need to do is re-run bin/server, and they will be running their preview server on the latest code automatically. Although we didn’t set out to build this functionality, it turned out to be a very nice side effect of our efforts to improve user experience.

Lessons learned

User experience is important, even for developer tools. Just because you are comfortable with the terminal doesn’t mean that it’s not worth improving a complex workflow.

Just as with user-facing products, get feedback from those that use your dev tools and iterate on improving the interface and experience.

Distill your workflow to its essential components and hide unimportant details behind abstractions. Use color and spacing to make the output of your scripts intelligible and hide information that isn’t useful.

Source code

For those interested, you can view the source for the bin/server script in this gist.