One Year with Hanami

One Year with Hanami

Have you ever heard of Hanami? Have you considered using it for your new project, but you don’t know what to expect? This talk will clear your doubts - my team has been using Hanami for more than a year and I’m going to share our experience with the framework.

Afa6e65b91b46f3317c3d3e94e9255f2?s=128

Grzegorz Witek

August 04, 2018
Tweet

Transcript

  1. ONE YEAR WITH HANAMI @ A R N V A

    L D , P U N E , 2 0 1 8
  2. GRZEGORZ

  3. GRZEGORZ

  4. None
  5. 5 WHAT IS HANAMI • long-standing Japanese tradition of welcoming

    spring • web framework written in Ruby image source: https://hanamirb.org
  6. 6 BRIEF INTRODUCTION Hanami is a full-featured web framework Hanami

    is modular Hanami is lightweight Hanami promotes good practices
  7. 7 Exploration Familiarity WHY WE CHOSE HANAMI? ☼

  8. 8 OUR TIMELINE June 2017 R U N N I

    N G P R O D U C T I O N January 2017 F I R S T C O M M I T July 2017 2 N D A P P L I C A T I O N March 2018 H A N A M I 1 . 1
  9. 9 OUTLINE The web part The data part The application

    part The support part
  10. PART 1: THE WEB

  11. 11 HANAMI WEB GEMS router controller view helpers

  12. 12 Each action is a separate class with call method.

    Testing controller is as simple as calling Action.new.call(params) one controller action = one class
  13. 13 Each action is a separate class with call method.

    Testing controller is as simple as calling Action.new.call(params) one controller action = one class /apps
 /admin
 /config
 /controllers
 /orders
 /index.rb
 /create.rb
 /customers
 /index.rb
 /create.rb
  14. 14 controller actions are magical Hanami Action module wraps around

    your class’ call method. The value you return from call is ignored, instead you must modify class’ attributes
  15. 15 controller actions are magical Hanami Action module wraps around

    your class’ call method. The value you return from call is ignored, instead you must modify class’ attributes class Index
 include MyApp::Action
 
 def call(params)
 “this is action”
 end
 end Index.new.call({}) [200,
 … a lot of headers,
 []]
  16. 16 controller actions are magical Hanami Action module wraps around

    your class’ call method. The value you return from call is ignored, instead you must modify class’ attributes class Index
 include MyApp::Action
 
 def call(params)
 status 200, “this is action”
 end
 end Index.new.call({}) [200,
 … a lot of headers,
 [“this is action”]]
  17. 17 controller actions are magical Hanami Action module wraps around

    your class’ call method. The value you return from call is ignored, instead you must modify class’ attributes class Index
 include MyApp::Action
 
 def call(params)
 self.body = “this is action”
 self.status = 403
 end
 end Index.new.call({}) [403,
 … a lot of headers,
 [“this is action”]]
  18. 18 Views in Hanami are objects that encapsulate logic that

    is used in the template Templates are representation of the data returned to the user views != templates
  19. 19 Views in Hanami are objects that encapsulate logic that

    is used in the template Templates are representation of the data returned to the user views != templates # view
 class Index
 include MyApp::View
 
 def users_age
 Time.now.year - user.year_of_birth
 end
 end # template
 <div class=“user”>
 <span class=“age”>
 <%= users_age %>
 </span>
 </div>
  20. 20 Views in Hanami are objects that encapsulate logic that

    is used in the template Templates are representation of the data returned to the user built-in helpers are private
  21. 21 Views in Hanami are objects that encapsulate logic that

    is used in the template Templates are representation of the data returned to the user built-in helpers are private # view
 class Index
 include MyApp::View
 
 def total_cost
 format_number(cost)
 end
 end # template
 <div class=“order”>
 <span class=“cost”>
 <%= total_cost %>
 </span>
 </div>
  22. PART 2: THE DATA

  23. 23 HANAMI DATA GEMS model validations events (experimental)

  24. 24 Repository pattern separates the entities (individual objects) from the

    repository (a collection of objects) It means that queries will be in different class than individual object methods repository pattern
  25. 25 Repository pattern separates the entities (individual objects) from the

    repository (a collection of objects) It means that queries will be in different class than individual object methods repository pattern class OrderRepository < Hanami::Repository
 associations do
 belongs_to :customer
 end 
 
 def future
 orders.where { delivered_at.is(nil() }
 end
 end class Order < Hanami::Entity
 def description
 “#{product.name} #{total_cost}”
 end
 end
  26. 26 3 layers around the database Hanami model library relies

    on Rom-rb which relies on Sequel Sometimes we can’t achieve what we want in Hanami model and we need to go down to another layer of abstraction
  27. 27 Validations are a mixin that can be included anywhere

    - they perfectly fit controllers or service objects validations separated from entities
  28. 28 Validations are a mixin that can be included anywhere

    - they perfectly fit controllers or service objects validations separated from entities class Create
 include MyApp::Action
 
 params do
 required(:title).filled(:str?)
 required(:amount).filled(:int?)
 end
 end
 
 class CreateOrder
 include Hanami::Validations
 
 validations do
 required(:title).filled(:str?)
 end
 end
  29. PART 3: APPLICATION

  30. 30 HANAMI APPLICATION GEMS hanami cli

  31. 31 Starting a new Hanami project creates /apps directory with

    one application there Having multiple applications in one project is not a special case, but a standard mountable apps are first class citizens
  32. 32 Starting a new Hanami project creates /apps directory with

    one application there Having multiple applications in one project is not a special case, but a standard mountable apps are first class citizens /apps
 /admin
 /config
 /controllers
 /orders
 /customers
 /web
 /config
 /controllers
 /api
 /config
 /controllers
  33. 33 not that modular Hanami libraries are independent of each

    other. However, Hanami application gem relies on most of the gems. Even if you don’t need mailers - you’ll have them in Gemfile.lock
  34. 34 Hanami promotes good engineering practices: separating layers of the

    application, writing code that’s easy to test, making most of the code private emphasis on architecture
  35. PART 4: SUPPORT

  36. 36 HANAMI SUPPORT GEMS mailer utils

  37. 37 Hanami utils do not monkey patch standard Ruby classes.

    Instead they add their own classes on top of the standard ones no monkey patching
  38. 38 Hanami utils gem provides a simple class that helps

    implementing service objects in a consistent manner interactors
  39. 39 magic in interactors Similarly to controller actions, the result

    is based on instance variables, not on the value you return from your call function
  40. 40 magic in interactors class CreateUser
 include Hanami::Interactor
 
 expose

    :user
 
 def call(params)
 @user = User.new(params)
 end
 end
 
 creator = CreateUser.new
 result = creator.call(params)
 result.user Similarly to controller actions, the result is based on instance variables, not on the value you return from your call function
  41. 41 small ecosystem Hanami is still considered a new framework,

    despite being more than 3 years old. There’s still few resources and libraries that help develop Hanami applications
  42. PART 5: SUMMARY

  43. 43 YOU CAN USE HANAMI FOR most web applications even

    non-web applications (model, validations, mailers)
  44. 44 YOU MIGHT RECONSIDER IF YOU BUILD application that needs

    a lot of external libraries project with a lot of complex queries simple CRUD applications
  45. WE’RE HIRING

  46. GRZEGORZ

  47. GRZEGORZ

  48. ONE YEAR WITH HANAMI @ A R N V A

    L D , P U N E , 2 0 1 8 wonderful