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

viewing ruby blossom kaigi2017

viewing ruby blossom kaigi2017

Slides from my talk about hanami at rubykaigi2017

Links:
railshurts.com/quiz
awesome-hanami.org
www.ossboard.org
octostar.herokuapp.com
contributors.hanamirb.org
hanamirb.org
gitter.im/hanami/chat
discuss.hanamirb.org

E7dfc74cd6e3194a22ef6fac2c51f0ae?s=128

Anton Davydov

September 18, 2017
Tweet

Transcript

  1. ❤ 
 Hello ruby kaigi! 
 ❤

  2. None
  3. Japan is awesome

  4. What have I learned here?

  5. One ramen per day is normal

  6. None
  7. None
  8. Juice pack

  9. None
  10. None
  11. Tax free

  12. None
  13. Anton Davydov github.com/davydovanton
 twitter.com/anton_davydov davydovanton.com

  14. Stickers

  15. None
  16. Hanami core

  17. ruby rom-rb dry-rb rails crystal etc

  18. moscow.rb

  19. None
  20. Luca Guidi github.com/jodosha

  21. None
  22. General Ideas

  23. Long-term maintenance

  24. Modularity Forget about fat models

  25. None
  26. Simplicity and Lightweight Framework is just a tool

  27. Architecturally Sound Isolation everywhere

  28. Zero Monkey-Patching Don’t think about framework or language

  29. railshurts.com/quiz

  30. railshurts.com/quiz

  31. Threadsafe

  32. None
  33. hanami != rails

  34. Typical parts of any web project

  35. Web Project Business
 logic Data flow

  36. Data flow

  37. Container Architecture Clean Architecture

  38. Project request

  39. App App App request

  40. App App App lib request

  41. App App App lib App App App lib App App

    App lib request
  42. App App App lib App App lib App App App

    lib request App
  43. apps/ ├── admin │ ├── application.rb │ ├── assets │

    │ └── ... │ ├── config │ │ └── ... │ ├── controllers │ │ └── ... │ ├── templates │ │ └── ... │ └── views │ └── ... └── web ├── ...
  44. Business Logic

  45. lib/ ├── project_name │ ├── interactors │ │ └── create_user.rb

    │ ├── entities │ │ └── user.rb │ ├── mailers │ │ └── templates │ └── repositories │ └── user_repository.rb └── project_name.rb
  46. lib/ ├── project_name │ ├── interactors │ │ └── create_user.rb

    │ ├── entities │ │ └── user.rb │ ├── mailers │ │ └── templates │ └── repositories │ └── user_repository.rb └── project_name.rb
  47. lib/ ├── project_name │ ├── interactors │ │ └── create_user.rb

    │ ├── entities │ │ └── user.rb │ ├── mailers │ │ └── templates │ └── repositories │ └── user_repository.rb └── project_name.rb
  48. lib/ ├── project_name │ ├── interactors │ │ └── create_user.rb

    │ ├── entities │ │ └── user.rb │ ├── mailers │ │ └── templates │ └── repositories │ └── user_repository.rb └── project_name.rb
  49. Gems

  50. hanami - Base repository, CLI router - Rack compatible HTTP

    router for Ruby controller - Full featured and fast actions for Rack utils - Ruby core extensions and class utilities model - Persistence with entities and repositories
  51. validations - Validations mixin for Ruby objects helpers - View

    helpers for Ruby applications view - Presentation with a separation assets - Assets management for Ruby mailer - Mail for Ruby applications
  52. Differences

  53. # rack class HelloApp def call(env) [200, { **env },

    ['Hello!']] end end
  54. # hanami-router class HelloApp def call(env) [200, { **env },

    ['Hello!']] end end router = Hanami::Router.new router.get '/', to: 'hello_app'
  55. # sinatra class Hello < Sinatra get '/' do 'Hello!'

    end end
  56. # hanami Hanami::Router.new do get '/' do [200, { **env

    }, ['Hello!']] end end
  57. Rails and Hanami

  58. Controllers

  59. class UsersController < AC def new end def send_sms end


    private def user_params end end Controllers: Rails
  60. Controllers: hanami action module Web::Controllers::Board class Index include Web::Action params

    do required(:email).filled end def call(params) end end end
  61. Controllers: hanami module Web::Controllers::Board class Index include Web::Action params do

    required(:email).filled end def call(params) end end end
  62. Controllers: hanami module Web::Controllers::Board class Index include Web::Action params do

    required(:email).filled end def call(params) end end end
  63. Model

  64. class User < ActiveRecord::Base
 include Gravtastic before_destroy :yank_gems has_many :rubygems,

    through: :ownerships validates :name, presence: true # ... end Model: Rails
  65. class User < ActiveRecord::Base
 include Gravtastic before_destroy :yank_gems has_many :rubygems,

    through: :ownerships validates :name, presence: true # ... end Model: Rails
  66. class User < ActiveRecord::Base
 include Gravtastic before_destroy :yank_gems has_many :rubygems,

    through: :ownerships validates :name, presence: true # ... end Model: Rails
  67. class User < ActiveRecord::Base
 include Gravtastic before_destroy :yank_gems has_many :rubygems,

    through: :ownerships validates :name, presence: true # ... end Model: Rails
  68. class User < ActiveRecord::Base
 include Gravtastic before_destroy :yank_gems has_many :rubygems,

    through: :ownerships validates :name, presence: true # ... end Model: Rails
  69. Model: hanami hanami + ROM = ❤ rom-rb.org

  70. Model: hanami entity class User < Hanami::Entity # ... end

  71. Model: hanami entity >> user = User.new(id: 1) => #<User:0x007fa14d1e0528

    @attributes={:id=>1}> >> user.id => 1 >> user.id = 1 NoMethodError: undefined method `id=' for #<User:0x007fa14d1e0528 @attributes={:id=>1}> Did you mean? id
  72. Model: hanami entity >> user = User.new(id: 1) => #<User:0x007fa14d1e0528

    @attributes={:id=>1}> >> user.id => 1 >> user.id = 1 NoMethodError: undefined method `id=' for #<User:0x007fa14d1e0528 @attributes={:id=>1}> Did you mean? id
  73. Model: hanami entity >> user = User.new(id: 1) => #<User:0x007fa14d1e0528

    @attributes={:id=>1}> >> user.id => 1 >> user.id = 1 NoMethodError: undefined method `id=' for #<User:0x007fa14d1e0528 @attributes={:id=>1}> Did you mean? id
  74. class UserRepository < Hanami::Repository associations do has_many :books end def

    find_by_name(name) users # => ROM relation users.where(name: name).limit(1).order { id }.one end end Model: hanami repository
  75. >> repo = UserRepository.new => #<UserRepository relations=[:users]> >> repo.find(1) =>

    #<User:0x007fa14d1a1fa8 @attributes={…}> >> repo.find_by_name(‘Anton’) => #<User:0x007fa14d1a1fa8 @attributes={…}> Model: hanami repository
  76. View

  77. View: Rails rails view (partials?) + rails helper

  78. View: Hanami hanami view (ruby class) + templates

  79. Assets

  80. Pros and Cons

  81. No magic

  82. module Web::Controllers::Board class Index include Web::Action def call(params) end end

    end
  83. Action test describe Web::Controllers::Board::Index do let(:action){ Board::Index.new } let(:params){ Hash[]

    } it 'is successful' do response = action.call(params) response[0].must_equal 200 end end
  84. Action test describe Web::Controllers::Board::Index do let(:action){ Board::Index.new } let(:params){ Hash[]

    } it 'is successful' do response = action.call(params) response[0].must_equal 200 end end
  85. Action test describe Web::Controllers::Board::Index do let(:action){ Board::Index.new } let(:params){ Hash[]

    } it 'is successful' do response = action.call(params) response[0].must_equal 200 end end
  86. No monkey-patching

  87. Best practices

  88. Dependency Injection

  89. None
  90. The logic separation

  91. Interactors out the box

  92. None
  93. None
  94. TDD

  95. None
  96. None
  97. TDD

  98. Good but not great documentation

  99. Missing Gems

  100. WebSockets
 Pagination
 WebPack GraphQL
 Devise 2016

  101. WebSockets
 Pagination
 WebPack GraphQL
 Devise Now

  102. awesome-hanami.org

  103. Projects are good
 for new contributors

  104. www.ossboard.org

  105. octostar.herokuapp.com

  106. contributors.hanamirb.org

  107. Contacts hanamirb.org gitter.im/hanami/chat discuss.hanamirb.org

  108. github.com/davydovanton
 twitter.com/anton_davydov davydovanton.com Thank you ❤