Part 3: The Development Environment

If you've been following our Underneath the UI series, by now you should have a good idea of how our front-end and API stacks look. In part 3, we'll talk about eve's development environment—how we wire everything up, our daily engineering process, the continuous integration and delivery solutions we employ in-house and so on.

Local Environment

The simpler a tool or workflow is to adopt and use, the easier it is for a busy development team to get value from it. This isn’t just a nice-to-have property, it’s essential. —Lei Zhang, Head of Bloomberg’s Developer Experience group

We've all been there: our first day at a new job, so fresh and excited for all the upcoming challenges. But before anything else, we need to set up our local development environment. Let's start with installing… erm, PHP? It can't be that hard, right? Only, what version is the company using again? Should we use Homebrew, Docker, a pre-built binary package, or go for the hardcore mode and build everything from source? What extensions should be included by default? What would be a sensible ini value for upload_max_filesize? Then, what about the database? The web server, or a combination of them for that matter? The environment variables? One hundred hours and a thousand config files later, the excitement is all gone and we start questioning our career choice.

Perhaps the best thing about Laravel, our backend framework of choice, is that it's not just one single technical solution but an exhaustive developer experience. Apart from the built-in functionalities, Laravel provides a vast offering of first-party packages to aid in almost all of your business and technical needs. Want to integrate your application with payment processors such as Stripe? Pull in Cashier. Need to enable full-text search for your content? Install Scout. And to solve the local environment issue, Laravel provides Homestead, a shared dev environment solution powered by Vagrant.

Out of the box, Homestead comes with a complete set of Ubuntu, Git, multiple PHP versions, Composer, PostgreSQL/MySQL, Redis, nginx, etc. With Homestead, a fully-functional workstation is literally a single vagrant up command away:

$ vagrant up
Bringing machine 'homestead' up with 'virtualbox' provider...
==> homestead: Checking if box 'laravel/homestead' version '10.1.1' is up to date...
==> homestead: Clearing any previously set forwarded ports...
==> homestead: Clearing any previously set network interfaces...
==> homestead: Preparing network interfaces based on configuration...
==> homestead: Forwarding ports...
==> homestead: Machine booted and ready!
==> homestead: Checking for guest additions in VM...
==> homestead: Setting hostname...
==> homestead: Configuring and enabling network interfaces...
==> homestead: Mounting shared folders...

$ vagrant ssh
Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-48-generic x86_64)

 _                               _                 _
| |                             | |               | |
| |__   ___  _ __ ___   ___  ___| |_ ___  __ _  __| |
| '_ \ / _ \| '_ ` _ \ / _ \/ __| __/ _ \/ _` |/ _` |
| | | | (_) | | | | | |  __/\__ \ ||  __/ (_| | (_| |
|_| |_|\___/|_| |_| |_|\___||___/\__\___|\__,_|\__,_|

* Homestead v12.0.0
* Settler v11.0.0 (Ubuntu 20.04)

Last login: Tue Apr  6 09:51:36 2021 from
➜  api art tinker
Psy Shell v0.10.7 (PHP 7.4.11 — cli) by Justin Hileman
>>> app()->version()
=> "8.33.1"

Swift and steady. No more configuration hell. Also, since everyone has the same setup now, gone is the infamous "It works on my machine ¯\(ツ)/¯™" syndrome. One can't ask for a developer experience smoother than that, really.

Version Control and Branching Model

Like almost everyone else nowadays, we use Git (hosted by GitHub) as our version control software. Our repository is a monorepo—a repository that contains the code for several projects. As with effectively everything else in this industry, there are arguments for and against monorepos (or their counterpart, polyrepos), but we've found this approach to suit us the best—as do software giants like Google, Facebook, Microsoft, Uber, Twitter, Airbnb and others.

For branching model, instead of the popular Git flow which can be unnecessarily complex and has been discouraged by its own author, we embrace the much simpler GitLab flow catering to our setup:

GitLab flow

With this model, we maintain two long-lived branches: master, which is deployed onto staging, and production, which is deployed onto, well, production. All feature branches are created from and merged into master, which in turn is periodically merged into production. Hotfixes, due to their high-priority nature, are branched directly from production; however, they are synchronized back to master after deployment, ensuring the integrity between the two main branches.

This model has been proven to work extremely well with our continuous deployment pipeline, which we'll talk about in the next section.

Continuous Deployment

At eve, we maintain a continuous integration and deployment (CI/CD) pipeline that is at the same time powerful and straightforward, as shown in the diagram below:

continuous integration and deployment pipeline

Whenever we push our code to GitHub, a build is triggered via GitHub Actions, installing dependencies and compiling assets. Depending on the changeset, a combination of these checks (or all of them) will be performed:

Every pull request creates a deploy preview, a complete application front-and-back ready for the team(s) to review and give feedback. If any of the above checks fails for whatever reason, the build is considered to have errored, and the code is strictly prohibited from being merged into master—and as a result, production. This is one way we ensure the quality of our codebase. We also constantly review each other's work—both as code (via GitHub's PR feature) and a complete app (via deploy reviews). In addition, our tests are integrated with Codecov for us to collect and analyze the coverage, further solidifying the test suites.

When (and only when) a pull request passes all checks and receives approval from its reviewers, it can be merged into master. The merge will trigger another build and auto-deploy to our Staging environment. This environment is an almost-exact replica of our production environment—except for data and credentials for obvious reasons—and acts as a quality assurance ground. Twice a week, or four times per sprint, we trigger a production release. How do we do that, you ask? By typing these lines into a terminal:

$ git switch production
$ git merge origin/master --ff
$ git push

Three minutes later, all the fresh features, improvements and fixes are brought to our end-users. Oh, you were expecting something more fancy? Sorry to disappoint.

And That's a Wrap!

So there you have it—our last article in the first series on the technologies and practices we exercise at eve. Of course, as we are still at a very early phase of our business, nothing is set in stone. As we grow, we'll be constantly fine-tuning our processes and tools to adapt to the needs. Our core technical value, however, will always remain the same: highest-quality engineering with speedy turnarounds accompanied by the best developer experience one can ask for. At the end of the day, we want our customers to have as much fun using our products as we do building them.

Are you a developer looking forward to the best destination of your career? Our engineer positions are always open—just drop us an email at