Lessons on Mobile Platforms from an Ancient JavaScript Game

I recently realized that I’ve been continuously programming in JavaScript for about 16 years. That is, I’ve been writing at least little snippets (and sometimes heaps) of JavaScript at least once a month for 16 years. 16 years! That’s insane. That’s a much longer run than I’ve had with any other language, and it doesn’t look like it’s going to end anytime soon. The funny part is that I’ve never been particularly fond of JavaScript as a language, but there is just no way around it as long as I continue do some sort of web development. I suspect that a lot of other developers who came of age in the late 90s have reached similar accidental JavaScript seniority and that would partly explain why by some metrics it’s on track to become the world’s most popular programming language.

Reminiscing about my early exploits in JavaScript, I searched through my backups to unearth a game I wrote in 1998 and included in my very first application for a paid programming job (I got the job). I was shocked to discover that in a modern browser the game still works exactly as intended, with zero modifications to the code. Here it is, in all its original low-res 90s glory: AsteroidMan, a PacMan clone written in JavaScript.

Screen Shot 2013-11-10 at 1.39.29 PM

In 1998, Netscape 4 and Internet Explorer 4 were the browsers at the cutting edge. They didn’t support much manipulation of the DOM yet, but it was possible to dynamically change the value of a form field — and the source of an image, which enabled games like this one based on a grid of images. One other neat technique for client-side apps I remember from that time was to use frames (yeah, frames, not those new-fangled iframes) to keep global JS state in the parent document, which was preserved across page navigation in the child frames. In my backups I also found a LucasArts-style adventure game I wrote that way. No, it’s too embarrassing to post now.

What do we learn from this exercise in JavaScript archaeology? The web is an insanely good application distribution and execution platform. I opened that HTML page from my backups in a browser and it looked and worked exactly as it did 15 years ago. There was zero installation or configuration required. The game does not only work in recent Chrome, Safari and Firefox on my laptop, it runs on my Android phone and on my iPad. I doubt any more traditional client software written 15 years ago would still run in a modern incarnation of the target platform, especially with zero installation and configuration by the user. Imagine a Windows 98 app running on Windows 8 (that’s a brilliant versioning scheme right there, Microsoft). The web platform is singular in how extremely portable and backwards compatible it is.

Here’s what this means for today. In case you hadn’t noticed, there is currently a big trend away from web apps towards native apps, namely iOS and Android apps. I seriously doubt a native iOS or Android app written today will work in a modern iOS/Android environment in, say, 4 years from now. I can guarantee you that neither iOS or Android will even still be around in a recognizable form 10 years from now. As platforms they are very likely a dead end while the web has a proven track record of being very open ended.

Unfortunately the current trend is unlikely to reverse soon because for now those platforms are a very profitable dead end, both for the platform stewards and for the programmers who serve them. If you have only rudimentary Android or iOS skills you should have no problems finding a well-paying job right now. The trend is a bit less profitable or downright onerous for creators of consumer products (that would be me and also my employer) because building natively for both iOS and Android and maybe even Windows Mobile is an expensive time sink.

I don’t expect any innovation from Apple in this regard since they have always been all about user and developer lock-in. But in my mind Google has a huge opportunity here. Google should push to make web apps first-class citizens in Android. Basically, an Android app may be a light-weight wrapper around a web app with some JavaScript APIs to call out to device APIs. This isn’t a novel idea, Phonegap and others have been trying to tack something very similar on top of Android, but it would help immensely if this approach was sanctioned and widely promoted by Google and ideally developed into an open standard. Such a fairly simple extension to the web has a much better shot at a long shelf life and at getting adopted by other mobile environments. It should also dramatically smooth out the pretty steep learning curve for Android development and thus increase Android’s developer mindshare.

The lesson for developers should be obvious: Think twice before you embark on a mobile-first strategy with native apps only. Consider Phonegap or other hybrid frameworks. Especially if you’re building for longevity or for low maintenance cost, for heaven’s sake, just build a web app.

Robolectric 2.2: Some Pages from the Missing Manual

When I have a conversation about Android development with anyone I usually end up complaining about how hard and annoying testing is. I think Google did a huge disservice to the community by neglecting testing infrastructure since as a result there is no culture of testing in Android development. There are some open source efforts to improve the situation though, and the main tool that has been preserving bits of my sanity while coding for Android is Robolectric.

I use it mostly to write unit tests for activity and fragment classes, since doing that with the tools provided by Android is really rather painful (and slow). With the just released Robolectric version (2.2) I feel its API, especially around maintaining the activity lifecycle, has finally evolved to where tests are really easy and intuitive to write. There is some basic documentation for the new API but I haven’t come across good real world examples, so I thought it could be useful to document some patterns I’ve been using.

Testing Activities

My activity tests tend to have the following shape, here for a fictional class MyActivity:

@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {

    private ActivityController controller;
    private MyActivity activity;

    @Before
    public void setUp() {
    	controller = Robolectric.buildActivity(MyActivity.class);
    }

    @After
    public void tearDown() {
    	controller.destroy();
    }

    private void createWithIntent(String myExtra) {
        Intent intent = new Intent(Robolectric.application,
                MyActivity.class);
    	Bundle extras = new Bundle();
    	extras.putString("myExtra", myExtra);
    	intent.putExtras(extras);
    	activity = controller
    		.withIntent(intent)
    		.create()
    		.start()
                .visible()
    		.get();
    }

    @Test
    public void createsAndDestroysActivity() {
    	createWithIntent("foo");
        // Assertions go here
    }

    @Test
    public void pausesAndResumesActivity() {
    	createWithIntent("foo");
    	controller.pause().resume();
        // Assertions go here
    }

    @Test
    public void recreatesActivity() {
    	createWithIntent("foo");
    	activity.recreate();
        // Assertions go here
    }

}

In Robolectric 2.2, ActivityController is now the canonical API (actually, the only API) for this sort of test. It has methods that make the underlying activity go through state changes. To fully create an activity as it would be presented to a user you generally want to call create(), start() and visible() on it. I’m also putting a destroy() call in an @After method to ensure tearing down the activity always works properly.

As a rule, every activity test I write has at least the 3 tests above, covering the most common state transitions – create/destroy, pause/resume, and recreate. You might be surprised how often you initially implement broken recreate logic. On an actual device, a recreate happens for example when the screen rotates, something that’s quite common but easily overlooked in manual testing.

Often I’ll want to write multiple tests that start an activity with different intents. This is hinted at in the createWithIntent() method which takes a customizable extra parameter for the intent. For a very simple class you might omit that and just create the activity without any intent in the setUp() method.

Testing Fragments

For fragment unit tests I am using a base class that can make any fragment go through the lifecycle of a parent activity:

public class FragmentTestCase {

    private static final String FRAGMENT_TAG = "fragment";

    private ActivityController controller;
    private FragmentActivity activity;
    private T fragment;

    /**
     * Adds the fragment to a new blank activity, thereby fully
     * initializing its view.
     */
    public void startFragment(T fragment) {
        this.fragment = fragment;
        controller = Robolectric.buildActivity(FragmentActivity.class);
        activity = controller.create().start().visible().get();
        FragmentManager manager = activity.getFragmentManager();
        manager.beginTransaction()
        		.add(fragment, FRAGMENT_TAG).commit();
    }

    @After
    public void destroyFragment() {
        if (fragment != null) {
            FragmentManager manager = activity.getFragmentManager();
            manager.beginTransaction().remove(fragment).commit();
            fragment = null;
            activity = null;
        }
    }

    public void pauseAndResumeFragment() {
    	controller.pause().resume();
    }

    public T recreateFragment() {
    	activity.recreate();
        // Recreating the activity creates a new instance of the
        // fragment which we need to retrieve by tag.
    	fragment = (T) activity.getFragmentManager()
    			.findFragmentByTag(FRAGMENT_TAG);
    	return fragment;
    }

}

The general idea is that the best way to put a fragment through realistic state transitions is to add it to a real activity and then make that activity change states. Using a blank FragmentActivity works well for this purpose.

The helper methods allow me to very quickly write at least 3 tests covering the most common transitions, same as above for activities. This is an example for a MyFragment class:

@RunWith(RobolectricTestRunner.class)
public class MyFragmentTest extends FragmentTestCase<MyFragment> {

    private MyFragment fragment;

    @Before
    public void setUp() {
        fragment = new MyFragment();
    }

    @Test
    public void createsAndDestroysFragment() {
        startFragment(fragment);
        // Assertions go here
    }

    @Test
    public void pausesAndResumesFragment() {
        startFragment(fragment);
        pauseAndResumeFragment();
        // Assertions go here
    }

    @Test
    public void recreatesFragment() {
        startFragment(fragment);
        fragment = recreateFragment();
        // Assertions go here
    }

}

***

I’ve had pretty solid results with these patterns so far. I’m beta testing an app with real users right now, fully covered with tests like the above, and I haven’t seen any crashes yet (knock on wood). But I’m sure this can be improved upon. I’d be curious to hear how others use Robolectric since I can find so few real world examples out there.

The Test-Infected Programmer’s Android Apothecary

Earlier this week I gave a lightning talk about testing at an Android meetup in New York. Because, on the surface, testing is not the most exciting topic in the world, I tried to spice it up with a snazzy title and a slightly gimmicky structure. The jury is out whether it worked or not (it didn’t draw many laughs), but decide for yourself based on the slides.

Since the slides are not that useful without the accompanying stage show, here’s a very quick summary. The premise is that test infrastructure provided by the Android SDK out of the box has quite a lot of shortfalls and for someone serious about unit testing there are a bunch of 3rd-party libraries that help ease the pain.

These are the libraries I presented:

Robolectric

  • Fixes the problem of having to run tests on an Android emulator, which can significantly improve test execution speed and plays nicer with most Continuous Integration environments
  • Works by replacing some Android core classes with “shadows” which are hand-written fakes, so some caution is warranted because behavior can be subtly different from the real implementations in the Android VM

FEST Android

  • Simplifies assertions about Android objects such as views
  • Based on FEST fluent assertions, a way to make assertions more readable, type-safe and intuitive

ViewSelector

  • The self-promotion part of the talk: This is a library I wrote myself, based on concepts from assert_select in Rails and Android’s own UiSelector
  • Makes assertions about complex Android UIs easier by selecting views with CSS-style selectors
  • Alpha-quality software, in the sense that the API is not completely stable (I’ll have a more in-depth blog post once I’m happy with the API)