At Shopify, content is deeply integrated into our design process. Content strategists are frequently involved at any and every stage of product development, from user research to development to deployment to marketing. We scrutinize every word you see in Shopify’s user interface, whether it’s a multi-page checkout flow or a single button.
Shopify is a web-based platform, and the web is a visual medium. We’ve worked hard on design tools like Polaris to promote accessibility, consistency, and usability across all our UI, and that work will continue.
Normally, content strategy is one piece of a much larger design puzzle: content strategists typically collaborate with UX researchers, designers, front end developers, and product managers to ship a new feature. Building a complex graphical user interface requires this kind of collaboration across a wide variety of UX practices.
But what happens when the content is the interface?
That’s the question we’ve been grappling with as we work on the Shopify App CLI, the open-source command-line tool we officially launched last week. The process raised some fascinating content strategy questions and while we haven’t answered them all yet, I’d like to share some of what we’ve learned so far.
These questions, and the answers we landed on, explain our own thinking around the CLI tool. But ultimately, these content strategy principles are worth considering for any product you work on, whether you’re building for the web, native platforms, or the command line. What are the constraints you face? What does your user already know, and what do you have to teach them? When do you follow existing UX patterns, and when should you decide to create a new one?
So without further ado, here are the content strategy principles we followed while building the Shopify App CLI, and what we learned along the way.
Why we built a CLI
First, to understand the reasoning behind our content strategy principles, we need to discuss the project itself: what is a CLI, and why did we build one?
When you’re starting to build a new Shopify App, there are a bunch of common tasks involved:
- Setting up a local development environment
- Provisioning API keys and access tokens
- Writing tons of boilerplate code just to get to “hello world”
- Creating Shopify development stores and dummy content for testing
- Deploying to production-grade hosting
As a developer, you could already do all these tasks yourself, but it can be tedious and time-consuming.
The goal of the CLI is to make it faster and easier for you to get up and running with a new app by automating as much of this process as possible. Since developers already do much of their work in a command-line environment, creating a CLI puts many of Shopify’s services a few keystrokes away, in a context you already know well.
![Content Strategy: Register your App](http://cdn.shopify.com/s/files/1/0533/2089/files/Content-Strategy-Registering-your-App.2019-11-20_08_58_11.gif?v=1574258465)
Building blocks of a CLI
As a user interface environment, the command line is pretty much as minimal as you can get: a blank window with a blinking cursor.
There are common UI elements we don’t have access to in a CLI:
- Mouse clicks, touch-screen gestures
- Buttons
- Icons
- Modals
- Hover-state tooltips
- Empty-state helpers
- Predictable color schemes (developers can heavily customize their terminal environment)
So what does that leave us with? These are the only UI elements that we can truly rely on—and even then, to varying degrees of certainty:
- The standard ASCII alphabet (always)
- Spacing and indentation (always)
- 16 RGB colors (almost always)
- Unicode symbols (almost always)
- Bold, italic, and underlined text (usually)
- Emoji (maybe)
In other words, not much. But nothing drives creativity like constraints, and for years CLI creators have used this short list of ingredients to create a wide variety of ingeniously lo-fi interactions.
"But nothing drives creativity like constraints"
The Shopify App CLI includes, for instance, several CLI UI elements created by creatively deploying standard Unicode characters:
- A process spinner to indicate activity is happening, made out of Braille symbols
- A progress bar that fills up with a percentage label to indicate how long a process will take
- A system of nested frames to indicate that the tool is delegating a task to a sub-process
None of these visual elements approach the complexity and polish that you’d find in any modern web app, but they’re perfectly suited to the purposely spartan context of the command line.
You might also like: The Shopify App CLI: A Tool to Help You Build Faster.
Convention matters
There’s a deeper, less obvious benefit to designing command-line interfaces, which is that you’re building on more than 50 years’ worth of design convention before you’ve written your first line of code. There aren’t any other digital design systems that can claim that kind of longevity and consistency.
"You’re building on more than 50 years’ worth of design convention before you’ve written your first line of code."
The command line as we know it today can trace its lineage to the family of Unix operating systems that emerged in the early 1970s, and many of the key concepts of command-line programs have been essentially unchanged for decades. Experienced users are therefore usually able to quickly transfer their knowledge of one CLI tool to another. A graphical user interface might be able to give users a richer experience visually, but it also requires people to learn that new interface first, which can be frustrating and time-consuming.
Minimal design overhead also means the experience of using the CLI can be made fairly smooth across different platforms, offering a comparable experience to users on PCs, Macs, and the many flavors of Linux.
Of course, there are tradeoffs. Casual users rarely open their terminal and CLI tools can be intimidating or inscrutable for less experienced users. But that also means the user who installs a command-line tool is probably both already experienced and motivated.
The command-line club isn’t for everyone. But then, it doesn’t have to be. And for those who know the magic words, it can be an incredibly fast and powerful way to work.
You might also like: Building Shopify Apps: App Developers Share Their Experiences.
Content strategy on the command line
But determining what those words should be, and how people will learn to use them, are exactly the kind of questions that content strategists puzzle over every day. In the case of the Shopify App CLI, we drew on that deep tradition of CLI design, so many of the big design decisions were already made for us.
We did, however, set a few content strategy rules.
1. Verb first, then noun
One of our general rules for product content at Shopify is to use the active voice. Just as it’s more direct and clear to say “the boy hit the ball” (active) instead of “the ball was hit by the boy” (passive), we wanted to keep the CLI in active voice. The commands you run in the Shopify App CLI follow the same rule:
shopify create project
shopify generate page
2. But sometimes defer to convention
Every rule has its exceptions. In the case of the Shopify App CLI, that’s the command:
shopify tunnel start
Notice the difference? It reverses our usual rule, putting the noun (“tunnel”) before the verb (“start”). The reason is convention: in Unix/Linux-flavored systems, it’s common to start or stop continuous processes or services with this kind of pattern. Consider widely used commands like these:
-
service apache start
(start the web server) -
ufw enable
(turn on the firewall)
Could it have been shopify start tunnel
? Absolutely. But “starting and stopping processes” has a long-standing and deeply established mental model for developers. We’ve decided that, in this case, we shouldn’t break that pattern.
3. Good news whispers, bad news shouts
The whole point of a CLI is that it’s fast and gets out of your way. It’s also aimed at developers, who are frequently debugging problems, whether with their own app, their local development environment, or the CLI itself. In other words, if everything’s going well, we try to convey that information with a minimum of fuss. And if something does go wrong, we try to give as much information as possible about the error, so that devs can get to the root of the problem.
"And if something does go wrong, we try to give as much information as possible about the error, so that devs can get to the root of the problem."
A consumer-facing app would likely never expose errors in this way. That’s partly because giant error messages would quickly clutter a graphical UI and look awfully unfriendly to a casual user. But it’s also because those users are less likely to be able to troubleshoot—or even diagnose—the problem themselves.
In contrast, because our target user for the Shopify App CLI is technically experienced and used to doing self-serve support, it’s likely faster to just give them all the relevant information. The alternative would be cumbersome and time consuming: file a support ticket, then wait for us to investigate, duplicate the issue and respond, and finally see if the fix worked (and if it didn’t, do it all over again).
Some people feel confident enough to change their own tire on the side of the road; for others, it’s better to wait for the tow truck and have someone else handle it. We’re fairly confident that our users would rather wield the lug wrench themselves.
So our general rules for output are:
- Make success messages as concise as possible
- Make error messages as detailed as possible
4. No dead ends
A great error message doesn’t just tell you something went wrong; it helps you understand how you can fix the problem. The Shopify App CLI has some commands, for instance, that can only be run inside your app project directory. The error message you get in that case is: “You are not in a Shopify app project.” But it also gives the user a clear path forward: “Run shopify create project
to create your app.”
This simple example illustrates the experience we want to create across the tool: error messages should be forks in the road, not dead ends.
5. Don’t speak for others
Under the hood, the Shopify App CLI relies on hundreds of existing open-source libraries. Many of those tools are themselves command-line interfaces that may in turn print their own outputs to the command line. It’s neither practical nor desirable to intercept and re-interpret all those messages, and often they contain valuable information that the user might need.
As with our rule about success and error messages, if everything’s going well, then we try to keep the noise to a minimum and don’t show highly verbose success messages. But if one of those tools deeper in the stack is running into trouble, we let it scream.
"As with our rule about success and error messages, if everything’s going well, then we try to keep the noise to a minimum and don’t show highly verbose success messages."
We’ve included a design touch intended to let users know whether it’s the Shopify App CLI itself having the problem, or a sub-process. Sub-processes, when they’re outputting text to the screen, do it inside a frame, which is our way of indicating that we’ve called on some other program which is doing a job on the Shopify App CLI’s behalf.
For instance, the tool uses git to clone a repository of boilerplate code. It installs dependencies. It runs a tunnel to your local development environment using ngrok. By showing these programs as “sandboxed” in these frames in the command line output, we can more easily track down errors if there’s a problem.
You might also like: GraphQL vs REST: How One Shopify Partner Increased Performance and Reliability.
6. Help users help themselves
Clear, concise help text becomes especially important in an all-text interface, since there are no visual markers to indicate which tasks are available or require attention. Command line tools typically print help text directly to the terminal, illustrating how to use the various commands, and the Shopify App CLI is no different.
Broadly speaking, we once again take the same approach as success and error messages: if you typed the command correctly, the tool says nothing and does what you asked. If there was some sort of error with the command—it was incomplete, for example, or misspelled, or called an unsupported option—then we immediately output help text for that command. Users can also request more detailed help text by using “help” as the verb:
shopify help generate
shopify help deploy
We use a combination of color and indentation to keep the help text consistent and quickly scannable. The extended inline help docs also include example commands that illustrate common real-world use cases. The goal of these examples is to help people build their general understanding by observing specific commands and variations.
For instance, when running shopify help generate
, one of the example commands demonstrates how to add a single, specific webhook:
shopify generate webhook PRODUCTS_CREATE
Most users probably aren’t looking to add this particular webhook to their app. But they can easily abstract this example and understand that running shopify generate webhook COLLECTIONS_CREATE
will behave consistently. It only takes one or two examples to grasp the general principle at work.
Constraints can lead to clarity
The Shopify App CLI is an open-source tool in active development—we’re still working toward making these ideals a reality. Having developers, designers, and content strategists work together on a product with a text-only UI has been a unique and valuable challenge.
From a UX content and design perspective, the command line is the most austere environment most of us have ever worked in: a black void with a single blinking cursor. But these constraints also force the design process toward focus and clarity. Sometimes it feels like putting on X-ray glasses to look through the interface, straight to the functionality within. We can’t wait to see how Shopify app developers put that power to use.
What are your thoughts on the Shopify App CLI? Share in the comments below.