Improve developer experience with a good CI/CD pipeline
Developer Experience (DX) is an important thing you should care about as a manager or a leader of the team. Try all the ways you can to make your developers happy, because a startup with a good DX is a highly productive startup. There are many ways to improve it and one of them is to have a good CI/CD pipeline.
I recently lead a small team on a side project, we're building a SaaS product using Laravel for the backend and React.js for the frontend. Even though we're just a small team of a few people, I decided to spend a couple of hours automating the deployment.
1. How it was
In the beginning, we decided to not do anything fancy, just focus on building an MVP that works. So when somebody wants to deploy a new version, he just simply:
- Access to the server
- Git pull
- Restart the node
Well, simple enough. We're all happy with that. But after some time, when we get more and more commits, we feel very difficult to deploy a new version for QA to test it.
For example, the QA team found 3 bugs belonging to 3 features, they assigned that bugs to 3 diference developers. Then the developer fixed the bug, we have to deploy it for the QA team to test again before merging. What should you do in that case? We will:
- Deploy bug #1 -> wait for QA to test -> if it is good then:
- Deploy bug #2 -> wait for test -> then:
- Deploy bug #3...
And every time a developer wants to deploy something to the dev server for testing, he needs to ask the channel if anyone is using dev server or not.
So as you can see, we have a bottleneck here, the development process become so slow. We decided to make it faster by implementing a good CI/CD pipeline.
2. Frontend pipeline
This is the part I want to automate the most, imagine sometimes the designer said: "move the button to the left 2px", changing the CSS will take me only 2 seconds, but then the deployment will cost me a lot more time, I really hate it.
Back a few years ago, there were no fancy tools for this kind of automation, I have to write a ton of codes to just automate this shit (like write a bash file to ssh to the server and run npm run build
then npm run start
,...etc,..). But nowadays, we have hundreds of services to help us do that easily. And my choice this time is Vercel because our frontend is using Next.js frameworks which are maintained by them, so of course their CI/CD supports Next.js out of the box.
Now when a developer push a new commit to any branch, Vercel will deploy a new version to a new URL. It will also comment that version's URL to the PR or the commit so the QA team can easily see & test it without asking developers.
3. Backend pipeline
For the CI/CD of the backend side, we're using CircleCI to help us build docker images and automate the test on every commit. The configurations of the CI part of CircleCI are pretty easy, you just need a simple config.yml to let it build images on every commit, the documentation has an example for that. The CD part is more interesting, below are something that we customized for our specific needs:
3.1 Deploy multiple apps to a single server
This is not something fancy, but it's worth mentioning. Previously, our dev server was only able to run 1 site on a server because we were not using Docker for the Laravel app (we used Nginx as a web-server and mapped the default domain to /public
path of the app).
Now after creating Docker images, we are able to run multiple containers in the same server easily, each container will be mapped to a different port, and in Nginx config, we use the proxy module to map each domain to the correct port. So now, we have dev1.site.com
, dev2.site.com,
dev3.site.com
,... all are running on the same server, saved a lot of money for servers haha LOL
3.2 Auto trigger dev deployment by Git tags
In the config.yml of CircleCI, we defined a workflow that looks like this:
So if developers want to deploy a commit, they can just add a tag like this: deploy-dev1-fix-abc
. The string "deploy-dev1" will let CircleCI know that this commit should be deployed to dev1
domain. The job's definition looks like this:
The special thing here is that we use $CIRCLE_TAG as a param to pass to deploy_dev.sh
script. The sh script is located on our server, which will use tag name to decide which one it should deploy to.
3.3 Deploy to Production by "Approve approach"
Deploy to Production need to be more careful than to Dev server, so you should not trigger it automatically by a Git tag because you will get a mistake sometimes. So what we did is only deploy the master branch to Production server if the lead engineer click to "Approve" button on CircleCI interface. The configuration of the workflow is simply like this:
Now, a commit that is pushed to master
branch will be built and on hold until the lead developer approves:
4. Results
As I said before, DX is an important part of an engineering team, improving it will also improve the productivity of your team, and having a good CI/CD pipeline will help your team improve DX a lot. As a result, after a while of using the new CI/CD pipeline, we work so much more efficiently, QA team doesn't have to wait for deployment, developers don't have to ask for permission to deploy, and also save a lot of time by not deploying manually anymore. Everyone is happy (until the build failed haha)