Slide 1

Slide 1 text

Object Oriented Design An Introduction to Beautiful Code Design Tuesday, November 6, 12

Slide 2

Slide 2 text

Hello World @styliii styliii.com github.com/styliii Tuesday, November 6, 12

Slide 3

Slide 3 text

Procedural Code collect data parse data if name is Li if name is not Li puts “Hi Li” puts “Bye” Tuesday, November 6, 12

Slide 4

Slide 4 text

Procedural Code Tuesday, November 6, 12

Slide 5

Slide 5 text

Procedural Code Data f1(x) f4(x) f3(x) f2(x) Tuesday, November 6, 12

Slide 6

Slide 6 text

Procedural Code Data f1(x) f4(x) f3(x) f2(x) Tuesday, November 6, 12

Slide 7

Slide 7 text

Procedural Code Data f1(x) f4(x) f3(x) f2(x) f5(x) Tuesday, November 6, 12

Slide 8

Slide 8 text

Procedural Code Data f1(x) f4(x) f3(x) f2(x) Tuesday, November 6, 12

Slide 9

Slide 9 text

Procedural Code Data f1(x) f4(x) f3(x) f2(x) Tuesday, November 6, 12

Slide 10

Slide 10 text

Procedural Code Data f1(x) f4(x) f3(x) f2(x) new f5(x) Tuesday, November 6, 12

Slide 11

Slide 11 text

Object Oriented Code f1(x) f4(x) f3(x) f2(x) Data Tuesday, November 6, 12

Slide 12

Slide 12 text

Object Oriented Code f1(x) f4(x) f3(x) f2(x) Tuesday, November 6, 12

Slide 13

Slide 13 text

Object Oriented Code f1(x) f4(x) f3(x) f2(x) Tuesday, November 6, 12

Slide 14

Slide 14 text

Object Oriented Code Tuesday, November 6, 12

Slide 15

Slide 15 text

History: Gang of Four Tuesday, November 6, 12

Slide 16

Slide 16 text

Change Tuesday, November 6, 12

Slide 17

Slide 17 text

Unhealthy Code rigid fragile - distant and seemingly unrelated code breaks after ever change immobility - code hopelessly entangled, you can’t reuse viscous - behaving badly is the most attractive alternative Tuesday, November 6, 12

Slide 18

Slide 18 text

Dependencies “Dependency will kill your code. Design will save it.” Tuesday, November 6, 12

Slide 19

Slide 19 text

SOLID Principles Single Responsibility Open/Closed Liskov Substitution Interface Segregation Dependency Inversion Tuesday, November 6, 12

Slide 20

Slide 20 text

Single Responsibility A class should have one, and only one, reason to change. Tuesday, November 6, 12

Slide 21

Slide 21 text

Open/Closed Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. Tuesday, November 6, 12

Slide 22

Slide 22 text

Liskov Substitution Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. Tuesday, November 6, 12

Slide 23

Slide 23 text

Interface Segregation Many client specific interfaces are better than one general purpose interface. Tuesday, November 6, 12

Slide 24

Slide 24 text

Dependency Inversion Depend upon abstractions. Do not depend upon concretions. Tuesday, November 6, 12

Slide 25

Slide 25 text

Dependency Inversion SOLID Single Responsibility Open/Closed Liskov Substitution Interface Segregation Tuesday, November 6, 12

Slide 26

Slide 26 text

Dependency Inversion SOLID Single Responsibility Open/Closed Tuesday, November 6, 12

Slide 27

Slide 27 text

Let’s Code! Tuesday, November 6, 12

Slide 28

Slide 28 text

Let’s Code! require 'sqlite3' class Employer attr_accessor :name, :url, :about @@db ||= SQLite3::Database.new('jobs.db') @@db.results_as_hash = true def initialize(name="", url="", about="") @name = name @url = url @about = about end def insert_employer @@db.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end Tuesday, November 6, 12

Slide 29

Slide 29 text

SRP in Play require 'sqlite3' class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end class Database @@db ||= SQLite3::Database.new('jobs.db') @@db.results_as_hash = true def insert_employer @@db.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end end Tuesday, November 6, 12

Slide 30

Slide 30 text

Make Database Class Work class Database @@db ||= SQLite3::Database.new('jobs.db') @@db.results_as_hash = true def insert_employer @@db.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end end Tuesday, November 6, 12

Slide 31

Slide 31 text

Make Database Class Work class Database @@db ||= SQLite3::Database.new('jobs.db') @@db.results_as_hash = true def insert_employer @@db.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end end class Database attr_accessor :connection def initialize @connection = SQLite3::Database.new('jobs.db') self.connection.results_as_hash = true end def insert_employer self.connection.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end end Tuesday, November 6, 12

Slide 32

Slide 32 text

Abstract the Employer leftovers class Database attr_accessor :connection def initialize @connection = SQLite3::Database.new('jobs.db') self.connection.results_as_hash = true end def insert_employer self.connection.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end end Tuesday, November 6, 12

Slide 33

Slide 33 text

Abstract the Employer leftovers class Database attr_accessor :connection def initialize @connection = SQLite3::Database.new('jobs.db') self.connection.results_as_hash = true end def insert_employer self.connection.execute("INSERT INTO employers (name, url, about) VALUES (?, ?, ?)", [@name, @url, @about]) end end def insert_record(table, attribute_names, attributes) question_marks = Array.new(attribute_names.size, "?").join(", ") self.connection.execute("INSERT INTO #{table} (#{attribute_names.join(", ")}) VALUES (#{question_marks})", [attributes]) end Same As Tuesday, November 6, 12

Slide 34

Slide 34 text

class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end Our Employer Class Tuesday, November 6, 12

Slide 35

Slide 35 text

Objects Interacting class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end Tuesday, November 6, 12

Slide 36

Slide 36 text

Objects Interacting class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def save Database.new.insert_record(table, attribute_names, attributes) end Tuesday, November 6, 12

Slide 37

Slide 37 text

Objects Interacting class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def self.table @@table ||= "employers" end def save Database.new.insert_record(table, attribute_names, attributes) end Tuesday, November 6, 12

Slide 38

Slide 38 text

Implement Save class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def self.table @@table ||= "employers" end def save Database.new.insert_record( table, attribute_names, attributes) end Tuesday, November 6, 12

Slide 39

Slide 39 text

Implement Save class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def self.table @@table ||= "employers" end def save Database.new.insert_record( table, attribute_names, attributes) end self.class. Tuesday, November 6, 12

Slide 40

Slide 40 text

Hardcode First class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def self.table @@table ||= "employers" end def save Database.new.insert_record( table, attribute_names, attributes) end self.class. Tuesday, November 6, 12

Slide 41

Slide 41 text

Hardcode First class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def self.table @@table ||= "employers" end def save Database.new.insert_record( table, attribute_names, attributes) end self.class. attribute_names = ["name", "url", "about"] attributes = [self.name, self.url, self.about] Tuesday, November 6, 12

Slide 42

Slide 42 text

Generalize Attributes class Employer attr_accessor :name, :url, :about end def self.table @@table ||= "employers" end def save attribute_names = self.instance_variables.map do |var| var.to_s.sub("@", "") end attributes = attribute_names.map do |att_name| self.send(att_name.to_sym) end Database.new.insert_record(self.class.table, attribute_names, attributes) end Tuesday, November 6, 12

Slide 43

Slide 43 text

SRP for Methods too! class Employer def self.table @@table ||= "employers" end def save Database.new.insert_record(self.class.table, self.attribute_names, self.attributes) end def attribute_names self.instance_variables.map do |var| var.to_s.sub("@", "") end end def attributes attribute_names.map do |att_name| self.send(att_name.to_sym) end end end Tuesday, November 6, 12

Slide 44

Slide 44 text

SRP for the Class require 'sqlite3' class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end def self.table @@table ||= "employers" end def save Database.new.insert_record(self.class.table, self.attribute_names, self.attributes) end end Tuesday, November 6, 12

Slide 45

Slide 45 text

Modules module Attributable def attribute_names self.instance_variables.map do |var| var.to_s.sub("@", "") end end def attributes attribute_names.map do |att_name| self.send(att_name.to_sym) end end end Tuesday, November 6, 12

Slide 46

Slide 46 text

Including the Module require 'sqlite3' require 'module' class Employer include Attributable attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end def self.table @@table ||= "employers" end def save Database.new.insert_record(self.class.table, self.attribute_names, self.attributes) end end Tuesday, November 6, 12

Slide 47

Slide 47 text

What else? require 'sqlite3' require 'module' class Employer include Attributable attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end def self.table @@table ||= "employers" end def save Database.new.insert_record(self.class.table, self.attribute_names, self.attributes) end end Tuesday, November 6, 12

Slide 48

Slide 48 text

Adding onto Module module Attributable def attribute_names self.instance_variables.map do |var| var.to_s.sub("@", "") end end def attributes attribute_names.map do |att_name| self.send(att_name.to_sym) end end end module Persistable def save Database.new.insert_record(self.class.table, self.attribute_names, self.attributes) end end Tuesday, November 6, 12

Slide 49

Slide 49 text

Anything Else? require 'sqlite3' require 'module.rb' class Employer include Attributable, Persistable attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end def self.table @@table ||= "employers" end end Tuesday, November 6, 12

Slide 50

Slide 50 text

Don’t Depend on Concretion Tuesday, November 6, 12

Slide 51

Slide 51 text

Don’t Depend on Concretion class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end Tuesday, November 6, 12

Slide 52

Slide 52 text

Don’t Depend on Concretion class Employer attr_accessor :name, :url, :about def initialize(name="", url="", about="") @name = name @url = url @about = about end end def initialize(args={}) args.each do |key, value| self.send("#{key.to_sym}=", value) end end Same As Tuesday, November 6, 12

Slide 53

Slide 53 text

Great Job :) require 'sqlite3' require 'module' class Employer include Attributable, Persistable attr_accessor :name, :url, :about def initialize(args = {}) args.each do |key, value| self.send("#{key.to_sym}=", value) end end def self.table @@table ||= "employers" end end Tuesday, November 6, 12

Slide 54

Slide 54 text

SOLID Principles Single Responsibility Open/Closed Liskov Substitution Interface Segregation Dependency Inversion Tuesday, November 6, 12

Slide 55

Slide 55 text

Resources Sandi Metz’s presentation on SOLID: http:/ /t.co/YqMiX7bq Diff between OO and Procedural Code: http:/ /www.youtube.com/watch? v=D8jZ0l_GwXQ Practical Object - Oriented Design in Ruby by Sandi Metz Source Code: https:/ /github.com/kcurtin/scrape_source https:/ /github.com/styliii/RubyJobScraper.git Books: Practical Object-Oriented Design in Ruby: An Agile Primer by Sandi Metz Pictures: http:/ /www.flickr.com/photos/yubacollege/4402710242/sizes/l/ http:/ /www.flickr.com/photos/dunechaser/6042984689/ http:/ /www.flickr.com/photos/ashclements/62704073/sizes/z/ Tuesday, November 6, 12