3. So what does it mean for the App to be
Reactive?
His Majesty
Reactive Manifesto
4. ReactiveApp should be …
Message-Driven
• Components communicate via asynchronous messages (errors are messages also)
Resilient
• System stays responsive in the face of failure
Elastic (Scalable)
• System stays responsive under varying workload
Responsive
• System responds in timely manner if at all possible
5. Or if we put it in a diagram …
Resilient
Message-Driven
Scalable
Responsive
6. OOP, State of the Union
Resilient
Message-Driven
Scalable
Responsive
We’ll pack Events
into Messages TheGood
TheBad
TheUgly
State and Behavior
are Joined
State is Mutated
Error Handling up to
the Client
8. Event-Driven → Message-Driven
Everything is a message
• Including errors
Everyone (each component) can be Producer and Consumer of
messages
Producer Consumer
Stream of
Messages
UI Component
Remote Service
Scheduled Job
Whoever’s
Subscribed
Events
Computation Result
Query Result
9. Making Streams of Messages with RxJava
Observable – Representation of the Message Producer
Observer – Representation of the Message Consumer
• onNext
• onCompleted
• onError
onNext
onNext
onNext
onCompleted
ObservableStream
of Messages
10. Making Streams of Messages with RxJava
Observable – Representation of the Message Producer
Observer – Representation of the Message Consumer
• onNext
• onCompleted
• onError
onNext
onNext
onError
ObservableStream
of Messages
12. Making an Observable
The real Power lies in
• Observable.create
public static Observable<SomeDataType> getData(String someParameter) {
return Observable.create(subscriber -> {
try {
SomeDataType result = SomeService.getData(someParameter);
subscriber.onNext(result);
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
});
}
13. Consuming an Observable
At it’s Core very simple
• observableInstance.subscribe
observableInstance.subscribe(new Observer<SomeDataType>() {
@Override
public void onNext(SomeDataType message) {
// Do something on each Message received
}
@Override
public void onError(Throwable error) {
// Do something on Error
}
@Override
public void onCompleted() {
// Do something when Observable completes
}
});
14. Consuming an Observable
At it’s Core very simple
• observableInstance.subscribe
observableInstance.subscribe(
(SomeDataType message) -> {/*onNext*/},
(Throwable error) -> {/*onError*/},
() -> {/*onCompleted*/});
15. OOP + RxJava, State of the Union
Resilient
Message-Driven
Scalable
Responsive
Observer + Observable
16. Making the System Scalable
How to approach the problem
• Scale up – I don’t think so
• Scale out – That’s more like it
• A lot of Cores and Memory!
Desired Characteristics of our System
• Program logic should execute in Parallel
• Data immutability is Allowed/Encouraged
The answer
• Functional programming
17. Making the System Scalable
Why FP Approach
• State HandledTransparently
• Highly composable
When we apply this to Rx world …
• Data manipulation
• Composable FP style Observable methods
• State change
• Each change of state will be a new message in the Stream
18. Composable methods with RxJava
There are methods for
• Content filtering
• Time filtering
• Data transformation
• Stream composition
observableInstance.filter(element -> element < 10)
observableInstance.timeout(100, TimeUnit.MILLISECONDS)
observableInstance.map(number -> number * number)
Observable<String> mergedObservable = Observable
.merge(firstObservable, secondObservable, thirdObservable);
20. OOP + RxJava, State of the Union
Observer + Observable
Resilient
Message-Driven
Scalable
Responsive
Observable
Methods (FP style)
+
Transparent State
21. WHEN the System Fails
With classic OOP the Client has to
• try/catch
• Resource cleanup
With RxJava the Client has to
• onError
• Error is a First-class Citizen
onNext
onNext
onError
ObservableStream
of Messages
23. OOP + RxJava, State of the Union
Observer + Observable
Error is a First-
Class Citizen
Resilient
Message-Driven
Scalable
Responsive
Observable
Methods (FP style)
+
Transparent State
24. Let’s Get ResponsiVle
Responsive
• To Our Client
• Already improved Scalability and Resilience
• Asynchronous execution
Responsible
• To Our System (to our Resources)
27. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
28. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
remoteService.getData
29. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
subscriber.onNext(data)
30. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
subscriber.onNext(data)
subscriber.onNext
31. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
subscriber.onNext(data)
subscriber.onCompleted()
32. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
subscriber.onNext(data)
subscriber.onCompleted()
subscriber.onCompleted
33. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
observable.subscribe
remoteService.getData()
subscriber.onNext(data)
subscriber.onCompleted()
34. Asynchronous Streams
“Out of the Box”
main
Main thread
Stack
observable.subscribe
(onNext, onCompleted)
remoteService.getData()
subscriber.onNext(data)
subscriber.onCompleted()
35. Asynchronous Streams
“Out of the Box”
Main thread
Stack empty
observable.subscribe
(onNext, onCompleted)
remoteService.getData()
subscriber.onNext(data)
subscriber.onCompleted()
36. Asynchronous Streams
Let’s get Asynchronous
• Thread handling with Observable
• subscribeOn(Scheduler) -Thread Observable will run on
• observeOn(Scheduler) -Thread Observer will run on
• Available Schedulers
• immediate – use CallerThread
• newThread – do work on newThread
• trampoline – enqueue work on CallerThread
• io – Thread pool used for IO tasks
• computation – Thread pool used for Computation tasks
38. Asynchronous Streams
Asynchronous in practice
Main thread
observable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe(onNext, onCompleted)
39. Asynchronous Streams
Asynchronous in practice
Main thread
observable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe(onNext, onCompleted)
IOthread
remoteService.getData()
subscriber.onNext(data)
40. Asynchronous Streams
Asynchronous in practice
Main thread
observable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe(onNext, onCompleted)
IOthread
remoteService.getData()
subscriber.onNext(data)
Computation
thread
41. Asynchronous Streams
Asynchronous in practice
Main thread
observable
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
.subscribe(onNext, onCompleted)
IOthread
remoteService.getData()
subscriber.onNext(data)
subscriber.onCompleted()
Computation
thread
42. Responsible Client
Being Reactive isn’t just about doing something fast,
it’s about not doing it at all.
Or to be more precise, to do only what’s necessary.
43. Responsible Client
Being Responsible
• Observable works only when someone’s listening
• subscribe triggers Observable Stream
• Client (Consumer of Stream) tells us when he’s done listening
• unsubscribe
44. Responsible Client
Two flavors of Unsubscribing
• Client (Consumer) is unsubscribed from “outside”
Subscription subscription = observableInstance.subscribe(
(Long message) -> {/*onNext*/},
(Throwable error) -> {/*onError*/},
() -> {/*onCompleted*/});
// Do some logic;
subscription.unsubscribe();
45. Responsible Client
Two flavors of Unsubscribing
• Client (Consumer) is unsubscribed from “inside”
observableInstance.subscribe(new Subscriber<Long>() {
@Override
public void onNext(Long message) {
// Do something on each Message received
unsubscribe();
}
@Override
public void onError(Throwable e) {
// Do something on Error
}
@Override
public void onCompleted() {
// Do something when Observable completes
}
});
46. OOP + RxJava, State of the Union
Observer + Observable
Error is a First-
Class Citizen
Asynchronous +
Resources on Demand
Message-Driven
Scalable
Responsive
Resilient
Observable
Methods (FP style)
+
Transparent State
Now, in this lecture I won’t try to force some vague definition on you. If you want that, go to a wiki page and read it there
What I will do he is I’ll state my case of what RxJava is good for, what are RxJava’s features and you can make your own definition of what RxJava is
Java, JS, Scala, Clojure, Swift
Reactive Programming raises the level of abstraction of your code so you can focus on the interdependence of events that define the business logic, rather than having to constantly fiddle with a large amount of implementation details. Code in RP will likely be more concise.
The benefit is more evident in modern webapps and mobile apps that are highly interactive with a multitude of UI events related to data events. 10 years ago, interaction with web pages was basically about submitting a long form to the backend and performing simple rendering to the frontend. Apps have evolved to be more real-time: modifying a single form field can automatically trigger a save to the backend, "likes" to some content can be reflected in real time to other connected users, and so forth.
Apps nowadays have an abundancy of real-time events of every kind that enable a highly interactive experience to the user. We need tools for properly dealing with that, and Reactive Programming is an answer.
Rx works great for event-heavy frontends and apps. But it is not just a client-side thing, it works great also in the backend and close to databases. In fact, RxJava is a key component for enabling server-side concurrency in Netflix's API. Rx is not a framework restricted to one specific type of application or language. It really is a paradigm that you can use when programming any event-driven software.
NAGLASITI DA SU SVE APLIKACIJE REAKTIVNE!!!!!!!!!!!!!!!!!! ZAHER
Reactive = Responsive
Responsive – cornerstone of usability and utility, requires rapid detection of errors and quick responses, requires predictable response times and quality of service,
requires pre-planned graceful degradation of service, awareness of time is first class
Resilient – Recovers from errors (failure is a routine, the system will inevitably fail at some tome), failure is not disruptive, failure is expected, so failure is normal part of your domain model, implementation etc.
Requires replication, containment, isolation and delegation, requires separation between normal control flow and error handling
Replication - other copies (data and services) replaced lost copies.
Containment and isolation - firewalls stop disaster from spreading.
Delegation - indirection to allow new copies to step into “holes”.
Elastic – Scale up and down, As demand rises and falls, you must gracefully scale up to meet increasing demand and scale down to conserve resources.
Detect changing input patterns, automatically adjust services (human intervention must be minimal), scale across commodity hardware, no bottlenecks od contention points
To scale down, you must be able to drain services from nodes (harder it the node holds data)
Message-Driven – To react, you must be message driven (interact with the world through messages),
Asynchronous message passing - It can’t be command and control. Blocking while waiting for a response fails to scale. (See Amdahl’s Law)
Defines boundaries, promotes loose coupling and isolation - Clear separation between components (whether or not the messages cross process boundaries), which encourages
effective decomposition into focused services that are isolated from each other and loosely coupled.
Promotes location transparency – source and receiver can change, so services can be migrated to adopt to changing load dynamics
Handle errors as messages - Also, you can use the same message infrastructure to communicate error scenarios as well as normal processing.
Promotes global management and flow control through back pressure - Think of the messages as forming a stream. If a common implementation infrastructure is used, it’s possible to
monitor and manage traffic flow. Back pressure is the idea of communication between sender and receiver to control
the rate of flow. We’ll return to it.
https://www.youtube.com/watch?v=4L3cYhfSUZs
You end up with a model of your world (domain). And all of this is a big blob which is very hard to scale.
Resilient – you can, and usually you must also handle errors, but OOP as a concept doesn’t enforce that on you
The biggest mistake of OOP was the idea that we should faithfully model the world in code
Controversial, but I believe much of our code bloat and inflexibility is actually caused by this mistaken belief.
Example: Does a payroll calculator need the concepts of Pay, Deductions, etc.? Or should we just stream numbers through math logic?
From – future, iterable, array
Just – up to 10 values
Scalability is the trait where a software solution can handle increased loads of work. This can be larger data-sets, higher request rates, combination of size and velocity etc.
When talking about systems scalability, we usually differentiate between
"Scale up" - the ability to grow by using stronger hardware
"Scale out"- the ability to grow by adding more hardware
A solution that can scale out can usually grow to lager loads in a more cost effective way. An important thing to know here is Amdahl's law that states that the ability to scale out is limited by the sequential part of the software
At it’s core FP is all about transforming data
No state, no higher meaning, just a bunch of functions transforming a bunch of data
I know, most of you are Java developers and Java is at its core Object-oriented language, but in this case FP really is a Perfect fit
If you look at it: we have streams of we can say independent messages, what else to do than put those messages through a bunch of functions that will transform/filter etc. the data and give us some meaningful result
Functions without shared state, functions that are side effect free
When dealing with errors in RxJava, you should be aware that they terminate the
Observable chain of actions. Much like with your normal procedural code, once you
are in the catch block, you can't go back to the code that has thrown the exception.
RxJava is single-threaded by default, calling subscribe will block calling thread
This achieves concurrency
A Scheduler is an object that schedules units of work. You can find common implementations of this class in Schedulers
Internally Java thread pools - RxJava-managed pool of reusable Thread instances
RxJava's Observable chains seem a good match for the threads. It would be great if we could subscribe to our source and do all the transforming, combining, and filtering in
the background and, when everything is done, have the result to be passed to the main
threads. Yes, this sounds wonderful, but RxJava is single-threaded by default. This
means that, in the most cases, when the subscribe method is called on an Observable
instance, the current thread blocks until everything is emitted.
In order to have multi-threaded logic, we'll have to learn just these two things:
• The types of schedulers we can chose from
• How to use these schedulers with an arbitrary Observable chain of operations
The computation scheduler is very similar to the new thread one, but it takes into
account the number of processors/cores that the machine on which it runs has, and
uses a thread pool that can reuse a limited number of threads. Every new Worker
instance schedules sequential actions on one of these Thread instances. If the thread
is not used at the moment they are executed, and if it is active, they are enqueued to
execute on it later.
The Input-Output (IO) scheduler uses a ScheduledExecutorService instance to
retrieve the threads from a thread pool for its workers. Unused threads are cached and
reused on demand. It can spawn an arbitrary number of threads if it is necessary.
The IO scheduler is reserved for blocking IO operations. Use it for requests to servers,
reading from files and sockets, and other similar blocking tasks. Note that its
thread pool is unbounded; if its workers are not unsubscribed, the pool will grow
indefinitely.
The Schedulers.from(Executor) method
This can be used to create a custom Scheduler instance. If none of the predefined
schedulers work for you, use this method, passing it to a java.util.concurrent.
Executor instance, to implement the behavior you need.