At Capmo we are continuously searching for new ways to improve our product development process to be more agile, inclusive and to support different work modes, sync as well as async. This article describes how we tackled a particular problem we encountered as soon as we had more than one person on the team working on our web application — the problem of design and product management not being able to give feedback on multiple increments being worked on in parallel early in the process when having a limited amount of environments to deploy to.
Our starting point
We started off having three separate environments for our web application, development, staging and production. This is a fairly standard setup as seen in many teams. We used to merge commits for new increments directly to our development branch which was directly tied to our development environment — every commit would trigger an immediate deployment (we use CircleCI for that). This setup works well as long as the team is small, working synchronously and closely together. As we grew, and we got more than one person on the team working on work items in parallel, we noticed certain drawbacks: our development environment started to become a digital version of the wild west, multiple things being crumbled together, leading to confusion, broken deployments and reduced clarity. We found ourselves continuously overwriting things as we go and a certain communication overhead coming with that. After all, we needed new code running somewhere such that PMs and designers could check out and review new things as they were built, without the need of standing next to an engineer’s computer while they present their work. At this point we started discussing about switching to gitflow as our primary workflow for development, yet we weren’t quite satisfied with the added complexity it brings to our otherwise nice and simple workflow — having master tied to staging and production and having a single branch per feature/task/bug. Plus, this wouldn’t actually have solved our problem to a degree we would have been satisfied, as new increments ending up on the development branch would be likewise hard to review and prone to get messy. Please note here that we try to ship as early and as fast to production as possible (using feature toggles), hence introducing some lengthy review cycles we didn’t like either.
Zooming in on the problem
After some discussion, we figured that the sole bottleneck in this endeavour is the mere fact that we had only three environments where our web application was running. If we would have more environments, the problems we were seeing would be a lot smaller. We cycled through different options we’ve read other teams are using: one environment per engineer, multiple environments to share, but all of that comes with trade-offs and limitations in one or the other form, being it communication overhead or something else. Going back and forth, we came to conclusion that the ideal solution would be to have infinite environments running the same time.
Branch deployments for the rescue
Luckily, we were already using Zeit 2.0 to deploy our web application to our three environments at the time. Zeit 2.0 has a quite neat feature: it allows to deploy web apps to individual serverless environments without deleting or overwriting the previous one. Rather, once a new environment has been created successfully, one simply uses aliases to bind new deployments to domains such as app.capmo.de. Since they are serverless, they only produce costs as soon as content is served, so it’s easily feasible to have many of them running in parallel.
Within our CI we then configured a job, which simply runs on all branches except master to create a new Github deployment, compute a dynamic subdomain based on the branch name and an alias. Such a domain could look like some-awesome-feature.dev.capmo.de whereas one needs to configure a wildcard CNAME entry for dynamic subdomains (*.dev.capmo.de).
To create a new deployment inside Github, use the following snippet. Please note that we run on CircleCI, so some constants might not be available when using a different CI. The following gist illustrates parts of our workflow.
Well, that’s it actually. It’s really simple and easy to do, comes with almost zero additional costs and enables a variety of process improvements since designers, PMs or testers can access new increments as they are actively being built in an async manner, before pull requests are merged. To make things more accessible for the rest of the team, we use Github’s API to create deployments for each PR, linking the newly created environment directly to each pull request.
Ultimately, we are quite happy with the approach, integration took only a couple of hours (less if we would have had a guide) and it still runs as part of our daily business at no additional cost providing fast and early feedback loops to improve on quality later in the process. We strongly believe that this increases overall speed/quality ratio and allows us to deliver high quality in a shorter amount of time.
Side note — branch deployments can also be used for some last minute validations or testing before things are being shipped as they are shareable with people outside the product team as well.
Stay tuned for more articles on closing the gap between engineering, design and product management. We are currently building the same workflow for our mobile application, aiming at a similar experience as compared to our web application.