A Great Local Development Environment is not a Nice-to-have, but a Must-have

I always think a great local development environment is the foundation of building great software. When the local development environment is slow, inconsistent, complicated, and even buggy, it’s hard to expect the software to be built with high quality…


This content originally appeared on Level Up Coding - Medium and was authored by Jingjie Zhan

I always think a great local development environment is the foundation of building great software. When the local development environment is slow, inconsistent, complicated, and even buggy, it’s hard to expect the software to be built with high quality.

Photo by Christopher Gower on Unsplash

In the past, I have joined industry-leading companies that took me days, weeks, or in one case, a month to get the code working on my computer so that I could start to work. In the process, I had to install a bunch of software and tools, run one script after another that I barely knew what they did because they were very long. And one single mistake caused me days to debug.

Has this occurred to you before?

Today the post will focus on how to create a great local development environment for building microservices.

Introduction

There are several important goals of a great local development environment:

  • Extremely easy to start: one command to run
  • Fast rebuild/rerun: < 2 seconds
  • Consistent: same environment across different machines
  • Easy to understand: minimal build scripts

The goal of this post is to provide one solution that intends to satisfy all of these requirements.

We are going to use this very simple Golang service. What it does is to return “Hello world” when going to localhost:8080. We are using Golang in this case, but the techniques mentioned in this post can be easily applied to other languages. The GitHub link to the repo will be at the end.

Step 1: Make it easy and consistent

It’s important to have the mindset that developers are customers. How do you want your customers to have the best experience when working on the codebase? Some of the not-so-good experiences are:

  • Installing many tools and software
  • Running one script after another
  • Taking forever to build the code
  • Finding out the code that works on other people’s computers doesn’t work on yours, or the other way around

The solution to fix all the above is using Docker containers.

Photo by Guillaume Bolduc on Unsplash

Docker container is a lightweight virtualization technology that’s the de facto standard for building and sharing code. In this case, Docker is:

  • Easy to start: No need to install things locally, like the programming language, or various packages. All of them are baked into the Docker image.
  • Consistent: Same environment everywhere.

Here’s the Dockerfile for containerizing the above Golang service.

This makes use of Docker multi-stage build. It makes it easy to use the same Dockerfile for both local developments, and also for building a production-quality Docker image.

There are two stages here. Only the first stage, named “builder”, is used for local development. The second stage is for putting the Golang binary into a much smaller image, alpine, which is faster and safer for production distribution.

Step 2: Make it fast

The main concern people have when building and running applications in Docker containers is speed.

Most people think the Docker’s overhead cannot be overcome. However, Docker is very flexible, when you use Docker in a specific way it can achieve native speed.

Photo by Macau Photo Agency on Unsplash

Here’s a benchmark that was tested on my machine for the three approaches to build and run the Golang service, and averaged over 3 times.

  • Native build+run: run “go run main.go” directly on the computer. No Docker.
  • Non-optimized Docker build+run: run “docker build” and “docker run” with the above Dockerfile.
  • Optimized Docker build+run: it leverages 3 techniques 1. Docker multi-stage build that I mentioned above 2. rebuild inside the Docker container 3. Docker bind mount
Native build+run: 0.49s
Non-opimized Docker build+run: 2.69s
Optimized Docker build+run: 2.56s the first time, 0.21s the second time and after.

The non-optimized docker build+run is more than 5 times slower than the native build+run. No surprise.

The optimized Docker build+run is only slow for the first time, but for the second time and after it’s even faster than the native speed! Surprise!

Other than Docker Multi-stage build, there are two techniques that help drive down time the most.

Rebuild INSIDE the Docker container

docker run -t name-of-service

The -t flag is the most important technique, and a rather less documented one, that makes 10X the difference in build speed. What it does is preventing the container from exiting when running in the background.

This enables us to rebuild the Golang service INSIDE the container, which eliminates the most time-consuming Docker activities: 1. rebuilding the docker image 2. creating a new container based on the image, and 3. connecting to the container.

It makes it possible to simply issue commands to the container. For example:

// Build and run the Golang service.
docker exec -it helloworld-service go run /go/src/app/main.go

I was inspired by this post:

Tips & Tricks for Making Your Golang Container Builds 10x Faster

Docker bind mount

docker run --mount type=bind,source=$(shell pwd),target=/go/src/app

The bind mount enables Docker to use the files directly in the local filesystem, without copying them into the container each time.

This has the added benefits that if there are some auto-generated changes from your code, they will be reflected in the local filesystem.

Step 3: Make it convenient

So now we have a local development system built on top of Docker that’s fast. Let’s make it more convenient to use. Because you don’t want to type a long Docker command each time. A simple Makefile can help.

# Build and run the Golang service
make run
# Run all the tests
make test
# Stop and remove the containers
make clean

Here’s the link to the GitHub repo with all the code.

zhanjingjie/hello-world-service

Thank you all for reading this. If there’s one lesson to take away, it is that it’s not easy to build a production-quality local development environment. It might seem easy given the few lines of code, but the road to the solution was less than obvious.

This post drills into only one area of building a production-grade microservice, but there are much more. You can check out my previous post:

Build production-grade Microservices

I’m working on a mission to help engineering teams and engineers move faster with production quality. To learn more, please check out:

Production Code | BasePlates


A Great Local Development Environment is not a Nice-to-have, but a Must-have was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Jingjie Zhan


Print Share Comment Cite Upload Translate Updates
APA

Jingjie Zhan | Sciencx (2021-02-23T13:42:38+00:00) A Great Local Development Environment is not a Nice-to-have, but a Must-have. Retrieved from https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/

MLA
" » A Great Local Development Environment is not a Nice-to-have, but a Must-have." Jingjie Zhan | Sciencx - Tuesday February 23, 2021, https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/
HARVARD
Jingjie Zhan | Sciencx Tuesday February 23, 2021 » A Great Local Development Environment is not a Nice-to-have, but a Must-have., viewed ,<https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/>
VANCOUVER
Jingjie Zhan | Sciencx - » A Great Local Development Environment is not a Nice-to-have, but a Must-have. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/
CHICAGO
" » A Great Local Development Environment is not a Nice-to-have, but a Must-have." Jingjie Zhan | Sciencx - Accessed . https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/
IEEE
" » A Great Local Development Environment is not a Nice-to-have, but a Must-have." Jingjie Zhan | Sciencx [Online]. Available: https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/. [Accessed: ]
rf:citation
» A Great Local Development Environment is not a Nice-to-have, but a Must-have | Jingjie Zhan | Sciencx | https://www.scien.cx/2021/02/23/a-great-local-development-environment-is-not-a-nice-to-have-but-a-must-have/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.