Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Snake using Streams (Geecon 2016)

Building Snake using Streams (Geecon 2016)

In this talk you will learn how stream-based programming can be used to implement web frontend and multiplayer backend of the classic game: Snake.

Building dynamic applications using imperative approach tends to create lots of unmaintainable code. Stream-based programming tries to solve this problem by introducing fully declarative way of defining application logic. While using streams, you will focus on WHAT needs to be done, not HOW and WHEN.

The talk is divided into 3 parts. In the first part you will learn how to create a frontend of the Snake web game using streams as building blocks. Then, we will move to the server side and use Scala and Akka Stream library to create backend service that will allow the game to be played by multiple players. In the third part, we will discuss reactive streams and how they make asynchronous communication safe.

Michał Płachta

May 13, 2016
Tweet

More Decks by Michał Płachta

Other Decks in Programming

Transcript

  1. GeeCON / 13.05.2016 @miciek Streams? • way of defining application

    logic • focused on data transformations • explicit time dependencies • declarative
  2. 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?
  3. 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
  4. 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))
  5. 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)
  6. 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)
  7. 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
  8. 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)
  9. 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”
  10. 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
  11. 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
  12. 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
  13. GeeCON / 13.05.2016 @miciek Reactive Streams API public interface Publisher<T>

    { public void subscribe(Subscriber<? super T> s); } public interface Subscriber<T> { 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<T, R> extends Subscriber<T>, Publisher<R> {}
  14. GeeCON / 13.05.2016 @miciek Reactive Streams API implementations • Project

    Reactor • Ratpack • Vert.x • Slick • Akka Stream • JDK 9 • Integrations: ◦ Kafka, ◦ Mongo, ◦ Cassandra
  15. GeeCON / 13.05.2016 @miciek Akka Stream model Publisher => Source

    Processor => Flow Subscriber => Sink Our Snake implementation uses Reactive Streams!
  16. 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?
  17. 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/