Skip to content

Latest commit

 

History

History
204 lines (159 loc) · 10.7 KB

STYLE_GUIDE.md

File metadata and controls

204 lines (159 loc) · 10.7 KB

Style Guide

Mission statement

The AWS Copilot CLI prioritizes human experiences over machines. We value a consistent user experience across commands. This means that similar things should be done in similar ways, but that dissimilar things should be done in different ways.

Command grammar

Commands follow the style "noun verb" or only "verb". For example, app ls or init. The noun represents an entity and should be singular. Command names are lowercase words or acronyms (no hyphens, colons, underscores).

We don’t nest commands beyond a single level. If you want to add an additional noun under an existing command, create an additional command and use flags instead. For example, adding a service to an app should be svc init --app <name> instead of app add svc.

Typical command structures are:

  • Showing an individual resource: copilot [entity] show [identifier] [options]
  • Listing all resources: copilot [entity] ls [options]
  • Creating a new resource: copilot [entity] init [identifier] [options]
  • Updating a resource: copilot [entity] update [options]
  • Deleting a resource: copilot [entity] delete [identifier...] [options]

Input

Arguments

The rule-of-thumb is to use at most one argument per command. Commands with positional arguments introduces additional cognitive load to the user as they have to remember the order of the arguments.

A command should have an argument when there is only one required input for it. For example, app init [name]. All other inputs are present as flags as they're optional. The argument’s name should be obvious to the user. If there is any possible confusion, the long description of the command should bring clarity on what the input represents.

The exception to the rule is if you want to write a bulk command, where the type of the arguments are the same and their order doesn’t matter, such as copilot env delete test-pdx test-iad.

Flags

Flags are used when you need more than one required input of different type or if the inputs are optional. Every flag needs to have a description and should use full sentences. All flag names are lowercase and the same across commands. Long flag names can use hyphens if necessary to disambiguate.

Flags can also have a single character short name such as env init -n MyEnv -a MyApp. Required flags must have a short name, only provide a short name to an optional flag if you think it will be frequently used.

Optional flags must have a default value. We want users to have the freedom to execute complex operations, but by providing sane defaults we reduce the cognitive load to accomplish a task.

Prompting

Prompt the user for any required flag that the user did not provide a value for. Prompting is a human-friendly way of showing options: prompt

Don’t prompt the user if a flag value was provided to enable scripting. Prompts should be written to stderr. Highlight the important words in a prompt by bolding and italicizing the words.

Deleting and modifying production resources

Any command that deletes or acts on a production resource should prompt the user to make sure they want to proceed with the action. The flag -y, --yes should be present in these commands to skip confirmation.

Autocomplete

Command names and flag names should be autocompleted using the keys.

Use full sentences

Guidance text for the user must use full sentences, begin with a capital letter, and end with punctuation. For example, the description for env init is “Creates a new environment in your application.” and not “creates a new environment in your application”. Similarly, when we prompt the user for additional information, we use full sentences.

Stdout vs. Stderr

The console displays text written to both stdout and stderr. However, when you pipe the output of one command to another, only stdout is passed over. Any data that can be used as input to a subsequent command should be written to stdout. All other information should be written to stderr.

Typically, for listing or showing a resource we write a table to stdout. For mutation commands, we write the prompts and diagnostic messages to stderr and at the end write the id of the resources created to stdout.

Screen sizes

By default most terminals default to 80x24 character screens. Break your sentences such that they don't go beyond 80 characters in a single line. Otherwise, new line breaks might be oddly placed in screens of varying sizes. While displaying progress, don't show more than 24 lines at a time. Otherwise, the cursor won't be able to move above 24 lines and you'll have truncated progress events.

Output

Colors

We use colors to set highlights — catching the user’s eye with important information. We do not use color as the primary means of communication. Running without color support should not meaningfully degrade the UX. For categorical data we use distinctive colors.

Common categorical data are debug, info, warning, success, failure messages. We respectively use white, default, yellow, bright green and bright red for these messages. For highlighting user input, use cyan. For highlighting created resources, use bring cyan. For highlighting follow-up commands, use bring cyan and wrap the text with the back quote character (`).

Data

Commands that perform “read” operations should write their results to stdout.

If the data can be in a table format, make sure it's grep-parseable. Display data in a human-readable format (friendly numbers, singular vs. plural, no ISO). Commands that output tables should provide a --json flag and other possible formats like --yaml to display the raw response in JSON/YAML format.

$ copilot env ls
test-pdx
$ ecs env ls --json
{"environments":[{"app":"appName","name":"test","region":"us-west-2","accountID":"123456789012","prod":false,"registryURL":"","executionRoleARN":"arn:aws:iam::123456789012:role/buildspec-test-CFNExecutionRole","managerRoleARN":"arn:aws:iam::123456789012:role/buildspec-test-EnvManagerRole"}]}

If the command can listen on updates, then provide a --follow flag.

List commands

For list commands like app ls, env ls, and svc ls, prefer formatting the output in a table. Include the name of the resource in the first column, and useful contextual metadata in additional columns. In general, prefer less information in list commands, as the amount of data shown grows with the number of entities being listed and can quickly become overwhelming.

$ copilot svc ls
Name                Type
--------            ---------------------
kudos-api           Load Balanced Web App

Show commands

For show commands, like app show, env show, and svc show, include as many details as is useful, but try to logically organize the information into sections. In those sections use whatever format makes the most sense - tables for data that will have multiple rows, or key/value for non-row-based data. In the example svc show call below, the command has three logical sections: About, Configurations, and Routes. 'About' uses a key/value layout to describe the svc, while 'Configurations' and 'Routes' use tables, as that data varies by environment.

copilot svc show
About
  Application       ecs-kudos
  Name              api
  Type              Load Balanced Web App

Configurations
  Environment       Tasks               CPU (vCPU)          Memory (MiB)        Platform          Port
  test              1                   0.25                512                 LINUX/X86_64      80

Routes
  Environment       URL                                                              Path
  test              ecs-k-Publi-1Q9VOJGS3OQG1-100102515.us-west-2.elb.amazonaws.com  *

Prefer high-level summaries in show commands, rather than comprehensive views. Hiding less frequently useful data behind flags helps to not overwhelm users.

Progress

Commands that perform actions (mutations) should write their updates to stderr. Non-instantaneous operations must provide a signal to the user that it’s not stuck and still making progress on the task.

Use a spinner with a short text for short processes less than 4 seconds.

For long operations, use a spinner and display sub-tasks with status updates if the operation is going to take more than 4 seconds. Prefer listing all sub-tasks up front. task-progress

Otherwise, display them sequentially over time. sequential-task-progress

Recommended actions

Commands that are missing prerequisites should suggest other commands to run prior to invocation. For example:

$ copilot svc init
✘ could not find an application attached to this workspace, please run `app init` first

Commands that perform actions successfully should suggest additional steps to follow. For example:

$ copilot svc init -n frontend -t "Load Balanced Web Service" -d ./frontend/Dockerfile
✔ Success! Wrote the manifest for service frontend at 'copilot/frontend/manifest.yml'

Recommended follow-up actions:
- Update your manifest copilot/frontend/manifest.yml to change the defaults.

Errors

Failure messages should be written to stderr.

✘ Failed! could not create directory "copilot": no permissions

Wrap external dependency errors to display errors as: {what happened}: {why it happened}

Acknowledgments

Thanks to the following resources for their inspiration: