Slide 1

Slide 1 text

Notes from a PHP Immigrant Yitz Schaffer @YitzOfTheBits Vitals NYC.rb

Slide 2

Slide 2 text

My History 2008-

Slide 3

Slide 3 text

How I (think about) code and coding

Slide 4

Slide 4 text

PHP and Ruby def sum(a, b) a + b end function sum($a, $b) { return $a + $b; }

Slide 5

Slide 5 text

PHP and Ruby some_values = [ :foo, :bar, :baz ] $someValues = [ 'foo', 'bar', 'baz' ];

Slide 6

Slide 6 text

PHP and Ruby module Foo class Adder < MathOperation def initialize(initial_value) @initial_value = initial_value end def add_one @initial_value + 1 end end end Foo::Adder.new(4).add_one => 5 namespace Foo class Adder extends MathOperation { private $initialValue; public function __construct($initialValue) { $this->initialValue = $initialValue; } public function addOne() { return $this->initialValue + 1; } } (new \Foo\Adder(4))->addOne() => 5

Slide 7

Slide 7 text

PHP and Ruby [1, 2, 3].map { |x| x + 1 } array_map(function($x) { return $x + 1; }, [1, 2, 3]);

Slide 8

Slide 8 text

PHP: lots of things are not objects Ruby: everything is an object (?) 1 3.45 'abc' [$something] function bar() {} class Foo {} mysql_connect()

Slide 9

Slide 9 text

Metaprogramming!

Slide 10

Slide 10 text

Cool Metaprogramming Tools: AOP class Womper def expensive_operation(foo, bar) ... end end

Slide 11

Slide 11 text

Cool Metaprogramming Tools: AOP class Womper cache_method :expensive_operation def expensive_operation(foo, bar) ... end end

Slide 12

Slide 12 text

Cool Metaprogramming Tools: AOP class Womper cache_method :expensive_operation def expensive_operation(foo, bar) ... end end memory

Slide 13

Slide 13 text

Cool Metaprogramming Tools: AOP class Womper cache_method :expensive_operation def expensive_operation(foo, bar) ... end end Redis

Slide 14

Slide 14 text

Cool Metaprogramming Tools: AOP class Womper cache_method :expensive_operation def expensive_operation(foo, bar) ... end end LOLDB

Slide 15

Slide 15 text

Cool Metaprogramming Tools: AOP class Womper cache_method :expensive_operation def expensive_operation(foo, bar) ... end end LOLDB https://rubygems.org/gems/cache_method

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Types! def render(Tweet p): Html ... end

Slide 18

Slide 18 text

interface Renderer { public function render(Tweet $tweet); } Types!

Slide 19

Slide 19 text

interface Renderer { public function render(Tweet $tweet); } interface Renderer def render(tweet) end Types!

Slide 20

Slide 20 text

abstract class Renderer { public function render(Tweet $tweet); } Types!

Slide 21

Slide 21 text

abstract class Renderer { public function render(Tweet $tweet); } class AbstractRenderer def render(tweet) fail NotImplementedError end end Types!

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

:it_is_still_a_string Symbol, i.e. Stringleton

Slide 25

Slide 25 text

irb(main):004:0> Array.instance_methods - Object.instance_methods Broad base of built-in methods

Slide 26

Slide 26 text

irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], :[]=, :at, :fetch, :first, :last, :concat Broad base of built-in methods

Slide 27

Slide 27 text

irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, Broad base of built-in methods

Slide 28

Slide 28 text

irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, : slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :| Broad base of built-in methods

Slide 29

Slide 29 text

irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, : slice, :slice!, :assoc, :rassoc, : +, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :s huffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch Broad base of built-in methods

Slide 30

Slide 30 text

irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, : slice, :slice!, :assoc, :rassoc, : +, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :s huffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch, :pa ck, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :min max, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slic e, :each_cons, :each_with_object, :chunk, :slice_before, :lazy] Broad base of built-in methods

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Built-in method aliases

Slide 33

Slide 33 text

Built-in method aliases

Slide 34

Slide 34 text

Built-in method aliases

Slide 35

Slide 35 text

function blow_it_up($data) { $data['foo'] = 'BOOM'; return $data; } $a = ['foo' => 'bar']; $b = blow_it_up($a); $a['foo'] // 'bar' PHP: pass-by-copy for non-objects

Slide 36

Slide 36 text

def blow_it_up(data) data[:foo] = 'BOOM' data end a = {foo: 'bar'} b = blow_it_up(a) a[:foo] => 'BOOM' Ruby: regular ol' pass-by-value

Slide 37

Slide 37 text

def blow_it_up(data) data[:foo] = 'BOOM' data end a = {foo: 'bar'} b = blow_it_up(a) a[:foo] => 'BOOM' Ruby: regular ol' pass-by-value

Slide 38

Slide 38 text

[ 'baz', 'quux' ] { foo: 'bar' } Lists and Maps: Array, Hash, array()

Slide 39

Slide 39 text

array( 'foo' => 'bar' ) array( 'baz', 'quux' ) Lists and Maps: Array, Hash, array()

Slide 40

Slide 40 text

[1, 2, 3, 4, 5].select { |x| x.even? } Filtering Lists

Slide 41

Slide 41 text

[1, 2, 3, 4, 5].select { |x| x.even? } => [2, 4] Filtering Lists

Slide 42

Slide 42 text

array( 1, 2, 3, 4, 5 ) Filtering Lists

Slide 43

Slide 43 text

array( 0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5 ) Filtering Lists

Slide 44

Slide 44 text

array( 0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5 ) Filtering “Lists” i.e. Hashes

Slide 45

Slide 45 text

array( 0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5 ) apply filter… function($x) { return $x % 2 == 0; } Filtering “Lists” i.e. Hashes

Slide 46

Slide 46 text

array( // 0 => 1, 1 => 2, // 2 => 3, 3 => 4, // 4 => 5 ) apply filter… Filtering “Lists” i.e. Hashes function($x) { return $x % 2 == 0; }

Slide 47

Slide 47 text

array( 1 => 2, 3 => 4 ) apply filter… Filtering “Lists” i.e. Hashes

Slide 48

Slide 48 text

array( 1 => 2, 3 => 4 ) Filtering “Lists” i.e. Hashes

Slide 49

Slide 49 text

array( 1 => 2, 3 => 4 )[0] PHP Notice: Undefined offset: 0 Filtering “Lists” i.e. Hashes

Slide 50

Slide 50 text

array( 1 => 2, 3 => 4 )[0] PHP Notice: Undefined offset: 0 Filtering “Lists” i.e. Hashes array_values(array( 1 => 2, 3 => 4 ))[0] => 2

Slide 51

Slide 51 text

function calculateScore(factors) { // ... return $aCalculatedScore } Instructions vs. Definitions def score # ... a_calculated_score end

Slide 52

Slide 52 text

class Person { public function renderSalutation() { $fullName = ''; $fullName .= $this->firstName(); $fullName .= ' '; $fullName .= $this->lastName(); return $fullName . ', ' . $this->renderTitle(); } } Variable and Method Names

Slide 53

Slide 53 text

class Person { public function renderSalutation() { // extracted method from up here return $fullName . ', ' . $this->renderTitle(); } public function fullName() { $fullName = ''; $fullName .= $this->firstName(); $fullName .= ' '; $fullName .= $this->lastName(); return $fullName; } } Variable and Method Names

Slide 54

Slide 54 text

class Person { public function renderSalutation() { return $this->fullName() . ', ' . $this->renderTitle(); } public function fullName() { $fullName = ''; $fullName .= $this->firstName(); $fullName .= ' '; $fullName .= $this->lastName(); return $fullName; } } Variable and Method Names

Slide 55

Slide 55 text

class Person def renderSalutation full_name = '' full_name += full_name + first_name full_name += ' '; full_name += last_name full_name + ', ' + renderTitle end end Variable and Method Names

Slide 56

Slide 56 text

class Person def renderSalutation full_name + ', ' + renderTitle end def full_name full_name = '' full_name += full_name + first_name full_name += ' '; full_name += last_name end end Variable and Method Names

Slide 57

Slide 57 text

> Array(nil) => [] > Array([]) => [] > Array('foo') => ['foo'] > Array(['foo']) => ['foo'] Data Type Coercion

Slide 58

Slide 58 text

> Hash(nil) => {} > Hash(foo: 'bar') => {:foo=>'bar'} Data Type Coercion

Slide 59

Slide 59 text

vowel = Proc.new do |x| ['a', 'e', 'i', 'o', 'u'].include?(x.downcase) end Higher-order syntax sugar

Slide 60

Slide 60 text

vowel = Proc.new do |x| ['a', 'e', 'i', 'o', 'u'].include?(x.downcase) end 'what is my first vowel?'.split('').find { |letter| vowel.call(letter) } => 'a' Higher-order syntax sugar

Slide 61

Slide 61 text

vowel = Proc.new do |x| ['a', 'e', 'i', 'o', 'u'].include?(x.downcase) end 'what is my first vowel?'.split('').find { |letter| vowel.call(letter) } 'what is my first vowel?'.split('').find(&vowel) => 'a' Higher-order syntax sugar

Slide 62

Slide 62 text

> ['foo', 'bar'].map(&:reverse) Higher-order syntax sugar

Slide 63

Slide 63 text

> ['foo', 'bar'].map(&:reverse) => ["oof", "rab"] Higher-order syntax sugar

Slide 64

Slide 64 text

> ['foo', 'bar'].map(&:reverse) => ["oof", "rab"] Higher-order syntax sugar > p = :reverse.to_proc => # > p.call('jim') => "mij"

Slide 65

Slide 65 text

> { Date.new => [1,2,3] } => { # => [1,2,3] } Arbitrary Object as Hash key

Slide 66

Slide 66 text

matching_object_for(params) do |obj| obj.do_something end Indirection of block control (evil)

Slide 67

Slide 67 text

matching_object_for(params) do |obj| obj.do_something end def matching_object_for(params) obj = Model.find(params[:id]) yield obj unless obj.meaning == 42 end Indirection of block control (evil)

Slide 68

Slide 68 text

class Whatever def initialize @state = SomeState.new end def foogle with_alternate_state do calculated_value end end def with_alternate_state original_state = @state.dup @state.mutate! yield @state = original_state end end Block as state sandbox (evil)

Slide 69

Slide 69 text

Better Specs { rspec guidelines with ruby } http://betterspecs.org/

Slide 70

Slide 70 text

http://cleancoders.com/episode/clean-code-episode-20/show

Slide 71

Slide 71 text

Notes from a PHP Immigrant Yitz Schaffer @YitzOfTheBits Vitals NYC.rb