Skip to content

Instantly share code, notes, and snippets.

@PratyushSingh07
Created August 25, 2024 18:00
Show Gist options
  • Select an option

  • Save PratyushSingh07/6509549e64dbee0d695b98c6657a17b2 to your computer and use it in GitHub Desktop.

Select an option

Save PratyushSingh07/6509549e64dbee0d695b98c6657a17b2 to your computer and use it in GitHub Desktop.



GSoC'24 Final Report - The Mifos Initiative | Functional Enhancements to Mobile Wallet for G2P Use Cases


Contents

Pre GSoC

  • Before GSOC 2024, I continued my work on the Mifos Mobile project, where I was deeply involved in various aspects of Android development. My contributions spanned across different areas, including the implementation of Jetpack Compose for modernizing the UI, refactoring the project's architecture to align with the latest best practices, and performing comprehensive code refactors to enhance maintainability and scalability. Additionally, I took charge of setting up the project, ensuring that the development environment was optimized for efficiency and collaboration. My work on Mifos Mobile laid a strong foundation for further development, allowing the project to evolve with a cleaner and more modular codebase.

  • Following my involvement in Mifos Mobile, I expanded my contributions to several other Mifos projects, notably Mifos Passcode and Mobile Wallet. In these projects, I played a crucial role in driving the adoption of Jetpack Compose, further refining the architectural patterns, and improving the overall code quality. My efforts in these areas were not limited to just implementation but also involved strategic planning and problem-solving to address the unique challenges posed by each project. Whether it was optimizing user authentication workflows in Mifos Passcode or enhancing the transaction handling capabilities in Mobile Wallet, my focus remained on delivering robust and user-friendly Android applications that meet the high standards expected by the Mifos community. Through these experiences, I gained valuable insights into Android development and honed my skills in managing complex, multi-faceted projects within the open-source ecosystem.

Work Accomplished

MVP to MVVM

  • Before 2024, the Mobile Wallet project followed the Clean Architecture pattern with the Model-View-Presenter (MVP) design. MVP was instrumental in separating concerns within the app, where the Presenter acted as an intermediary between the Model and the View, managing the business logic and updating the UI accordingly. This structure facilitated testability and allowed for a more modular codebase. However, the reliance on the Presenter sometimes led to challenges in maintaining the code, especially as the app grew in complexity. The Presenter often became a bottleneck, accumulating responsibilities that made the code harder to manage and extend.

  • As the project evolved, a decision was made to transition from MVP to Model-View-ViewModel (MVVM) while still adhering to the principles of Clean Architecture. MVVM brought several advantages to the Mobile Wallet project. The ViewModel, unlike the Presenter, does not hold references to the View, which reduces the risk of memory leaks and makes the architecture more resilient. This change also allowed for better separation of concerns, with the ViewModel handling UI-related data and exposing it to the View through observable patterns like LiveData or StateFlow. This approach not only enhanced the testability of the code by enabling more straightforward unit tests for the ViewModel but also improved the responsiveness and scalability of the application.

MVVM

  • Throughout this transition, the SOLID principles played a critical role in ensuring that the architecture remained robust and maintainable. By adhering to the Single Responsibility Principle (SRP), each class and component in the MVVM structure had a well-defined role, which reduced the chances of any single class becoming too complex. The Open/Closed Principle (OCP) allowed the system to be extended with new features without modifying existing code, making the app more adaptable to changes. The Interface Segregation Principle (ISP) and Dependency Inversion Principle (DIP) ensured that the various layers of the architecture remained loosely coupled, which further enhanced the flexibility and testability of the codebase. This adherence to SOLID principles, combined with the shift to MVVM, positioned the Mobile Wallet project to be more sustainable and easier to manage as it continues to grow and evolve.

Xml to Compose View

  • The Mobile Wallet project initially relied on XML for UI development, a traditional approach that required separate codebases for different platforms like Android, desktop, and web. This method, while effective, often led to inconsistencies across platforms and increased the development effort. However, the project has since transitioned to using Jetpack Compose, a modern toolkit that allows developers to build UIs with a single codebase that can be deployed across multiple platforms. This shift has significantly simplified UI development, as Compose's declarative approach enables developers to write and maintain less code while achieving more consistent results. By unifying the codebase for Android, desktop, and web applications, Compose has enhanced productivity and ensured that the user experience remains consistent regardless of the platform.

  • One of the standout advantages of Jetpack Compose in the Mobile Wallet project is its ability to streamline UI development through a single, cohesive codebase. Unlike XML, where different layouts and UI elements needed to be managed separately for each platform, Compose's declarative syntax allows developers to define the UI once and apply it across various platforms. This not only reduces the likelihood of discrepancies between platforms but also speeds up the development process, as changes made to the UI can be propagated across all platforms simultaneously. This cross-platform capability of Jetpack Compose has made it an invaluable tool in the Mobile Wallet project, as it ensures that users enjoy a seamless and consistent experience, whether they are using the application on their mobile device, desktop, or web browser.

  • In addition to simplifying cross-platform development, Jetpack Compose has enabled the creation of a Design System Module within the Mobile Wallet project. This module acts as a library of reusable UI components that can be easily plugged into different parts of the application. By leveraging this Design System, developers can maintain a consistent visual language throughout the app, ensuring that all UI elements adhere to the same design principles and guidelines. This plug-and-play approach not only accelerates the development process by reducing the need to reinvent the wheel for each new feature but also enhances the overall user experience by providing a cohesive and polished interface. The combination of Jetpack Compose and the Design System Module has thus transformed the way the Mobile Wallet project approaches UI development, making it more efficient, consistent, and scalable.

Multi Modular Approach

  • In the ongoing effort to optimize the Mobile Wallet project, we have strategically broken down the application into four higher-level modules: build-logic, core, feature, and mifospay. This modular architecture allows us to better organize and manage the complexity of the application. The core module serves as the backbone of the project, housing essential components like network communication, UI elements, and analytics functionalities, among others. By centralizing these fundamental elements, the core module ensures that critical infrastructure is consistently applied across the application, promoting a more reliable and streamlined development process.

  • The feature module is dedicated to encapsulating all the individual features and screens of the wallet application. By isolating each feature within its own module, we can develop, test, and maintain features independently, reducing the risk of cross-contamination between different parts of the application. This separation also allows for more focused and efficient development, as teams can work on specific features without affecting the rest of the application. This modularity is particularly beneficial when scaling the application, as new features can be added with minimal disruption to the existing codebase.

  • Finally, the mifospay module is where app-level logic resides, including crucial components like the Navigation Host and AppState management. This module acts as the central hub that ties together the various features and core functionalities, ensuring a cohesive user experience. The advantages of this modular approach are manifold: it has significantly enhanced code organization, making the codebase more navigable and easier to manage; it has improved build times by allowing for more efficient compilation processes; and it has promoted reusability and maintainability of the code by enabling developers to reuse components across different parts of the application and easily update or refactor specific modules without impacting the entire system. This modular architecture has thus played a pivotal role in the ongoing success and scalability of the Mobile Wallet project.

Hilt to KOIN

  • Migrating from Hilt to Koin in a project involves rethinking how dependency injection is managed, shifting from a more annotation-based approach to a more programmatic one.

  • To successfully migrate to Koin, certain libraries need to be included to replace Hilt's functionality. The koin-android library is essential for setting up Koin in an Android environment, providing the necessary components to inject dependencies into Android-specific classes like Activities, Fragments, and Services. This library also handles lifecycle-aware components, ensuring that dependencies are injected and managed in alignment with the Android lifecycle.

[libraries]
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koinComposeMultiplatform" }
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" }
  • For projects that aim to leverage Koin across multiple platforms, the koin-compose and koin-compose-viewmodel libraries come into play. These libraries enable Koin to be used in a multiplatform context, supporting dependency injection within Compose and ViewModel layers across Android, desktop, and potentially other platforms. This flexibility is a significant advantage for projects that target multiple environments, allowing for a consistent and reusable dependency injection setup.

  • The migration to Koin also involves refactoring classes that manage shared preferences, such as the PreferencesHelper class. This class would need to be adapted to use Koin for injecting dependencies like SharedPreferences, rather than relying on Hilt's annotation-based injection. By moving to Koin, this class can become more flexible, as dependencies are defined programmatically, making it easier to adjust and extend the functionality as the project evolves.

  • Overall, migrating from Hilt to Koin requires careful planning and a good understanding of Koin's architecture. However, the benefits—particularly in terms of code readability, flexibility, and Kotlin integration—make this transition a worthwhile investment for many projects.

Retrofit to KToR

  • Migrating from Retrofit to Ktor for network operations involves a series of steps aimed at transitioning from one HTTP client library to another, optimizing the network communication in your project. Retrofit, a popular HTTP client for Android, provides a straightforward API for making network requests and handling responses. Ktor, on the other hand, is a more modern, Kotlin-native HTTP client that offers greater flexibility and integration with Kotlin’s coroutine-based concurrency model.

  • In the context of your existing project, updating the :core:network module involves several key steps:

    • Replace Retrofit Implementation: Within the :core:network module, locate and replace all Retrofit-related code with Ktor equivalents. This includes updating service interfaces to use Ktor’s HttpClient calls.

    • Update Dependency Injection: If your project uses dependency injection (e.g., Hilt or Koin), ensure that Ktor’s HttpClient is properly injected into your repositories or data sources instead of Retrofit instances.

    • Refactor Networking Logic: Review and refactor any custom networking logic or utilities to be compatible with Ktor. This might involve adjusting how requests are made, responses are handled, and errors are processed.

    • Test the Integration: Thoroughly test the new implementation to ensure that Ktor integrates seamlessly and performs as expected. Pay close attention to edge cases, error handling, and compatibility with other parts of your application.

      Network

Project Cleanup

  • After breaking down the project into distinct modules, we undertook a significant cleanup of the codebase to align with this new architecture. This process was meticulous, requiring us to carefully analyze and restructure the code without losing any critical logic. The objective was to eliminate redundancy and ensure that each module functioned independently while still contributing to the overall system. This cleanup was essential for maintaining the integrity of the application as we transitioned to a more modular structure, ensuring that the codebase remained efficient and manageable.

  • One of the key aspects of this cleanup was refactoring the existing navigation system to adopt Navigation Compose. The previous navigation approach, while functional, was becoming increasingly cumbersome as the project grew in complexity. By switching to Navigation Compose, we were able to streamline the navigation logic, making it more intuitive and easier to manage within the modular framework. This refactor not only simplified the process of navigating between screens but also improved the overall maintainability of the code, as Navigation Compose offers a more declarative and flexible way to handle in-app navigation.

  • Additionally, we removed feature packages that were previously housed within the mifospay module, redistributing them to their respective modules. This transformation was crucial for fully realizing the benefits of our modular architecture. By relocating these feature packages, we ensured that each feature was encapsulated within its own module, allowing for better isolation and independence. This change not only reduced the size and complexity of the mifospay module but also made it easier to manage, test, and deploy individual features. Overall, this cleanup and restructuring process has resulted in a more organized, maintainable, and scalable codebase, setting the stage for future growth and development.

Impact

  • The impact of the changes and improvements made to this project has been profound, influencing multiple aspects of development, maintenance, and user experience
    • Enhanced Code Organization and Maintainability: By breaking down the project into four higher-level modules (build-logic, core, feature, and mifospay), you've significantly improved the organization of your codebase. This modular structure has made it easier to manage and navigate, allowing developers to focus on specific areas without getting bogged down by the complexity of the entire project. The modularity also enhances maintainability, as updates and bug fixes can be applied to individual modules without risking unintended side effects elsewhere in the application.

    • Improved Development Efficiency and Build Times: The transition from XML to Jetpack Compose has streamlined UI development, allowing you to maintain a single codebase for Android, desktop, and web applications. This has not only increased productivity by reducing the amount of code that needs to be written and maintained but also ensured consistency across different platforms. The adoption of Navigation Compose further simplified the navigation logic, contributing to more efficient development processes. Additionally, by refactoring the codebase and removing unnecessary feature packages from the mifospay module, you've optimized build times, making the development process faster and more responsive.

    • Scalability and Reusability: The creation of a Design System Module in Jetpack Compose has promoted the reuse of UI components across different parts of the application, enhancing consistency and reducing duplication of effort. This, combined with the modular architecture, has made it easier to scale the project as new features can be added with minimal disruption. The modularization also supports better testability and isolation of features, allowing for more reliable and efficient testing and debugging.

What more can be done?

  • Looking ahead, I see a significant opportunity to further enhance our project by implementing Compose Multiplatform for an end-to-end solution. This would allow us to extend the benefits of Jetpack Compose beyond Android, enabling us to build and maintain a single codebase that works seamlessly across Android, iOS, desktop, and web platforms.

  • By adopting Compose Multiplatform, I could streamline development even further, reducing the need for platform-specific code and ensuring a consistent user experience across all platforms. This approach would simplify maintenance and updates, as changes made on one platform would automatically be reflected across others. Additionally, this would allow us to leverage shared components and logic, cutting down on duplication and increasing code reuse across the entire project.

  • Implementing Compose Multiplatform would also future-proof the project, making it easier to adapt to new platforms and technologies as they emerge. As the demand for cross-platform applications continues to grow, embracing this strategy would position our project at the forefront of modern development practices, ensuring that it remains competitive and relevant in an increasingly diverse digital landscape.

Conclusion

  • In conclusion, the strategic decisions and architectural changes implemented in your project have led to substantial improvements in both the development process and the overall quality of the application. The transition to a modular architecture has provided a more organized and maintainable codebase, allowing for easier management and scalability. The adoption of Jetpack Compose, along with the shift to Navigation Compose, has modernized the UI development process, improving consistency across platforms and enhancing productivity. By refactoring and optimizing the code, you've also achieved faster build times and better reusability, setting the stage for more efficient development in the future.

  • These changes have not only addressed the immediate challenges of managing a complex codebase but have also positioned the project for continued success. The emphasis on SOLID principles and modular design ensures that the application remains adaptable and resilient as it evolves. Ultimately, these improvements have created a more robust, scalable, and user-friendly product that is better equipped to meet the demands of both developers and users alike.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment