Developer Workspace
You want developers to be able to integrate code into the Main Line with high confidence and be productive quickly when they join a team. This pattern describes how to set up an environment consistent with other developers and with what the integration Build uses and the Main Line expects.
Working Consistently
Integrating code to the Main Line should be a low-friction process. If something works for a developer, it should pass the Integration build and also work for any other developer. This isn’t universal, and errors caused by incomplete or inconsistent development environments reduce productivity and can be costly.
You want developers to be able to set up a development environment that allows them to easily change, build, test, and run the software you are working on, and identify and fix issues quickly. Developers should be able to:
- Be productive quickly when joining a team or working on a new part of the code base.
- Build, test, and run code in a development environment and have some confidence that it will behave the same way on other developer’s machines and in integration environments, avoiding “works for me” conversations.
- Debug and fix issues related to the build process without needing to repeatedly push changes to the CI environment.
Finding (and fixing) issues in a development environment is far more effective than finding them during continuous integration or after deployment. The further away from the initial work a problem surfaces, the longer it typically takes to resolve.
To do any development, developers need:
- The Code.
- Tools and Language environments. Compilers, interpreters, build tools, dependency managers, and the like define how code works and must be consistent across every entity building and running a component.
- Library Dependencies. Every build artifact should be reproducible from what is in version control.
- The Build Pipeline: The sequence of steps to run to build, test, and deploy a system, as well as the tools that execute them.
Getting access to the code, the project dependencies, and the build scripts is a simple matter of getting them out of the source code repository. But having access to the code isn’t enough to ensure a consistent build. You also need the right versions of the right tools, and you need to have designed a consistent build process.
There are a few ways to set up the tool dependencies:
- Provide a checklist and ask developers to do their own setup; this is simple but error-prone and might take an inconsistent amount of time.
- You can compensate for errors in a manual process by adding tooling to verify that the correct tools are installed. This finds errors quickly and is valuable, but it doesn’t necessarily make fixing errors easier or faster.
- You could provide a detailed list of commands to execute. This requires less thought and addresses a lack of knowledge but can still be error-prone. Not all steps might be scriptable.
- You could provide a fully automated script; this would be easy to execute and repeatable, but tooling adds development overhead to the project, especially as you make the script more robust. And the more automated the process the more constraining it is.
- You can mandate the use of containers for development. This ensures uniformity but makes using other productivity tools, such as IDEs, challenging.
As much as you want to provide a path for uniform environments, you understand there is room for variation. Experimentation with different installation approaches enables the discovery of new techniques, though supporting alternate paths can be difficult. And there may be times when you want the team to investigate the impact of using updated or different tools, which is essential to improving the tech stack.
Once you specify the tools and dependencies, developers need to be able to build and test code using mechanisms that match the CI environment. While an IDE might make coding more efficient, the CI build typically doesn’t run in an IDE, so having a mechanism to execute the build and test cycle using the same steps, with a standard set of tools, at the right versions is essential.
You want a way to ensure that a developer has the right tools to build the application and that each application uses the correct dependencies while allowing that a developer setup may not perfectly match CI or production. You want to avoid differences that have a high to moderate likelihood of having a negative impact on your development pipeline.
As Close as Possible
** Enable processes that make it simple to create a new developer workspace that quickly allows a new developer to build and run tests and the application. The process should be as simple and reproducible as possible and allow the developer to closely follow the CI build process, and identify known variations.**
The workspace process should have the following elements:
- Easy-to-find bootstrap documentation that specifies how to find the setup tools.
- One or more set-up scripts
- Instructions on executing builds and tests for the code you are working on.
For example, a bootstrap document can specify steps like these:
- install a package manager (for example, homebrew)
- install a version management client (git)
- check out the source code
- check out the tool set up repository
- run the set up script.
The bootstrap document can start as a checklist that specifies commands to execute manually and can evolve into a script. The developer setup process should also include a verification script to confirm tools and versions. While there may be preferences among team members about variations in the process (using different package managers for example), it’s fine for the process to be opinionated:
- The goal is to provide a path to a productive workspace. Developers can explore other paths
- The verification script makes individual expiration feasible.
Once the setup has been run, the developer should be able to make a small change, run a build/test process, and push the change to the CI environment to see a passing build.
A Developer Workspace is a compromise between reproducing a standard build and test environment and ease of use. It may be impossible to match all dependencies fully, and in some cases, it’s desirable to allow for variations to allow the team to test the impact of, for example, updating a compiler version.
Extensions
While a minimal developer workspace provides mechanisms for development and unit testing comparable to what happens in a CI environment, it can be valuable to enable some level of integration testing using either containerized services or, more simply, connectivity to resources in a shared development environment. Things that may be different in a developer workspace when compared to the CI environment or deployment environments:
- Configuration Values for external services
- Configuration Values for Feature Flags
- Secrets
- Replicas of dependent systems, such as databases, etc
Cautions
Automated setup can be incremental, depending on where you are on the project. If something is easy to script, do it, but allow for incremental improvements. It’s better to have a semi-automated process that the team can improve than wait for a perfect setup.
Next Steps
A developer workspace is necessary but not sufficient for reliable testing and integration:
- A Uniform Build will help developers to get predictable results in their workspace and not be surprised by the results in CI.