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

Designing process flows with #Baker

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →
Avatar for Bekir Oguz Bekir Oguz
September 14, 2017

Designing process flows with #Baker

Baker is a library that reduces the effort to orchestrate (micro)service-based process flows. Using our intuitive scala/java dsl, developers can declare the orchestration logic in a recipe which is made out of interactions (system calls), ingredients (data) and events. A visual recipe as a graph is also generated so you can easily discuss the logic with other stakeholders, i.e. product owners, testers, etc... The recipe is compiled into a petrinet which is running in an akka actor, and probably in an akka cluster. It is already applied in ING to achieve less spaghetti orchestration code in apis, and more reusability, scalability and resilience.

Avatar for Bekir Oguz

Bekir Oguz

September 14, 2017

Other Decks in Programming

Transcript

  1. 7

  2. We need a cleaner way to allow design changes in

    complex APIs 8 Example: initial design of the API A B C D E 1 2 3 4 5
  3. A B C D E 1 2 3 4 5

    We need a cleaner way to allow design changes in complex APIs 9 Example: API after one design change
  4. A B C D E 1 2 3 4 5

    We need a cleaner way to allow design changes in complex APIs 10 Example: API after ten design changes
  5. We need a cleaner way to allow design changes in

    complex APIs 11 Example: API after ten design changes A B C D E 1 2 3 4 5
  6. Open Kinder- / Jongerenrekening Open Groei Groter rekening Another Product

    Verify customer rules Verify customer rules Verify customer rules Register individual Register individual Register Individual Send a present Send a present Not applicable Send a message to the customer Send a message to the customer Send a message to the customer Open a payments account Open a savings account Open a payments account Enable billing Enable billing Assign package There is more need for reuse between teams 12
  7. Baker is a Scala library that simplifies the development of

    complex orchestration logic. What? Baker! github.com/ing-bank/baker
  8. Defining ingredients 17 case class CustomerInfo(name: String, address: String, email:

    String) // ingredients val customerInfo = Ingredient[CustomerInfo]("customerInfo") val trackingId = Ingredient[String]("trackingId") val order = Ingredient[String]("order")
  9. Defining events 18 // events val goodsShipped = Event("GoodsShipped", trackingId)

    val orderPlaced = Event("OrderPlaced", order) val paymentMade = Event("PaymentMade") val valid = Event("Valid") val sorry = Event("Sorry")
  10. Defining interactions 19 // interactions val validateOrder = Interaction( name

    = "ValidateOrder", inputIngredients = order, output = FiresOneOfEvents(valid, sorry) ) val shipGoods = Interaction( name = "ShipGoods", inputIngredients = Ingredients(goods, customerInfo), output = FiresOneOfEvents(goodsShipped) )
  11. Defining a recipe 20 // recipe val webShopRecipe: Recipe =

    Recipe("WebShop") .withInteractions( validateOrder, manufactureGoods .withRequiredEvents(valid, paymentMade), shipGoods, sendInvoice .withRequiredEvent(goodsShipped) ) .withSensoryEvents( customerInfoReceived, orderPlaced, paymentMade)
  12. Compile the recipe 21 // compiles the recipe val compiledRecipe

    = RecipeCompiler.compileRecipe(webShopRecipe) // list of validation errors val errors: Seq[String] = compiledRecipe.validationErrors // .dot (graphviz notation) representation val visualization: String = compiledRecipe.getRecipeVisualization
  13. A Baker instance can be created from the valid recipe.

    It takes care of the execution of the recipe. The only thing left is to provide sensory events to Baker! Baker runtime 23
  14. Initializing Baker instance 24 You can create a new Baker

    instance by providing the recipe and implementations of the interactions: val compiledRecipe = RecipeCompiler.compileRecipe(webShopRecipe) val validateOrderImpl = validateOrder implement { (order: String) => { // Some logic here valid.instance() // or maybe invalid event to be returned } } val implementations = Seq(validateOrderImpl, manufactureGoodsImpl, sendInvoiceImpl, shipGoodsImpl) val baker = new Baker(compiledRecipe, implementations)
  15. For each client request you do the following: Firing events

    25 val processId = UUID.randomUUID().toString baker.bake(processId) baker.handleEvent(processId, orderPlaced.instance(testOrder)) baker.handleEvent(processId, paymentMade.instance()) baker.handleEvent(processId, customerInfoReceived.instance(testCustomerInfoData)) val actualIngredients: Map[String, Any] = baker.getIngredients(processId) val actualEvents: Seq[RuntimeEvent] = baker.events(processId)
  16. 26

  17. 27

  18. 28

  19. 29

  20. 30

  21. 31

  22. 32

  23. 33

  24. 34

  25. 35

  26. 36

  27. 37

  28. 38

  29. 39

  30. 40

  31. 41

  32. 1. It is hard to develop complex orchestration APIs 2.

    We need a cleaner way to allow design changes in complex APIs 3. There is more need for reuse between teams Does Baker help with the Why? 42
  33. 1. It is hard to develop complex orchestration APIs With

    Baker, you think about what you want, not about the order. Baker can validate the recipe for you. Clear insight in the current model by visualising the recipe. 2. We need a cleaner way to allow design changes in complex APIs 3. There is more need for reuse between teams Does Baker help with the Why? 43
  34. 1. It is hard to develop complex orchestration APIs With

    Baker, you think about what you want, not about the order. Baker can validate the recipe for you. Clear insight in the current model by visualising the recipe. 2. We need a cleaner way to allow design changes in complex APIs Baker links the interactions when compiling the recipe. If interactions are added, removed or changed, Baker will update the model accordingly. 3. There is more need for reuse between teams Does Baker help with the Why? 44
  35. 1. It is hard to develop complex orchestration APIs With

    Baker, you think about what you want, not about the order. Baker can validate the recipe for you. Clear insight in the current model by visualising the recipe. 2. We need a cleaner way to allow design changes in complex APIs Baker links the interactions when compiling the recipe. If interactions are added, removed or changed, Baker will update the model accordingly. 3. There is more need for reuse between teams The possibility to share interactions, ingredients and events between recipes allows for much more reuse of code among teams. Does Baker help with the Why? 45
  36. Process logic is isolated in an Akka actor, this gives

    us the following benefits: • Event sourcing through persistent actors • Supporting many data stores, i.e. cassandra • Distributing actors with Cluster Sharding Akka 48
  37. On creation of the Baker instance, the recipe is compiled

    into a Petri net. A Petri net is a mathematical model that can be used for reasoning about concurrency. This Petri net is then used to determine when & what interactions to execute. PetriNet 49
  38. • Simple, uses only a few concepts and components •

    Exact mathematical definition of execution semantics • Intuitive graphical notation • Well-developed mathematical theory for process analysis Advantages 60
  39. 71 Features Recipe Developer friendly Java/Scala dsl Compile-time recipe validation

    Type safety Runtime Execution of the recipe, powered by akka and petrinet model
  40. 72 Features Recipe Developer friendly Java/Scala dsl Compile-time recipe validation

    Type safety Runtime Execution of the recipe, powered by akka and petrinet model Persisted state through event sourcing
  41. 73 Features Recipe Developer friendly Java/Scala dsl Compile-time recipe validation

    Type safety Runtime Execution of the recipe, powered by akka and petrinet model Persisted state through event sourcing Data encryption
  42. 74 Features Recipe Developer friendly Java/Scala dsl Compile-time recipe validation

    Type safety Runtime Execution of the recipe, powered by akka and petrinet model Persisted state through event sourcing Data encryption Automatic retries on technical failures
  43. 75 Features Recipe Developer friendly Java/Scala dsl Compile-time recipe validation

    Type safety Runtime Execution of the recipe, powered by akka and petrinet model Persisted state through event sourcing Data encryption Automatic retries on technical failures Parallel execution of paths
  44. Property Based Testing 77 val recipeGen: Gen[Recipe] = for {

    name <- nameGen sensoryEvents <- Gen.listOf(eventGen) suchThat (_.nonEmpty) interactions <- interactionsGen(sensoryEvents) suchThat (_.nonEmpty) } yield Recipe(name) //turn the lists into var args .withSensoryEvents(sensoryEvents: _*) .withInteractions(interactions.toList: _*)
  45. Property Based Testing 78 forAll(recipeGen) { recipe => val validations

    = ValidationSettings( allowCycles = false, allowNonExecutableInteractions = false) val compiledRecipe = RecipeCompiler.compileRecipe(recipe, validations) if (compiledRecipe.validationErrors.nonEmpty) { logRecipeStats(recipe) logCompiledRecipeStats(compiledRecipe) } compiledRecipe.validationErrors.isEmpty }