As Okode grows, one of our top priorities has been to make our developers happy. Their mission is to create great applications focusing on what they do best: coding. All tasks related to construction, static analysis, packaging, signing or publishing in app markets must be automated to optimize their time and to remain focused on their work without distractions.
Adjusting the parameters and configuration of the continuous integration server becomes a crucial activity, where our engineers must balance costs, average construction times and development of support utilities for CI seeking optimization and continuous improvement.
Today we build more than 100 builds / day reaching production directly from CircleCI.
The results, when done well, bring a clear benefit to the organization and to the productivity of our software engineers which makes them, ultimately, happier coders.
Continuous Integration at Okode
Historically in Okode we have used continuous integration and deployment tools based on Cloud services. Services such as Jenkins or Travis CI have been crucial to initially define what our task workflows should look like based on each type of application developed. Creating a Cordova-based hybrid App that is published in the App Store is not the same as an Angular-based SPA Web site that is published in AWS S3 / AWS Cloudfount. And yet, both the App and SPA workflow share similar activities such as TypeScript code transpiling, static analysis, unit testing and e2e and WebPack packaging.
As more applications are developed in Okode, the need to align and orchestrate the construction of each one in a similar way becomes more evident, which has recently led us to develop even our own CLI!.
After evaluating different alternatives currently we have migrated all of our construction workflows to CircleCI because:
- Allows us to use Linux nodes (vm or containers), use custom Docker images and build macOS for iOS.
- Supports creating complex workflows for testing and building, with multiple parameterized conditional stages.
- Allows access via SSH to a building node for debugging.
- It is possible to install additional tools, SDKs and toolchains to the building nodes when necessary.
- It’s very fast (incredibly fast!) finding a free node to start building.
- Allows to share the workflow configuration in small snippets of .yml code called Orbs that can be reused between projects.
Agile Development Requires Fast Builds
Any commit, however small, needs to be validated by the continuous integration environment. Our developers publish hundreds of commits a day, integrating changes that evolve our customers’ applications to incorporate new functionalities into the main branch of development (usually develop
when we use GitFlow).
Instead of running a full build of the application, which in many cases requires building on several platforms (iOS / Android), packaging, signing and sending to beta distribution channels such as Fabric, TestFlight or Google Play Alpha, we prefer to make a fast build performing the following tasks in parallel when possible:
- Optimized build for production
- Static analysis
- Unit testing
- E2E testing
What we are looking for with this strategy is fail as soon as possible when it is detected that some of the metrics of code quality don’t pass. That is, we complete a fast build as quickly as possible so that the developer can fix errors detected as soon as possible and publish code changes to SCM to, again, launch a new fast build.
Only in case it is necessary to deliver a full new version of the application in a user testing environment (preproduction) or publishing for end users (production) is it when a more complete multichannel build workflow (iOS, Android, desktop Web) is made with packaging, signing and sending the bundles to the distribution channels.
Reusing Configuration Using CircleCI Orbs
When creating multiple mobile Apps, many of them based on the same technology, it became clear at Okode that it was necessary to have a building configuration reuse mechanism since most of them are all built in a similar way.
For example, for most our npm-based projects it is necessary to initially download the dependencies using npm install
. However, since CircleCI supports cache between constructions, it is preferable to try to download the node_modules
folder of a previous compatible build (as long as the dependencies have not changed, for which the md5 of the package-lock.json
is calculated and compared) and if it is still necessary to install them, the operation is done with npm ci
so there is no need to recalculate transitive dependencies and optimize their download.
All this process can be stored in an yaml snippet like following:
cache-key-npm: &cache-key-npm key: cache-npm-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Environment.CIRCLE_BRANCH }}-{{ checksum "package-lock.json" }} executors: node: docker: - image: circleci/node:12 commands: npm-install: description: Run npm install steps: - restore_cache: << : *cache-key-npm - run: name: Installing NPM dependencies command: if [ ! -d "node_modules" ]; then npm ci; fi - run: name: Restoring package-lock.json command: git checkout package-lock.json - save_cache: << : *cache-key-npm paths: - node_modules
CircleCI allows to register configuration files in the Orbs registry so that they can be shared between different workflows or between different organizations:
There are more sophisticated examples where for some of our customers it is necessary to initiate a VPN connection to an AWS VPC so that the generated artifacts are stored in private binary repositories. These are some examples of common commands that typically need to be reused in different application construction workflows at Okode and that it is possible to share as an Orb in the CircleCI registry and import it into the .circleci/config.yml
of each application that needs them.
Continuous Delivery: From GitHub to App Store / Google Play
How many builds can be made of an application and published for production? Well, it is true that the number is limited by the maximum frequency that the distribution channel can support (App Store for example requires an average time of Apple validation between 1 or 2 days before publication). However, this is not something that affects Web SPA applications or Cloud serverless services or microservices of a Kubernetes cluster. For these cases it is perfectly possible to reach production in seconds after the last git push
command from a developer.
At Okode all our applications are automated to deliver to Google Play / App Store directly from CircleCI. Which is the same as saying directly from GitHub after the creation of a tag by the developer.