SlideShare a Scribd company logo
Rails Traps
Reuven M. Lerner • reuven@lerner.co.il

    International Rails Conference
    November 12th, 2012 • Tel Aviv
Who am I?

• Web developer since 1993
• Linux Journal columnist since 1996
• Long-time developer/trainer/consultant in
  Ruby, Rails, and PostgreSQL (and many
  more)
What do I do?

• Web development, especially in Rails
• Teaching/training
 • 4-day Ruby course in Herzliya next week
• Coaching/consulting
What is a trap?
Rails traps
It looks really good ...
... but it’s not worth the
         long-term
      consequences
Rails traps
Rails traps

• Techniques that look like they’ll benefit us...
• ... but which will haunt us down the road
• There is some overlap these and “anti-
  patterns,” a term that people use to
  describe “design patterns that you should
  avoid”
Rails traps
Trap #1:
    Always using Rails
• Rails is wonderful. Really, it is.
• But it’s not the only framework.
• (And Ruby isn’t the only language!)
• Use Rails because it’s the right framework
  for the job
Alternatives
• My favorite: Sinatra
• Ridiculously easy to create Web apps, built
  in Ruby, works with ERb and Haml (and
  other gems we know and love), and
  fantastic documentation
• But really, you should use what you know, if
  it gets the job done. (Even PHP...)
Trap #2:
Ignoring Rails’ opinions
• One of the best things about Rails is that
  it’s opinionated
  • Files go in specific places
  • MVC split is (fairly) obvious
  • ActiveRecord naming is pre-set
• If your opinions differ, you may have trouble
Don’t be a salmon
Opinions may differ...
   but not in Rails
• Yes, you can configure Rails to conform to
  your opinions
• But in doing so, you’re likely to encounter
  pain — now, and in the future
• Different parts of Rails make the same
  assumptions, so expect extended pain
• Stick with the defaults as much as possible
Some examples

• Always have a synthetic primary key, and
  always call it “id”
• Naming conventions for tables, classes
• Fat models and skinny controllers
• DRY things up with filters, callbacks
Trap #3:
     Ignoring the logs
• Logs are a developer’s best friend
• Is there a problem? Check the logs!
• Having a problem? Write to the log!
• (Check the database log, too!)
• Using a debugger should be your last
  resort, not your first one
Trap #4:
  Ignoring the console
• The console (especially with Pry) is one of
  the most useful parts of Rails
• Don’t ignore it, or think that it’s primitive
• The console is a critical part of my
  development and debugging process
• It helps me “feel” my way through the app
Trap #5:
     Not being RESTful
• For years, Rails has encouraged us to use
  RESTful resources
• You don’t have to; config/routes.rb still
  contains the following line (in a comment):
  match ':controller(/:action(/:id))(.:format)'

• Maybe you don’t have to be RESTful. But life
  is far easier when you accept REST.
Being RESTful

• Think “resources” rather than controllers
• Resources should be nouns, and actions
  operate on those nouns
• Those actions can usually be mapped onto
  the standard seven methods
What REST gives you
• Convention over configuration
• Ease of maintenance/understanding
• Routes, forms, and helpers that just work
• Scaffolds (yes, I like scaffolds)
• Forces you to think (and rethink) the
  structure of your application, which an
  definitely improve it
Trap #6:
   Only being RESTful
• REST is a technique, not a religion
• If you have non-RESTful controller actions,
  you are not an evil person!
  • (Well, not too evil)
• Add new member or collection methods
  when you need them — but not more
  often than that
Trap #7:
    Self authentication
• Rails doesn’t have a built-in authentication
  system. (This drives me crazy.)
• There are gems (e.g., Devise) that do a
  fantastic job, and which have been used and
  tested by many sites
• Security is hard to get right!
• Please don’t roll your own. Use a gem.
Trap #8:
Premature optimization
• Cache everything!
• Index everything!
• Get huge servers!
• Use bit masks in the database to avoid
  overloading the system!
Think about Ruby
• Ruby isn’t optimized for program speed, but
  rather for programmer speed
• That is an important competitive advantage
• Computers are cheap, but people are not
• First make sure your software is
  maintainable. Then worry whether it’s fast.
• And then benchmark before optimizing!
Trap #9:
DB operations in Ruby
• Of course, there are some places where
  you should consider speed
• Databases are really smart and efficient
  about handling data
• Plus, the data is far smaller as tuples than as
  ActiveRecord objects
• Let the database do the serious data lifting
Don’t do this
• Please don’t do this:
  Person.all.select {|p| p.age > 40}

• This will be incredibly slow.
• Serious databases (e.g., PostgreSQL) let you
  create server-side functions and views, which
  can manipulate the data before it ever gets
  to Ruby, at database speeds
Trap #10:
   Different databases
• I often see people using SQLite in
  development, and PostgreSQL in
  production
• Don’t do this, especially if you’re using an
  open-source database in production
• Databases are different — different data
  types, integrity solutions, and transactional
  behavior.
Trap #11:
       NoSQL or Bust
• I hear many people say that SQL is slow,
  bad, complex, or otherwise
• All of their problems will disappear if they
  switch to NoSQL!
• Really?
• That’s like saying, “Hashes are great, so I’ll
  use them instead of arrays.”
Trap #12:
The cloud! The cloud!
• Cloud solutions are great ...
• ... in certain circumstances.
• I’m using Heroku with three of my clients
  right now, and I’m very pleased with their
  product and support.
• But that doesn’t mean it’s a better, or even
  cheaper, option for everyone out there.
My cloudy questions
• How much direct control do I want/need
  over my company’s servers?
• Is the cost of cloud services lower than the
  cost of configuring and maintaining these
  myself?
• How likely am I to have to scale up
  massively, at a moment’s notice?
Trap #13:
Long controller actions
• It’s so tempting! You want to do so much
  in your controller action.
• But the user doesn’t want to wait for your
  e-mail to be sent.
• Use Resque, Delayed Job, or whatever you
  want... but put such things in the
  background, and answer the user ASAP.
Trap #14:
   No DB constraints
• Is your Rails application the only program
  that will ever touch the database?
• (Answer: Almost certainly not.)
• So why are your constraints only in Rails?
• A good database will let you specify not
  only NOT NULLs, but also valid values to
  protect your data
Trap #15:
Lack of callbacks, filters
• Callbacks (on ActiveRecord models) and
  filters (on controller actions) let you
  separate the “real work” from the less-
  important work
• Keep code short, readable, and DRY
Trap #16:
       Not using “lib”
• We talk a lot about MVC in Rails
• But don’t forget the “lib” directory
• It’s a great place to place modules and
  classes that are used across your app, or
  that aren’t specifically tied to MVC
• (Remember that lib isn’t automatically in
  the load path, as of Rails 3.x.)
Trap #17:
 Modifying migrations
• Migrations are one of my favorite parts of
  Rails.
• Migrations are reversible: If you make a
  mistake, you can migrate down, change the
  migration file, and then migrate up.
• Only do this before you have shared your
  migration with other people
Why not?

• Once you have pushed your migration,
  someone might have applied them
• Maybe you know to migrate backward,
  revert the old version, git pull, and then
  migrate forward... but does everyone?
Trap #18:
  Using class variables
• When I teach Ruby, everyone loves class
  variables! (They also love to call them
  “static variables.”)
• There is a place for class variables, but it’s a
  very limited one:
• Data that needs to be shared across all
  instances of a class
Class variable
         alternatives
• Class-level constants
• Class methods
• A module with methods or constants
• A model (for some types of constants)
And don’t forget


• Class variables vs. class instance variables
• This is where your understanding of the
  Ruby object model really comes in handy
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
class Confusion
  @x = 11             # class instance variable
  @@x = 22            # class variable
  def initialize
      @x = 999        # instance variable
  end
  def return_x
      @x              # returns 999
  end
  def self.return_x
      @x              # returns 11
  end
  def return_double_x
      @@x             # returns 22
  end
  def self.return_double_x
      @@x             # returns 22
  end
end
Trap #19:
      Cool technology
• Don’t use technology because it’s cool.
  Use technology because it gets the job
  done, and helps the business.
• So it might be cool to use a pub-sub system
  written in a .NET port of Clojure that
  transfers XML using EBCDIC...
• ... but is it necessary?
                         Is it the easiest and
  best solution? Is it maintainable?
Choosing technologies
• My preference is to use things that are
  proven, stable, and a little boring
• (Like me)
• The stability and viability of a project is far
  more important than the latest cool hack
• (Which I’ll install on my own machine to
  play with, but not use on clients’ projects)
Trap #20:
Not learning, improving

• You cannot survive in our business without
  learning new techniques all of the time
• The Ruby and Rails worlds move especially
  fast, with new gems released all of the time
What to do?
• Podcasts (Ruby Rogues, Ruby show, Ruby 5)
• Newsletters (Ruby Weekly)
• Blogs
• Books (remember those?)
• Learn other languages! You can pick up a
  lot of ideas and techniques from them
Bonus trap:
Not enjoying yourself
• Ruby and Rails make programming fun
• If you’re not having fun, then maybe you’re
  not doing it right
• (Or go join the wild party that I hear .NET
  developers are having!)
Thanks!
(Any questions?)

    reuven@lerner.co.il
   http://www.lerner.co.il/

       054-496-8405
“reuvenlerner” on Skype/AIM

More Related Content

Rails traps

  • 1. Rails Traps Reuven M. Lerner • reuven@lerner.co.il International Rails Conference November 12th, 2012 • Tel Aviv
  • 2. Who am I? • Web developer since 1993 • Linux Journal columnist since 1996 • Long-time developer/trainer/consultant in Ruby, Rails, and PostgreSQL (and many more)
  • 3. What do I do? • Web development, especially in Rails • Teaching/training • 4-day Ruby course in Herzliya next week • Coaching/consulting
  • 4. What is a trap?
  • 6. It looks really good ...
  • 7. ... but it’s not worth the long-term consequences
  • 9. Rails traps • Techniques that look like they’ll benefit us... • ... but which will haunt us down the road • There is some overlap these and “anti- patterns,” a term that people use to describe “design patterns that you should avoid”
  • 11. Trap #1: Always using Rails • Rails is wonderful. Really, it is. • But it’s not the only framework. • (And Ruby isn’t the only language!) • Use Rails because it’s the right framework for the job
  • 12. Alternatives • My favorite: Sinatra • Ridiculously easy to create Web apps, built in Ruby, works with ERb and Haml (and other gems we know and love), and fantastic documentation • But really, you should use what you know, if it gets the job done. (Even PHP...)
  • 13. Trap #2: Ignoring Rails’ opinions • One of the best things about Rails is that it’s opinionated • Files go in specific places • MVC split is (fairly) obvious • ActiveRecord naming is pre-set • If your opinions differ, you may have trouble
  • 14. Don’t be a salmon
  • 15. Opinions may differ... but not in Rails • Yes, you can configure Rails to conform to your opinions • But in doing so, you’re likely to encounter pain — now, and in the future • Different parts of Rails make the same assumptions, so expect extended pain • Stick with the defaults as much as possible
  • 16. Some examples • Always have a synthetic primary key, and always call it “id” • Naming conventions for tables, classes • Fat models and skinny controllers • DRY things up with filters, callbacks
  • 17. Trap #3: Ignoring the logs • Logs are a developer’s best friend • Is there a problem? Check the logs! • Having a problem? Write to the log! • (Check the database log, too!) • Using a debugger should be your last resort, not your first one
  • 18. Trap #4: Ignoring the console • The console (especially with Pry) is one of the most useful parts of Rails • Don’t ignore it, or think that it’s primitive • The console is a critical part of my development and debugging process • It helps me “feel” my way through the app
  • 19. Trap #5: Not being RESTful • For years, Rails has encouraged us to use RESTful resources • You don’t have to; config/routes.rb still contains the following line (in a comment): match ':controller(/:action(/:id))(.:format)' • Maybe you don’t have to be RESTful. But life is far easier when you accept REST.
  • 20. Being RESTful • Think “resources” rather than controllers • Resources should be nouns, and actions operate on those nouns • Those actions can usually be mapped onto the standard seven methods
  • 21. What REST gives you • Convention over configuration • Ease of maintenance/understanding • Routes, forms, and helpers that just work • Scaffolds (yes, I like scaffolds) • Forces you to think (and rethink) the structure of your application, which an definitely improve it
  • 22. Trap #6: Only being RESTful • REST is a technique, not a religion • If you have non-RESTful controller actions, you are not an evil person! • (Well, not too evil) • Add new member or collection methods when you need them — but not more often than that
  • 23. Trap #7: Self authentication • Rails doesn’t have a built-in authentication system. (This drives me crazy.) • There are gems (e.g., Devise) that do a fantastic job, and which have been used and tested by many sites • Security is hard to get right! • Please don’t roll your own. Use a gem.
  • 24. Trap #8: Premature optimization • Cache everything! • Index everything! • Get huge servers! • Use bit masks in the database to avoid overloading the system!
  • 25. Think about Ruby • Ruby isn’t optimized for program speed, but rather for programmer speed • That is an important competitive advantage • Computers are cheap, but people are not • First make sure your software is maintainable. Then worry whether it’s fast. • And then benchmark before optimizing!
  • 26. Trap #9: DB operations in Ruby • Of course, there are some places where you should consider speed • Databases are really smart and efficient about handling data • Plus, the data is far smaller as tuples than as ActiveRecord objects • Let the database do the serious data lifting
  • 27. Don’t do this • Please don’t do this: Person.all.select {|p| p.age > 40} • This will be incredibly slow. • Serious databases (e.g., PostgreSQL) let you create server-side functions and views, which can manipulate the data before it ever gets to Ruby, at database speeds
  • 28. Trap #10: Different databases • I often see people using SQLite in development, and PostgreSQL in production • Don’t do this, especially if you’re using an open-source database in production • Databases are different — different data types, integrity solutions, and transactional behavior.
  • 29. Trap #11: NoSQL or Bust • I hear many people say that SQL is slow, bad, complex, or otherwise • All of their problems will disappear if they switch to NoSQL! • Really? • That’s like saying, “Hashes are great, so I’ll use them instead of arrays.”
  • 30. Trap #12: The cloud! The cloud! • Cloud solutions are great ... • ... in certain circumstances. • I’m using Heroku with three of my clients right now, and I’m very pleased with their product and support. • But that doesn’t mean it’s a better, or even cheaper, option for everyone out there.
  • 31. My cloudy questions • How much direct control do I want/need over my company’s servers? • Is the cost of cloud services lower than the cost of configuring and maintaining these myself? • How likely am I to have to scale up massively, at a moment’s notice?
  • 32. Trap #13: Long controller actions • It’s so tempting! You want to do so much in your controller action. • But the user doesn’t want to wait for your e-mail to be sent. • Use Resque, Delayed Job, or whatever you want... but put such things in the background, and answer the user ASAP.
  • 33. Trap #14: No DB constraints • Is your Rails application the only program that will ever touch the database? • (Answer: Almost certainly not.) • So why are your constraints only in Rails? • A good database will let you specify not only NOT NULLs, but also valid values to protect your data
  • 34. Trap #15: Lack of callbacks, filters • Callbacks (on ActiveRecord models) and filters (on controller actions) let you separate the “real work” from the less- important work • Keep code short, readable, and DRY
  • 35. Trap #16: Not using “lib” • We talk a lot about MVC in Rails • But don’t forget the “lib” directory • It’s a great place to place modules and classes that are used across your app, or that aren’t specifically tied to MVC • (Remember that lib isn’t automatically in the load path, as of Rails 3.x.)
  • 36. Trap #17: Modifying migrations • Migrations are one of my favorite parts of Rails. • Migrations are reversible: If you make a mistake, you can migrate down, change the migration file, and then migrate up. • Only do this before you have shared your migration with other people
  • 37. Why not? • Once you have pushed your migration, someone might have applied them • Maybe you know to migrate backward, revert the old version, git pull, and then migrate forward... but does everyone?
  • 38. Trap #18: Using class variables • When I teach Ruby, everyone loves class variables! (They also love to call them “static variables.”) • There is a place for class variables, but it’s a very limited one: • Data that needs to be shared across all instances of a class
  • 39. Class variable alternatives • Class-level constants • Class methods • A module with methods or constants • A model (for some types of constants)
  • 40. And don’t forget • Class variables vs. class instance variables • This is where your understanding of the Ruby object model really comes in handy
  • 41. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 42. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 43. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 44. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 45. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 46. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 47. class Confusion @x = 11 # class instance variable @@x = 22 # class variable def initialize @x = 999 # instance variable end def return_x @x # returns 999 end def self.return_x @x # returns 11 end def return_double_x @@x # returns 22 end def self.return_double_x @@x # returns 22 end end
  • 48. Trap #19: Cool technology • Don’t use technology because it’s cool. Use technology because it gets the job done, and helps the business. • So it might be cool to use a pub-sub system written in a .NET port of Clojure that transfers XML using EBCDIC... • ... but is it necessary? Is it the easiest and best solution? Is it maintainable?
  • 49. Choosing technologies • My preference is to use things that are proven, stable, and a little boring • (Like me) • The stability and viability of a project is far more important than the latest cool hack • (Which I’ll install on my own machine to play with, but not use on clients’ projects)
  • 50. Trap #20: Not learning, improving • You cannot survive in our business without learning new techniques all of the time • The Ruby and Rails worlds move especially fast, with new gems released all of the time
  • 51. What to do? • Podcasts (Ruby Rogues, Ruby show, Ruby 5) • Newsletters (Ruby Weekly) • Blogs • Books (remember those?) • Learn other languages! You can pick up a lot of ideas and techniques from them
  • 52. Bonus trap: Not enjoying yourself • Ruby and Rails make programming fun • If you’re not having fun, then maybe you’re not doing it right • (Or go join the wild party that I hear .NET developers are having!)
  • 53. Thanks! (Any questions?) reuven@lerner.co.il http://www.lerner.co.il/ 054-496-8405 “reuvenlerner” on Skype/AIM

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n