With the release of Flutter 2, the framework gained the unprecedented feature of running on every major platform. Flutter was already our go-to technology for developing solid apps on iOS and Android, without having to code the same app twice. With Flutter 2, an app can be compiled for iOS, Android, Windows, macOS, Linux, web browsers, cars, and TVs from a single codebase. Or at least that’s the promise. We decided to put Flutter 2 to the test and build a cross-platform prototype. As a bonus, since this is an imaginary app without NDA, we can be fully transparent about all details during the development.
The use case for our little demo app was inspired by a friendly coffee truck called A Lot Of Mies that is right outside our office every now and then. Wondering where to get coffee on other days, we thought of how great it would be to have an app that could locate food trucks and other traveling cuisine and where we could immediately order our coffee or food for pick-up. Hence, the idea for fdtrck was born.
Phase 4: Deploy automation
It’s no secret: developers love to automate things. Why do stuff manually, when you can have computers do the work for you? This might sound rather lazy and frankly, that is part of it (more time to play with the office dogs, amiright?). However, we would like to focus on other benefits of automating, such as security, stability, and speed.
From backlog to production
How does a new feature end up in a production app? For this, we always roughly follow the same process (there are a few flavors depending on the specific project). First of all, our code is version controlled, meaning we can create, compare and merge different ‘versions’ of the codebase (called commits, organized in branches), and - in the case we made an oopsie - revert to any earlier version. One of these versions is the current production version. All versions are stored in the repository.
So, the developer takes a ticket from the backlog (that is dev-lingo for picking up a task from the todo list). The developer then creates a copy of the code and starts working on it. Whatever changes they make, we have to integrate this with the existing code, meaning we have to make sure it still works when we combine the new and current code. The goal of integration is to deliver new code versions to the repository and it usually takes a few iterations for a new feature to be perfected. If the code builds and all tests have successfully passed, we can merge the new changes.
We take one or multiple integrated changes and merge them into one version that we want to release. There are QA processes etc. in between that we won’t discuss now. First, we test if everything still works as it should in the final version. This code then has to be made ready for deployment, which in the case of fdtrck means we have to make a production build for every platform we want to deploy to. Then those builds can be sent to the production environments (i.e. the app stores and the webserver).
There are different deployment environments:
- Development: just for internal testing. This environment is more often broken than working. We also sometimes have multiple of these environments running.
- Staging: here we test if stable versions are really stable. Usually, this is where the changes are accepted by our clients or a product owner.
- Production: the real deal. Where users log in, App Store reviews are written and sensitive data is processed.
From manual to continuous
Of course, the integration and deployments can be done manually, and in some cases, this needs human intervention. But wouldn’t it be cool to automate? Yes, that would be cool. And it’s not something we’ve made up ourselves: automated integration and deploys are widely used and commonly known as Continuous Integration and Continuous Deployment (or CI/CD). CI/CD tries to minimize the manual work involved with integrating or deploying projects.
Here’s why CI/CD is cool:
- Speed: This is a no-brainer. A scripted deployment is simply faster than a developer. It also allows deploying more often, so no need to save up a bunch of fixes and features for a single deploy day.
- Stability: Computers outperform humans at executing the exact same tasks consistently over and over again. Humans, particularly at the end of the workday, tend to forget a step or mix something up. Also, computers start from scratch with a clean environment every time, so you don’t get problems from previous versions leaking into your next deployment.
- Security: If most work is automated, fewer DevOps engineers need access to the production environment, providing extra security. It is also possible to check at every deployment (or even every integration) on possible vulnerabilities in the packages we use.
CI/CD in fdtrck
For fdtrck we used two very important systems for our CI/CD pipelines. The first is Gitlab (a recent Dutch unicorn), where we manage our code and do QA. For the automated deploys, we work with Bitrise. For other projects, we also work with Gitlab for the deploys, but in the case of apps, we need an Apple environment to create iOS versions. Something which Bitrise solves seamlessly for us.
Ideal to work with when you want to give some work out of your hands, Bitrise. A different service that keeps the servers up to date for you. Bitrise makes it easy to work with by making a step-by-step plan that you can change and make yourself. First, copy the code, build and upload to the App Store and Playstore. If your knowledge about CI/CD is limited, Bitrise will probably be a good match. Bitrise manages your signing keys so you don't have to store them separately. You can make it so they are downloaded from a secure server and copied into your folder, and then proceed to make Bitrise sign your builds for you. By dividing team roles, eventually results in better security, you can choose who has access to different apps where they should have access. By using workflows, it’s easy to find and fix errors before pushing it to the App Store and Play Store. Bitrise takes work out of your hands, efficient and noob friendly we might say.
Particularly when working on code with multiple developers, integration of the new code can create a lot of overhead. By working with automated integration and deployment scripts, which include an abundance of automated tests, we make sure we can deliver fast, reliably, and securely.
CI/CD is actually so good, we dare to deploy on Fridays.