3 things you must know to think reactive - Geecon Kraków 2015
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?