Composing functions into applications

The Serverless Way

rodric rabbah
Oct 16, 2017 · 4 min read

Serverless computing is a new model of programming for the cloud that has gained traction with developers because of key value propositions: little to no concern about infrastructure operations, auto provisioning and auto scaling, and pay-per-use with zero cost for idle time. The fastest disruption in serverless has occurred with Functions-as-a-Service (FaaS), which are cloud-native, usually stateless, functions that scale on demand. FaaS is now offered by all major cloud vendors, and IBM was an early entrant into this new market with OpenWhisk, now an open source Apache incubator and a growing open source community around it.

It does not take long programming in this style to realize that FaaS fosters a model where code is organized into small functions, and developers need a way to orchestrate an application’s execution through many functions. IBM Cloud Functions, built on Apache OpenWhisk, offers sequences as a form of composition to construct data pipelines, where the result of one function becomes the input of another.

But applications are more than just sequential compositions, and control flow orchestration is ubiquitous to programming languages. I’ll illustrate some examples below, you can imagine how these might look in your favorite language.

  • A sequence is the equivalent of a semicolon:
function main(args) { 
let result = A(args);
return B(result);
}
  • Control flow using test and branch or more commonly if-then-else:
function main(args) { 
if ( C(args) ) {
return A(args);
} else {
return B(args);
}
}
  • And of course, exception and error handling with try-catch:
function main(args) { 
try {
return A(args);
} catch (e) {
return B(e);
}
}

It’s also common for a language to offer various looping constructs such as do, for and while, among others.

With functions-as-a-service, the building blocks of most applications and REST APIs can run serverlessly. Functions are activated in response to incoming events (which might be HTTP requests for example), and resources are automatically reserved for the duration of that function’s execution. As more functions are activated, more resources may be allocated.

What about the compositions however? If one represents the composition as shown above and runs it as a serverless function, they are subject to “double billing” — the composition waits for the result of each function it calls, and hence must pay for the wait time. This violates one the serverless principles: pay for what you use, not idle time.

Serverless compositions, simply put, eliminate the double billing dilemma. In fact, without intrinsic support from the serverless platform, it is impossible to avoid double billing and still be serverless.

Composer for IBM Cloud Functions is a new programming model from IBM Research for building serverless applications that compose functions, APIs and services. It is built on top of Apache OpenWhisk and works with standalone deployments or with IBM Cloud Functions.

Composer is not a new programming language. Instead, it is a library of combinators — meta programming using functional programming — which you use in your preferred language. It makes it possible to write straightforward code to express control and data flow, and may be used with polyglot functions. The composer library is currently available in Node.js but the same approach can be generalized to other programing languages, like Python, Swift, and Java. It is worth noting that even though the library is available in JavaScript, it does not require one to develop in that language. Our goal is compositions that are easy to express and program, familiar to developers, and which offer the same benefits that make FaaS attractive and disruptive.

Here is a sequence, if-then-else and try-catch using composer, matching the examples shown earlier.

composer.sequence('A', 'B')  // functions are referenced by name
composer.if('C', 'A', 'B') // if ( C(args) ) A(args) else B(args)
composer.try('A', B') // try { A(args) } catch(e) { B(e) }

In IBM Cloud Functions, compositions are represented as and execute as OpenWhisk actions. They run with support from a composition conductor, which manages the program state as the composition executes. The conductor also runs as an action, but unlike the manual composition shown earlier, it will not suffer from double billing. Instead, the execution of an application unfolds with continuation passing between functions, to resolve the next state of the computation and hand off the control flow. This is illustrated below.

The current technology preview of Composer does not yet fully utilize continuation passing, which is in the works and will be contributed to Apache OpenWhisk. We have made it available on GitHub for feedback, early adopters, and contributors.

We believe this is only the start of new programming abstractions and models for the serverless cloud. It does not take much to imagine a rich future of innovation around programming models, compilation, and runtime optimizations. Our group at IBM Research is excited about the opportunities and is at the forefront tackling these issues.

Apache OpenWhisk

Apache OpenWhisk is a serverless cloud platform that…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store