Building a Functional toolset for Android

Business requirements are hard. As developers we feel the pressure on the day to day to get features that deliver business value out of the door, and that pressure does not decrease over time. The real risk of having to grok a feature and accumulate technical debt is a real concern that will come back down the line.

Having a nice open source library stack and knowing your patterns helps both speeding up your development cycles, and having to care less about technical debt caused by maintenance. In this regard Java comes with a great standard library and healthy library ecosystem, and several decades of tips, guidelines, rules, and patterns to follow. With the rise of multi-core CPUs on mobile and multi-threaded applications, the introduction of lambdas in new languages (Swift, Kotlin, Rust, Go...) and the addition in some of the more mainstream ones (C++ or Java), the rediscovery of functional programming has been a hot topic for the last couple of years.

The biggest problem with functional programming, as with any paradigm change, is the transition phase where the tools are not complete, and the users are getting used to the new idioms. After spending years learning how to properly do Command, Strategy, or Façade patterns, hearing about a new set of patterns that are not exactly familiar may be daunting: what is Partial Application, Currying, Monoids, why do you Map/Reduce instead of looping?. Because Android doesn't provide standard libraries for them, theye're time consuming to research and learn. The community on desktop and server has been hard at work to provide some: JavaSlang, Cyclops, FunctionalJava, Java 8's Stream and CompletableFuture... But none of these libraries are available below Java 8, not until recently.

The new tools

Over the past few months I've been working on creating a growing set of libraries to bring functional concepts, these patterns, into Java 6 and Android via RxJava. The benefits in our apps have been immediate: expressing our needs in RxJava chains with algebraic data types simplifies data modelling, partial application solves problems with communicating data between parts of the app and makes for nicer APIs, Function composition reduces boilerplate, and simple tuples to avoid creating new local types.

Each library is separate and has dependency only on RxJava. Looking at the implementation and the readmes can help you understand these new concepts and patterns, and how they can be applied through your app.

I have also created a compilation jar so you can add only one dependency to have all libraries always up-to-date. I've named it FunctionalRx.

  • RxSealedUnions: Arguably the best of them yet the most misunderstood. Algebraic data types (called unions in this library) are a blessing: they're an overloaded version of enums, where each of the elements of the enum can be of its own class. You don't have to check if they're present or absent or whether they inherit a class like sealed classes in kotlin. You define a Union by creating a Factory which provides a constructor for each of the possible types, and it exposes two methods to operate on them without worrying about nulls or exceptions.

Unions are used in languages like Scala, F#, and Clojure to define DSLs: parts of your code that are only allowed to perform a series of actions with some values, and no others. Commonly this has been done with the Command, Strategy, or Visitor pattern, but in Java it suffered from allowing unwanted extensibility.

As an example, your app may need to do a networked operation that sadly has to survive rotation. You have to store the state and result of the operation in a field, but what would you use? An enum? A flag? An object with null fields you have to check for results? Enter unions:

interface Success<T>(){
    T giveResult();
}

interface Error<E extends NetworkException>{
    E giveError();
}

interface Loading {}

interface Idle {}

Union4<Idle, Loading, Success<String>, Error> myUnion = 
        startObservableRequest("id", "154878");

Now, what would we do next? If we had an enum we'd use a switch, if it was an inheritance class we'd have to if check the type. In the case of enums it's simpler, we do a switch statement that's happening inside the union, for which you provide what to do for each of the cases.

myUnion.continued(  (idle) -> hideLoadingScreen(),
                    (loading) -> showLoadingScreen(),
                    (success) -> showToast(result.giveResult()),
                    (error) -> logError(error.giveError()));

Go, imagine the same principle applied to any validation for any kind of user input/output, where before you had to rely on nullability now you can define your own types, even empty classes, that represent better the state of your app.

  • RxFunctions and RxActions: Your app is defined by a series of methods that, if correctly implemented, should give the same results for the same parameters. These methods can be composed, united, or operate against each other, to form different functions. This way your UI can be broken down in smaller, easier to understand, more testable pieces:
Action1<String> showToast() { /* */ }

Action1<String> logDebug() { /* */ }

Action1<String> logAndToast() {
    return RxActions.act(showToast(), logDebug());
}

or even composing functions:

Func1<User, Boolean> nameNotNull() {
    return (user) -> user.name != null;
}

Func1<User, Boolean> hasConfirmedAccount(int days) {
    return (user) -> user.confirmedPassword;
}

Func1<User, Boolean> isActive(int days) {
    return (user) -> user.daysSinceLogin < days;
}

Func1<User, Boolean> inactiveUsersFilter =
        RxFunctions.and(
                nameNotNull(),
                RxFunctions.or(isActive(5),
                            RxFunctions.not(hasConfirmedAccount())));

Func1<User, Boolean> usersTodayFilter =
        RxFunctions.and(nameNotNull(),
                        isActive(isActive(1));
  • RxPartialApplication and RxCurrying: Another way of composing functions, this time by creating a new function that takes fewer parameters. How do you make a function taking 5 parameters into another taking only 2? By storing some of them inside the creation function, ready to be used when the function with fewer parameters is called.

This can be useful when you're defining your UI, but you don't want your UI implementations go into your business layer, so you hide them. One common example is the network function you have to call on a background thread, but on the tests it has to be executed immediately by using a different Scheduler.

Func2<String, Scheduler, Observable<Result>> networkOnAnyThread() { /* */ }

Func1<String, Observable<Result>> networkOnNewThread =
        RxPartialApplication.applyEnd(networkOnAnyThread(),
                                        Schedulers.newThread());


Func1<String, Observable<Result>> networkOnImmediate =
        RxPartialApplication.applyEnd(networkOnAnyThread(),
                                        Schedulers.immediate());

Note that these partially applied functions can be created at runtime without needing to go back and rewrite a class. Normally they're later sent to other functions as parameters.

You can also use partial application during API usage to avoid having to add fields to your class to fulfill just one dependency, for example a function using the Context to fetch a string from resources:

static Func2<Context, Integer, String> getStringInternal() { 
    (context, id) -> context.getString(id);
}

public Func1<Integer, String> getString =
    RxPartialApplication.apply(getStringInternal(), this);

NetworkRequests.
   requestOrReturnErrorFromResources(getString);

This way your network layer can use strings from resources without knowing about Context or anything on the view layer, and it can be swapped out during testing.

  • RxTuples: This one is the most straightforward. Sometimes you have to put two elements together before sending them on the RxChain, but they're not of the same type. This causes a small headache, do you use an array of Objects and then cast them back? Do you create a new type containing only both elements, and equals/hashCode/toString? Nah, better use a Tuple. Where a list has any size and can hold elements of mostly the same type, a Tuple is a container of fixed size where you know the type of every element inside it. Like a Pair, but containing from 3 to 9 elements!

Combined with the zip() operator, it's the base to operate with multiple data streams. For example, to get the elements of a stream along with the order they were received:

Observable.zip(getUserTaps(), Observable.range(0, Integer.MAX_VALUE), 
               RxTuples.<String, Integer>toPair());

or maybe you want to combine the latest result of your user location, compass, and network location for analytics:

Observable.combineLatest(networkStatusObservable(),
        locationObservable(),
        compassSensorObservable(), 
        RxTuples.<NetworkStatus, LocationData, CompassPosition>toTriplet());
  • RxMemoization: Memoization is a technique that stores the results of a function for the same set of parameters, which makes it useful for caching heavy computations that are called often with the same values.
Func1<String, Integer> parser = 
        RxMemoization.memoize((String s) ->
                                {   System.out.println(s);
                                    return Integer.parseInt(s); });

// All the results for the same parameter correspond to the same object

parser.call("0"); // Integer@65E46F
// Log: "0"
parser.call("0"); // Integer@65E46F
parser.call("0"); // Integer@65E46F
parser.call("1"); // Integer@335A8B
// Log: "1"
parser.call("4"); // Integer@564E21
// Log: "4"
parser.call("1"); // Integer@335A8B
parser.call("4"); // Integer@564E21
parser.call("0"); // Integer@65E46F
parser.call("2"); // Integer@564E21
// Log: "2"
  • RxComprehensions: Reduces boilerplate and general chunkyness of chaining Observables with nested flatMap() operations.
// Without comprehensions
profileClicks()
        .flatMap { position ->
            getUserFromProfile(position)
                    .flatMap { user ->
                        requestFriendListForUser(position, user.id)
                                .flatMap { friends ->
                                    storeUserAndFriends(user, friends)
                                            .flatMap { result ->
                                                toUserDisplayString(position, user, friends, result)
                                            }
                                }
                    }
        }


// With comprehensions

doFM(
    () -> profileClicks(),
    pos -> getUserFromProfile(pos),
    pos, user -> requestFriendListForUser(pos, user.id),
    pos, user, friends -> storeUserAndFriends(user, friends),
    pos, user, friends, result -> toUserDisplayString(pos, user, friends, result));

Short and long term plans

In the near future all the quirks with Jack & Jill will be ironed out, and everyone will get access to lambdas and method references. Once they're available, all the libraries above will not require methods to return FuncN or ActionN, they will work for any method by using method references. Imagine the possibilities!

Following this entry I am starting a series about how to build some real life complex business requirements in an almost purely functional project using the tools above and a Flux-like architecture with passive view.

The first step is understanding Functions and Method References.

The "Intro to FRP" Series
  1. Functional libraries for Java
  2. Advantages of using generic method references, Functions and Actions as parameters
  3. Transforming APIs based on inheritance to simpler, composable, ones by means of Functions
  4. Review of Android lifecycle issues with traditional callbacks
  5. The reactive approach to composable and cancellable callbacks with observable sequences
  6. The Observable in RxJava as a composable sequence for your existing code