2. 2SEC-2015
Who am I?
Vadym Khondar
Senior Software engineer
8 years experience
2.5 years with EPAM
Development team lead
Web, JavaScript, Java
vadym@khondar.name
5. 5SEC-2015
Evolution of Internet
938 millions in June, 2004
3,035 millions in June, 2014
http://www.internetworldstats.com/emarketing.htm
1,440 millions in May, 2015
6. 6SEC-2015
Evolution of expectations
• You see response to your actions quite quickly
• You don’t notice if something breaks
• You can collaborate
• You have everything you need at the place you are
7. 7SEC-2015
1995 1997 1999 2001 2003 2005 2007 2009 2011 2013 2015
Evolution of challenges
Tens of servers
Seconds of response time
Hours of offline maintenance
Gigabytes of data
Millisecond response times
100% uptime
Cloud
Mobile devices
Internet of Things
8. 8SEC-2015
Definition of reactive system
Reactive Systems are:
• Message-driven (react to events)
• Elastic (react to load)
• Resilient (react to failures)
• Responsive (react to users)
http://www.reactivemanifesto.org/
15. 15SEC-2015
1. Encapsulation principle may be violated
2. Separation of concerns principle may be violated
3. Not easily composable
4. Inversion of control
Observer pattern problems
16. 16SEC-2015
$(function() {
var currentWord = '';
$('#textin').keypress(function(event) {
var key = String.fromCharCode(event.keyCode || event.charCode);
if (!key.match(/[w]/) && currentWord) {
var link = 'https://twitter.com/hashtag/' + currentWord;
$('#textout').append($(' ')).append(
$('<a/>').attr('href', link).text('#' + currentWord)
);
currentWord = '';
} else if (key) {
currentWord += key;
}
});
});
Example: Hash tagger
State
Mixing logic with
presentation
No easy way to
compose with
another handler of
keypress
17. 17SEC-2015
Callback hell
public class ReportsEntryPoint {
@Override
public void onModuleLoad() {
String documentIdString = Window.Location.getParameter("docId");
if (documentIdString != null && !documentIdString.isEmpty()) {
try {
final Long documentId = Long.parseLong(documentIdString);
MainService.Util.getInstance().findReport(documentId, new AsyncCallback<ReportDto>() {
// Getting Report information first
@Override
public void onSuccess(ReportDto result) {
final ReportDto processedReport = result;
MainService.Util.getInstance().getUserInfo(processedReport.getUserId(), processedReport.getCompanyId(),
new AsyncCallback<UserCompanyDto>() {
// Getting user information for future form initialization
@Override
public void onSuccess(UserCompanyDto result) {
UserDataHolder.getInstance().setUserCompanyDto(result);
MainService.Util.getInstance().getDProfile(processedReport.getCompanyId(), new AsyncCallback<DProfileDto>() {
// Getting company profile for future form initialization
@Override
public void onSuccess(DProfileDto result) {
UserDataHolder.getInstance().setDProfileDto(result);
MainService.Util.getInstance().getPProfile(processedReport.getCompanyId(), new AsyncCallback<PProfileDto>() {
// Getting company profile for future form initialization
@Override
public void onSuccess(PProfileDto result) {
UserDataHolder.getInstance().setPProfileDto(result);
MainService.Util.getInstance().getFormDto(processedReport, new AsyncCallback<FormDTO>() {
// Getting report document form
@Override
public void onFailure(Throwable caught) {
Window.alert("Can't get document: " + caught.getMessage());
ReportEditorEntryPoint.windowClose();
}
@Override
public void onSuccess(FormDTO result) {
if (result == null) {
Window.alert("Can't get document.");
ReportEditorEntryPoint.windowClose();
return;
}
// -- some code to process if finally everything is ok!
}
})
http://callbackhell.com
25. 25SEC-2015
combine() – stream containing events from either combined streams
concat() – stream containing items of first stream and then of another stream
Stream transformation
map(Type1 => Type2) – stream of values from given function applied to each element in source stream
filter(Type => Boolean) – stream of values from source stream for which given function returns True
reduce((Type1, Type2) => Type1) (or scan(Fn, seed)) – stream of single value which is result of applying
given function to element in source stream and result of previous call to given function
skip(num) – stream produced from source stream by skipping num elements
take(num) – stream produced from source stream by taking num first elements
Transforming
Combining
26. 26SEC-2015
Example: Hash tagger reactive
No global state
Clear separation of concerns
Declarative description
$(function () {
var keyStream = Rx.Observable.fromEvent($('#textin'), 'keypress')
.map(function (event) {
return String.fromCharCode(event.keyCode || event.charCode);
});
var endOfWordStream = keyStream.filter(function (char) {
return !String(char).match(/[w]/);
});
var wordStream = keyStream.buffer(endOfWordStream);
var uiUpdater = Rx.Observer.create(function (word) {
word = word.join('').trim();
var link = 'https://twitter.com/hashtag/' + word;
$('#textout').append($(' ')).append(
$('<a/>').attr('href', link).text('#' + word)
);
});
wordStream.subscribe(uiUpdater);
});
Composable API
27. 27SEC-2015
Behavior (Signal)
Behaviors are used to express continuous dependency between values.
They are often referred to as function from time domain to value domain.
They are also called signals or properties.
Example:
𝛼 = 90 - minute x 6 angle of minute arrow on the clock
32. 32SEC-2015
Producer Consumer
import scala.concurrent.{ future, promise }
import scala.concurrent.ExecutionContext.Implicits.global
val p = promise[T]
val f = p.future
val producer = future { // async
val r = produceSomething()
p success r // completion of future
scontinueDoingSomethingUnrelated()
}
val consumer = future { // async
startDoingSomething()
f onSuccess { // what to do on completion
case r => doSomethingWithResult()
}
}
33. 33SEC-2015
Single item Many items
Pull/
Synchronous
Optional
Iterator/
Iterable
Push/
Asynchronous
Future
Observer/
Observable
34. 34SEC-2015
Reactive programming
Benefits
• gives you a base for
creating reactive systems
• gives you means of
handling async in more
elegant way
• stimulates you to write
more concise code
Drawbacks
• might be harder do
debug
39. 39SEC-2015
• Rx JS (http://reactivex.io/) – Observable on steroids
• Bacon.js (https://baconjs.github.io/) – EventStreams and
Properties (behaviors)
• Kefir.js (https://rpominov.github.io/kefir/) - inspired by Bacon.js
and RxJS with focus on high performance and low memory usage
Tools - Frontend
40. 40SEC-2015
• Java 8 (hello to Streams, lambdas, CompletableFuture)
• Scala (gives a good taste of functional paradigm while letting you
have old habits)
• RxJava (https://github.com/ReactiveX/RxJava/)
Tools - Backend
Hello to everybody.
First of all, I am very excited to have an opportunity to speak to you today.
My speech is about some of the useful programming patterns collectively called ‘reactive programming’.
Today I will try to explain what do these buzz words mean, why would anyone bother and how reactive programming principles can be applied on practice in day-to-day work.
There is more than one way to be reactive with no chance to cover them all in half an hour speech so we will particularly look on functional reactive programming and advantages it can bring to you.
So. Why do we have this whole conference devoted to digital engagement?
If we go sites like internetworldstats.com we could find some interesting figures. For the last decade amount of Internet users has grown in more than 3 times.
Now, the latest statistics from Facebook states 1,4 billion monthly active users. And that is just for single application!
It appears that last decade changed significantly the role and availability of digital services in our lives. We check-in, share and consume opinions, authorize with Facebook/twitter in lots of places. Permanent presence with smartphones and other personal devices is perceived now as quite natural.
If you pressed a button and saw a glitch before an intended action happened you start thinking the app is not good enough.
It is not interesting for you to know that datacenter experiences blackout and that is why you can’t access something.
It’s quite good to have all the documents required with you or read news while you’re on the way to your job.
Applications stop to be local to your computer – you expect integration and availability
With internet and devices becoming ubiquitous our expectations from the services being used are changed, so as the engineering challenges being faced.
From tens of servers, seconds of response, gigabytes to internet of things, 100% uptime, miliseconds response
2003 – Android
2004 – Facebook
2006 – AWS, twitter
2007 – iPhone
2010 – Instagram, Azure
2011 – Google+
These expectations led engineers to solve similar problems. If we generalize, they all come to following set of properties that system architecture should have to be able to react to different stimulus: events, load, failures and of course user. That is summarized in Reactive manifesto.
Message or event driven nature enables loose coupling between components that is a good thing for quickly replacing failed component. This aspect also contributes to system flexibility as it enables location transparency and thus horizontal scaling. Careful encapsulation of the state or even lack of it within the system allows vertical scalability (usage of multiple cores). Provided system is elastic and resilient it can still provide acceptable responsiveness to user interaction and that is the key of user experience.
Let’s look at the problem that reactive systems try to solve.
Our frontend is usually single threaded thus blocking on anything there is equivalent to death.
For web-application we may want to move from multiple small requests towards single big request. Achieving that requires efficient concurrency handling on backend because otherwise single fat request processing can be slower than multiple light ones even despite saved network latency.
We want to model the real world where actions are driven by certain events – e.g. toggling the switch, moving mouse, change in the temperature. Common about these events are that they appear at some moment and we don’t know in advance when they do.
That is usual thing to deal with for every programmer, I guess. What do we usually do to handle events?
The answer is plain old Observer pattern. We register a callback to be executed when event of interest occurs and it gets executed by call to notify().
So far so good – we seem to start being reactive doing some stuff whenever something happens.
But is this all that we need?
It’s really simple and well understandable but can cause us troubles:
- To make certain state available in multiple related observers we tend to move it to broader scope that it should be.
- Usually, we put everything needed to process event within callback and these actions may be quite of different nature, e.g. calculations and UI updates. It might be not good to mix.
- When you need to consider in your reaction several events simultaneously you start making spaghetti.
- You place the code important to understand how your app functions within callback handlers – the flow is inverted thus harder to understand.
Let’s take a look on example.
Hash tagger listens text area for key presses, accumulates them and then adds new hashtag to output area once word is ready.
This implementation is obviously quite simple but it demonstrates the issues we highlighted: state is more global then it should, logic holds changing presentation, no easy way to combine one callback with another.
If previous one was not bad enough for you, here is another sample from project I worked on. It has all those issues but multiplied in 10 times and this is from real code of GWT-based application dealing with async javascript UI for reports display.
You may not try to read code, it does not really matter – I tried hard to fit it into the slide so removed failures handling as well as business logic. You can think that something is bad with your code if it has characteristic shape.
This code seems to contain many boilerplate present there just to support how we express the idea in programming language.
Can we do better?
If we look around we may notice that we already have some nice stuff.
If you are Java developer like me you most probably enjoy enhancements that Java 8 brought with Streams, Optionals and Lambdas. Making at least some boilerplate implicit gives us more space to think what we want to say rather than how we want to say with more concise code.
If we look around we may notice that we already have some nice stuff.
If you are Java developer like me you most probably enjoy enhancements that Java 8 brought with Streams, Optionals and Lambdas. Making at least some boilerplate implicit gives us more space to think what we want to say rather than how we want to say with more concise code.
But these constructs are using pull synchronous model and not capable dealing with asynchronous data.
It’s now right time to come to the next questions – What is reactive programming?
If we dig into history we can find that definition of reactive programming is quite similar to the one of dataflow programming first invented at late 60s.
Traditional control flow or imperative programming is focused on sequence of instructions that might potentially modify data.
Data flow instead is focused on data movement and models the program as graph with explicit connections between data processing functions that are triggered whenever the inputs are available.
Reactive programming uses two main abstractions to model dataflow:
Discrete one with events and their streams.
Probably, the most common dataflow model is stream. Anything can really be defined as such stream - mouse moves, mouse clicks, key presses, etc.
2. Continuous one with functions that represent value-time dependency. Such functions are called behaviours or signals
Having one stream we can use it to define other streams.
We do it by defining different combinators on top of the stream.
Combinator takes some code (function) that transforms underlying stream into new one. Ability to pass functions as parameters as well as return them and overall treating them as first class members is characteristic of functional programming paradigm. So here is where functional programming comes in shiny and this is why whenever talking about reactive programming you most probably will hear functional reactive programming or FRP.
The key idea here is that we don’t work with values in regular way but obtain new stream by applying transformation function to it.
There is a handful of most common transformer functions. Using these allows to hide explicit state manipulation and stimulates
In this example we don’t have currentWord accumulator as global state – it is hidden.
Usual semantics with imperative approach is calculate the statement value once it encountered. But in reactive paradigm this is dependency established once and updated going forwards whenever member values change so angle changes with minute of an hour without need from you to do something about this.
Another often mentioned example is cell formulas in MS Excel.
Signal changes can emit events and events can produce signals – it easy to convert between each other.
The game is about using ‘Vaus’ spaceship to kick the ball and break the bricks
First – we define some constants for convenience of coordinate calculations.
Second – we define what should our paddle position depend on – mouse.
Third – we define property that expresses actual dependency between mouse position and vaus position.
Finally, we just tie this property to presentation once.
You don’t always deal with sequences but still want all that good when working simple value?
Here is where another useful abstraction for handling async results without blocking fits - Futures. There are slight difference in terminology but essentially these are the same.
The idea is to decouple producer and consumer of asynchronous operation in composable way.
Summarizing the concepts which we just walked through we can see that they cover all the cases we usually have within software systems which have very similar interfaces and are composable.
Talking about async part – we get the means of work with values that we will get in future as if they were present and means for expressing processing (potentially infinite) stream of items that might appear sometime like if they were available.
That is what reactive programming gives to you: it makes implicit a significant amount of computation that must be expressed explicitly in other programming paradigms.
It’s all about asynchronous computations and means to conveniently deal with it.
In this way you put good foundation into your API and encourage users to become closer to reactive but still give an option to remain synchronous.
From my personal experience I can say that it greatly widens your outlook. Sometime it may be mind blowing. But definitely it will make your code better.
That is the edge between using the stuff I’ve been talking about and understanding the roots behind as a whole picture.
You may want to review how you usually deal with the state. We may not be ready to completely refuse mutable state and become functional purists but it is worth looking into functional techniques of its implicit management – this can save us hade-ache especially with distributed multithreaded systems.