Slide 1

Slide 1 text

GeeCON / 13.05.2016 @miciek Building Snake using Streams Michał Płachta

Slide 2

Slide 2 text

GeeCON / 13.05.2016 @miciek Streams? ● way of defining application logic ● focused on data transformations ● explicit time dependencies ● declarative

Slide 3

Slide 3 text

GeeCON / 13.05.2016 @miciek What you will learn? ● how frontend web app written in streams looks like ● how backend app written using streams looks like ● how do Reactive Streams keep our streams safe?

Slide 4

Slide 4 text

GeeCON / 13.05.2016 @miciek Meet Snake & Fruit Snake Fruit

Slide 5

Slide 5 text

GeeCON / 13.05.2016 @miciek Our First Stream: “Ticks” stream

Slide 6

Slide 6 text

GeeCON / 13.05.2016 @miciek “Directions” stream

Slide 7

Slide 7 text

GeeCON / 13.05.2016 @miciek “Snake’s Head Positions” stream

Slide 8

Slide 8 text

GeeCON / 13.05.2016 @miciek Stream operators: map & scan stream.map(f) ● transforms values from stream using function f ● returns a new stream with transformed values stream.scan(init, f) ● accumulates values from stream using function f ○ f(acc,val)=>new_acc ● returns a new stream that outputs accumulator value

Slide 9

Slide 9 text

GeeCON / 13.05.2016 @miciek Once again: the code

Slide 10

Slide 10 text

GeeCON / 13.05.2016 @miciek Displaying values from the stream

Slide 11

Slide 11 text

GeeCON / 13.05.2016 @miciek Streams are reusable

Slide 12

Slide 12 text

GeeCON / 13.05.2016 @miciek Streams & Operators are lazy No elements or No terminal function

Slide 13

Slide 13 text

GeeCON / 13.05.2016 @miciek “Key presses” stream

Slide 14

Slide 14 text

GeeCON / 13.05.2016 @miciek “Left Key Presses” stream

Slide 15

Slide 15 text

GeeCON / 13.05.2016 @miciek “Right Key Presses” stream

Slide 16

Slide 16 text

GeeCON / 13.05.2016 @miciek Stream operators: filter stream.filter(p) ● checks each value from stream against the predicate passed as p ● returns a new stream that outputs only values that satisfy condition p Already used: ● map(f) ● scan(init, f(acc, val))

Slide 17

Slide 17 text

GeeCON / 13.05.2016 @miciek “Left Rotations” stream

Slide 18

Slide 18 text

GeeCON / 13.05.2016 @miciek “Right Rotations” stream

Slide 19

Slide 19 text

GeeCON / 13.05.2016 @miciek “Actions” stream

Slide 20

Slide 20 text

GeeCON / 13.05.2016 @miciek Stream operators: merge stream.merge(stream2) ● stream is merged with stream2 ● returns a new stream that outputs values from both stream and stream2 as they appear Already used: ● map(f) ● scan(init, f(acc, val)) ● filter(p)

Slide 21

Slide 21 text

GeeCON / 13.05.2016 @miciek New “Directions” stream based on user input

Slide 22

Slide 22 text

GeeCON / 13.05.2016 @miciek Recap: Current “Directions” stream

Slide 23

Slide 23 text

GeeCON / 13.05.2016 @miciek “Directions” stream: Better, but no timing! vs

Slide 24

Slide 24 text

GeeCON / 13.05.2016 @miciek Stream operators: sampledBy stream.sampledBy(stream2) ● last value from stream is taken when any value appears in stream2 ● returns a new stream that outputs values from stream sampled by values from stream2 Already used: ● map(f) ● scan(init, f(acc, val)) ● filter(p) ● merge(stream2)

Slide 25

Slide 25 text

GeeCON / 13.05.2016 @miciek “Directions” stream: user input & timing

Slide 26

Slide 26 text

GeeCON / 13.05.2016 @miciek “Snake Head Positions”: no change needed

Slide 27

Slide 27 text

GeeCON / 13.05.2016 @miciek User moves the snake: the code

Slide 28

Slide 28 text

GeeCON / 13.05.2016 @miciek Current implementation ● “ticks” ● “key presses” ● “left key presses” ● “right key presses” ● “left rotations” ● “right rotations” ● “actions” ● “dir changes” ● “directions” ● “snake head positions” + map, scan, filter, merge & sampledBy 10 streams

Slide 29

Slide 29 text

GeeCON / 13.05.2016 @miciek “Snakes” stream

Slide 30

Slide 30 text

GeeCON / 13.05.2016 @miciek Stream operators: slidingWindow stream.slidingWindow(n) ● aggregate last n values ● returns a new stream that outputs arrays of last n values from the stream ● can be implemented using scan Already used: ● map(f) ● scan(init, f(acc, val)) ● filter(p) ● merge(stream2) ● sampledBy(stream2)

Slide 31

Slide 31 text

GeeCON / 13.05.2016 @miciek Quiz: Eating a fruit? using 6 operators ● map(f) ● scan(init, f(acc, val)) ● filter(p) ● merge(stream2) ● sampledBy(stream2) ● slidingWindow(n) & 11 streams ● “ticks” ● “key presses” ● “left key presses” ● “right key presses” ● “left rotations” ● “right rotations” ● “actions” ● “direction changes” ● “directions” ● “snake head positions” ● “snakes”

Slide 32

Slide 32 text

GeeCON / 13.05.2016 @miciek “Fruit eaten events” stream

Slide 33

Slide 33 text

GeeCON / 13.05.2016 @miciek Frontend in action!

Slide 34

Slide 34 text

GeeCON / 13.05.2016 @miciek Architecture: 11 streams, 2 ins & 2 outs

Slide 35

Slide 35 text

GeeCON / 13.05.2016 @miciek Snake’s going multiplayer

Slide 36

Slide 36 text

GeeCON / 13.05.2016 @miciek Snake Server App Requirements ● client must send snake positions to the server each time it changes ● server must generate fruits ● server must keep scores ● server must broadcast: ○ positions of all snakes to other players ○ positions of fruits to all players ○ current scoreboard to all players

Slide 37

Slide 37 text

GeeCON / 13.05.2016 @miciek Let’s design Server App Flow! one player flow Game Event

Slide 38

Slide 38 text

GeeCON / 13.05.2016 @miciek WebSocket connected to the Flow

Slide 39

Slide 39 text

GeeCON / 13.05.2016 @miciek WebSocket as a stream: Server App

Slide 40

Slide 40 text

GeeCON / 13.05.2016 @miciek Snake App Flow (one player)

Slide 41

Slide 41 text

GeeCON / 13.05.2016 @miciek Let’s implement Server Flow for one player

Slide 42

Slide 42 text

GeeCON / 13.05.2016 @miciek Moved to server: “Fruit eaten events” stream

Slide 43

Slide 43 text

GeeCON / 13.05.2016 @miciek “Fruits” stream

Slide 44

Slide 44 text

GeeCON / 13.05.2016 @miciek “Fruits” stream using Akka Stream

Slide 45

Slide 45 text

GeeCON / 13.05.2016 @miciek “Score updates” stream

Slide 46

Slide 46 text

GeeCON / 13.05.2016 @miciek “Scores” stream

Slide 47

Slide 47 text

GeeCON / 13.05.2016 @miciek “Scores” stream using Akka Stream

Slide 48

Slide 48 text

GeeCON / 13.05.2016 @miciek Game Logic Server Flow

Slide 49

Slide 49 text

GeeCON / 13.05.2016 @miciek Game Logic Flow using Akka Stream

Slide 50

Slide 50 text

GeeCON / 13.05.2016 @miciek Merging Player Flows outputs

Slide 51

Slide 51 text

GeeCON / 13.05.2016 @miciek Server app flow using Akka Stream

Slide 52

Slide 52 text

GeeCON / 13.05.2016 @miciek Backend in action!

Slide 53

Slide 53 text

GeeCON / 13.05.2016 @miciek What if there are thousands of players?

Slide 54

Slide 54 text

GeeCON / 13.05.2016 @miciek Crossing Async Boundary Push Model ● not safe when Subscriber slower ● perfect when Subscriber faster ● too slow when Subscriber faster ● perfect when Subscriber slower Pull Model

Slide 55

Slide 55 text

GeeCON / 13.05.2016 @miciek Reactive Streams Streams with supply & demand ● “as fast as possible, but not faster” ● consumer wants to pull elements (= demand) ● only then publisher can push ○ it supplies elements until demand is satisfied

Slide 56

Slide 56 text

GeeCON / 13.05.2016 @miciek Reactive Streams Lack of demand = Backpressure

Slide 57

Slide 57 text

GeeCON / 13.05.2016 @miciek Example of Reactive Streams

Slide 58

Slide 58 text

GeeCON / 13.05.2016 @miciek Reactive Streams

Slide 59

Slide 59 text

GeeCON / 13.05.2016 @miciek Reactive Streams API public interface Publisher { public void subscribe(Subscriber s); } public interface Subscriber { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Subscription { public void request(long n); public void cancel(); } public interface Processor extends Subscriber, Publisher {}

Slide 60

Slide 60 text

GeeCON / 13.05.2016 @miciek Simple API, hard implementation... https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#specification

Slide 61

Slide 61 text

GeeCON / 13.05.2016 @miciek Reactive Streams API implementations ● Project Reactor ● Ratpack ● Vert.x ● Slick ● Akka Stream ● JDK 9 ● Integrations: ○ Kafka, ○ Mongo, ○ Cassandra

Slide 62

Slide 62 text

GeeCON / 13.05.2016 @miciek Akka Stream model Publisher => Source Processor => Flow Subscriber => Sink Our Snake implementation uses Reactive Streams!

Slide 63

Slide 63 text

GeeCON / 13.05.2016 @miciek ● NO ○ frontend is pushing every 100ms ● Possible solutions: ○ Reactive Streams web frameworks? ○ conflate/expand? ○ buffer between frontend & backend? Is Snake Multiplayer safe?

Slide 64

Slide 64 text

GeeCON / 13.05.2016 @miciek Links Build YOUR OWN Snake using Streams - blog post (step-by-step tutorial) michalplachta.com/2016/05/11/reactive-ui-by-example/ Client Side Code github.com/miciek/web-snake-react-bacon Server Side Code github.com/miciek/snake-multiplayer-akka-streams Play with streams and operators! rxmarbles.com/ Akka Streams doc.akka.io/docs/akka/2.4.4/scala/stream/ BaconJS - streams in JavaScript baconjs.github.io/

Slide 65

Slide 65 text

GeeCON / 13.05.2016 @miciek Building Snake using Streams Michał Płachta THANK YOU www.michalplachta.com