Under the hood of the first insurance In-Car app
“The beginning is the most important part of the work.” — Plato
When Plato uttered these words, he probably was not thinking of software development and how start-ups operate to be able to quickly finish a prototype to be the first ones to hit the market. Nevertheless, there lies some related wisdom in those words that are applicable for today’s fast-paced agile world.
When development started on the Polestar in-car app we were more or less a start-up within an enterprise, wanting to develop the world’s first insurance in-car app for the newly launched Android Automotive platform. Which meant cutting some corners in order to reach a solid MVP.
As of January 2022, we can proudly say that we achieved that goal. However, there will be an increasing spotlight on us to keep delivering new high-quality features to our customers and at the same time be able to quickly adapt to the ever changing business landscape.
That’s why with support from management we took one step back and had a look on how we can lay a technical foundation where we can feel comfortable to stand on. As a team we want to focus on innovation and delivering features instead of constantly squashing bugs and fighting against cross cutting concerns such as execution context, navigation, logging, analytics, etc.
Let’s pop the hood!
When you first launch the Polestar Insurance app you are presented with a home view where you can see a list of available features within the app. For the MVP everything was developed within the standard app module that you get when creating a new Android project. But going forward we wanted to have a technical strategy to be more flexible when scaling the application in terms of feature growth and brand theming.
The first step would involve in breaking up the app module into multiple modules. The app module would act as a container and be responsible to “glue” the application together in terms of dependency injection, remote service configurations, etc. In terms of UI, it would only contain the home screen that would have the sole purpose of dynamically loading up the different features of the app depending on country and brand configuration.
This structure would yield in each list item being translated to its own feature module. Besides the sources, the module has its own internal navigation graph for the different views.
Each feature module follows Uncle Bobs CLEAN architecture. The reasoning for choosing CLEAN as an application architecture besides being referred to in Google’s “Guide to app architecture”, was mainly because we apply it on our backend services and a developer can switch between working on the backend and frontend to some degree seamlessly and be familiar with the structure. Also, due to Androids complex testability issues, the architecture facilitates the ability to increase testability of the application when having a clear logical split in these onion layers, as Uncle Bob would say.
We believe that with this kind of module structure in-place we can really focus on our core goal of being innovative. Having separate feature modules gives us the flexibility and confidence to experiment in isolation without affecting other areas of the app. A new feature module could be put behind a remote feature toggle and could enable us to perform some A/B testing. Depending on the feature, we might only do a partial rollout so we could gather some insights before rolling out the functionality on a wider scale.
As for the presentation architecture we have chosen to go with Googles recommendation of MVVM and that is what the team had the most experience in and there is plenty of resources online that would aid us in troubleshooting certain issues that one might run into. Even if we have chosen to go with MVVM on the presentation layer, thanks to the modular feature structure, we have the possibility to experiment with some other MVx architecture such as MVI. If we feel that some other design pattern could give us additional benefits, we might transition to that one instead.
Another example of where we already see a benefit with having the features broken down into separate modules, is that even if we are still using the good old xml layouts for our views, we have been considering doing a proof of concept with Jetpack Compose in a new upcoming feature and evaluate if this is something we might make as a standard going forward.
As mentioned previously, the app module loads the features dynamically depending on configuration, but we have also the requirement to make the application adhere to a certain look and feel depending on the brand. In order to solve this, we have an additional Resources module that contains all colors, dimensions, strings, etc. By using flavors, we could easily solve that challenge by “theming” the application by overlaying these resource files. Changes done on the Resources module, would then propagate throughout the application.
Android Automotive has given us as an insurance provider new possibilities and channels to reach and interact with our customers in a more hands on experience and be there for assistance in any unfortunate event. However, there are some technical challenges due to the platform being rather new and documentation is rather lacking. Developing and trying to research about automotive specific APIs is a bit difficult and the community has not become so established yet. The upside is that we can set quite a high minimum SDK level (29) and have only a handful of device screens to consider.
However, we are blessed that it is a brand-new project. We don’t have to consider or deal with legacy code, and we can leverage the latest libraries for our development such as Dagger Hilt for dependency injection, Android Jetpack for simplifying Android development, Retrofit, OkHttp and Moshi for remote service requests and additionally, everything is written in Kotlin!
Going back to Plato, we have put a lot of effort now in the beginning to address certain issues that we feel will pay us back in the future upcoming sprints. But with all that said, we have only begun our journey. The architecture we have chosen to go forward with still has its rough edges, but it is all a continuous learning experience where we want to keep up with the latest that is happening and to be able to stay active in the game.
The focus on this article has mainly been on the frontend experience and technical challenges of the in-car app but we are also in the middle of a similar journey with our backend services where they are also evolving to handle new business capabilities and requirements but that is a story for another time.
As we started with a quote from Plato, it would be suitable to end it with one as well that describes what lies ahead of us.
“Success is not final. Failure is not fatal. It’s the courage to continue that counts.”
— Winston Churchill