A Guide to a Modern Android App — Part 1: Modularization and Architecture

Marcello Galhardo
Quandoo
Published in
4 min readNov 2, 2018

“Architecture is about intent, not frameworks.” — Uncle Bob.

Building a quality software is a complex task. This isn't just a matter of satisfying the business requirements. The software needs to be robust, easy-to-maintain, testable, and flexible to adapt to the various changes that an agile team needs to face.

In this series of posts, I will walk you through planning and refactoring of a modern Android application built for a large-scale user base.

In Part 1: Modularization and Architecture I will introduce you to the Quandoo App, and give you an overview of our approach to convert it into a modern and powerful app using Clean Architecture and multi-modules.

What is the Quandoo App?

Quandoo is an app for discovering new restaurants and for tables reservation, with more than 17,000 eating/dining places in 12 countries worldwide to choose from.

What you need to know about the app is: the home screen displays a list of cuisines and the restaurants nearby. On a tap, you can access more details. Feel free to explore our app in the Play Store or App Store.

Quandoo started as a monolithic module that was split through packages. Now we decided to convert it into a multi-module application using the Settings screen as a Proof of Concept:

The Settings Screen

Splitting an Application

We followed Google's instructions to create a base module that will be used as the foundation for all the other modules. We named this module "core" and moved all our codebase into it.

After that, we extracted the code related to the Settings screen to a different module that depends on the core. Here’s the result:

The Project Modules

To finalize, we created a Router class whose job is to invoke a module Activity through intent and a valid URL.

The Module Structure

Our module structure is strongly inspired by Florina Muntunescu’s presentation Shaping Your App’s Architecture with Kotlin and Architecture Components at Kotlin Conf 2018 in Amsterdam.

Module Structure

Data Layer

The Data package is responsible for abstracting all the source data that our module uses. The package sends requests to APIs, saves entities in the databases, and creates cache strategies. We heavily depend on the following libraries:

Data Layer

Domain Layer

The Domain package is responsible for the business rules of our module. It contains our Models and Use-Cases.

  • Models are Data Classes that represent our Domain.
  • UseCases are a single, atomic, and stateless object that represents a method.
  • We use RxJava and Lce: Load-Content-Error to return results from the Domain to the other layers.
Domain Layer

Presentation Layer

The Presentation package is responsible for presenting the data, animations, lists, and for interacting with the Android Framework. We use the Model-View-ViewModel and the Navigator pattern.

  • The ViewModels uses the Architecture Component.
  • The communication between our ViewModel and Fragment is accomplished through LiveData instances.
  • The Navigator encapsulates navigation logic as fragment manipulation and activity intents.
  • The Activity is an entry point to the module.
  • A Fragment represents a screen; a module can have multiple screens.
  • We use CustomViews as reusable components of our UI.
Presentation Layer

Testing a Module

“Code without tests is broken as designed .”— Jacob Kaplan-Moss.

As for the tests, we opted for the following structure:

Conclusion

Our main goal is to be able to modularize the project without impacting the user experience and to keep shipping the updates to our users, with the goal to support features such as App Bundle and Dynamic Delivery as soon as possible. As a result of the modularization, we are improving the separation of concerns, defining better limits to our features, and making the feature dependency clear.

The final structure of our module looks like this:

The Final Version of a Module Structure

References

--

--