Hanami: because sometimes, you need to re-invent the wheel

Hanami: because sometimes, you need to re-invent the wheel

Hanami is a modern web framework for Ruby. It’s a full-featued MVC framework with asset integration. What could it possibly have to offer over Rails? As it turns out, quite a bit: a lightweight framework, OOP, plain old Ruby and, above all, simplicity. Sometimes it is worth it to re-invent the wheel.

Presented at Utrecht.rb.

241eb3a089132c5a0c65e765558a6735?s=128

Arjan van der Gaag

May 02, 2016
Tweet

Transcript

  1. None
  2. What would you like to complain about? [ ] Too

    much magic [ ] Too much boilerplate source: @phillip_webb
  3. What would you like to complain about? [ ✔ ]

    Too much magic [ ] Too much boilerplate source: @phillip_webb
  4. ARJAN VAN DER GAAG (@AVDGAAG) HANAMI …because sometimes, you need

    to
 re-invent the wheel
  5. ARJAN VAN DER GAAG arjanvandergaag.nl • @avdgaag • brightin

  6. “Hanami is a Ruby MVC web framework comprised of many

    micro-libraries. It has a simple, stable API, a minimal DSL, and prioritises the use of plain objects over magical, over-complicated classes with too much responsibility.”
  7. “The natural repercussion of using simple objects with clear responsibilities


    is more boilerplate code.”
  8. ARJAN VAN DER GAAG (@AVDGAAG) CONTROLLER

  9. ARJAN VAN DER GAAG (@AVDGAAG) class Create include Web::Action def

    call(params) # book = ... redirect_to routes.book_path(book.id) end end
  10. ARJAN VAN DER GAAG (@AVDGAAG) class Create include Web::Action params

    do param :book do param :pages, type: Integer, size: 0..9999 param :title, presence: true end end def call(params) if params.valid? # ... end end end
  11. ARJAN VAN DER GAAG (@AVDGAAG) MINIMAL INTERFACES

  12. ARJAN VAN DER GAAG (@AVDGAAG) class Show include Web::Action expose

    :book def call(params) @book = BookRepository.find(params[:id]) end end
  13. ARJAN VAN DER GAAG (@AVDGAAG) RSpec.describe Show do it 'is

    successful' do response = Show.new.call('id' => '1') expect(response[0]).to eql(200) end end
  14. ARJAN VAN DER GAAG (@AVDGAAG) class Show include Web::Action expose

    :book def initialize(repository: BookRepository) @repository = repository end def call(params) @book = @repository.find(params[:id]) end end
  15. ARJAN VAN DER GAAG (@AVDGAAG) RSpec.describe Show do it 'exposes

    the book found in the repository' do book = Book.new action = Show.new(repository: double(find: book)) action.call('id' => '1') expect(action.exposures[:book]).to be(book) end end
  16. ARJAN VAN DER GAAG (@AVDGAAG) VIEW

  17. ARJAN VAN DER GAAG (@AVDGAAG) class ApplicationController < ActionController::Base helper

    :all end
  18. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Views::Books class Index include

    Web::View end end
  19. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Views::Books class Index include

    Web::View def render 'hello, world' end end end
  20. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Views::Books class Index include

    Web::View include MyHelper end end
  21. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Views::Books class Index include

    Web::View def books locals[:books] end end end
  22. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Views::Books class Index include

    Web::View def books locals[:books].map do |book| Web::Presenters::BookPresenter.new(book) end end end end
  23. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Presenters class BookPresenter include

    Hanami::Presenter def title super.upcase end end end
  24. ARJAN VAN DER GAAG (@AVDGAAG) module Web::Presenters class BookPresenter include

    Hanami::Presenter def title super.upcase end end end book = Book.new(title: 'Pride & Prejudice') presenter = Web::Presenters::BookPresenter.new(book) presenter.title # => "PRIDE &AMP; PREJUDICE"
  25. ARJAN VAN DER GAAG (@AVDGAAG) MODEL

  26. ARJAN VAN DER GAAG (@AVDGAAG) class Book include Hanami::Entity attributes

    :title, :author, :pages end Book.new(title: '1984') # => #<Book @id=nil @title='1984' @author=nil
 # @pages=nil>
  27. ARJAN VAN DER GAAG (@AVDGAAG) class BookRepository include Hanami::Repository end

    BookRepository.find(1) # => #<Book @id=1 @title="1984" @author="George # Orwell" @pages=1234> BookRepository.persist(Book.new(title: '1984')) # => #<Book @id=2 @title="1984" @author=nil # @pages=nil>
  28. ARJAN VAN DER GAAG (@AVDGAAG) class AccountRepository include Hanami::Repository def

    self.find_by_username(username) query do where(username: username) end.first end end
  29. ARJAN VAN DER GAAG (@AVDGAAG) MONOLITH FIRST

  30. LIB APPS/WEB

  31. LIB APPS/WEB APPS/API

  32. LIB APPS/WEB APPS/ADMIN APPS/API

  33. ARJAN VAN DER GAAG (@AVDGAAG) WASTE OF EFFORT TO RE-

    CREATE LOTS OF MOSTLY THE SAME TOOLS?
  34. ARJAN VAN DER GAAG (@AVDGAAG) SOMETIMES, YOU NEED TO
 RE-INVENT

    THE WHEEL
  35. “With large, ongoing software projects, a lot of the features

    that help with simple demo apps become irrelevant. Or worse, they become disadvantages and bottlenecks, and sometimes downright obstacles to any further development.” Filip Hracek, The ‘Hello World’ Fallacy
  36. ARJAN VAN DER GAAG (@AVDGAAG) SIMPLICITY > CONVENIENCE

  37. ARJAN VAN DER GAAG (@AVDGAAG) YOU’RE WRITING RUBY

  38. What would you like to complain about? [ ✔ ]

    Too much magic [ ] Too much boilerplate source: @phillip_webb
  39. ARJAN VAN DER GAAG (@AVDGAAG) SEE HANAMIRB.ORG

  40. ARJAN VAN DER GAAG (@AVDGAAG) EMACS INTEGRATION https://github.com/avdgaag/projectile-hanami

  41. ARJAN VAN DER GAAG arjanvandergaag.nl • @avdgaag • brightin