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
- 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
- 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.
- 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!)
Editor's Notes
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n
- \n