Slide 1

Slide 1 text

@kerrizor *.rb SOLID 101: A REVIEW FOR RUBYISTS

Slide 2

Slide 2 text

@kerrizor *.rb

Slide 3

Slide 3 text

T.J. Higgins, JSD @kerrizor *.rb

Slide 4

Slide 4 text

@kerrizor *.rb

Slide 5

Slide 5 text

@kerrizor *.rb

Slide 6

Slide 6 text

@kerrizor *.rb • Idempotent • CAP Theorem • Service • Correctness • SOLID BIG WORDS PEOPLE USE

Slide 7

Slide 7 text

@kerrizor *.rb • Single Responsibility Principle • Open-Closed Principle • Liskov Substitution Principle • Interface Segregation Principle • Dependency Inversion Principle S.O.L.I.D.

Slide 8

Slide 8 text

@kerrizor *.rb

Slide 9

Slide 9 text

@kerrizor *.rb

Slide 10

Slide 10 text

@kerrizor *.rb • Object: A representation of a thing (a noun) • Method: An action of a thing (its verbs) • Properties: Description of a thing (its adjectives) “CLASSICAL” OBJECTS

Slide 11

Slide 11 text

@kerrizor *.rb • Object: A collection of related behaviors • Method: A behavior • Properties: Details of behavior “MODERN” OBJECTS

Slide 12

Slide 12 text

AN OBJECT SAYS WHAT? An object is a collection of behaviors (methods) and state (properties or variables) that are related. @kerrizor *.rb

Slide 13

Slide 13 text

@kerrizor *.rb

Slide 14

Slide 14 text

SINGLE RESPONSIBILITY PRINCIPLE A class should have one and only one reason to change, meaning that a class should have only one job. @kerrizor *.rb

Slide 15

Slide 15 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Player attr_accessor :name, :kicking_average def initialize(options = {}) @name = options[:name] @kicking_average = options[:kicking_average] end def stats { kicking_average: @kicking_average } end end

Slide 16

Slide 16 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Team attr_accessor :name, :players def initialize(name = nil, players = []) @name = name @players = players end def team_kicking_average players.collect{ |p| p.stats[:kicking_average] }.sum / players.size end def output_average "

Team kicking average: #{team_kicking_average}

" end end

Slide 17

Slide 17 text

OPEN-CLOSED PRINCIPLE Objects or entities should be open for extension, but closed for modification. @kerrizor *.rb

Slide 18

Slide 18 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Player attr_accessor :name, :position def initialize(options = {}) @name = options[:name] @position = options[:position] end def kicking_order if @position == "First Base" 1 elsif @position == "Second Base" 2 ... end end

Slide 19

Slide 19 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Player attr_accessor :name, :position def initialize(options = {}) @name = options[:name] @position = options[:position] end def kicking_order if @position == "First Base" 1 elsif @position == "Second Base" 2 ... elsif @position == "Scorekeeper" 10 end end end

Slide 20

Slide 20 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Player attr_accessor :name, :kicking_average def initialize(options = {}) @name = options[:name] @kicking_average = options[:kicking_average] end def position nil end def kicking_order nil end end

Slide 21

Slide 21 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class FirstBaseperson < Player attr_accessor :name, :kicking_average def initialize(options = {}) @name = options[:name] @kicking_average = options[:kicking_average] end def position "First Base" end def kicking_order 1 end end

Slide 22

Slide 22 text

LISKOV SUBSTITUTION PRINCIPLE Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T. @kerrizor *.rb

Slide 23

Slide 23 text

@_jnf & @kerrizor MountainWest RubyConf 2016 LISKOV SUBSTITUTION PRINCIPLE @kerrizor *.rb

Slide 24

Slide 24 text

LISKOV SUBSTITUTION PRINCIPLE Subtypes (children) must be substitutable for their base types (parents). @kerrizor *.rb

Slide 25

Slide 25 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class ThirdBaseperson < Player attr_accessor :name, :kicking_average def initialize(options = {}) @name = options[:name] @kicking_average = options[:kicking_average] end def position { position: "Third Base" } end def kicking_order 1 end end

Slide 26

Slide 26 text

INTERFACE SEGREGATION PRINCIPLE The dependency of one class to another one should depend on the smallest possible interface. @kerrizor *.rb

Slide 27

Slide 27 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Team def calculate_salaries salaries = [] players.each do |player| if player.is_a? ThirdBase salary = player.salary[:salary] elsif player.respond_to? :favorite_pitch salary = "One Candy Bar per recess" elsif player.name == "Kerri" salary = Sandwich.new(type: "Tuna Fish w/Potato Chips") else salary = player.salary end end salaries.reject(:unavailable_at_cafeteria?) end end

Slide 28

Slide 28 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Team def calculate_salaries players.collect(&:salary) end end class Pitch def salary "One Candy Bar per recess" end end class BenchSitter def salary Sandwich.new(type: "Tuna Fish w/Potato Chips") if name == "Kerri" end end

Slide 29

Slide 29 text

DEPENDENCY INVERSION PRINCIPLE Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions. @kerrizor *.rb

Slide 30

Slide 30 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Team def print_roster RosterPrinter.new(players.collect(&:name)).print end end class RosterPrinter def initialize(roster = []) @roster = roster end def print roster.each do |name| puts "Name: #{name}" end end end

Slide 31

Slide 31 text

@kerrizor Ancient City Ruby 2015 @kerrizor Ancient City Ruby 2015 @kerrizor *.rb class Team def print_roster(printer = RosterPrinter) printer.new(roster).print end end class HtmlRosterPrinter def initialize(roster=[]) @roster = roster end def print roster.each do |name| "

Player Name: #{name}

" end end end

Slide 32

Slide 32 text

@kerrizor *.rb

Slide 33

Slide 33 text

@_jnf & @kerrizor MountainWest RubyConf 2016 July 22nd & 23rd, 2016 @kerrizor *.rb http://cfp.osfeels.com

Slide 34

Slide 34 text

@kerrizor *.rb