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

Sanity on Rails — How to write maintainable Rails applications in 2017

Sanity on Rails — How to write maintainable Rails applications in 2017

Rails is not your application! Don’t overcomplicate your development life by trying to make everything fit within its MVC structure. A framework provides tools and abstractions, use them to build your business logic, don’t force your business logic to fit into them.

Michael Kohl

August 12, 2017
Tweet

More Decks by Michael Kohl

Other Decks in Programming

Transcript

  1. Sanity on Rails
    Michael Kohl

    Deccan RubyConf 2017

    View Slide

  2. • Michael Kohl (@citizen428)

    • CTO @ Lockstep Labs

    • Based in Bangkok, Thailand

    • Ruby developer since ~2004

    • Former mentor at RubyLearning
    Deccan RubyConf 2017
    locksteplabs.com
    Yours truly

    View Slide

  3. Deccan RubyConf 2017
    locksteplabs.com
    The problem

    View Slide

  4. Deccan RubyConf 2017
    locksteplabs.com
    The problem
    • Recurring problems

    • Dependencies

    • Framework entanglement

    • Implicit code

    • Good news: easily avoidable

    View Slide

  5. Deccan RubyConf 2017
    locksteplabs.com
    Dependencies

    View Slide

  6. Deccan RubyConf 2017
    locksteplabs.com
    Dependencies
    • Bootstrap the app faster

    • Prevent “not invented here syndrome”

    • Get peer reviewed

    • Easily get outdated

    • Memory footprint & startup times

    • Have more dependencies

    View Slide

  7. Deccan RubyConf 2017
    locksteplabs.com
    Dependencies
    • Be selective about dependencies

    • Look for actively maintained gems

    • Use gems for common tasks

    • Prefer developers with vested interest

    View Slide

  8. Deccan RubyConf 2017
    locksteplabs.com
    Dependencies

    View Slide

  9. Deccan RubyConf 2017
    locksteplabs.com
    Dependencies

    View Slide

  10. Deccan RubyConf 2017
    locksteplabs.com
    Framework entanglement

    View Slide

  11. "A basic conceptional structure

    (as of ideas)"

    – Merriam Webster

    "A basic structure underlying a
    system, concept, or text." –

    Oxford English dictionary
    Deccan RubyConf 2017
    locksteplabs.com
    Frameworks

    View Slide

  12. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Controllers
    • Abstracting HTTP communication

    • Authentication

    • Authorization

    • Sessions / cookies

    • Param validation / transformation

    • Redirection / rendering

    View Slide

  13. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Controllers
    # Actions
    resources :actions, only: [:index]
    namespace :actions do
    resource :enqueue_cvs, only: [:create]
    resource :import_cvs, only: [:create]
    resource :generate_suggestions, only: [:create]
    resource :logs, only: [:destroy]
    end
    # Users
    resources :users, except: [:new, :edit, :show]
    namespace :users do
    resources :filters, only: [:create]
    resources :passwords, only: [:create, :edit, :update]
    end

    View Slide

  14. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Models
    • Wrapper around datastore

    • ActiveRecord configuration

    • Associations

    • Validations

    • Finders / scopes

    • Simple accessors / mutation methods

    View Slide

  15. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Models
    • Extract POROs

    • Various extraction patterns

    • Service objects

    • Form objects

    • Query objects

    • many more

    • Use namespacing

    View Slide

  16. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Models
    ! tree app/services/cv
    app/services/cv
    "## file_mover.rb
    "## importer.rb
    "## parser.rb
    "## repository.rb
    "## suggestion_handler.rb
    $## viewer.rb

    View Slide

  17. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Models
    require_dependency 'cv'
    class Cv
    # Class for importing CV files into ElasticSearch in a standardized way.
    class Importer
    attr_accessor :file_name, :content, :md5sum, :file_type, :attributes, :parse
    def self.import(file_name, content, attr = {})
    new(file_name, content, attr).import
    end
    def initialize(file_name, content, attr = {})
    self.file_name = File.basename(file_name)

    parse_attributes(attr)
    end
    def import
    add_to_es
    extract_plaintext
    parse_cv if parse
    end

    View Slide

  18. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Models
    Credit: Code Climate

    View Slide

  19. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Models
    class AbandonedTrialQuery
    def initialize(relation = Account.scoped)
    @relation = relation
    end
    def find_each(&block)
    @relation.
    where(plan: nil, invites_count: 0).
    find_each(&block)
    end
    end
    Credit: Code Climate

    View Slide

  20. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Views
    • Response generation

    • Should be mostly logic free

    • Rails conflates view model & template

    • Helpers become dumping grounds

    View Slide

  21. Deccan RubyConf 2017
    locksteplabs.com
    Frameworks - Views
    class UserView < ApplicationView
    include ActionView::Helpers::TagHelper
    forward :first_name, :last_name
    def formatted_full_name
    content_tag :strong, "#{first_name} #{last_name}"
    end
    end

    View Slide

  22. Deccan RubyConf 2017
    locksteplabs.com
    Implicit code

    View Slide

  23. Deccan RubyConf 2017
    locksteplabs.com
    Implicit code
    • “Convention over configuration”

    • Magic:

    • AR configuration

    • Instance variables in views

    • Implicit code:

    • AR callbacks

    • before_action/after_action

    View Slide

  24. Deccan RubyConf 2017
    locksteplabs.com
    Implicit code
    • Hard for newcomers to understand

    • Hard to follow code flow

    • Easy, not simple

    • Doesn’t apply in all cases

    View Slide

  25. Deccan RubyConf 2017
    locksteplabs.com
    Implicit code
    • Be more explicit!

    • Reading is more important than writing!

    • POROs to encapsulate processes

    • Don’t try to be too clever!

    View Slide

  26. • Be selective when adding gems

    • Build business logic on top of what Rails
    provides, don’t mix it with framework
    code

    • Explicit is often better than implicit

    • There are no silver bullets, all software
    development involves tradeoffs.
    Deccan RubyConf 2017
    locksteplabs.com
    Summary

    View Slide

  27. • How DHH Organizes His Rails Controllers

    http://jeromedalbert.com/how-dhh-organizes-
    his-rails-controllers/

    • 7 Patterns to Refactor Fat ActiveRecord Models

    http://blog.codeclimate.com/blog/2012/10/17/7-
    ways-to-decompose-fat-activerecord-models/

    • Objects on Rails

    http://objectsonrails.com
    Deccan RubyConf 2017
    locksteplabs.com
    Resources

    View Slide

  28. Deccan RubyConf 2017
    locksteplabs.com
    Thank you!

    View Slide