Modular Android Project

Raka Westu Mogandhi
prismapp
Published in
4 min readAug 19, 2017

This article I wrote after successfully present it at Facebook Developer Circles #2 at Jogja Digital Valley, August 15 2017. You can see it on this slide.

This is a concept of Android development which is good to be implemented when we have multiple teams.

Do you have any idea how people develop Android application nowadays?

  1. Create project in Android Studio
  2. Android Studio generate project and files needed for initial development. It also generate a module called app.
  3. Development is only use this app module.

Is that wrong? Not at all, that’s the right way to develop a single application.

So what is this Modular Android Project concept stands for?

It’s a concept of Android development workflow when we have multiple teams working on single application.

Background

Why is this concept could be a solution to your teams ?

  • Once your application codebase is big, it becomes hard to add or just update a feature. You need to edit many files in many packages.
  • Working with multiple teams means you need to conform many implementation style. It’s just not possible to use many implementation styles in single application.
  • When we want to adapt or just trying a new technology concept on specific feature set, we may need to refactor the entire application because the new technology is not applicable on current implementation.

Solution

Have you heard of microservice concept?

Microservice is a particular way of designing software applications as suites of independently deployable services.
Source: https://nearsoft.com/blog/the-microservices-approach-and-how-it-beats-monolithics/

Do you think it can be implemented in Android project? Yes, of course. We can use Android module to apply it.

What is Android module ? It’s a component of Android project. There are two types of Android module: application and library.

  • Application module can be deployed into APK which can be run on Android device or emulator.
  • Library module cannot be deployed into APK, you need to implement it on application module so it can be deployed as part of the application.
    There are many examples of this library module. You may also have recognized it. There are Android support libraries, Firebase libraries, or third party libraries like Glide, RxJava, or Retrofit.

So, how can we decompose an application project into several modules?

There are many approach to do it. You need to consider your business needs and your teams. As far as I know we can decompose an application into several component based on features or functions.

  • Decomposition based on features means the application component should be based on its business features.
    For example we have an e-commerce application, we can divide it into several components: authentication, product, checkout, history and analytics.
  • Decomposition based on functions means the application component should be based on its functions.
    For example we can just divide an application into core (which have generic function without UI) and ui (which have UI that implements core component).

Case Study

On this part I will provide an example how to implement this modular concept on e-commerce application.

Authentication Module

Authentication module includes all user authentication related action. This module needs to have login, register, forgot password, etc.

We can define some abstracted functions to be implemented on this module.

  • Start login page → Auth.startLoginPage(ACTIVITY, LOGIN_RESULT_LISTENER)
  • Start register page → Auth.startRegisterPage(ACTIVITY)
  • Start forgot password page → Auth.startForgotPasswordPage(ACTIVITY)
  • Check if user has logged in → (Boolean) = Auth.isLoggedIn()
  • Get authentication user data → (UserID, Access Token, etc. ) = Auth.getAuthenticatedUser()

What is LOGIN_RESULT_LISTENER ? It’s a defined interface which will be triggered when login action is completed.

Product Module

Product module includes all product related action. In e-commerce application, user can see product catalog, product details, add it to favorites, see product favorites.

  • Start product catalog page → Prod.startProductCatalog(ACTIVITY, CHECKOUT_ACTION_CALLBACK)
  • Start product favorites → Prod.startProductFavorites(ACTIVITY, CHECKOUT_ACTION_CALLBACK)

What is CHECKOUT_ACTION_CALLBACK ? It’s a defined interface which will be triggered on product buy action on product details page. Because buy action is implemented on checkout module. Product module doesn’t need to know how it’s implemented, so it’s defined as an interface.

Checkout Module

Checkout module includes all buy action related action. Add items to the cart, manage shopping cart, start payment are included features.

  • Add item to cart → Checkout.addToCart(ACTIVITY, ITEM_NAME, ITEM_PRICE, PAYMENT_COMPLETED_LISTENER)
  • Start shopping cart page → Checkout.startShoppingCartPage(ACTIVITY)

PAYMENT_COMPLETED_LISTENER is a defined interface to be called when payment is completed.

History Module

History module includes transaction history page which holds any transactions done by user.

  • Show transaction history → History.startTransactionHistoryPage(ACTIVITY)

Analytics Module

Analytics modules is only used to track event needed for internal analytics so there are only one function provided in this module.

  • Track event → Analytics.trackEvent(EVENT_NAME)

Application Module

After working on each components of the application, we need to compose how each component communicate with each other in a single application module.

Application module will be used as starting point of the application. It depends on any previously created modules. Here are the examples.

class MainActivity : AppCompatActivity {    override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
checkIfUserIsAlreadyLoggedIn()
initCheckoutListener()
}
private fun checkIfUserIsAlreadyLoggedIn() {
if (Auth.isLoggedIn()) {
// Start product catalog
startProductCatalog()
} else {
// Start login page
Auth.startLoginPage(this, object : LoginResultListener {
override fun onLoginSuccess() {
// Handle login success
startProductCatalog()
}

override fun onLoginFailure() {
// Handle login failure
}
})
}
}

private fun startProductCatalog() {
Prod.startProductCatalog(this, object:ProductActionListener{
override fun onProductBuyActionClicked(product: Product){
Checkout.addToCart(this, product.name, product.price)
}
override fun onShoppingCartActionClicked() {
Checkout.startShoppingCartPage(this, object:PaymentCompletedListener{
override fun onPaymentCompleted() {
// Handle payment completed
History.startTransactionHistoryPage(this)
}
})
}
})
}

Conclusion

There are some advantages and disadvantages when implementing this concept.

Advantages

  • Good for teams. Each teams has smaller focus. Also because each module can be developed independently, each teams can have different implementation style.

Disadvantages

  • Communication between modules is important. There should be a documentation how to use each module.
  • Duplicate code is common → Can be minimized when moved to generic module.
  • Build time is increased because each module needs to be compiled first.

--

--

Raka Westu Mogandhi
prismapp

Just an Ordinary Software Engineer that always Learn