Save 37% off PRO during our Black Friday Sale! »

Service Objects with Dry.rb: Monads and Transactions

8f4b861a5b83575337b98d144a4ef4ca?s=47 psadauskas
November 10, 2021

Service Objects with Dry.rb: Monads and Transactions

Service objects are an important tool in your toolbox, and Dry.rb's Transaction library is one of the most powerful, and one of the most magic. It's a "business transaction" DSL, and has error handling as a primary concern. We'll start by exploring Monads in Ruby (they're not scary!). Then we'll see how that simple concept unlocks another level of service objects that are far more robust and testable, and how to wire them all together with Dry::Transaction. Finally we'll touch on extending transactions with custom steps, and how to integrate them into an existing application.

8f4b861a5b83575337b98d144a4ef4ca?s=128

psadauskas

November 10, 2021
Tweet

Transcript

  1. Dry::Transaction Paul Sadauskas RubyConf Denver 2021

  2. Hi! Paul Sadauskas Lead Architect at TextUs • github.com/paul •

    @theamazingrando Like everyone else, we’re hiring! https://textus.com/jobs This is the talk that made me want to join TextUs — Jason Taylor Ruby on Rails Podcast Ep 389, Oct 27 2021
  3. The Problem Model Controller Where do I put my business

    logic?
  4. Service Objects • Adapter • Command • Decorator • Query

    Object • View Model • Presenter • Form Object https://refactoring.guru
  5. Command Pattern The Command Pattern creates objects which encapsulate actions

    and parameters
  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. Dry-rb

  14. Dry::Transaction Dry::Transaction is a business transaction DSL. It provides a

    simple way to define a complex business transaction that includes processing over many steps and by many different objects. It makes error handling a primary concern by taking a “Railway Oriented Programming” approach to capturing and returning errors from any step in the transaction. • A business transaction is a series of operations where any can fail and stop the processing. • A business transaction may resolve its operations using an external container. • A business transaction can describe its steps on an abstract level without being coupled to any details about how individual operations work. • A business transaction doesn’t have any state. • Each operation shouldn’t accumulate state, instead it should receive an input and return an output without causing any side-effects. • The only interface of an operation is #call(input). • Each operation provides a meaningful piece of functionality and can be reused. • Errors in any operation should be easily caught and handled as part of the normal application flow. — From the Dry-Transaction documentation
  15. Anatomy of a Transaction • Each “step” is run in

    the order declared in the `step` DSL • Each step returns a “Result”, which is “Success” or “Failure” • If Success, it gets passed to the next step • If Failure, execution halts, no more steps are run, and that Failure is returned.
  16. Monads Monads are monoids in the category of endofunctors. --

    Wikipedia or something
  17. Maybe Monad A wrapper than can contain only two possible

    items: • Just/Some - wraps the value • Nothing/None - when the value is missing Monad Presence Absence Haskell/Elm Maybe Just Nothing Rust Option Some None Dry::Monad Maybe Some None
  18. Maybe Monad

  19. None
  20. None
  21. None
  22. Maybe #bind Some: • Yields its value to the block

    • Block must return a Maybe • Returns the result of the block None: • Doesn’t call the block • Returns self
  23. Maybe #fmap Some: • Similar to bind • Block doesn’t

    return a monad • (fmap wraps block result in one) None: • Same as bind • Doesn’t call the block
  24. Maybe #value_or Safe way to extract a value or default

    Some: • Doesn’t call block • Returns value None: • Calls block
  25. Maybe helpers

  26. None
  27. Result Monad

  28. None
  29. None
  30. Step Adapters “Normal” step Step adapters (try and map)

  31. None
  32. Error Handling

  33. Error handling

  34. Error handling — Matcher DSL

  35. Error handling — Matcher DSL

  36. Error handling — Matcher DSL

  37. Testing

  38. Testing — Step Injection

  39. Testing — Step injection

  40. Custom Step Adapters

  41. Custom Step Adapters

  42. Custom Step Adapter - Merge

  43. Custom Step Adapter - Validate

  44. Custom Step Adapter - Other Useful Ones We Wrote

  45. Bye! Paul Sadauskas Lead Architect at TextUs • github.com/paul •

    @theamazingrando Like everyone else, we’re hiring! https://textus.com/jobs This is the talk that made me want to join TextUs — Jason Taylor Ruby on Rails Podcast Ep 389, Oct 27 2021