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

The Art Of Self-Defense - How To Protect Yourself From Nils

The Art Of Self-Defense - How To Protect Yourself From Nils

Presentation given on Łódź Ruby User Group.

karol.galanciak

January 13, 2016
Tweet

More Decks by karol.galanciak

Other Decks in Programming

Transcript

  1. The art of self-defense - how to protect yourself from

    nils Karol Galanciak - full-stack developer at Twitter: @Azdaroth
  2. NoMethodError: undefined method 'name' for nil:NilClass

  3. 1. Use right set of methods

  4. 1. Use right set of methods 1. Prefer Hash#fetch over

    Hash#[] name = params[:name] name = params.fetch(:name)
  5. 1. Use right set of methods 2. Use bang finder

    methods for required objects user = User.find_by(name: name) user = User.find_by!(name: name)
  6. 1. Use right set of methods 3. Use Hash#dig for

    hashes from input you don’t own payload = { data: { type: "users", attributes: { email: "[email protected]" }, relationships: { source: { data: { type: "sources", id: 20 } } } } } source_id = payload[:data][:relationships][:source][:data][:id] source_id = payload.dig(:data, :relationships, :source, :data, :id)
  7. 2. Null Object Pattern

  8. 2. Null Object Pattern # controller def current_user @current_user ||=

    User.find_by(id: user_id) || GuestUser.new end # model class GuestUser def name "Anonymous user" end end # view <%= current_user.name %>
  9. 2. Null Object Pattern class GuestUser def name "Anonymous user"

    end def comments Comment.none end end
  10. 2. Null Object Pattern class Comment::Persistence attr_reader :logger private :logger

    def initialize(logger: nil) @logger = logger end def save!(comment) comment.save! logger.log("comment: #{comment.attributes} created!") if logger end end
  11. 2. Null Object Pattern class Comment::Persistence attr_reader :logger private :logger

    def initialize(logger: NullLoger) @logger = logger end def save!(comment) comment.save! logger.log("comment: #{comment.attributes} created!") end module NullLogger def self.log(*) end end end
  12. 3. Do Not Make Demeter Sad

  13. 3. Do Not Make Demeter Sad comment.author.name

  14. 3. Do Not Make Demeter Sad class Comment < ActiveRecord::Base

    belongs_to :author delegate :name, to: :author, prefix: true, allow_nil: true end class Comment < ActiveRecord::Base belongs_to :author def author_name author && author.name || "Anonymous" end end comment.author_name
  15. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value * percentage end end
  16. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value.to_d * percentage end end
  17. 4. Apply Explicit Conversions class Tax < ActiveRecord::Base # percentage

    def calculate(value) value.to_s.to_d * percentage end end
  18. 5. Use proper database constraints class CreateComments < ActiveRecord::Migration def

    change create_table :comments do |t| t.integer :author_id, null: false t.text :content, null: false t.timestamps end add_foreign_key :comments, :authors end end
  19. Bonus: Never, ever, use Object#try and safe navigation operator &.

  20. Bonus: Never, ever, use Object#try and safe navigation operator &.

    comment.try(:author).try(:address).try(:primary) .try(:city).try(:region).try(:country) comment&.author&.address&.primary&.city&.region &.country http://www.reactionface.info/face/troll-face
  21. http://www.jasondemakis.com/wp-content/uploads/2015/09/yoda-there-is-no-try1.png