Context I thought it was time to write a about how to design a proper, architecture that you may apply to any . This series of articles is the sum of all the knowledge that I’ve learned from working on different projects for different companies. For obvious reasons, I cannot disclose any information, but I can tell you that I’ve worked on projects for social network apps, cruise apps, airplane apps, e-commerce apps, radio streaming apps, and bank apps. Working on all these different projects has taught me the that you need to keep in mind when you are working on a large project. There are things related to the and there are things related to how the architecture that you choose to apply is going to impact your . series of articles scalable medium-large projects does and donts technology itself engineering team Before you start This article assumes that you are at a or . That means that you feel comfortable working with the most well-known technologies related to Android development, such as Dagger, Kotlin, RxJava, Google-related libraries (FCM, Remote Config, Crashlytics) and obviously, the Android SDK. semi-senior senior level I’m going to start talking about the , then show the that I have created for this article, and then in the next article I'll go on through each of the architecture. tech-stack setup example app layer Tech-stack setup Since some time ago I have permanently moved from to because MVVM has become the first Android architecture, through Android’s LiveData and ViewModels. Also, since this article aims towards a architecture this is going to be a architecture, with , a , and a . MVP MVVM officially supported large-scale multi-module feature modules core module base module The technologies that I’m going to use here are; for dependency injection, as my networking layer, to wrap the network layer into repositories. Dagger OkHttp/Retrofit RxJava Example App I have created as an example - no pun intended - of how this architecture works. This example app shows different real world scenarios, scenarios where we have to use cache, perform search, mix different endpoints, and so on. an example app Each shows different use cases and different scenarios. I often see that when you look for examples online you only see the most straightforward, simple and unrealistic scenarios¹. For example, just fetching something from the backend and display it on the UI. In my personal experience that’s not how real-world development works like. In the real world, you’re going to have to go back and forth with different resources within your company, and due to different constraints you may have to settle with some-what good API endpoints², or you may have to hit different endpoints to display the whole information to the user. feature module RxJava Example #1 The "RxJava Example #1" shows how we can conditionally zip two API calls together. In this example, we use two different endpoints to fetch the "recently viewed news" and the regular paginated news. If we do a Pull-to-Refresh or open the Activity from scratch, we are going to fetch both, the recently viewed news and the first page of the paginated news. If we continue to scroll down until we reach the next page, we are only going to call the API to fetch the second page. This example also handles error situations like doing a Pull-to-Refresh without internet connection . RxJava Example #2 The "RxJava Example #2" shows how we can zip responses from different endpoints through RxJava. In this example, we zip the responses from two different endpoints, one that provides the user's "business skills information" and another that provides the user's "personal information". We zip these requests together through RxJava and use wrapper objects to carry the responses around. Also, we handle different error situations for each endpoint and update the UI accordingly. This example supports Pull-to-Refresh behavior and handling no internet connection states. Cache Example The "Cache Example" shows how we can use a and a to display data to the user, update data dynamically, and without using any sort of EventBus technology, get these updates into the UI by relying on Room's Flowables. cache repository network repository In this example, we fetch a list of recipes from a mock endpoint host on ApiAry, store those recipes on cache, and allow the user to bookmark the recipes. When we bookmark a recipe we can see the change reflected on the recipe list as soon as we do it, all this thanks to Room's Flowables. This example also supports Pull-to-Refresh behavior and handles different error states, such as trying to fetch the list of recipes without internet connectivity. LiveData Example The "LiveData Example" shows how we can achieve a complex search by relying on LiveData. In this example, we can search image posts using the , through this API we are able to search using a String as the search term, and we have a few filtering options. We can select if we want to get the posts (Top) or if we want to get the posts (Viral). If we choose to filter by top posts, we can also specify a date windows, getting the top posts from the , , or . Imgur API query latest most trendy day week month This example supports handling the Pull-To-Refresh gesture and pagination. Also, we handle different error states such as trying to search for something without internet connection (it shows a Snackbar if we are seeing content or a full error state if we open the Activity from scratch). All this is done through LiveData. Notes [1] By unrealistic scenarios I mean when you go through an article and they show you how to fetch data, save it on cache, and display it on a RecyclerView. That’s all well and good; But what happens if you fetch a 500 (Internal error)? What happens if you fetch a 304 (Not Modified)? Do you waste time and store a duplicate response on the cache? What happens if there’s no internet connection? All these edge-case scenarios, that are actually very likely to happen in the real world, are totally omitted by most articles. [2] Some may argue that if this was to happen, you should push forward and settle for nothing else other than what you want. But that’s not how a company works. A company needs to deliver a product. Backend and frontend developers, they have deadlines, and trying to fix an endpoint so it is more mobile-friendly may take time, time that the backend resources don’t have.