“It works for me” Getting developers up and running on a new team is a challenge that every company faces. This challenge is magnified when you are in a small startup with limited resources to provision computers that satisfy all of the developers’ current and future needs. Furthermore, as the startup grows, new team members join and new use cases arise, requiring additional tools to be installed, while also keeping old tools up to date. In the best case, you’ve had the foresight to write scripts using ansible or puppet that can provision a machine from scratch and update software packages on existing machines; in the worst case, each developer is responsible for maintaining their own development environment, having to be careful of what packages they install and how these packages may conflict with other packages. Eventually, it all converges on a simple conversation:
Alice: “Hey, Bob, the latest version of <the product> is broken.” Bob: “That’s weird; it works for me.” “It works for me.” These four words will lead to two developers wasting hours figuring out the slight difference between their two development environments, preventing Alice and Bob from getting their work done. Did Alice forget to run the previous update script, causing the current update script not to work? Did Bob use an API from version 2.0 of a library, but Alice only has version 1.0 installed? Or does Alice have version 3.0, which no longer has the API? Did the previous version work? Or was the breaking change introduced two weeks ago, and Alice just realized it? Finally, and most importantly, how do they get their machines into the same state so that they can both continue their work? Apex.AI was once a small startup with limited resources–five people in a stuffy, white-walled room reminiscent of that one Silicon Valley episode– and we wanted to avoid becoming Alices and Bobs. Thus, the Awesomely Agile Apex.AI Development Environment (ADE) was born–we’ve never really agreed on what the A stands for, though– and even though we are no longer a small startup, we continue to use and improve it. A common, consistent, and reproducible development environment ADE (pronounced [ey]-[dee]-[ee]) is a modular Docker-based tool that ensures all developers in a project have a common, consistent development environment. In other words, ADE leverages Docker containers as a way to create a reproducible development environment, simplifying the process of getting new developers up and running. The idea of using Docker as a development environment is not unique [1] [2] [3], but ADE works in such a way that developers do not need to have any knowledge about Docker to get started: ade start starts the container, ade enter enters the container, and ade stop stops the container; anything that should persist between restarts (e.g. a repository clone, log files, etc.) is kept in the home directory, which maps to a directory on the host. Once inside the container, developers have the correct version of development tools and third-party dependencies installed and ready to use, and they can launch editors and IDEs such as Atom, VSCode, and CLion. Best of all, if the developer wants to try out a tool (or update to a newer version of a library), they can install it, knowing that rolling back will simply require a restart of ADE (ade stop and ade start, or ade start -f). Alternatively, if the new tool proves to be useful, making it available to the rest of the team is as simple as updating the Docker image, an update which other developers can then download with ade start --update. Ensuring that the update does not break the build is a topic for its own blog post describing how ADE integrates with our Continuous Integration (CI) pipeline.
Some terminology For the rest of the blog post, it is worth making a distinction between ade-cli, the ADE image, and ADE. ade-cli is a command line tool that provides the commands ade start, ade enter, and ade stop. ADE image is the Docker image which ade-cli uses to create a container; this image needs to be built in an ADE-compatible way and is project-specific (e.g. ADE is used in the Autoware.Auto project). Finally, ADE refers to a container started from the ADE image with ade-cli. The new developer only needs to have knowledge of ade-cli, learning about ADE image as needed.
ADE for Docker power-users While ADE was developed with the average developer in mind, it does not hide away Docker; ADE allows anyone with knowledge of Docker to leverage features that are not provided by ade-cli out of the box. For example, when working with real sensors, developers need to mount USB devices, open ports, or use custom network configurations to be able to get data to their application. Instead of writing complicated (and limited) wrappers around native Docker commands, ade-cli allows using native Docker commands to make these devices available inside the development environment. Moreover, the .aderc configuration file allows the power-user to use these custom arguments as the default arguments. ADE for customer support Every release of Apex.OS* is created with a corresponding ADE image. By versioning ADE images alongside Apex.OS*, we enable customers and our support team to work in the same environment; even months after a release, our support team is able to quickly load the customer’s environment to provide timely and accurate feedback. Thus, while customers are not required to use ADE to run Apex.OS*, we strongly encourage it during development. Getting started with ADE If you want to take ADE for a test run, look at the Autoware.Auto project. To start using ADE in your project, read more about how to create your own images and configurations in the ade-cli documentation. Stay tuned for a future blog post, where we’ll add more A’s to ADE–and talk about how ADE integrates with our CI pipeline.
*As of January 2023 we renamed our products: Apex.Grace was formerly known as Apex.OS, and Apex.Ida was formerly known as Apex.Middleware.