And then Google said: “Let there be guidance!”

Hello, Medium community! We are The D. and with this first piece, we are introducing a series of articles that will each be written by our teammates within their areas of expertise.
So look out for future posts about AI, cybersecurity, iOS, programming, design and much more! Meanwhile, meet the rest of the team here.
At the bottom of this article, you may also find a short bio of Abdallah, author of this story and our Senior Android developer.

AbdAllah Abd-El-Fattah
The D.
11 min readDec 19, 2018

--

Source: Giphy

I suppose that you — as an Android geek — have already heard about the “Android Architecture Components” presented by Google during Google IO’17 last year.

However, if for some mystery reason this is your first time hearing about them, then don’t worry — I got you covered!

The “not so old” times:

For so many years (9 to be exact), the Android platform team didn’t care about how you wrote Android application code!

Yes, they didn’t care. Most importantly they admitted it publicly. In a famous Google+ post, Dianne Hackborn — the one who architected the Android platform in its early days — stated that one should not think about the Android platform as an application framework, but more of a “system framework”, a framework that is more sophisticated/rich than just a plain operation system, but at the same time, doesn’t tell you anything about your app internals.

Basically the Android framework — and hence its team — considered its only responsibility to be handling the communication between an app and the underlying OS. The communications, only the communications, and nothing but the communications.

So once the app starts — i.e an activity starts — you are on your own my friend. Follow your instinct, fly to the moon, organize your code-base the way you want, or even don’t. They. Don’t. Care.

This lack of guidance from Google’s side was reflected in so many ways, for example, one could find tons of code lines which are responsible for the business logic written in the activity itself, leading to all sort of errors that one can think about — from tiny issues to memory leaks. Not to mention the lack of testability and separation of concerns.

And even when the team introduced the Fragments framework back in Android 3.0, they introduced it with the same mindset.

But in my own opinion, the main three issues regarding this whole thing are:

1. The lifecycle problem(s).

The lifecycle of any given app — from an app developers perspective — should be as straight as [start, run code, finish] and that is about it! But with the Android platform you have a lot — and I mean a lot — more than this.

For example you can have an activity that is started, but not visible fully to the user, and you can also have an activity that is stopped but not fully destroyed, not to mention that you can — since you don’t really isolate your code — have this zombie activity that is finished but yet can’t be released from memory — laying around, eating your device battery. Throw in a couple of fragments in this activity with their own lifecycle and it will be really (and I mean really) ugly.

This lifecycle handling was one of the hardest challenges facing anyone who wrote Android apps and at the same time the FIRST problem that one had to find a solution for, because after all — if you didn’t get it right, your app — simply — would not work properly!

Now to be fair, the lifecycle events are really important from the system point of view, due to the nature of mobile devices: As an example you can be viewing your social feeds when suddenly you receive a call — in this situation the system needs to have the power to “pause” and “resume” your app in a way that is transparent for the user himself, no doubt about that.

Oh, and don’t forget that most of the components that handle the interaction with the hardware in the Android system need to know about the lifecycle as well, which means that your activity/fragment needs to babysit them by passing the needed lifecycle event — that you get from the activity/fragment classes — to components that need those lifecycle events. So even if your activity/fragment doesn’t need the lifecycle events, it still has to override the lifecycle methods only to pass them to whatever components need them. This will quickly grow to a mess, having those 20-something onStart() and onStop() methods in your activity/fragment which don’t provide any added value for your app itself, just babysitting the other components.

But the point is, if — almost — every app will face those problems, then why should every app attempt to solve them? Why do we have to re-fix them with each new app? Shouldn’t we be given a standard way to solve this, at least?

2. The growth of bad habits

By a show of hand — let’s see who has ever written all of his app logic into the activities/fragments of his app?

Come on, no shame in it, we all have done it once or twice, some more than others, some still convinced that this is the only way to do things.

Those were the dark ages for Android development.

During such moments, when you find yourself responsible for refactoring an app that has been built in such a way, you start asking yourself one question: How did we end up here?

Simple answer: lack guidance.

When you are working on a platform backed by a giant tech lead like Google, you can expect a certain level of guidance to be provided. When/if you don’t find such guidance, you start thinking that all is allowed unless stated otherwise, and that’s exactly when everything starts flying out of the window.

There’s a set of software engineering principles that you’d better adhere to. If you decided to customize them as per your domain/needs, then that is totally fine — as they’re not your holy book after all (even if you decided to break some of them for some — hopefully — good reasons), but you can’t just simply ignore all of them at once and hope that everything will *magically* be OK!

Principles, such as the Single responsibility principle, interface segregation principle, dependency inversion principle, etc.. should be your guidance even if you’re missing it from Google in the first place.

Don’t get me wrong, I’m not saying you MUST adhere to them. I’m saying that unless you have good reasons not to — and 90% you actually don’t — you SHOULD adhere to them to make your life — and your fellow devs — easier.

Now, back to the all-code-in-activities-fragments way of doing things. When you do such things, you end up with a very fat activity, meaning that your business logic can’t be tested efficiently nor can it be reused in any other place in your app, and even worse, you end up with a GOD object that does everything at the same time, which makes adding new features to your app much harder because any change you do will break some other feature, and, additionally, you can’t do proper fixes as well [Sounds familiar?].

This Is a totally bad programming habit for all the reasons in the world, including your own health. No doubt about that.

Now imagine the following: What if — for some mysterious reason — the tech giant that supports the platform itself, the mighty GOOGLE, said that this is — indeed — a bad habit? And that you should move your app logic outside of the activities/fragments?

Just imagine if that happened, how many of us — the devs/sw engineers — would continue going with this old bad habit? I’m not saying that none of us would stop using it overnight, but still, this habit would decrease dramatically.

If you can’t imagine it, no need, it did happen in IO’17. :)

3. Application developers fight and newcomers get lost in the middle.

Now since we agreed that writing code in the activity/fragment is a very bad habit, we need to find a better way, and finding that other “better way” should be fairly simple “given the same set of principles”, right?

Well, you would think! But we — as a dev community — love to argue over the simple stuff, I mean you know about the famous spaces vs tabs war, right?

So just like that, the Android dev community started its own war, between the MVC, MVP (both passive view and supervising controller) and MVVM, all the way to the new MVi (seriously, there’s such a thing, just google it) and the clean architecture. Everyone adapted a situation and decided that their way is the best and everyone else should follow them, while in fact, none of those architecture patterns were perfect for all use cases (it’s “it depends” kinda situation). It was quite a mess for a while.

And the thing is that the architecture discussion doesn’t have a silver bullet to finish it off, as a matter of fact, it has a lot of factors that range between personal preferences all the way to the different nature of apps we build, so this “discussion” will most likely be going to last forever and ever with nothing that can be done to stop it.

Now let’s assume you’re a new Android dev who just started writing Android apps, and you’ve just found out that it’s not very flexible to write all of your code in the activities/fragments of your apps, and you’re looking for a better path. You started to search around and you found not one or two, but tons of articles claiming that they are doing the right thing, although they are doing it in very different ways!

You’re confused, you’re frustrated, you adapted one architecture pattern, and in the middle of the process you switched to another, then added a 3rd party library that’s actually more convenient to a third architecture pattern et voilà: you created a Frankenstein monster all over the place, so you’re right where you started: an app that can’t be extended nor maintained. So — as a result — you abandon all of your software engineering beliefs and go back to your old — still very bad — habits.

Now to the question: what caused the whole thing?

Again: Lack of guidance.

If the majority of the community did agree on an architecture pattern that is more suitable for MOST of the use cases, then this young Android poor dev could’ve just started with this architecture pattern as a guideline, and as he grows older, wiser and more experienced, he would understand the tradeoffs between the different architecture patterns, and could then accordingly choose for himself. But, as a beginner, he can’t make such a decision. Simply because he doesn’t understand their tradeoffs.

The Android community needed more mentorship.

And again, this is exactly what happened at Google IO’ 17.

And then Google said: “Let there be guidance”

At Google IO’ 17, all of the voices of the Android dev community were finally heard, and Google decided to publish mainly 3 important things to help out with the above-mentioned issues. [We will discuss them briefly here, but actually, each of them needs its own article for the least. :) ]

  • The lifecycle objects and lifecycle-aware observables:

The first thing that they did was to try to address the lifecycle issue. How so, you ask? They introduced three very important concepts: lifecycle observer, lifecycle owner, and lifecycle object.

What’s the lifecycle observer? It’s an object that wants to be notified when a lifecycle owner changes its state. It will have hooks to the lifecycle events sent to it to be able to react accordingly if needed.

What’s the lifecycle owner? It’s a “thing” that has a lifecycle, it can be literally anything that needs to have a lifecycle of its own, and starting from API 28 the support activity/fragment implement this one method interface, but It doesn’t have to be an activity or a fragment, any class implements this interface is-a lifecycle owner.

What this means is that you don’t need necessarily an activity/fragment to use, you just need a lifecycle owner. This decoupling is usually preferred, and once you define which lifecycle owner you are interested in, you can start to observe it. It doesn’t need a fragment or an activity babysitting those components anymore only to send it the lifecycle events.

  • A lightweight ViewModel class:
    Remember the doing-everything activity/fragment? Now we are encouraged to move all of the business logic related to the code outside of the UI controllers “the activity/fragment new name”, so for starters, you can move all your data fields to a ViewModel to keep them for you. The interesting thing is that the ViewModel classes are not really SDK dependant, and thus the “lightweight” prefix in the title, meaning it can be tested locally on the JVM, without the need for the SDK itself.
    And if that’s not enough for you, you also need to know that the ViewModel is preserved across configuration changes, meaning it has a different/simpler lifecycle. For this exact reason, the ViewModel classes MUST not reference a view, LifeCycle, or any class that may hold a reference to the activity context. Think about them as a store to the UI related data that will be used from the UI controllers.
  • Lifecycle-aware data holder observable:
    Building on top of the lifecycle-aware components, the Android team introduced the LiveData class, which allows you to observe it from any lifecycle owner, and it will notify this lifecycle owner with its current data, if any, as well as any updates happening while the lifecycle owner is in an active state “either started or resumed”.
  • In case you didn’t notice it yet, the LiveData addition goes very nicely with the ViewModels, so by keeping your LiveData objects in a ViewModel object, and because the ViewModel survives through configuration changes the newly created UI controller will receive the same data that was being displayed in the destroyed one once the newly created UI controller subscribes to the LiveData object it needs, and on the other side — because it is Lifecycle-aware — the LiveData will handle the unsubscription on your behalf at the right time for free. Which means fewer memory leaks, and less zombie UI controllers hanging around, and I don’t think anyone will miss them actually.

Guide to app architecture

The wait is over, Google finally released an opinionated guide — that’s what the internal team called it for a while — regarding the app architecture in Android!
Yes, it’s not new. Yes, a lot of people have been using it for a while [it’s MVVM based architecture with a repository after all]. But it services like an entry point for anyone who wants to understand more about how to architect their Android app better. A good move in the right direction. And the most important thing is that they are actually using all of the above stuff throughout the guide itself, which is super cool because it feels nice that they are building something that’s really coherent and thought through.

You can read more about the guide if you like, we’re planning to have some upcoming articles addressing the main components of those releases with more depth and examples.

Again, it’s really nice to see this move from Google’s side, this kind of support, this level of working with, and for the community. Let’s hope it lasts. :)

Abdallah is a Software Engineer at The D.. He’s interested in app architecture & loves to keep up with new technologies as they emerge.
Currently, he works mainly with native Android projects in Kotlin.

--

--