We present the tutorial on the architecture of client-server android applications based on the materials of the course of Arthur Vasilov, which was held at Google Developers Group 2016 in Kazan.
Introduction to the architecture of android applications
Before proceeding directly to the study of how to build the architecture of client-server Android-applications, it would be good to know why this topic is important at all.
And this question is logical. First, the user is completely indifferent to the architecture of your application. Seriously, how many of you, when using programs and applications, often think about whether they did MVP or MVC? The answer is no one. Secondly, working with architecture requires additional efforts: it needs to be created, it needs to delve into and teach people how to work on it. But in order to create a clearer picture for answering this question, we need to return to the relatively recent past, namely in 2007 and 2008, when the first versions of iOS and Android devices were released, respectively.
We must admit that Google managed to lag behind Apple in terms of entering the mobile market and this led to some consequences, namely to the rush when the first version of Android was released. There is nothing surprising in that Google aspired first of all to finish the basic user functions, and care of convenience of developers was the second priority. Therefore, along with the first version of Android, Google did not provide developers with any standard recommendations for either development, or design and UX. That led to the fact that every developer or every company was forced to write as they wanted and as they could.
Of course, we must admit that in the future Google did a great job of popularizing the Android system among developers. But at the same time the original problems were not completely solved.
What are these problems? In terms of design, it is clear that completely different styles of applications confuse the user of the Android system, and it can be difficult to navigate. But what’s wrong with the lack of standards in the code itself? After all, as it was said just above, the user can not know in any way how good the code of your application is, and this does not affect its use. The problem is that not all developers have a good knowledge of design patterns and are able to develop a good application architecture. If you do not follow clear principles in architecture, you will very soon receive a code that:
- Unable to support. The code will have a lot of complex logic, it will not be located in strictly defined classes, it will be unclear how this or that part of your application works. From this it follows that when you add a new functional, you have to either long and hard to understand the written code, refactor it and do it right, or to do the task somehow, that is, figuratively speaking, through crutches. Due to the fact that not all developers understand the need for refactoring and are able to convince the leadership of this need, and not every manager agrees to delay the release of the new version and incur additional expenses due to refactoring, the second option is much more often chosen. This often leads to horrific consequences. Personally, I have repeatedly seen huge applications consisting of three Activity files. Of course, each of these activities consisted of thousands, and even tens of thousands of lines, which made them absolutely impossible to read. Moreover, every new functional implemented through crutches is the cause of additional bugs and crashes.
- It is impossible to test. This problem flows smoothly from the first. You will not be able to write unit tests if the entire application is one large module. Moreover, due to the peculiarities of writing tests for Android-applications on JVM, with a large number of dependencies from Android classes in the tested classes, you can not write tests. And the absence of tests:
- Gives you much less confidence that your code is working correctly.
- You will not be able to quickly check that the added changes do not break the work of the rest of your application.
This situation lasted long enough. Applications for Android continued to be written in different styles with completely different approaches to design and architecture. Someone was taking a design from the iOS system, and design patterns from Web development (in particular, attempts to use MVC in Android owe their existence to the Web developers who have switched to Android). And it’s hard to say why there were no attempts to fix this situation, Android is a very young system, and by the time of its release all the design patterns and architectural patterns were already widely known.
In general, everything went on as usual until 2014, when two important events happened at once. The first is well known to everyone — this is the presentation of the Material Design concept on Google I / O. You can treat this concept differently, someone considers it unsuccessful, someone says that in this way Google restricts the freedom of developers in choosing a design. But the fact that the emergence of this concept greatly improved the situation on average, is unquestionable.
It’s clear that the Google I / O conference is being monitored by everyone and that Google has put a lot of effort into popularizing the Material Design philosophy, so that Material Design was doomed to be used by everyone. But another significant event happened with less popularity, as it was just an article. This article is «Architecting Android … The clean way?» By Fernando Cejas. In fact, these are just an adaptation of the principles of Clean Architecture from «Uncle Bob» (Robert Martin) for use in Android. This article gave a huge push (and it is quite possible that this is just a coincidence and the article came out at a time when developers were already ready to look for better solutions) in the development of application architecture.
To put it briefly (and we will take a closer look at the course), a good architecture should allow writing tests for classes containing business logic and should build application modules independent of almost all external elements. And if to speak even easier, your code should be testable and it should be easy to apply and pleasant to read. The quality of the application code can even be measured by the standard unit of measure — the amount of WTF per minute (from Robert Martin’s book “Clean Code”).
Now we can roughly imagine what is required of us when building the application architecture and can go directly to the consideration of all topics!
The main tasks in the development of client-server applications
So what is the complexity of creating client-server Android-applications that would satisfy all the principles that were described earlier? There are 2 major problems, each of which in fact can be broken down into even more problems:
- Implementation of client-server interaction. It would seem, what is the problem here? We all know how to execute requests to the server using various tools, process the result and show it to the user. Yes and no. There are many factors. First, you need to be able to correctly handle errors, which can be very different: from the absence of the Internet and the wrong parameters in the query, to the non-responding server and errors in the response. Secondly, there can be more than one query in your application, and a lot, and it is quite possible that you will have to combine the results of these queries in a complex way: execute them in parallel, use the result of the previous query to perform the next and so on. Thirdly, and this is the most unpleasant — requests can take a considerable time, and the user is often not the most patient and quiet person — he can twist the device (and then you lose the current data in Activity), and maybe completely close the application, and then you You can get desync in the data (when the data on the server is updated, and the application does not know about it and displays incorrect or outdated information). And all this needs to be solved in some way.
- Provide the ability to test the classes that contain the business logic of the application. It also implies a lot of internal problems. First, you need to ensure the modularity of classes. This follows from the very essence and from the very name of Unit-tests. To ensure modularity, you need to separate classes into logical layers for each screen. That is, instead of writing all the code pertaining to one screen in one activity, it is necessary to divide it competently into several classes, each of which will have its own zone of responsibility. Secondly, if we talk about tests using JUnit, then we need to understand that the classes tested in this way should contain the minimum number of dependencies from Android-classes, since Java and its virtual machine know nothing about these classes (in more detail this moment will be described In a lecture about testing). Third, the most complex application logic is almost always associated with working with data from the server. We need to test various possible situations, such as the expected server response, server error, and various responses that lead to different behavior of the application. But when performing the test, we can not «drop» the server at will or force it to give us the data we need. In addition, server requests are executed long and asynchronously, and the tests must work consistently. All these problems can be solved if you substitute the implementation of the server for a certain layer, which will be accessed by the tested classes. All this will also be considered below.
These problems also have to be solved when creating a competent and correct architecture, and it is always not very simple. Moreover, sometimes it is impossible to achieve the desired result, and each method has its own shortcomings and advantages. We will study all these methods throughout the course, and after that you will be able to decide exactly how you want to develop client-server applications.
Part 2 Lectures 1 Course on the architecture of android applications: