Tuesday, July 19, 2016

Two Tips to Immediately Improve the Quality of Your Code

* While this post was written mainly with Java in mind, at the great peril of appearing to "Language Map", the concepts are certainly transferable across a great many languages, particularly those supporting OO semantics.

Stop Writing "public"

Think fast! What's the first thing you write when creating a new interface or class? Or, if your IDE has a template for producing this kind of boilerplate, what does the resulting code typically look like? I'm willing to bet it's something along these lines:

public class Foo {
    ...
}

Is this more or less the standard template that you (or your IDE) consistently regurgitate? I myself carried on like this without so much as a second thought for awhile before it became clear to me what a poor design decision it was, conscious or not. When everything is public:
  • As the producer… 
    • You (potentially) lose out on the opportunity to channel consumers into the pattern(s) of usage you intended for with your design.
    • You (potentially) leak implementation details that you really don't want consumers to develop a reliance upon.
  • As a consumer… 
    • Short of explicit samples or documentation, there isn't a clear indication as to how you're expected to engage.
Rather than blindly making everything public, think instead in terms of "modules".  A well-designed module will have a contract for consumers to make use of it, while simultaneously shielding them from internals that aren't meant for consumption outside of the module itself. Therefore, the visibility modifier for each class/interface should be determined through careful deliberation about where it should fall along this spectrum. Stop and ask yourself "Why should this be public?"

As an example, imagine a data access module that offers the flexibility of abstracting away data access by way of a generic Repository interface. The Repository allows us put() and remove() instances into/from storage respectively, while using a consumer-supplied implementation of a SelectionPredicate interface for instance fetching that allows retrieval to be fine-grained and context-specific. Internally, the module has Repository implementations for both JDBC-compatible databases as well as MongoDB, which are provided by way of a factory class (without exposing the implementation classes themselves). One way of crafting such a module might be a package like the one below:

repository
├── public interface Repository
├── public class RepositoryFactory
├── public interface SelectionPredicate
├── protected class JdbcFooRepositoryImpl
└── protected class MongoFooRepositoryImpl

Here, the things that are meant to be public are modified as such without the implementation details leaking out beyond the boundaries of the package. This opens up a path to comfortably evolving the internal implementation without disruption to consumers, while also gently nudging those consumers into a straightforward, obvious pattern of usage.

In short - the use of public should be a conscious and deliberate design decision, not simply a byproduct of habit.

Stop Writing "new"

The new operator of course instantiates a class by allocating heap memory for a new object instance, and returns a handle referring back to that bit of memory. While seemingly straightforward, widespread usage of new has design consequences that can be difficult to foresee, especially when working in smaller codebases. Namely:
  • Overuse can make it more difficult to reason about the relationships between abstractions. Invoking new reveals a direct dependency on the type being instantiated, and thus the calling code must know, in addition to its own business logic, the intimate details behind how to construct that dependency, and that dependency's dependencies, and that dependency's dependency's dependencies, and, and, and… As the codebase grows, the code will become increasingly sensitive to change and more difficult to distinguish between the parts that perform the business logic and the parts that simply bootstrap other dependencies.
  • It eliminates test seams. When classes initialize their own concrete dependencies, we lose the opportunity to programmatically swap out implementation types, which is insanely useful for the purposes of testing. If, for example, a component is responsible for performing database lookups, and as part of its initialization explicitly establishes a connection to its target database, there is no way to test that component in isolation. There is no way to supply a test double such as a mock database for the purpose of programmatically testing the component under different conditions (i.e. no items found, one item found, many items found, etc).
Instead of invoking new directly, components should have dependencies on abstractions, and instances of those abstractions should be provided as needed (e.g. at instantiation time, per invocation, etc). The following snippet illustrates the above points:

interface Widget {}

interface WidgetDao {
    public Collection<Widget> getWidgets();
}

class WidgetPrinter {
    private final WidgetDao widgetDao; 

    WidgetPrinter(WidgetDao widgetDao) {
        this.widgetDao = widgetDao;
    }

    public void print() {
        for(Widget widget : widgetDao.getWidgets()) {
            System.out.println(widget);
        }
    }

}

Here, WidgetPrinter is simply given a data access abstraction that can return Widget instances. Rather than constructing that dependency directly, that job is delegated elsewhere and the result is simply injected into the WidgetPrinter and used. In a testing context, we could inject some customized variation of the WidgetDao interface into WidgetPrinter that, for example, returns a hard-coded set of Widget instances. As a result of applying this pattern, the relationships between the abstractions become clearer, and there is a clear path to testing components.

Saturday, June 11, 2016

Code Contribution in Continuous Integration Environments

"What branch should I push my changes to?"

Having nudged our Android team into a continuous delivery model, I've been asked some form of this question on more than one occasion as people begin to consider how they'll contribute their changes. It's a great question that I think comes to mind for two reasons:
  1. Perhaps the new changes won't be completed by the time the next release is cut.
  2. Perhaps the app hasn't been regression tested with the new changes.
In both cases the underlying sentiment is that the new changes aren't quite ready for prime time, so there's naturally some hesitation to merge those changes in with the main line of development. This thinking is a by-product of how most teams work in traditional, non-CI environments. Long-running changes are typically segregated in topic/feature branches, completed and tested in isolation, and finally merged into the main line of development.

The shortcoming with this approach in a CI environment is that topic branches typically aren't of the first-class citizen variety wherein any contribution to them will kick off a series of automated tests. By moving code into separate branches we're not only losing that automated feedback loop that tells us if we've broken any existing behavior, but we're also pushing off early integration with others' contributions, which is a common pain point in traditionally maintained projects.

So how can we bridge the gap between changes not ready for wider distribution and having those same changes automatically vetted for accuracy?

Branching by Abstraction

As described by Jez Humble and David Farley in Continuous Delivery, in this development pattern:

  1. A layer of abstraction is first created over the behavior under change. This new layer should initially delegate to whatever currently gives the system its existing behavior. 
  2. With this abstraction in place, development of the new behavior can begin in an area that is unreachable by production flow of execution. 
  3. Once the new behavior is completed, the abstraction layer should be updated to delegate to the new behavior. 
  4. Finally, the old behavior and the abstraction layer are both eligible for removal at the discretion of the maintainers.

As an example, let's assume the following (overly) simple example:

class CalculationResult

class AwesomeApplication {
    fun performSomeComplexCalculation(): CalculationResult {
        // do the leg work behind calculating a
        // complex result before returning it...

        return CalculationResult()
    }
    
    fun main(args: Array<String>) {
        val result = performSomeComplexCalculation()
    }
}

Here we have our AwesomeApplication class with a single function named performSomeComplexCalculation(). The role of this function, as the name implies, is it perform some calculation logic and return a typed result to the caller.

Let's assume now that we've decided to modularize our application by moving the calculation logic out into a separate calculation service. This will likely be a long-running change that entails more than just grabbing the calculation result. We'll need to test our remote call implementation and the various delivery results coming back to us (e.g. successful calls, unsuccessful calls, transient network failures, etc).

As described earlier, we'll start by creating an abstraction layer around invoking our calculation logic:

class CalculationResult

interface Calculator {
    fun calculate(): CalculationResult
}

class InProcessCalculator : Calculator {
 override fun calculate(): CalculationResult {
        // do the leg work behind calculating a
        // complex result before returning it...

        return CalculationResult()
    }
}

class AwesomeApplication constructor(private val calculator: Calculator = InProcessCalculator()) {
    fun main(args: Array<String>) {
        val result = calculator.calculate()
    }
}

As you can see, we've done a bit of refactoring to start. We've created an Calculator interface along with a default implementation named InProcessCalculator, and ported the existing calculation logic into this new implementation class. AwesomeApplication now depends on having a Calculator instance in order to be constructed. (Using some sugary Kotlin magic the default calculator type will be used if left unspecified at object instantiation time).

In short, now we have an abstraction (the interface) we can pivot implementations on. Now begins the work of creating a new Calculator implementation, which will at present have no bearing on the application code flow.

class CalculationResult

interface Calculator {
    fun calculate(): CalculationResult
}

class InProcessCalculator : Calculator {
 override fun calculate(): CalculationResult {
        // do the leg work behind calculating a
        // complex result before returning it...

        return CalculationResult()
    }
}

class RemoteCalculator : Calculator {
 override fun calculate(): CalculationResult {
        // do network calls to get results, etc...

        return CalculationResult()
    }
}

class AwesomeApplication constructor(private val calculator: Calculator = InProcessCalculator()) {
    fun main(args: Array<String>) {
        val result = calculator.calculate()
    }
}

Here we've introduced a new RemoteCalculator type. It isn't used anywhere yet, so the production flow of execution remains intact. We can continue adding changes to this implementation along with supporting tests in order to take advantage of the CI environment - all changes from other collaborators are integrated and tested with each commit/push.

When we are ready to start using the RemoteCalculator type, we can simply update the calls sites where AwesomeApplication is constructed. If , for example, you're using dependency injection, you'll start returning instance(s) of RemoteCalculator for all Calculator bindings. In this example, we'll just change the defaulted parameter value.

class AwesomeApplication constructor(private val calculator: Calculator = RemoteCalculator()) {
    fun main(args: Array<String>) {
        val result = calculator.calculate()
    }
}

Lastly, once we are satisfied with our migration, we can optionally refactor by deprecating (or deleting) InProcessCalculator along with the Calculator abstraction if we so choose. (Although in this particular case, Calculator probably represents a good abstraction point that you probably wouldn't want to remove).

Tuesday, May 10, 2016

The Significance of Kotlin for Android

Introduction

To this point of its existence, Android has leveraged Java as its development language of choice. While the selection of Java no doubt opened the framework up to a large pool of developers and the extensive ecosystem of existing libraries and frameworks, that decision as of late is beginning to show its wrinkles:
  • Android isn't compatible with the latest version of Java... which was released well over two years ago. Java 8 was released in March of 2014. Java 7, the latest version compatible(-ish) with Android, reached end-of-life status in April of 2015... which in some sense means Android itself is currently in an end-of-life state.
  • Given that, the latest additions to Java 8 aren't readily available, if at all, including:
    • lambdas and their related features (method references, higher-order functions, etc)
    • streams
    • an improved calendar API
    • an improved type inference system
While there may be backport libraries available to address many of these shortcomings, and if you're able to overlook the annoyance of having to bolt on libraries for what are standard features as of Java 8, some of the commonplace problems with the language itself endure:
  • its verbosity makes for fertile ground for bugs while also hindering its readability 
  • the inability to add behavior to existing 3rd-party types adds to the verbosity
  • the capturing nature of anonymous inner-classes are a common source of Context leaks in Android
  • exception handling idioms promote poor handling of null values
  • mutability by default
Ironically, Java's admirable insistence on backward compatibility means that unless we start changing the way we write Java code, these problems aren't going anywhere anytime soon.

Enter Kotlin.

Kotlin

Kotlin is a statically typed, compiled language targeting the JVM. (It can also target Javascript for those looking to do end-to-end client-server development). Kotlin's standard library offers Java developers many language features aimed at providing an improved development experience, while also offering interoperability with Java.

To get a sense of just how semantically rich Kotlin code can be, have a look at this small snippet of code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
data class Car(val makeModel: String, var miles: Int? = null)

fun main(args: Array<String>) {
    val cars = listOf(
        Car("Nissan Sentra", 150000), 
        Car("Honda Civic"),
        Car("Lexus ES-350", miles = 16000))
    
    val fewestMiles = cars.minBy { it.miles ?: Int.MAX_VALUE }
    
    println("The car with the fewest miles is the ${fewestMiles?.makeModel}")
}

A line-by-line examination:
  • line 1 -
    • data classes provide a few generated boilerplate goodies out of the box
      • sensible equals(), hashCode(), and toString() implementations based on initialization parameters
      • a copy() function supporting property overrides via named parameters
      • generated componentN() methods to support destructuring declarations
    • the val keyword preceding makeModel effectively stores the parameter as private and final and an accompanying accessor method is synthesized
    • the var keyword preceding miles effectively stores the parameter as private and accompanying accessor and mutator methods are synthesized
  • line 3 - standalone functions as first-class types
  • line 4 - immutable references (mutable references as well, though not demonstrated above)
  • line 6 - defaultable parameter values
  • line 7 - named parameters
  • line 9 - 
    • higher-order functions
    • enhanced collections and extension functions (more on this later)
    • the Elvis operator (?:) provides a concise syntax for supplying alternative values to null
  • line 11 -
    • in-line string interpolation (as opposed to token-based or string concatenation)
    • concise syntax for null-safe operations
That's quite a few features demonstrated in just 12 lines of code, and that's just scratching the surface.

I've been using Kotlin in my day-to-day for a few months now. Here are three features that have thus far stood out to me.

Statically Checked Null Types

Not the sexiest feature, but probably the one from which the accuracy of my code's error handling benefitted the most.

In Kotlin, a variable that can potentially hold a null reference must be explicitly declared with a ? suffixing the type declaration:

1
2
var cannotBeNull: String = ""
var canBeNull: String? = null

The compiler recognizes those are two distinct types:
  • String, and
  • String?
Therefore a compiler error will result if one type is used in place of the other, no different than, say, trying to pass an Int where a String is expected.

A nullable type can be cast to its non-null variant in one of two ways.
  1. In the favorable, idiomatic approach, the reference is explicitly checked for null. If the code is running in a branch of execution where the compiler infers that the reference cannot possibly be null, it is then treated as its non-nullable counterpart. This feature is referred to as "smart casting".  (See lines 11-13 in the below snippet).
  2. The second way to cast a nullable type to its non-nullable counterpart is to apply the unary !! operator.  This operator returns the non-null value if a value is present or otherwise throws a NPE. Use this sparingly as a workaround of last resorts and only in cases where you absolutely know a value cannot be null, or if you just like NPEs. (See line 17 in the below snippet).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
fun computeSomeMessage(): String? { ... }

fun saySomething(message: String) {
  println("I would just like to say, $message")
}

val message = computeSomeMessage()  // <-- type is String?

saySomething(message)  // <-- will not compile

if(message != null) {
  saySomething(message)  // <-- compiles; message was smart casted
}

// message is forcibly casted to a non-nullable String
// this could result in a NPE
saySomething(message!!)

Kotlin's approach to handling null values is even more favorable than Java 8's Optionals (if they were even available for Android) because, while Optionals provide structured semantics for handling possible null values, a handle to an Optional itself can still be null.

Ultimately this means putting in more work around handling possible null values in your application, but better to make those decisions at compile-time rather than your users suffering unexpected app crashes.

Functions, Higher-order Functions, and Inline Functions

Where classes should be used to abstract over state, functions should be used to abstract over actions. Up until Java 8, Java developers have been missing out a concise way to express the latter. What has existed is anonymous classes. However, using anonymous classes in Android gave rise to a common class of program errors due to one easily overlooked aspect of Java's anonymous classes - they capture the variables available to them through their enclosing scope (its closure). Thus, if an anonymous class instance is created in an Activity, for example, that Activity's associated Context is captured in the anonymous class instance. As long as that anonymous class instance lives on, so does the Context and all the references it retains, until it is garbage collected or the app eventually dies due to an eventual OutOfMemoryError.

As mentioned earlier, Kotlin indeed offers first class support for lambdas and higher-order functions (functions that accept function literals as arguments or return function literals). The emitted bytecode behind lambdas looks no different than that of an anonymous class instance - every time you use one, an extra class and object are created. Not great for performance. But as an improvement over Java's anonymous classes, Kotlin's lambdas only capture if they close over references in the enclosing scope. In other words, if a lambda is defined with in an Activity, but does not reference any of its members, it will not retain an reference to the Activity, and therefore you need not worry about leaking the Context.

With regards to the performance implications mentioned in the previous paragraph, functions can be inlined. The inline declaration instructs the compiler to replace the call to the function with the actual code implementing the function rather than generating another anonymous class instance, thereby giving you all the benefits of using lambdas without sacrificing performance. This does have its limitations, however. If a higher-order function accepts another function as a parameter and that function is simply called, then that higher-order function may be inlined. However, if a reference to the function parameter is retained, it may not be inlined since there must be a generated object in order to retain that state.

Lastly, another nice little feature is that Kotlin allows us to substitute lambadas where SAM interfaces are used. This helps improve the overall readability of the code, and therein its supportability.

1
2
3
4
5
6
7
8
// Java 
button.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) { /* do something... */ }
});

// Kotlin
button.setOnClickListener { /* do something... */ }

Extension Functions

Extension functions grant us the ability to add behavior to existing classes without the need to extend, decorate, etc. This even applies to classes outside of our control (e.g. the core JDK).

As an example, I prefer read and write code that reads as fluently as prose. So code like this tends to not sit well with me:

1
2
3
4
5
val future: Future<Foo> = executor.submit(...)

if(!future.isDone() && !future.isCancelled()) {
  // do something...
}

I find the use of the negation operator (line 3) in these cases to be both an unnatural way to read as well as easy to overlook when scanning through code. A more fluent way to rewrite this API would be to introduce a new isRunning() extension function on the JDK's Future interface.

1
2
3
4
5
6
7
fun <T> Future<T>.isRunning() = !this.isDone && !this.isCancelled

val future: Future<Foo> = executor.submit(...)

if(future.isRunning()) {
  // do something...
}

This is obviously a trivial example, but hopefully the convenience of the feature is apparent.

My only worry with this this feature is that, if abused, newcomers to a codebase may find it confusing and frustrating to have to discover new behaviors and properties added to well-known classes at the whims of one rogue developer. I had such an experience working on a Scala project that used a lot of implicit conversions, and as a newcomer to the project and the language, it really impeded my ability to grasp what was going on.

Monday, May 25, 2015

What To Expect When You're Expecting...

(...To Move Your App to Android Studio)


Introduction

I recently migrated a decently sized Android project that was originally built in Eclipse with ADT into Android Studio. I've been developing in Java for nearly 14yrs now and Eclipse has been my weapon of choice for ~10 of those years (just... don't ask about the other four). Inasmuch, all the tinkering and whatnot I've done in Android for the past 4-5yrs has been in Eclipse, too. Between all the buzz about Android Studio and the irrefutable, stone cold fact that all the cool kids use IntelliJ, I had been looking forward to changing IDEs for some time to see how much greener the grass is on the other side. As fate would have it, business-related happenings at my current place of employment made the new "build flavors" configuration option (by way of Studio's Gradle plug-in) a veritable must-have, so thus began my journey to the other side.

While I'm satisfied with the variant-based solution we eventually arrived at in switching over to Studio, there were some unexpected hurdles to overcome during the transition in order to begin implementing that solution. The following is an account of those hurdles and what I did to get over them.

Some information about my setup:
  • Android Studio 1.1.0 (though I think this write-up still holds for the 1.2.x branch)
  • Gradle Plug-in 1.1.2
  • Robolectric 3.0-rc2
  • OS X Yosemite
  • The migration itself was performed using Studio's "Import Project" wizard
  • Pre-Lollipop build

MultiDex

As you well know, your source code morphs a few times before it's actually ready to be run on an Android enabled device. Assuming Java as your language of choice, that lifecycle looks a little something like this:

  1. Firstly, your .java files are compiled into your normal VM-spec compliant .class files. 
  2. Since Android devices run a different variant of VM, named Dalvik (the default runtime for pre-Lollipop devices), the aforementioned .class files are then converted into Dalvik EXecutable files (.dex)
  3. Lastly, those .dex files (along with your compiled manifest, resources, etc) are packaged into an installable package (.apk) file.
Through this process, those of you with large projects or perhaps projects that have runtime dependencies on large third-party libraries, may have frustratingly come to learn that the Dalvik specification limits the number of methods that can be referenced within a single .dex file to 65,536.  (Why? <shrug>).  Should you breach this limit you'll be met with an aptly descriptive build error that looks like something along these lines:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

What was really odd in my case was that before the transition to Studio I wasn't hitting this limit. It was only after the migration that my app wouldn't build as a result of hitting this 65k method limit. My (lazy schmuck) theory as to why this happened was that the import wizard may have converted some of the .jar files in my libs/ folder into Gradle managed dependencies, and in that process they maybe got swapped for later versions of those same libraries... which were larger? I know, I know. At the time I just wanted to get things working again, so rather than investing time in figuring out what changed I went about resolving the problem the build system was reporting.

While the recommended solution to this problem is to reduce the number of method references in your application, sometimes this just isn't possible (such as in the case of third-party libraries). Therefore Google's Android Team has produced a solution wherein your build's supplementary .dex files are referenced by the support library (for pre-Lollipop builds), or just natively supports handling multiple .dex files (for builds done against Lollipop or later).

In my case (pre-Lollipop with a custom android.os.Application class), enabling multidex handling involved two steps:

1) Updating the app's build.gradle file to set the multiDexEnabled flag, and importing the multidex support library as a dependency:

android {
  defaultConfig {
    multiDexEnabled = true
  }
}
dependencies {
  compile 'com.android.support:multidex:1.0.0'
}

2) Overriding Application.attachBaseContext() in my custom Application class:

@Override 
protected void attachBaseContext(Context base) { 
    super.attachBaseContext(base); 
    MultiDex.install(this); 
}

The extra emphasis on there being two steps comes from a mistake I made early on. I initially didn't realize the change to my Application class needed to be done. This resulted in the app building, but constantly crashing at runtime due to ClassNotFoundExceptions. Oblivious to what was going on, I unarchived my .apk file and noticed a few .dex files:
  • classes.dex
  • classes1.dex
  • ...
Strangely enough, it was within classes1.dex that the classes identified in the ClassNotFoundExceptions were hiding. Tugging on this thread led me on a few Google searches that helped bring me to the realization of the mistake I had made, which, hopefully now you won't.


Robolectric

...is now a first class citizen in the development cycle (as of Studio 1.2.x)! Rejoice ye responsible developer!

That's not to say we're completely problem free though.


Test Runner Configuration

Robolectric doesn't seem to resolve the application ID correctly when testing against different build flavors. However, creating a dummy BuildConfig with a hard-coded application ID (reflective of the main source tree) seems to be enough to get by in lieu of a real fix. 

My hacky little custom BuildConfig looks something like this:

public class TestBuildConfig {
    public static final boolean DEBUG = BuildConfig.DEBUG;
    public static final String APPLICATION_ID = "your.main.package.name";
    public static final String BUILD_TYPE = BuildConfig.BUILD_TYPE;
    public static final String FLAVOR = BuildConfig.FLAVOR;
    public static final int VERSION_CODE = BuildConfig.VERSION_CODE;
    public static final String VERSION_NAME = BuildConfig.VERSION_NAME;
}

Just refer to this class in your test's configuration annotation, like so:

@Config(constants=TestBuildConfig.class)

...among whatever other configuration options you intend to pass along.

To be fair, I'm not sure if this is a byproduct of my using a release candidate of Robolectric... although in my defense this seems to be a rather glaring problem for a second release candidate. But hey, we're all friends here.


Test Directories

If you're using build flavors in your setup and you're wondering what the directory structure for flavor-specific tests is supposed to look like, here it is:

  -- src
    |-- flavor1
    |-- flavor2
    |-- main
    |-- test
    |-- testFlavor1
    `-- testFlavor2

assertj + assertj-android

If you're using assertj, don't bother trying to use the 2.x branch or later for testing your Android code. It uses a Path-based approach to making assertions, which isn't (yet?) compatible with Dalvik.

Stick with the latest release on the 1.x branch.

Dagger + ButterKnife

These amazingly work right out of the box with little-to-no configuration changes.

The one hiccup I experienced had to do with Studio's overzealous import wizard actually importing the generated code from these frameworks, thus resulting in subsequent builds failing due to classes already being defined when the frameworks attempt to re-generate them. The build system is likely to report an error along these lines:

Error:(7, 8) error: duplicate class: com.android.test.Foo$$ViewInjector


Annoying, yes, but thankfully simple to resolve. Traverse your source tree and delete all the classes with names that are suffixed with:
  • $$InjectAdapter
  • $$ModuleAdapter
  • $$ViewInjector

Saturday, January 3, 2015

Adventures in Code: Android MVP By Example

In this post, we'll take a look at an application of the MVP pattern in Android. Given that MVP is an architectural style as opposed to a rigid set of rules to be followed, it goes without saying that what follows is merely one schmuck's interpretation of that pattern, for better or for worse. Comments, feedback, and spirited debate are always welcome!

Note - this write-up assumes some working knowledge of Dagger. I found the documentation on the site to be really thorough, and having experience with Guice is a bit of a plus, but if you want a write-up on Dagger then let me know in the feedback.

Let's start by establishing what we're doing and why we're doing it before we get into the code.

What is MVP?

As mentioned earlier, MVP is an architectural pattern for designing software, that when used, is most commonly found in applications that have a user interface. The pattern assumes three logical components:

  1. Model (an interface defining what data will displayed by a View)
  2. View (an interface describing how data represented by a Model will be displayed)
  3. Presenter (an intermediary facilitating communication between the Model and View)
Simply illustrated...


A typical interaction might go something like this:

  1. A user interacts (click, touch, drag, fling, butt-dial, etc) with a screen element hosted by the View
  2. The View delegates this interaction to a Presenter 
  3. The Presenter interprets this interaction and in turns communicates with one or more associated Models
  4. If any results are forthcoming, they are then communicated back to the Presenter and then finally to the View


OK... But Why Use It?

A few reasons:
  • Separating the domain logic and the presentation logic into discrete components allows you to unit test the behavior of each in isolation, rather than having to test both in conjunction by doing instrumentation style testing on an emulator or a real device:
    • The UI (activities and fragments) can be tested with Presenter(s) that are test doubles (using a framework like Robolectric), and...
    • Presenters can be tested with Views that are test doubles (without any Android dependencies)
  • Having smaller, focused classes helps steer you away from code bloat within any one class 


Sold! Show Me How!

Let's assume for this example that we have an application that bootstraps itself by checking to see if the current installation has an account associated with it. For this, we'll design three components in line with the MVP style:

An interface for the Model...
... an interface for the View...
(It might be kind of hard to see at this point, but BootstrapView is shaping up to be a pretty passive component. For example, it knows how to show and hide its progress indicator... but it doesn't know when to do either!)

... and finally, an interface for the Presenter:
Now let's put some meat on those bones.

This being an Android application, we'll create an Activity named BootstrapActivity that implements our BootstrapView interface:
Let's turn our attention to the more noteworthy parts:
  • (Line 15) as you can see, BootstrapActivity is an extension of InjectingFragmentActivity. A full description of InjectingFragmentActivity goes beyond the scope of this post, but it should suffice to say that its onCreate() method is overridden to invoke Dagger to create a sub-graph of the application's dependencies and subsequently use that graph to inject `this` instance. As a result, we have an instance of a BootstrapPresenter after the call to super.onCreate() on line 22.
  • (Line 15) as previously mentioned, this class implements our BootstrapView that will later be used to drive the UI.
  • (Line 24) this is the jump off point for our domain logic. When the activity is created, the BootstrapPresenter is invoked to check for an existing account.
  • (Lines 34-54) the BootstrapPresenter instance will asynchronously invoke any of these methods depending where it is in it's invocation of checkForAccount().

Now let's look at an implementation of BootstrapPresenter:


Let's once again inspect the noteworthy stuff:
  • Take note that this class is a simple POJO and thus requires no special Android framework-y stuff in order to test
  • (Line 8) as expected, this class implements our BootstrapPresenter interface 
  • (Lines 10-18) the same instance of BootstrapView that invoked the call to checkForAccount() will be injected as an argument for constructing this instance of BootstrapPresenterImpl. Keeping this reference around his gives us a way to call back to the UI to perform the various actions exposed by the BootstrapView interface.
  • (Line 16) wrapping the reference to BootstrapView with a WeakReference here is critical to memory management in that it signals to the VM that the wrapped instance should not be retained on account of this referrer. In other words, if the only references to the wrapped instance are in the form of a WeakReference, then the garbage collector can feel free to reclaim the memory.
  • (Lines 22-24) while the WeakReference itself will not be null, its delegate may be if the previously described circumstances called for it to be garbage-collected. A simple null check will tell you everything you need to know.
  • Now we'll basically drive the behavior of BootstrapView:
    • (Line 27) instruct the BootstrapView to show the user that the application is currently doing work.
    • (Line 31) instruct the BootstrapView to stop doing whatever it was doing to show the user that the app was doing work.
    • (Lines 33-37) invoke BootstrapView to either take the user to the account registration or to whatever other entry point the application has defined for users that already have an account.
  • (Lines 41-43) this is obviously a dummy implementation for example purposes, but this type of behavior could be further decomposed into Services, Interactors, etc. that can likewise be injected into this instance and delegated to.
And there you have it. MVP on Android.