At the beginning of the year, we started working on an exciting project: N1-Headache. The company has created a product to help migraine patients keep a diary of their healthy and migraine days. N1-Headache analyzes all the data tracked by users and sends them suggestions on what their migraine factors might be.
The team already had a working version of their iOS application, and they wanted to build an Android application as well. Here is an overview of the most important features they wanted us to implement:
- Onboarding questionnaire.
- Track all the factors for a day.
- Display different reporting for patients to understand the effects of the factors they tracked.
- Configure patients medications and custom factors to later use in the questionnaires.
Starting a project from scratch, we discussed with the N1-Headache team to use Kotlin instead of Java. They were already in the process of moving their iOS code from Objective-C to Swift, so we agreed on using Kotlin for the Android app given how Swift and Kotlin share some core ideas like the usage of higher-order functions, null safety, more descriptive types like generics and structs/data classes.
We also adopted some of the new tools Google is working on within their Jetpack ecosystem, specially Lifecycles, Data Binding, Room and Constraint Layout. Besides, we followed the classic clean-ish architecture that lets us test our solutions in-depth!
One of our most important functional requirements was that most of the app had to work with no internet connectivity, that's why most of the code relies on a cache system built on top of the Android shared preferences and Room. Besides that, we wanted to have a pipeline to automatically execute our linting tools, start the emulator, and run all our tests every time a new feature was ready to be merged. Not only that, we wanted to have feedback early with every iteration, so we made the deployment of new betas automatically by merging our code to a specific beta branch. We managed to do it with the help of Fastlane, Bitrise and Google Play Console.
Let’s review the early feedback topic more in depth because I think it's crucial for the development of any software nowadays and I think the effort of having your software tested beforehand and to have a back and forth feedback loop between you, the developer, and the company that is hiring you, is vital for the success of the project. For that to happen, you need to be able to show your progress on a regular basis. That’s why as part of our methodology we release a new internal beta version every week, including a description of what was new on the app. We also had a short planning session every week prioritizing and evaluating the following steps that we shared with the rest of the team.
Given how strong the visual aspect is in the application we invested much time in creating UI tests:
- Functional UI tests with Espresso. Making sure some particular items were (or weren't) present in the screen using test doubles to replace production code and be able to simulate different scenarios.
- Screenshot tests. Taking a screen capture of the application in a particular scenario and storing it in the repository to later verify that it hasn't changed by mistake. This strategy uses test doubles too.
For the latter tests, we made heavy use of Shot, a library that takes those screenshots and compare them in test time generating a full HTML report that we used to nail down bugs and design issues.
That wasn't everything we tested, we also covered our whole API layer using mockwebserver and testing our client behavior by controlling the responses we sent from the fake server. We also tested our domain with no 3rd party lib involved to check that we captured the business rules correctly, and finally, how some of the most critical features we developed worked with a real database. If you want to read about our testing approach in mobile applications you can read our posts and katas on the matter:
- World class testing development. One, Two, Three and Four
Another critical issue we had to address was that CI builds were very slow given the number of tests we wrote, especially in the later stages of the development. We had to create different lanes for screenshot tests and non-screenshot tests (including functional UI tests written with Espresso, integration tests and unit tests) and run them in parallel. We were able to do it thanks to Bitrise and their new integration with Firebase Test Lab. With this solution, we were able to run all tests in a flexible time again!
Finally, we already wrote a post with some of the problems we faced and how did we solve them while using Kotlin, you can read more about it here.
The good news is that you can now see and download the application by yourself in the Play Store!
If you need to develop any similar product and you need help, we'll always be happy to review your project needs and try to find the best way to create the platform your users are going to love! Contact us at firstname.lastname@example.org