Kotlin Migration @ Pepperfry: Part Two — Process
This is the second part of a 3 part series on Kotlin migration undertaken for the Android app at Pepperfry. This migration included the move from Java to Kotlin along with the move from MVP to MVVM architecture.
In the first part, we discussed the motivation behind our migration:
In this part we will be discussing the process behind our migration: setup, modular approach, inclusion of test cases & weekly knowledge sharing sessions.
Setup
At first, we laid out the foundation of the new architecture creating base classes for Fragments & ViewModels. We also created extension functions for Image loading, String validations, etc.. Our app contains one activity and multiple fragments. Some of these fragments have common functionality like displaying a loading dialog, showing a toast, displaying a snackbar, checking if the user is logged-in, etc.. All of this was moved to a KBaseFragment
. The existing (Java)BaseFragment
had a lot of complex legacy code which was not migrated completely to the Kotlin KBaseFragment
.
Networking
Networking is at the heart of any Android app. We set out on cleaning our networking layer first. Originally our REST API calls were driven through OkHttp and Gson. We added Retrofit with it’s reactive adapter to the existing toolchain.
Our API calls return a particular status code for us to display a toast, snackbar or a dialog. For this, we created an extension function to extract base errors from our network Single
. Through the BaseVM
and KBaseFragment
, base error cases like network errors, authentication errors & server errors were automatically handled for each API call.
Modular approach
With a base and some extension functions in place, we started with the migration. As mentioned previously, we identified smaller independent modules which could be migrated in isolation. These were chosen to allow the team to learn and refine the planned architecture. Each member on the team picked up a module that they had previously worked on and started migrating it to Kotlin and MVVM. This helped them build the code around all the edge cases they knew and also clean up their code better.
All new features were written in Kotlin with MVVM. The entire Gift Registry feature of the Android app was built using the newly laid out architecture. We were able to deliver the feature in record time and it performed very well after deployment to users, enhancing our confidence in the new architecture.
Unit testing
Due to the limitations of the previous architecture (mentioned in the previous article), we could not test our business logic. This was one of the issues we set out to solve with the Kotlin+MVVM migration. For this, our ViewModel
objects were built with dependency injection in mind, to allow mocking during tests. This allowed us to isolate them and test the business logic inside them.
Adding unit tests helped us find out bugs early in the development cycle. There were multiple times we were updating our functions to handle edge cases identified while writing tests. We were also more comfortable making changes to the code when business requirements altered. We used Robolectric and Mockito to build our test cases.
Knowledge sharing
One of the most important aspects of the migration was that everyone on the team was learning new things every day. To make knowledge sharing among the team smoother, the senior team members held weekly knowledge sharing sessions, where everyone from the team would share Kotlin insights, tricks and extensions they had created. This was in addition to the existing code-review mechanism of the team.
This process helped us immensely as it ensured everyone was on the same page and mistakes were not repeated, which helped made the migration smoother.
In the 3rd and final part, we discuss our learnings from the migration. We also discuss how the migration benefited millions of our happy users.