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

Make Up Your Own "Hello, World!"

Make Up Your Own "Hello, World!"

We all love Ruby. Maybe we’ve only been paid to write code in Ruby (and maybe JavaScript). But there are so many other languages out there, and they all have strengths, weaknesses, and very different communities surrounding them.
Let’s talk about language exploration. We’ll discuss how to learn a new language, considerations when introducing things to production, and come up with some ideas for Ruby and it’s ecosystem. Plan on dipping your toes in Elixir, Go, Haskell, Rust, and Scala during the session.

Justin Campbell

March 10, 2015
Tweet

More Decks by Justin Campbell

Other Decks in Programming

Transcript

  1. Make up your own
    "Hello, World!"
    @justincampbell

    View Slide

  2. Learn (verb)
    4 gain or acquire knowledge of or skill in (something)
    by study, experience, or being taught
    4 commit to memory
    4 become aware of (something) by information or
    from observation

    View Slide

  3. View Slide

  4. View Slide

  5. How?

    View Slide

  6. View Slide

  7. View Slide

  8. You need a project

    View Slide

  9. I need a project

    View Slide

  10. HTTP

    View Slide

  11. Writes

    View Slide

  12. State

    View Slide

  13. Testing

    View Slide

  14. TDD

    View Slide

  15. TDD

    View Slide

  16. Goals
    4 HTTP
    4 Writes
    4 Shared State
    4 TDD

    View Slide

  17. 4 Billboard
    4 Blog
    4 Chat
    4 Counter
    4 Dice
    4 Stats
    4 Storage
    4 Twitter
    4 URL Shortener

    View Slide

  18. URL
    Shortener

    View Slide

  19. Shorten
    POST / "url=http://justincampbell.me" -------> ,---------,
    |Shortener|
    201 Created /1

    View Slide

  20. Expand
    GET /1 --------------------------------------> ,---------,
    |Shortener|
    301 Redirect Location: http://justincampbell.me

    View Slide

  21. Missing
    GET /54321 ----------------------------------> ,---------,
    |Shortener|
    404 Not Found

    View Slide

  22. Ruby

    View Slide

  23. # Ruby
    post '/' do
    token = shortener.shorten(params[:url])
    [201, "/#{token}"]
    end

    View Slide

  24. # Ruby
    post '/' do
    token = shortener.shorten(params[:url])
    [201, "/#{token}"]
    end
    get '/:token' do |token|
    full_url = shortener.expand(token)
    halt 404 unless full_url
    redirect full_url
    end

    View Slide

  25. # Ruby
    class Shortener
    def shorten(url)
    token = id_generator.next.to_s
    urls[token] = url
    token
    end
    def expand(token)
    urls[token]
    end
    end

    View Slide

  26. # Ruby
    class Shortener
    def id_generator
    @id_generator ||= (1..Float::INFINITY).enum_for
    end
    def urls
    @urls ||= Hash.new
    end
    end

    View Slide

  27. # Ruby
    def shortener
    Shortener.instance
    end
    class Shortener
    def self.instance
    @instance ||= new
    end
    end

    View Slide

  28. Thread-Safe?

    View Slide

  29. View Slide

  30. Clojure

    View Slide

  31. ; Clojure
    (def token
    (atom 0))

    View Slide

  32. ; Clojure
    (def token
    (atom 0))
    (defn next-token []
    (swap! token inc))

    View Slide

  33. ; Clojure
    (def token
    (atom 0))
    (defn next-token []
    (swap! token inc))
    (next-token) ; => 1

    View Slide

  34. ; Clojure
    (def token
    (atom 0))
    (defn next-token []
    (swap! token inc))
    (next-token) ; => 1
    (next-token) ; => 2

    View Slide

  35. View Slide

  36. # Ruby
    def shorten(url)
    token = id_generator.next.to_s
    urls[token] = url
    token
    end

    View Slide

  37. # Ruby
    def shorten(url)
    token = id_generator.next.to_s
    urls[token] = url
    token
    end
    {- Haskell -}
    shorten :: Url -> Token

    View Slide

  38. # Ruby
    def shorten(url)
    token = id_generator.next.to_s
    urls[token] = url
    token
    end
    {- Haskell -}
    shorten :: Url -> Token
    {- shorten is a function from a Url to a Token -}

    View Slide

  39. # Ruby
    def shorten(url)
    token = id_generator.next.to_s
    urls[token] = url
    token
    end
    {- Haskell -}
    type Token = String
    type Url = String
    shorten :: Url -> Token

    View Slide

  40. # Ruby
    def shorten(url)
    token = id_generator.next.to_s
    urls[token] = url
    token
    end
    {- Haskell -}
    type Token = String
    type Url = String
    shorten :: Url -> Token
    shorten url = token where
    {- increment token, store url -}

    View Slide

  41. {- Haskell -}
    type Token = String
    type Url = String
    shorten :: Url -> Token

    View Slide

  42. {- Haskell -}
    type Token = String
    type Url = String
    shorten :: Url -> World -> Token

    View Slide

  43. {- Haskell -}
    type Token = String
    type Url = String
    shorten :: Url -> World -> World

    View Slide

  44. {- Haskell -}
    type Token = String
    type Url = String
    data World = World { id :: Int,
    urls :: Map Token Url }
    shorten :: Url -> World -> World

    View Slide

  45. {- Haskell -}
    type Token = String
    type Url = String
    data World = World { id :: Int,
    urls :: Map Token Url }
    shorten :: Url -> World -> World
    shorten url world = newWorld where
    nextId = succ $ _id world
    token = show nextId
    newUrls = insert token url $ _urls world
    newWorld = World nextId newUrls

    View Slide

  46. {- Haskell -}
    type Token = String
    type Url = String
    data World = World { id :: Int,
    urls :: Map Token Url }
    shorten :: Url -> World -> World

    View Slide

  47. {- Haskell -}
    type Token = String
    type Url = String
    data World = World { id :: Int,
    urls :: Map Token Url }
    shorten :: Url -> World -> World
    expand :: Token -> World -> Maybe Url

    View Slide

  48. Nim

    View Slide

  49. # Nim
    type Token = string
    type Url = string
    var id = 0
    var urls = newTable[Token, Url]()
    proc shorten*(url: Url): Token =
    id += 1
    let token = intToStr(id)
    urls[token] = url
    return token
    proc expand*(token: Token): Url =
    if hasKey(urls, token):
    return urls[token]

    View Slide

  50. {- Haskell -}
    expand :: Token -> World -> Maybe Url
    # Nim
    proc expand*(token: Token): Url =
    # ...

    View Slide

  51. # Nim
    proc expand*(token: Token): Url =
    # ...

    View Slide

  52. # Nim
    proc expand*(token: Token): Url =
    # ...
    shorten("google.com") # => "1"

    View Slide

  53. # Nim
    proc expand*(token: Token): Url =
    # ...
    shorten("google.com") # => "1"
    expand("1") # => "google.com"

    View Slide

  54. # Nim
    proc expand*(token: Token): Url =
    # ...
    shorten("google.com") # => "1"
    expand("1") # => "google.com"
    expand("54321") # => nil

    View Slide

  55. View Slide

  56. nil

    View Slide

  57. NoMethodError: undefined method `name' for nil:NilClass

    View Slide

  58. NoMethodError: undefined method `name' for nil:NilClass
    Type Error

    View Slide

  59. Go

    View Slide

  60. // Go
    url, err := shortener.expand(token);
    if err != nil {
    http.NotFound(response, request);
    }
    http.Redirect(response, request, url, 301);

    View Slide

  61. // Go
    url, err := shortener.expand(token);
    // if err != nil {
    // http.NotFound(response, request);
    // }
    http.Redirect(response, request, url, 301);

    View Slide

  62. // Go
    url, err := shortener.expand(token);
    // if err != nil {
    // http.NotFound(response, request);
    // }
    http.Redirect(response, request, url, 301); // ???

    View Slide

  63. In two weeks, Im headed to
    India to give a keynote at a
    Go Conference. Last year
    this time, I was like, "why
    do I need a GOROOT and
    GOPATH?" - Bryan Lyles

    View Slide

  64. # Ruby
    get '/:token' do |token|
    url = shortener.expand(token)
    halt 404 unless url
    redirect url
    end

    View Slide

  65. # Ruby
    get '/:token' do |token|
    begin
    url = shortener.expand(token)
    redirect url
    rescue # ???
    halt 404
    end
    end

    View Slide

  66. Elixir/Erlang

    View Slide

  67. # Elixir
    {:ok, url} = Shortener.Core.expand(conn.params[:token])

    View Slide

  68. # Elixir
    {:ok, url} = Shortener.Core.expand(conn.params[:token])
    # ** (MatchError) no match of right hand side value:
    # {:error, "Token not found"}

    View Slide

  69. # Elixir
    case Shortener.Core.expand(conn.params[:token]) do
    {:ok, url} -> redirect conn, to: url
    _ -> conn.send 404, "Not found"
    end

    View Slide

  70. # Ruby
    case url = shortener.expand(token)
    when String
    redirect url
    when NilClass
    halt 404
    end

    View Slide

  71. # Ruby
    case result = shortener.expand(token)
    when result.success?
    redirect result.value
    else
    halt 404
    end

    View Slide

  72. # Ruby
    def halve(number)
    number / 2.0
    end
    halve 5 # => 2.5
    halve "5" # strings don't respond to `/`

    View Slide

  73. View Slide

  74. View Slide

  75. View Slide

  76. Embrace
    Conventions

    View Slide

  77. View Slide

  78. " Clojure
    Plug 'guns/vim-clojure-static'
    Plug 'guns/vim-sexp'
    Plug 'tpope/vim-classpath'
    Plug 'tpope/vim-fireplace'
    Plug 'tpope/vim-leiningen'
    Plug 'tpope/vim-sexp-mappings-for-regular-people'
    " CoffeeScript
    Plug 'kchmck/vim-coffee-script'
    " Elixir
    Plug 'elixir-lang/vim-elixir'
    " Go
    Plug 'fatih/vim-go'
    " Haskell
    Plug 'dag/vim2hs'
    Plug 'eagletmt/ghcmod-vim'
    Plug 'shougo/vimproc.vim'
    " JavaScript
    Plug 'pangloss/vim-javascript'
    " Nim
    Plug 'zah/nimrod.vim'

    View Slide

  79. " OCaml
    Plug 'ocamlpro/ocp-indent'
    Plug 'the-lambda-church/merlin'
    " PureScript
    Plug 'raichoo/purescript-vim'
    " Ruby
    Plug 'ecomba/vim-ruby-refactoring'
    Plug 'hwartig/vim-seeing-is-believing'
    Plug 'jgdavey/vim-blockle'
    Plug 'tpope/vim-rails'
    Plug 'tpope/vim-rake'
    Plug 'vim-ruby/vim-ruby'
    " Rust
    Plug 'wting/rust.vim'
    " Scala
    Plug 'derekwyatt/vim-scala'
    " Shell
    Plug 'markcornick/vim-bats'
    Plug 'rosstimson/bats.vim'
    " Thrift
    Plug 'solarnz/thrift.vim'

    View Slide

  80. make

    View Slide

  81. make
    default: deps test
    deps:
    which bundle || gem install bundler
    bundle check || bundle install
    test:
    bundle exec rspec spec/

    View Slide

  82. Why?

    View Slide

  83. New Perspective

    View Slide

  84. "If you do what you've
    always done, you'll get
    what you've always
    gotten"
    - Henry Ford

    View Slide

  85. Language
    Matters

    View Slide

  86. The principle of linguistic relativity
    holds that the structure of a language
    affects the ways in which its respective
    speakers conceptualize their world, i.e.
    their world view, or otherwise
    influences their cognitive processes.
    http://en.wikipedia.org/wiki/Linguistic_relativity

    View Slide

  87. Make you a better Rubyist

    View Slide

  88. @ work

    View Slide

  89. Hiring Filters:
    Write your app in Rails, and enter the hiring fracas. Or,
    use Haskell or Clojure and hire better people with less
    competition.
    — Ben Orenstein
    twitter.com/r00k/status/563821546016636928

    View Slide

  90. Bored People Quit
    - Michael Lopp
    randsinrepose.com/archives/bored-people-quit

    View Slide

  91. Thoughts + Ideas
    for
    Ruby:

    View Slide

  92. RSpec is hard

    View Slide

  93. # Ruby
    describe User do
    subject(:user) {
    described_class.new(first_name, last_name)
    }
    let(:first_name) { "Justin" }
    let(:last_name) { "Campbell" }
    it "concatenates a full name" do
    expect(user.full_name).to start_with(first_name)
    expect(user.full_name).to end_with(last_name)
    end
    end

    View Slide

  94. # Ruby
    describe User do
    def test_full_name
    user = User.new("Justin", "Campbell")
    assert_equal "Justin Campbell", user.full_name
    end
    end

    View Slide

  95. Outside-in?
    Inside-out?

    View Slide

  96. Inside-out?
    Outside-in?

    View Slide

  97. $ sbt test
    [info] Set current project ...
    [info] Run completed in 397 milliseconds.
    [info] Total number of tests run: 1
    [info] Suites: completed 1, aborted 0
    [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
    [info] All tests passed.
    [success] Total time: 2 s

    View Slide

  98. $ sbt ~test
    [info] Set current project ...
    [info] Run completed in 397 milliseconds.
    [info] Total number of tests run: 1
    [info] Suites: completed 1, aborted 0
    [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
    [info] All tests passed.
    [success] Total time: 2 s
    1. Waiting for source changes... (press enter to interrupt)

    View Slide

  99. $ rake ~test

    View Slide

  100. $ rake ~test
    task :test do |t|
    t.watch /^.+_test\.rb$/
    end

    View Slide

  101. $ lein test
    Retrieving lein-exec/lein-exec/0.3.1/lein-exec-0.3.1.pom from clojars
    Retrieving lein-exec/lein-exec/0.3.1/lein-exec-0.3.1.jar from clojars
    Retrieving org/clojure/clojure/1.6.0/clojure-1.6.0.pom from central
    Retrieving org/sonatype/oss/oss-parent/7/oss-parent-7.pom from central
    Retrieving org/clojure/tools.nrepl/0.2.3/tools.nrepl-0.2.3.pom from central
    [...]
    lein test ...
    Ran 1 tests containing 1 assertions.
    0 failures, 0 errors.

    View Slide

  102. $ bundle exec rspec
    Could not find rspec-5.0.0 in any of the sources
    Run `bundle install` to install missing gems.

    View Slide

  103. $ bundle exec rspec
    The following gems are missing
    * rspec (3.0.0)
    Installing rspec 3.0.0
    Bundle complete!
    ...............
    Finished in 0.16548 seconds
    15 examples, 0 failures

    View Slide

  104. # Ruby
    class Animal
    def initialize(type)
    @type = type
    end
    end
    Animal.new(:cat) # => #

    View Slide

  105. # Ruby
    class Animal
    def initialize(type)
    @type = type
    end
    end
    Animal(:cat) # NoMethodError

    View Slide

  106. # Ruby
    require 'newk/everything'
    class Animal
    def initialize(type)
    @type = type
    end
    end
    Animal(:cat) # => #

    View Slide

  107. View Slide

  108. "Learn a language a year"

    View Slide

  109. Too long
    +
    Too short

    View Slide

  110. Start Small

    View Slide

  111. Pick
    a
    Project

    View Slide

  112. URL Shortener

    View Slide

  113. Conway's
    Game of Life
    en.wikipedia.org/wiki/Conway's_Game_of_Life

    View Slide

  114. Which
    Language
    First?

    View Slide

  115. Haskell

    View Slide

  116. Clojure

    View Slide

  117. Go

    View Slide

  118. Fun + Community

    View Slide

  119. Fun!
    Compiler + Readability

    View Slide

  120. Community!
    Adoption + Friendliness

    View Slide

  121. Resources:

    View Slide

  122. View Slide

  123. learnxinyminutes.com

    View Slide

  124. !
    github.com/kata-seeds

    View Slide

  125. Share
    your
    Excitement

    View Slide

  126. Have
    Fun

    View Slide

  127. Dude, sucking at something is the first step towards
    being sorta good at something
    - Jake, Adventure Time

    View Slide

  128. Thanks!
    @justincampbell

    View Slide