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

Rails As She Is Spoke

Giles
May 14, 2013

Rails As She Is Spoke

A presentation I gave at the LA Ruby meetup in May 2013.

Giles

May 14, 2013
Tweet

Other Decks in Programming

Transcript

  1. a book about all the ways Rails gets OOP wrong

    and why it works anyway caveat
  2. module Foo1 def url_for # url logic end module Foo4

    end def url_for # url logic module Foo2 end def url_for end # url logic end module Foo5 end def url_for # url logic module Foo3 end def url_for end # url logic end end this happens five times
  3. class URL # url logic end this does not happen

    once. and it does seem like the simplest question ever
  4. “In Ruby, everything is an object and this unembarrassed object-

    orientation gives Ruby much of its power and expressiveness. […] In Rails, however, sadly, there are large swathes which are not object oriented, and in my opinion, these areas tend to be the most painful parts of Rails.” this is mostly true, especially if you’re talking about weird corners of the Rails internals
  5. “In Ruby, everything is an object and this unembarrassed object-

    orientation gives Ruby much of its power and expressiveness. […] In Rails, however, sadly, there are large swathes which are not object oriented, and in my opinion, these areas tend to be the most painful parts of Rails.”
  6. “In Ruby, everything is an object and this unembarrassed object-

    orientation gives Ruby much of its power and expressiveness. […] In Rails, however, sadly, there are large swathes which are not object oriented, and in my opinion, these areas tend to be the most painful parts of Rails.” I mostly agree with this. but only MOSTLY.
  7. NOT THE MOST PAINFUL PART OF RAILS EITHER when you

    ignore a really obvious, practical OOP choice like creating a URL class, and you instead create Lisp-like code, you’re probably going to be able to get away with ignoring the obvious, practical OOP choice.
  8. OOP VS HACK CITY most people, when they talk about

    object-oriented principles, they contrast with code that has no structure at all.
  9. (url_for (controller foo) (action bar) (et cetera)) this itself is

    not functional programming, but it does show the influence of Lisp cascading down from Ruby into Rails.
  10. this itself is not functional programming, but it does show

    the influence of Lisp cascading down from Ruby into Rails.
  11. a book about all the ways Rails gets OOP wrong

    and why it works anyway and it’s about Rails getting OOP wrong
  12. a book about why Rails uses OOP at times but

    chooses not to at other times except it’s really about this
  13. It is not the season yet; but here is some

    peaches what does ripen at the eye sight. as she is spoke
  14. It is not the season yet; but here is some

    peaches what does ripen at the eye sight. peaches aren’t even the same food as apricots
  15. It is not the season yet; but here is some

    peaches what does ripen at the eye sight. just plain doing it wrong
  16. A test is not a unit test if: • It

    talks to the database • It communicates across the network • It touches the file system • It can't run at the same time as any of your other unit tests • You have to do special things to your environment to run it. and he said this about testing
  17. A test is not a unit test if: • It

    talks to the database • It communicates across the network • It touches the file system • It can't run at the same time as any of your other unit tests • You have to do special things to your environment to run it.
  18. A test is not a unit test if: • It

    talks to the database has anyone in here ever written a unit test which talked to a database?
  19. When you pull the database, sockets, or file system access

    into your unit tests, they aren’t really about those methods any more; they are about the integration of your code with that other software. and he said this about testing
  20. When you pull the database, sockets, or file system access

    into your unit tests, they aren’t really about those methods any more; they are about the integration of your code with that other software. and he said this about testing
  21. INTEGRATION TESTING the good news is that this is an

    actual thing. integration testing is a thing and a thing worth doing.
  22. I’m not even going to get into all the ways

    Rails gets testing terminology hopelessly confused
  23. but if you’re curious you should check out “fast rails

    tests” has anyone here ever had problems with slow Rails tests?
  24. 0.39 he took Rails out of the picture and wrote

    true unit tests in the Michael Feathers sense. they ran in 0.39 seconds.
  25. 0.15 he took Rails out of the picture and wrote

    true unit tests in the Michael Feathers sense. they ran in 0.15 seconds.
  26. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end
  27. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end
  28. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end
  29. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end 1: CREATE NEW USER INSTANCE
  30. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end 2: SAVE USER TO DATABASE
  31. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end 3: SEND A WELCOME EMAIL
  32. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end 4: RENDER A TEMPLATE ? which isn’t even in the code anywhere
  33. EVERYONE KNOWS IT nobody who is good at Rails takes

    the Rails testing approach seriously with the exception of DHH. it’s a joke.
  34. BUT RAILS POPULARIZED TDD that’s worth something. before Rails it

    was hard to even persuade a lot of people to take TDD seriously in the first place. now everybody knows they need to do it. so maybe there’s more to the story.
  35. CLASS != OBJECT why did he say class? we’re not

    talking about class-oriented programming. we’re talking about object-oriented programming.
  36. the history of object-oriented programming is dominated by clumsy, class-based

    languages like Java, where that distinction was immaterial. but with Ruby, we have more flexibility.
  37. There should never be more than one reason for a

    class to change. let’s talk about how to parse this sentence
  38. There should never be more than one reason for an

    object to change. and compare it to this sentence
  39. foo = String.new class << foo def bar 42 end

    end foo.bar # => 42 this is 100% valid Ruby where you add a method to an object without adding it to a class. I hope it’s obvious that transformations of this nature do not make it effortless to reason about your software coherently.
  40. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end you never see this on day-to-day Rails work, but the code which gets @user from here out into your view is working at a similar level of crazy
  41. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end you never see this on day-to-day Rails work, but the code which gets @user from here out into your view is working at a similar level of crazy
  42. class UsersController < ApplicationController def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save UserMailer.deliver_welcome_email(@user) end end end end you never see this on day-to-day Rails work, but the code which gets @user from here out into your view is working at a similar level of crazy
  43. There should never be more than one reason for a

    class to change. that’s not this
  44. There should never be more than one reason for an

    object to change. it’s not this, either
  45. There should never be a really weird reason for an

    object to change. it’s outside the entire universe of the Single Responsibility Principle
  46. CLASS == OBJECT in Java you can treat these terms

    identically. in Ruby, you can’t.
  47. CLASS != OBJECT CLASS == OBJECT in Java you can

    treat these terms identically. in Ruby, it might not be as wise.
  48. CLASS == OBJECT CLASS != OBJECT the irony of course

    is that the way the languages work is exactly the opposite
  49. Class.is_a? Object # => true in Ruby you may actually

    have to differentiate between the reasons for a CLASS to change and the reasons for an OBJECT to change
  50. Class.is_a? Object # => true # redefine class # Foo

    to be class # Bar Foo = type(‘Foo’, (Bar)) in Python you can change an object’s class at runtime, or redefine a class to be another class
  51. __class__ python exposes a __class__ semi-secret variable and if you

    know what you’re doing you can basically do anything you want with it. it’s a little bit crazy.
  52. class Fixnum def weeks end end Rails implements that by

    adding a method called weeks to Fixnum
  53. “In Ruby, everything is an object and this unembarrassed object-

    orientation gives Ruby much of its power and expressiveness. […] In Rails, however, sadly, there are large swathes which are not object oriented, and in my opinion, these areas tend to be the most painful parts of Rails.” again I have to disagree!
  54. # 3 weeks from now Time.now + (3 * 7

    * 24 * 60 * 60) this is what we used to do
  55. There should never be more than one reason for a

    class to change. so this, to some extent, is classic thinking, but also, to some extent, legacy thinking. it’s a good rule of thumb. you should DEFINITELY give it serious consideration and it very often leads to good code. but you can’t be fanatical about it either. OOP zealotry is not the way to understand Rails.
  56. this is also confusing we talk a lot about idiomatic

    ruby, but we don’t talk enough about idiotisms
  57. INHERITANCE: IT’S A FACTORY ActiveRecord hides an absolutely classic example

    of the Factory design pattern inside its inheritance mechanics for no other reason that I can ascertain, other than that it happens to look cool
  58. INHERITANCE: STI, WTF single-table inheritance also breaks Ruby inheritance in

    ActiveRecord models broken going up, broken going down
  59. 10s -> 0.39s if you want fast development, you need

    ActiveRecord out of your domain models
  60. 6s -> 0.15s and plenty of very successful Rails hackers

    take ActiveRecord out of their domain models
  61. class User # domain logic end class UserRecord < ActiveRecord::Base

    # database interaction end and end up here and it’s a huge improvement if the previous version was thousands of lines long - which happens!
  62. the essence of Active Record the pattern is that you

    couple domain logic to database access
  63. Active Record (DESIGN PATTERN) ActiveRecord (RUBY GEM) these guys use

    ActiveRecord without using Active Record. and when people try and talk about that technique, they get tied up in knots.
  64. “ACTIVE RECORD” if you can use ActiveRecord (the gem) without

    using Active Record (the design pattern), then it’s not really Active Record (the design pattern).
  65. here’s david heinemeier hansson presenting the revolutionary idea that if

    you want to put a button on the screen, your code should just be like, “button.”
  66. WRITING CODE CAN BE EASY IF WE MAKE IT EASY

    this is one of the amazingly obvious insights behind Rails’s success. and the way you make it easy is by writing code! Rails is full of code which exists purely to make the experience of building applications a PLEASANT one. and that is SO IMPORTANT.
  67. DEVELOPER USER EXPERIENCE MATTERS one of the most important lessons

    of Rails is that crafting a productive, enjoyable user experience for the developer is an incredibly effective move
  68. [email protected] railsoopbook.com so email me about it. CAVEAT! you have

    to email me tonight. if you don’t remember until tomorrow, sorry, no deal.