Sunday, May 17, 2015

3 things you must know to think reactive - Geecon Kraków 2015

3 things you must know to think reactive - Geecon Kraków 2015

Over the past few years, web-applications have started to play an increasingly important role in our lives. We expect them to be always available and the data to be always fresh. This shift into the realm of real-time data processing is now transitioning to physical devices, and Gartner predicts that the Internet of Things will grow to an installed base of 26 billion units by 2020.

As reactive architectures gain in popularity, more and more developers find themselves faced with the challenge of "thinking reactive". To leave behind the well-known concepts of mutable, object-oriented, imperative and synchronous programming in favour of immutable, functional, declarative and asynchronous programming requires quite a mind shift and it isn't obvious to take the plunge.

In this talk we will explore three concepts from the world of functional programming that are at the core of building reactive applications: immutability, higher-order functions and manipulating immutable collections. We will first see how the "traditional" mutable, object-oriented approach of doing things can be problematic when it comes to multi-core programming, and then how to apply them to asynchronous systems.
Published in: Engineering

Transcript

  • 1. Agenda 1. Reactive? 2. Mutability & Immutability 3. Functions & Higher-order functions 4. Why functions? 5. Functional for Reactive
  • 2. Who is speaking? • freelance software consultant based in Vienna • Vienna Scala User Group • web, web, web
  • 3. Who is speaking? • freelance software consultant based in Vienna • Vienna Scala User Group • web, web, web • writing a book on reactive web- applications http://www.manning.com/ bernhardt dotd051315au 50% discount
  • 4. Did you say reactive?
  • 5. Disambiguation • Reactive Programming • Functional Reactive Programming • Reactive Application • Responsive Web-Application
  • 6. Disambiguation • Reactive Programming async data flows • Functional Reactive Programming async data flows + FP • Reactive Application architectural pattern • Responsive Web-Application Twitter Bootstrap
  • 7. Why Reactive: many cores • End of the single-core multi-core era • Many players in the space • Tilera, Cavium • Adapteva Parallela • Xeon PHI
  • 8. Why Reactive: many cores • Meizu MX4 Ubuntu Edition • Octa-core MediaTek MT6595 chipset • 2GB RAM / 20.7 MP rear camera, 2MP front-facing / 16GB built-in flash storage
  • 9. Why reactive: distribution (theory) • scaling out to handle large loads • scaling out / replication to handle node failure
  • 10. Why reactive: distribution (reality) • networks, networks, networks • they fail all the time • Jepsen series1 1 http://aphyr.com
  • 11. Reactive: how? public class PaymentController { public PaymentConfirmation makePayment(CreditCard card) { ... } public PaymentHistory getPastPayments() { ... } }
  • 12. Reactive: how? @Elastic(minNodes = 5, maxNodes = 15) @Resilient(gracefullyHandleNetworkPartitions = true) public class PaymentController { @Responsive(latency = 500, timeUnit = TimeUnit.MILLISECONDS) @MessageDriven(messageProvider = Provider.AKKA) public PaymentConfirmation makePayment(CreditCard card) { ... } @Responsive(latency = 800, timeUnit = TimeUnit.MILLISECONDS) public PaymentHistory getPastPayments() { ... } }
  • 13. Why Reactive: summary • distribution accross CPU cores • distribution accross networked machines • need tooling to work with this type of distribution
  • 14. Mutable state
  • 15. Why mutable ? • memory expensive! • can't afford to keep past state in it • re-use, overwrite, optimize
  • 16. Mutable issues - example 1
  • 17. Mutable issues - example 1 $scope.reservation = { id: 42, start: moment({ hour: 13, minute: 15 }), end: moment({ hour: 14, minute: 30 }) }; timeline.setOptions({ min: $scope.reservation.start.startOf('hour').toDate(), max: $scope.reservation.start.add(3, 'hour').toDate() });
  • 18. Mutable issues - example 1 $scope.reservation = { id: 42, start: moment({ hour: 13, minute: 15 }), end: moment({ hour: 14, minute: 30 }) }; timeline.setOptions({ min: $scope.reservation.start.clone().startOf('hour').toDate(), max: $scope.reservation.start.clone().add(3, 'hour').toDate() });
  • 19. Mutable issues - example 2 car.setPosition(0); car.setPosition(10);
  • 20. Mutable issues - example 2
  • 21. The problem with locks / latches • solution workaround for a broken conceptual model • huge coordination overhead! Even more so when distributed • hard to reason about • performance hit
  • 22. Mutability: summary • increased difficulty for the programmer (moving parts) • makes life hard when working concurrently
  • 23. Immutable state
  • 24. Immutable state - why now? • main memory is cheap! • disk memory is cheap! We can afford copies of past state around in order to reduce coordination efforts
  • 25. Immutable state - how? case class Car(brand: String, position: Int) val car = Car(brand = "DeLorean", position = 0) val movedCar = car.copy(position = 10) val movedCarLaterOn = car.copy(position = 30) Working with different version "Snapshots" of reality
  • 26. Immutable state - how? • clever immutable data structures, e.g. Bitmapped Vector Trie 2 • do not copy data around - point to unchanged data instead • constant time for all operations 2 http://lampwww.epfl.ch/papers/idealhashtrees.pdf
  • 27. Immutable all the way down • immutability changes everything 3 • programming languages • databases: insert-only, event stores • SSD drives 3 http://www.cidrdb.org/cidr2015/Papers/CIDR15_Paper16.pdf
  • 28. Immutability: summary • we can afford to keep everything, with good performance • reduces the headeache of coordination accross CPU cores and networked nodes • audit trail of changes for free
  • 29. Functions
  • 30. Functions, the Starwars Lego way (three kinds of awesome united)
  • 31. Pure function
  • 32. Side-effecting function
  • 33. Side-effecting function
  • 34. Side-effecting function The dark side clouds everything. Impossible to see the future is. -- Master Yoda
  • 35. Again a pure function (this time with a laser gun)
  • 36. Hmm...
  • 37. Function composition
  • 38. Function composition def assemble(parts: (Head, Body, Legs, Hair)): HanSolo = ... def arm(h: HanSolo, lg: LaserGun): ArmedHanSolo = ...
  • 39. Function composition def assemble(parts: (Head, Body, Legs, Hair)): HanSolo = ... def arm(h: HanSolo, lg: LaserGun): ArmedHanSolo = ... def build(parts: (Head, Body, Legs, Hair), lg: LaserGun): ArmedHanSolo = arm(assemble(parts), lg)
  • 40. Higher-order functions
  • 41. Definition A function that takes another function as parameter (or produces a function as result).
  • 42. Higher-order functions val users: List[User] = ... val (minors, majors) = users.partition(_.age < 18)
  • 43. Higher-order functions val users: List[User] = ... val isMinor = (user: User) => user.age < 18 val (minors, majors) = users.partition(isMinor)
  • 44. Higher-order functions def AuthenticatedAction(f: Request => User => Result) = Action { request => findUser(request).map { user => f(request)(user) } getOrElse { Unauthorized("Get out!") } } def showSettings = AuthenticatedAction { request => user => userSettingsService.findSettings(user).map { settings => Ok(views.html.settings(user, settings)) } getOrElse { NotFound("We lost all your settings. Sorry.") } }
  • 45. Functions - Why ?
  • 46. Functions • portable and re-usable behaviour • data changes, behaviour can be re- used • functions as data transformation pipelines
  • 47. Functions = data transformation pipelines val addresses = users.filter(_.age > 18) .map(_.address) .sortBy(_.city) Build increasingly complex behaviour through a series of transformations driven by composing functions
  • 48. Functional for reactive
  • 49. Reactive applications • distributed in nature • need to be resilient to failure, adapt to changes • asynchronous all the way down
  • 50. Asynchronous callback hell var fetchPriceList = function() { $.get('/items', function(items) { var priceList = []; items.forEach(function(item, itemIndex) { $.get('/prices', { itemId: item.id }, function(price) { priceList.push({ item: item, price: price }); if ( priceList.length == items.length ) { return priceList; } }).fail(function() { priceList.push({ item: item }); if ( priceList.length == items.length ) { return priceList; } }); } }).fail(function() { alert("Could not retrieve items"); }); }
  • 51. Asynchronous & functional val fetchItems = WS.get("/items").getJSON[List[Item]]() val fetchPrices = WS.get("/prices").getJSON[List[Price]]() val itemPrices: Future[List[(Item, Option[Price])]] = for { items <- fetchItems prices <- fetchPrices } yield { item -> items.flatMap { item => prices.find(_.itemId == item.id) } } itemPrices.recover { case ce: ConnectionException => log.error("Could not retrieve items") List.empty }
  • 52. Immutable Function Composition
  • 53. Thank you http://www.manning.com/bernhardt code dotd051315au 50% discount @elmanu / manuel@bernhardt.io Questions?