Tuesday, October 25, 2016

Build It Bigger: Managing Dependencies with Gradle

Finished version of "Built It Bigger"
It’s official. Yes, I did complete the “Build It Bigger” project for the Android Developer Nanodegree, but that was a week ago. The only news is that I’ve finally put my laziness aside to write about it!

Like the post on Popular Movies, I’ll detail the key features, how I chose to implement them, and the challenges involved. And of course, there will be plenty of screenshots of the finished product.

The Assignment:

The accompanying course for this project was all about Gradle; that mysterious thing in Android studio that keeps displaying yellow messages about “syncing”. Previously, my only encounter with Gradle was hopelessly updating the version number on older projects and occasionally adding the dependency for ButterKnife or the Android Support library.

But Gradle does much more than that. Despite the annoyances, it’s a full automation tool that saves you lots of time when working on large projects. Hence, the name “Build It Bigger”.

For this project, I had to create a joke telling app, with functionality separated into libraries. In addition, there were also free and paid versions that needed to share the same code base. There was even some “cloud code” to supply the jokes.

The Implementation:

The starting code was a simple screen with a prompt and a button to tell a joke. Nothing thrilling; just a place to begin.

Starting point for this project.

The first task was to create two libraries: one to supply the jokes, and the other containing an activity to display the joke. Note that because there needed to be free and paid versions, and because both versions tell jokes, this functionality is included in separate libraries, as it’s unchanged across builds. While the joke provider was a simple Java library, the joke presenter was an Android library, because it contains Android-specific components (an activity), its own resource files, and even a manifest.

At first, the joke provider library returned a hardcoded joke, but this was only temporary. I then needed to create a GCE (Google Cloud Endpoints) server to supply jokes in a more proper manner. After all, it would be silly charging for an app that just contains a handful of hardcoded jokes. The ability to add new jokes without requiring users to install updates is what makes an app more powerful than a joke telling book.

While the assignment only required a single GET request to download jokes, I wanted to further explore GCE. For this reason, the paid version of the app also has access to a POST request that allows users to upload jokes straight from the app. Free users don’t get an upload button and see the banner advertisement instead. We only want to hear from serious jokesters, and freeloaders are more likely to submit spam or bad jokes.

Paid users can submit jokes.

But inevitably, there will be that corny joke that nobody likes. What can we do to ensure the quality of jokes is maintained for all the users?

To solve this problem, I added a joke popularity system. After viewing a joke, users would get the chance to submit an up vote or a down vote. This is included in the activity from the joke presenting library, so it’s available to both free and paid users. All jokes start with a popularity of 3 and each vote is worth 1 point. Once a joke’s popularity reaches zero, it gets permanently booted off the server.

Bad jokes like this one can be voted off.

So where does the Gradle part come in?

While all this could technically be done by hand, it would be very tricky if you only want one Android studio project. Instead, Gradle handles most of the difficult work in the build process. Both joke supplying libraries are listed by Gradle as dependencies in addition to third party libraries. The build script also defines “product flavors” allowing both the paid and free versions to coexist on the same device. Finally, dependencies can be filtered by their product flavor. Only the free version contains ads, so Gradle excludes this dependency from the paid version. Similarly, only paid users can upload jokes, so the free version has no need for the material dialogs library. Only the paid version will include this dependency.

Only free users see ads.
The Challenges:

Compared with previous projects, this app was not particularly complicated. However, there were a few issues encountered during the development.

When configuring the API, I was surprised to find that endpoint names were not those supplied to the “name” parameter of the @ApiMethod annotation. Instead, they used the name of the Java bean the method returned. So with the default GCE template, the “joke” method was named “mybean”. To override this behavior, I learned it’s necessary to use the “path” parameter. So this method

@ApiMethod(name = “getJoke”, path = “get_joke”)
public JokeResponse getJoke() { … }

Would be known as “get_joke” in the endpoint. If this parameter were omitted, it would be known as “JokeResponse”.

There were a couple minor snags along the way, but this one stood out the most. To get the gradient on the “tell a joke” button I used the tool at http://angrytools.com/android/button/. Quite useful if you’re new to Android graphics and want a simple way to learn about each of the properties.

Conclusion:

While not as code-intensive as some of the previous projects, I like how the joke telling app turned out. Nowadays, the freemium model appears to be more common than having separate free and paid versions, but it’s nice to know Gradle product flavors can handle most of the difficult work for you. And abstracting functionality into libraries is certainly something I’ll be using a lot in the future.


Monday, October 3, 2016

Why I Won’t Be Using Java for My Next Android Project

     Ever since its inception in 1996, Java has been no stranger to criticism. Nevertheless, it’s popularity has only continued to grow in recent years. A lot of this recent growth is due to the widespread usage of the Android platform. Before Android, Java’s verbosity was a favorite among project managers because it made it look like people were getting a lot of work done. In its early days, Java even had a purpose, to provide somewhat-secure, cross-platform web apps. But is the Sun (pun intended) about to set on the Java empire? Recent trends show that more programmers are turning away from this twenty-year-old behemoth named after a coffee bean.

     In 2016 alone, we’ve seen fewer web apps using Java, JetBrains releasing the Kotlin language for JVM, and there are even rumors of Swift for Android. We don’t have any word from the project managers yet but we can reasonably expect them to migrate from Java by the time the aliens return.


     While we wait for that day to come, we as developers can take a stand. While I’ll likely be using Java for the remainder of my Udacity projects, personal projects are a different story. But why exactly is choosing a Java alternative so appealing when building an Android app? Here are my main reasons.

Verbosity:

     Project managers aside, no one needs verbose code. Unfortunately, Java has a lot of these problems. We need to reference a class name at least twice in order to initialize it. This is even worse than it sounds, given that Java class names are notoriously long. Many modern languages are still statically typed, but have proper type inference, which fixes this problem. What about parentheses after conditional and loop conditions? Most modern languages don’t need those either. Add in other features like the “new” keyword and a semicolon after every line, and you’re sure to have a mess of code.

Closures:

     When first learning Groovy to write Gradle scripts, I couldn’t help but applaud the use of closures. This excellent feature from Swift has already taken the iOS community by storm, and Groovy closures should really be doing the same for Android. Ever used AsyncTask or Runnable? You may have noticed that only static properties (from the class calling it) can be used in their methods. Closures, on the other hand, are methods that don’t need to belong to a class. You can use any variable from the class that’s using it. We could finally see a proper completion handler pattern for Android, which would make networking code and long running tasks much more readable.

Protocols:

     While Swift for Android is still a long wait away, Swift-like features such as protocol oriented programming could be very handy in Android apps. Protocols are much more flexible than java interfaces, with features such as optional methods. The ability to use protocols would allow for much cleaner MVC design.

Typing Time:

     This goes without saying, having previously mentioned Java’s verbosity. All this unneeded syntax wastes a lot of typing time. In an age where compiled languages that read like scripting languages are common, it’s hard to make an argument in favor of the old conventions. Building software is supposed to be about productivity. Unless you’re in a workplace that measures lines of code, using a Java replacement is something to consider.

NullPointerException:

     Even the experienced programmer encounters some of these. While no magical new programming language can eliminate null pointers, there are many better ways of handling these cases. In java, before using a class that may be equal to null, you need to check if it’s “!= null” or use “instanceof”. In many cases, this is necessary simply to call a single method. Instead, if you use Kotlin or Groovy, there are special operators that can handle null pointer exceptions for you, without needing to add an extra level of indenting.

The Future:

     It took Apple 30 years to finally do something about Objective-C, so Java still has a good 10 years to live. But if you have the choice, the advantages of using an alternative are clear. From saving time to advanced features, Java replacements can greatly improve your Android development productivity. For me personally, I’ll soon be porting an iOS app I wrote over to Android. I don’t intend to use a single line of Java. The only question is: who’s it gonna be?

Kotlin, Groovy, or something else? Let me know in the comments and I'll keep you posted when I start porting the app.