Developers working on the same project often have wildly different workflows, based on how they like to work and the tools they are familiar with. Despite that, there are usually a few common tasks that everyone has to do.
If we compare the flow state of writing software to Mario speeding through a level in Super Mario Bros., then development tools provide the stable bridge above the fiery pit that allows Mario to safely navigate through the complex castle that is his project.
To stay in the flow state, engineers must avoid the pitfalls that come with interactions across the systems that make up a development environment, such as source control, testing, linting, and code review tools. When all goes well, an engineer happily skims across the surface of these tools and repeats the process. As any engineer will tell you, this is sometimes easier said than done.
Over time, engineers here at Slack developed their own individual workflows for getting things done. The slack-cli project was born when we decided to take some of our ad-hoc shell scripts and package them together in a tidy way. Offering up a shared set of tools had a number of benefits:
- It let new engineers focus on getting up to speed with their new projects, not messing around figuring out how various systems fit together.
- It helped everyone stay in the flow and focused on their tasks at a higher level.
- It reduced the amount of edge-case “stuff” floating in developers’ brains from day-to-day (“ugh, where do the log files live again?”).
- Improvements made by one person made everyone’s work easier.
In some cases, this process is not much more involved than sharing common terminal aliases and scripts. In other cases, many individuals have riffed on a tool over time to support complex use cases. Overall, the goal was to reduce friction in a developer’s work day wherever possible.
Why build tools?
A good rule of thumb for a development tool is this: if a developer has to stop what she’s doing and open a browser window for the next step in her work, then that task is a good candidate for building tooling around.
Is it because engineers ought to do everything from the command line? No, but the internet is a veritable Candyland for the monkey mind, filled with delightful distractions that are unrelated to your current work. Slack wants to enable employees to do the best work of their lives, and providing a focused environment through tooling reinforces that value.
Having a place for tools to live opened up all kinds of interesting possibilities. Once we had a structure in place that made it easy for people to add new commands, we started to see the tool get used in both expected and unexpected ways. Here are some of the less obvious uses:
- Syncing files between developer machines and remote servers every time a file is saved.
- Distributing canonical SSH configurations from our ops team to engineers’ laptops.
- Automating installation of common git and bash configurations.
- Helpers for working with git — creating branches that are cross-referenced with our internal bug tracker, for example, or reverting Pull Requests with a single command.
- Tools for generating fake data on development servers or fixtures for writing unit tests.
- Displaying a random Beyoncé GIF, because you never know when you need some inspiration.
The slack command
Here it is, in all its glory: we created a single command-line executable called slack. It works very similarly to the git command line tools:
- if you run slack foo, it looks for an executable slack-foo located in the same directory as the slack command (passing along any additional command line parameters, of course).
- If you just run slack by itself, it prints out a list of all of the slack-*executables in the same directory as itself.
This strategy makes it easy for people to add new commands (just create a new script called slack-whatever), and it keeps things neatly separated. This lets us avoid stepping on each other’s toes and reduces the cognitive overhead of adding new commands.
The tools are installed in /usr/local/bin by a plain old Makefile. This means we don’t have to rely on people having the slack-cli code checked out on their computers, and we don’t have to fiddle with people’s $PATHs. Once the tools are installed, they just work.
To keep the tools up-to-date, we’ve created … a tool! slack update-tools will check out a fresh copy of the slack-cli git repository in your temporary directory, run make install, and clean up after itself.
Making it easy to update tools has helped ensure that people are generally up-to-date, and pushing out an important change is as simple as posting a “Hey, run slack update-tools because…” message inside the relevant channel on Slack.
Roll your own tool with magic-cli
We’ve found this pattern so helpful that we’d love to share it with the world. We’ve open sourced something called `magic-cli`, a general version of our tool. Check out the magic-cli repository on GitHub to get started.
This repository provides the basic command runner, with support for running subcommands located in the same directory as itself. You can rename the main executable from magic-cli to anything you want — if you work for Example.com, you could rename it to example and add custom commands like example-test, and everything will just work. We hope you find it as useful as we have.
This endeavor has created a new social group inside of Slack, allowing for cross-pollination across teams. slack-cli gives new hires a low-effort way to contribute, and their fresh perspective is invaluable for helping us remove friction. Such gaps in tooling are often overlooked, and fixing them is important as engineering organizations grow.
Are we really saying that someone can come in on day one and improve the day-to-day development process for the entire engineering team? Yes, we are! Which brings us back to why we’re here at Slack in the first place: to collectively make our working lives simpler, more pleasant, and more productive.