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

A Lever for the Mind

Tom Stuart
November 19, 2014

A Lever for the Mind

Humans are the cleverest animals in the known universe. But our brains, forged over millions of years in the unforgiving furnace of natural selection, are still primitive. They evolved to be good at hunting animals, making tools, recognising facial expressions and maintaining social bonds, but they’re just not very good at working with several difficult ideas simultaneously, and they’re particularly bad at reasoning about the counterintuitive emergent behaviour of complex non-human systems.

That’s a problem, because complex non-human systems now dominate our world.

Abstraction is our solution to this problem. Abstraction works as an adapter between the fearsome complexity of the universe and our simple primate minds; when the real world is too detailed, too confusing or too counterintuitive for us to work with directly, abstraction gives us big friendly levers to pull on instead. This one powerful idea underlies computers, design, culture, language, and everything else we rely on in our daily work.

This is a talk about abstraction: where it comes from, what it’s for, and how we can use it to make our programs better.

Given at RubyConf 2014 (http://lanyrd.com/2014/rubyconf/) and Bath Ruby Conference 2015 (http://2015.bathruby.org/). A video and transcript is available at https://tomstu.art/a-lever-for-the-mind.

Tom Stuart

November 19, 2014
Tweet

More Decks by Tom Stuart

Other Decks in Programming

Transcript

  1. Give me a lever long enough and a fulcrum on

    which to place it, and I shall move the world.” — Archimedes “
  2. 3

  3. <

  4. 3

  5. 1 + 2 + 3 + 4 + 5 +

    6 + 7 + 8 + 9 + 10 = ?
  6. 1 + 2 = 3 3 + 3 = 6

    6 + 4 = 10 10 + 5 = 15
  7. 15 + 6 = 21 21 + 7 = 28

    28 + 8 = 36 36 + 9 = 45 45 + 10 = 55
  8. 1 + 2 + 3 + 4 + 5 +

    6 + 7 + 8 + 9 + 10 = 55
  9. 1 + 2 + 3 + 4 + 5 +

    … … + 98 + 99 + 100 = ?
  10. ? 1 + 2 + 3 + 4 + 5

    + 6 + 7 + 8 + 9 + 10 =
  11. ? 1 + 10 + 2 + 9 + 3

    + 8 + 4 + 7 + 5 + 6 =
  12. 1 + 10 + 2 + 9 + 3 +

    8 + 4 + 7 + 5 + 6 = 55
  13. 1 + 2 + … + 9 + 10 =

    (10 ÷ 2) × (10 + 1)
  14. 1 + 2 + 3 + 4 + 5 +

    … … + 98 + 99 + 100 = ?
  15. 1 + 100 + 2 + 99 + 49 +

    52 + 50 + 51 = ? ⋮
  16. 1 + 2 + … + 99 + 100 =

    (100 ÷ 2) × (100 + 1)
  17. 1 + 2 + … + n = (n ÷

    2) × (n + 1)
  18. 1 + 2 + … + n = (n +

    1) × n ÷ 2 ( )
  19. 1 + 2 + … + 999 + 1000 =

    (1000 ÷ 2) × (1000 + 1)
  20. Card = Struct.new(:rank, :suit) three_of_diamonds = Card.new(3, :diamonds) queen_of_hearts =

    Card.new(12, :hearts) ace_of_spades = Card.new(14, :spades)
  21. Hand = Struct.new(:cards) do include Comparable def <=>(other) if highest_card_rank

    == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end # … end
  22. Hand = Struct.new(:cards) do include Comparable def <=>(other) if empty?

    && other.empty? 0 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end # … end
  23. Hand = Struct.new(:cards) do include Comparable def <=>(other) if one_pair?

    if other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  24. Hand = Struct.new(:cards) do include Comparable def <=>(other) if two_pair?

    if other.two_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end elsif one_pair? if other.two_pair? -1 elsif other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? || other.two_pair? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  25. Hand = Struct.new(:cards) do include Comparable def <=>(other) if three_of_a_kind?

    if other.three_of_a_kind? if highest_triple_rank == other.highest_triple_rank without { |c| c.rank == highest_triple_rank } <=> other.without { |c| c.rank == highest_triple_rank } else highest_triple_rank <=> other.highest_triple_rank end else 1 end elsif two_pair? if other.three_of_a_kind? -1 elsif other.two_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end elsif one_pair? if other.two_pair? || other.three_of_a_kind? -1 elsif other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? || other.two_pair? || other.three_of_a_kind? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  26. Hand = Struct.new(:cards) do include Comparable def <=>(other) if straight?

    if other.straight? if highest_straight_rank == other.highest_straight_rank without { |c| c.rank == highest_straight_rank } <=> other.without { |c| c.rank == highest_straight_rank } else highest_straight_rank <=> other.highest_straight_rank end else 1 end elsif three_of_a_kind? if other.straight? -1 elsif other.three_of_a_kind? if highest_triple_rank == other.highest_triple_rank without { |c| c.rank == highest_triple_rank } <=> other.without { |c| c.rank == highest_triple_rank } else highest_triple_rank <=> other.highest_triple_rank end else 1 end elsif two_pair? if other.three_of_a_kind? || other.straight? -1 elsif other.two_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end elsif one_pair? if other.two_pair? || other.three_of_a_kind? || other.straight? -1 elsif other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? || other.two_pair? || other.three_of_a_kind? || other.straight? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  27. Card = Struct.new(:rank, :suit) class Card::Rank TWO, THREE, FOUR, FIVE,

    SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } end class Card::Suit CLUBS, HEARTS, SPADES, DIAMONDS = 4.times.map { new } end three_of_diamonds = Card.new(Card::Rank::THREE, Card::Suit::DIAMONDS) queen_of_hearts = Card.new(Card::Rank::QUEEN, Card::Suit::HEARTS) ace_of_spades = Card.new(Card::Rank::ACE, Card::Suit::SPADES)
  28. class Card::Rank include Comparable ORDER = ( TWO, THREE, FOUR,

    FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } ) def <=>(other) ORDER.index(self) <=> ORDER.index(other) end end
  29. class Hand::Category include Comparable ORDER = ( HIGH_CARD, ONE_PAIR, TWO_PAIR,

    THREE_OF_A_KIND, STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH = 9.times.map { new } ) def <=>(other) ORDER.index(self) <=> ORDER.index(other) end end
  30. Hand::Rank = Struct.new(:hand) do include Comparable def category Hand::Category::ORDER. select

    { |category| category.matches?(hand) }.max end def <=>(other) if category == other.category category.compare(hand, other.hand) else category <=> other.category end end end
  31. Hand = Struct.new(:cards) do def rank Hand::Rank.new(self) end end if

    my_hand.rank > your_hand.rank puts 'I win!' end
  32. class Card::Rank ORDER = ( TWO, THREE, FOUR, FIVE, SIX,

    SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } ) def succ ORDER[ORDER.index(self).succ] end end
  33. class Card::Rank ORDER = ( TWO, THREE, FOUR, FIVE, SIX,

    SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } ) def succ ORDER[ORDER.index(self).succ % ORDER.size] end end
  34. When a thing looks complicated, it’s possible that we’re looking

    at it wrong and missing some of the pieces of the puzzle.” — Richard Feynman “