Continuing from my previous post about migrating to Kotlin, I want to talk about the architecture to accommodate it since we are rethinking everything.
First, we need to decide how we will rewrite the existing code base in Kotlin. I used Java to Kotlin migration tool that Intellij IDEA has. It is useful for getting things started. It renames the files and gives us a glimpse of how the code will look. The next step is fixing everything that it will break because it will break a lot of things. After finishing that, I started reading about Jetpack Components since they are the main reason we are migrating anyway. The same pattern (which I didn't use) was prominent everywhere, and it was heavily relying on Hilt, Room, Repository Pattern, and ViewModel. So before making any other change, I needed to learn more about these.
I have had a few library dependencies separated from the source code because I thought I would write another Android application sharing the same DNA. However, that never happened, and trying to overhaul the core, I moved them back into the source code.
I also had a database implementation that dates back to 2018. I could have gotten rid of it immediately in favor of Room. However, I wanted the project to keep building because making a graceful switch was only possible if I established the base structure for other components at that level of complexity.
Now that we have everything ready, it is time to remodel the codebase. I realized that following the separation of concerns principle is not a choice if I wanted the project to evolve. Creating a complex structure over something fluid as Android Support Libraries will only increase the time to move to something else. So, I started dissecting my
ListFragment implementation that supports
RecyclerView and works very well but assumes how the deriving UI element will look and what it will need. Sorting, ordering, filtering, and similar functionalities were there by default, and the items that it will list required to be in a format that it uses. This type of design limits what can be displayed on a particular UI and makes the development harder because not all UI types need the sorting or filtering functionality.
If a particular UI needs filtering, then it is the UI's job to implement it. This understanding gave me the freedom to have a fragment not deriving from my custom
ListFragment class, which also handles the loading of content, which we can easily do using
Lifecycle components and Kotlin coroutines.
I moved away from the assumption that the UI will look in a particular order. The UI can have a different structure, but the data source can stay the same. That meant going with MVVM (model-view-modelview). If the UI can be free of limits when dealing with data and if the latter can do the same, you can alter any of the parties and still have both sides functioning.
Following the MVVM design pattern also means inserting Repositories and ViewModels* between views and models, enabling us to create unique UI structures using existing components.
To understand the concept and Jetpack Components better, I read some blog posts and got the impression that a fragment doesn't have to do everything. I can create as many fragments as needed so that different scenarios can take place. To avoid more work while doing this, I learned to work with dependency injection with Hilt. I realized I was already trying to achieve the same structure: moving background tasks to the Application class and requesting them by casting
getApplication() to my application class type. I could have just used Hilt, and it could inject dependencies into my activities, services, or fragments.
Also, DataBinding is another component that I am going to rely on heavily. With the dummy fragments all over the place, it can significantly reduce another overhead.
Now that I found the ideal design pattern for my project, the only thing left to decide is how to move threads to coroutines.