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

Adopting Sorbet at Scale

Adopting Sorbet at Scale

Presented at RubyConf 2019

Avatar for Ufuk Kayserilioglu

Ufuk Kayserilioglu

November 19, 2019
Tweet

More Decks by Ufuk Kayserilioglu

Other Decks in Programming

Transcript

  1. 1

  2. Benefits 50% Reduction in serious injury 45% Reduction in risk

    of death 4 https://www.cdc.gov/motorvehiclesafety/seatbeltbrief/index.html
  3. Yet... 4% of Canadian drivers 13% of US drivers 54%

    of Turkish drivers 5 drive without a seatbelt https://en.wikipedia.org/wiki/Seat_belt_use_rates_by_country
  4. Why? 6 01 02 03 04 Find them uncomfortable Over

    65s find them restricting Do not think they ever need them Think they’re less likely to have an accident https://www.bbc.com/news/blogs-magazine-monitor-29416372
  5. - Costs too much ⏱ and - Cannot test every

    situation (Crash) Testing 8
  6. 18 # typed: true extend(T::Sig) sig do params(opts: T::Hash[Symbol, Integer])

    .returns(Integer) end def foo(opts) opts.fetch("bar") end foo(bar: 1) foo.rb
  7. 19 foo.rb:9: Expected Symbol but found String("bar") for argument arg0

    https://srb.help/7002 10 | opts.fetch("bar") ^^^^^^^^^^^^^^^^^ hash.rbi#L517: Method Hash#fetch has specified arg0 as Symbol 517 | arg0: K, ^^^^ Got String("bar") originating from: foo.rb:9: 10 | opts.fetch("bar") ^^^^^ Errors: 1 srb tc foo.rb
  8. view.rbi 21 # typed: true require "view_gem" View.render foo.rb #

    typed: true class View def self.render(file) end end
  9. view.rbi 22 # typed: true require "view_gem" View.render # ^

    error: Not enough arguments provided for method View.render. Expected: 1, got: 0 foo.rb # typed: true class View def self.render(file) end end
  10. 24 Sorbet is mandatory in CI May 2019 Sorbet over

    all files Mar 2019 Sorbet is open-sourced Jun 2019 Shopify gets access to Sorbet Jul 2018 Sorbet introduced in Core Oct 2018 Timeline
  11. 26 Built a runtime component No runtime component Problem ﹘

    Initial version built in-house (waffle-cone) ﹘ Shared our work with the Sorbet team ﹘ Later on switched to sorbet-runtime
  12. 27 Built a gem RBI generator All constants must resolve

    Problem ﹘ Initial version built on YARD ﹘ Decided that structure of constants more important ﹘ Built a runtime reflection based tool ﹘ Open sourced as tapioca
  13. 28 Built Rubocop rules Some Ruby constructs are not supported

    Problem ﹘ Initial rules bundled with waffle-cone ﹘ Extracted out to rubocop-sorbet ﹘ Open sourced
  14. 29 Built DSL plugins for Sorbet Metaprogramming Problem ﹘ Based

    on simple class method name matching ﹘ Can run Ruby scripts to generate interface ﹘ Contributed to Sorbet, documented ﹘ Slow and error-prone
  15. 30 RBI generator for models Rails support Problem ﹘ Rake

    task to generate RBI files for AR models ﹘ Based on sorbet-rails ﹘ Planning switch to sorbet-rails
  16. 45 Metaprogramming support ﹘ If you use a lot of

    DSLs, you will need to generate RBI files for them. ﹘ Limited ability to extend Sorbet to understand more syntax. DSL plugins too slow. Pitfall 1
  17. 46 Some missing stdlib signatures ﹘ Stdlib/core method signatures are

    maintained by the Sorbet team. ﹘ No full coverage, so you might get some errors for perfectly valid Ruby code. ﹘ Contribute missing signatures back to Sorbet. Pitfall 2
  18. 47 No constants via inheritance class Foo Bar = 42

    end class Baz < Foo end Baz::Bar # error: Unable to resolve constant Bar Foo::Bar # ok Pitfall 3
  19. 48 No dynamic superclass/mixin def superclass Class.new end def mixin

    Module.new end class Baz < superclass # error: ^ Superclasses must only contain constant literals include mixin # error: ^ include must only contain constant literals end Pitfall 4
  20. 49 Runtime type checking overhead ﹘ Checking types at runtime

    adds ~7% overhead. ﹘ Not a problem for dev and test. ﹘ Might not want it for production. Pitfall 5
  21. 51 Sorbet Playground ﹘ Play around at https://sorbet.run to get

    familiar ﹘ Read the docs at https://sorbet.org/docs/ Step 1
  22. 52 Add Sorbet to your project ﹘ Add sorbet, sorbet-runtime

    to your Gemfile ﹘ Run bundle exec srb init Step 2
  23. 53 Add Sorbet to your project ﹘ Add sorbet, sorbet-runtime

    and tapioca to your Gemfile ﹘ Run bundle exec tapioca init ﹘ Run bundle exec tapioca sync Step 2 (alt)
  24. 54 Start by typing new code ﹘ Easier to type

    when adding new code. ﹘ Add types to existing code when it is easy and convenient. ﹘ Use rubocop-sorbet to add template signatures to existing code in bulk Step 3
  25. 55 Lean on gradual typing ﹘ You can type as

    much or as little as you want. ﹘ Start small, increase coverage slowly. ﹘ Don’t break other people’s workflows. Step 4
  26. 56 Don’t overtype ﹘ It is OK to use simpler

    signatures ﹘ There is no harm in using T.untyped when needed. ﹘ Your colleagues should not need a PhD in type theory to make code changes. Step 5
  27. 57 Track your progress ﹘ Sorbet metrics via --metrics-file flag

    ﹘ Easy to parse JSON format ﹘ Set up a nightly task and dashboard to track progress Step 6
  28. Thank you Don’t forget to fasten your seatbelts! Reach out

    to me Twitter: @paracycle Github: @paracycle Join us at the Shopify booth!