Managing Development Shells (devshells)
In the remaining chapters of this book, we're going to begin improving the
foundation we laid in the previous chapter. We've already gained a lot by
integrating std
into our example Rust project, but there remains significant
room for improvement.
So far, we've seen that std
has a lot to offer in terms of bringing
organization to our Nix-infused repositories. In addition to organization, std
also brings with it many quality-of-life improvements. We're going to
investigate the first one in this chapter: development shells.
Works on My Machine
At the risk of beating a dead horse, this section will be a brief review of why development shells are needed and the benefits they provide to almost any project. Perhaps the most iconic words used to address this issue are:
Works on my machine!
Indeed, this single line has led to a plethora of innovations to address the lack of reproducibility that has defined the last decade of software. Many technologies have risen to tackle the issue, but Nix stands as one of the oldest technologies aimed specifically at tackling this problem.
The main solution Nix employs to tackle reproducible development environments is
nix-shell. We used this command in the last chapter to quickly enter a shell
environment that had the std
binary available. This command has further been
refined by receiving support in the official flake schema. With
flakes, it's now possible to define an entire reproducible development shell
which will include all necessary tools to work on a given project. The idea is
simple: if you want to contribute to a project, load up the development shell
and start making changes. The net result is a dramatic reduction in
system-dependent problems and a smoother contribution experience for a project.
Devshell
The wonderful individuals at numtide have taken the idea of development shells and accelerated productivity even further. The numtide/devshell project builds upon flake-based development shells by adding several quality-of-life features that further improve upon a developer's experience. These can be roughly summarized as follows:
- MOTD: A custom message of the day can be configured that appears when a user first enters the development shell. This can be useful for introducing users to a project and giving some basic instructions for getting started with contributions.
- Custom commands: Repository-specific commands can be configured to bring
uniformity to contributors. For example, a
fmt
command can be defined which runs the formatter(s) the same way they may be run in CI. - Menu: A repository-specific menu can be created that is accessed by running
menu
from the command-line. The contents of this menu are customizable and can include custom commands or other binaries that are available in the environment. - Package management: package management is made significantly easier by
allowing packages to be specified in several different locations. For example,
a custom command could be dependent on a package being available in the
environment and
devshell
will handle the dependency for you automatically.
The std
framework provides native support for integrating devshell
into our
standardized project. All that's required is a little bit of configuration on
our end and we'll be able to provide a rich development shell for contributors
to use with our example Rust project.