_Sup for Android_ Part 2: Electric Boogaloo

Monday, December 1, 2014 :: Tagged under: engineering pablolife. ⏰ 8 minutes.


Hey! Thanks for reading! Just a reminder that I wrote this some years ago, and may have much more complicated feelings about this topic than I did when I wrote it. Happy to elaborate, feel free to reach out to me! 😄


Welcome back! Part 1 covered architecture, and Part 3 covers testing and miscellany. Here we’ll talk about --

Libraries: “the cause of, and solution to, all of Android’s Problems.”

The first version of Sup was written in about 4 weeks. Being a developer with little Android experience, I was able to produce this quickly in large part due to extensive, wonderful libraries. The quote in the title illustrates how these libraries are both extremely helpful, and also serve to remind you that all software is broken, and we’re trying to get to the moon by stacking chairs.

The following are some libraries every Android developer should at least know about, whether or not I used it, and why.

Dagger

I’ll start with the most bittersweet: Dagger is a dependency-injection framework for Java. The other notable player in this space is Guice. Dagger builds on the ideas of Guice but is better-suited for mobile by both doing more work statically, and having the programmer specify some relationships more explicitly.

Many programmers don’t know what DI is or why it’s useful, so I’ll point you to Guice’s Motivation Page, which explains the utility behind DI pretty well.

To be clear, I love Dagger. I’m using it in this project because I wholeheartedly believe it provides a major net savings. But like any major abstraction in software, there’s an investment to learning and understanding it before you can cash in on that benefit. For many engineers, the cost of investment feels too high for what we think we’ll get out, so we don’t bother to invest in the first place (recall the Blub Paradox).

It can be a challenge to determine when an abstraction or tool is really worth it. Remember that even using version control at all was an item on The Joel Test because there was a time that many vendors thought it wasn’t worth the trouble of learning it, setting it up, and using it consistently.

There is a learning curve to Dagger, and while the homepage is full of simple, sweet examples, there will be times you will want to do something seemingly simple and Dagger won’t let you. You’ll read the options to the @Module annotation several times to get it working, and even after it is working, you may not exactly know why.

I feel pretty confident now in my knowledge of how it works, but it wasn’t easy, and when I had another team member join me for part of 2.0, this was a pain point for them. Fair warning!

That said:

If you’d like a good example for how to use Dagger (and a myriad of other libraries) in a Gradle project with different configurations for other build flavors, do take a look at u2020.

All that said, Dagger relies heavily on Annotations and code generation. This has repercussions for your project:

So, think carefully when deciding to use Dagger.

Picasso, ButterKnife

After the hoo-haa of Dagger, here are two unambiguously good additions to your project. There is absolutely no reason to use anything other than Picasso for loading network images into your ImageViews. The Transformation interface made the circle crop in Sup profiles an afterthought, caching makes sure images Just Work when offline, and it handles all its network requests in a separate thread. Just use it.

ButterKnife similarly exists only to make your code more readable and save you a ton of typing. If you’re working with classes that have a dozen or so views that need configuring, ButterKnife.inject(this) is all you need to wire up your classes.

Otto

We use Otto for our Event Bus. Guava has one, but as Otto’s homepage points out, it’s not especially suited for mobile. I trusted it because Square Open Source, but in retrospect I think I should have investigated its competitors more.

Otto is great, here are some gotchas:

Retrofit, OkHttp

Use these for your network requests. Volley over Retrofit is worthy of consideration, but there seems to be no major benefit and I prefer the interfaces of Retrofit.

The only caveat I’d mention for Retrofit is that it may take some tweaking if the service you’re querying has made certain design decisions on its data, as Sup did. Retrofit is great if the data being returned to you follows a proper, consistent resource model — almost all of their examples use return objects like List<User> on a GET /users call, Project for GET /project/{projectId}, etc.

Sup’s server was originally designed to accomodate the iOS client, which represented the JSON object returned by the server as a queryable dictionary. So POST /sups returned a JSON dictionary with certain naked values the client may have wanted, but GET /sups/statuses returned another dictionary of its own naked values. While they’re both on /sups, it’s not a clean interface, and required the Java client to define a fair number of 'shell classes' -- POJOs who’s only purpose is to hold the precise, naked values of each and every call. We have something like 40 of them.

The other caveat would be if your response objects use their data to describe themselves. Sit tight, because this one’s a doozy:

Given that

The solution was to let the the JSON object returned by the server describe its own contents, and program the client to parse the response object and render it according to its own spec. So something like:

{
  sections : [
    {
      name : "contacts",
      title : "Contacts",
      type : "suppable cell"
    },
    {
      name : "suggested",
      title : "Suggested Users",
      type : "suppable cell"
    },
    {
      name : "places",
      title : "Places",
      type : "nonsuppable"
    }
  ],
  contacts : [ /* list of contacts */ ],
  suggested : [ /* list of suggested */ ],
  places : [ /* list of places */ ]
}

This is great for the bullet points above! This is terrible if your library counts on the response being represented by a POJO and not a dictionary!

For that case I ended up just getting the response data raw and using a JSON parser on it. Not the end of the world, but gross. Be aware!

OkHttp is a lot more simple. I use it for non-API network operations like uploading to S3. They have a great recipes page that engineer Jesse Wilson said they were quite proud of in his OkHttp talk, and I would say rightfully so.

Realm

A new one! If you’re an Android vet, you may have been nodding along at the mentions of these previous libraries, but Realm for Android has just shipped two months ago!

Realm for iOS has existed for a while, and it was something our iOS engineers were discussing as a solution to data persistence (apparently CoreData is terrible). Android isn’t much better: you’ve got Preferences, raw files that you write yourself on Internal or External storage, or raw SQLite.

Sup 1.0 had a pretty simple, but laborious and fraught scheme: all individual data that required persistence (particular strings, booleans, etc.) were stored in SharedPreferences, and any data of which there can be many elements (items on the Contacts Screen, pending Sups) were stored in SQLite tables. Migrations were a pain. There was lots of data conversion, especially since SQLite doesn’t have a great representation for Dates.

Realm’s docs (correctly) make it seem pretty easy to operate. And it is! Go use it!

Some impressions, however:

Lastly, and this is a harder point to articulate -- Realm, like any other abstraction, especially a recently released one -- can and will fail in mysterious ways. Its performance is achieved with the help of native libraries, but this means when things go wrong, it won’t always be immediately clear why as the crash can happen at the native level. Looking at my Play Store stats, I’ve got a few (not many!) Realm-related crashes that I need a bit of time to pore over, and don’t know how to reproduce.

Furthermore, Realm objects achieve much of their ease and performance with a few tricks that may come out to bite you. For example, your data is represented as a Java Object you define, but if you pass that object to another thread (say, the callback to a network request) and attempt to access its fields without the proper ceremony, Realm will crash.

Per the other tools, I’m happily using it because I wholeheartedly believe that it has saved me time and effort. Just understand that there’s some unexplored territory here, and while SQLite is laborious and gross, it’s generally easier to understand its use and failures.

Lesser-knowns: Phrase, Timber, pidcat, Hugo, NineOldAndroids, and ActionBarSherlock?

These I’ll just sprint through.

Phrase does one small thing, and does it well. It’s explained here. I prefer it to String.format for user-facing Strings but it’s hardly world-changing.

Timber is great, if only because you no longer have to add public static final String TAG = "ClassName"; to every class and subsequently use it in every logging call. That you can ‘plant’ different trees based on your build type is icing on the cake.

pidcat is my preferred logging view. Just have a full-screen tmux pane with your logs, beats having to resize your IDE window.

Hugo: frankly I discovered it late and never used it much, but looks delightful.

NineOldAndroids is less and less important now that 4.x phones are gaining more users. That said, the Android Dashboards still place about 10% of users on API 10, and NineOldAndroids is handy for the very least for back-implementing View.getX and View.getY, inexplicably missing from API 10. Being able to use ObjectAnimators without fear is an added bonus.

Finally, ActionBarSherlock. We used to use it, but now with the Toolbar being the recommended approach I think you should probably just use AppCompat (we switched).

Thanks for the read! Disagreed? Violent agreement!? Feel free to join my mailing list, drop me a line at , or leave a comment below! I'd love to hear from you 😄