Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Why You Should Never Use an ORM
Search
John Nunemaker
PRO
May 17, 2011
Programming
56
9.4k
Why You Should Never Use an ORM
My presentation at RailsConf 2011 on thinking about your interface, your data and your code.
John Nunemaker
PRO
May 17, 2011
Tweet
Share
More Decks by John Nunemaker
See All by John Nunemaker
Atom
jnunemaker
PRO
10
4.3k
MongoDB for Analytics
jnunemaker
PRO
11
930
Addicted to Stable
jnunemaker
PRO
32
2.6k
MongoDB for Analytics
jnunemaker
PRO
21
2.3k
MongoDB for Analytics
jnunemaker
PRO
16
30k
Why NoSQL?
jnunemaker
PRO
10
940
Don't Repeat Yourself, Repeat Others
jnunemaker
PRO
7
3.4k
I Have No Talent
jnunemaker
PRO
14
960
Why MongoDB Is Awesome
jnunemaker
PRO
18
4.4k
Other Decks in Programming
See All in Programming
A comprehensive view of refactoring
marabesi
0
970
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
1
560
カクヨムAndroidアプリのリブート
numeroanddev
0
430
都市をデータで見るってこういうこと PLATEAU属性情報入門
nokonoko1203
1
550
Webの外へ飛び出せ NativePHPが切り拓くPHPの未来
takuyakatsusa
1
170
AIエージェントはこう育てる - GitHub Copilot Agentとチームの共進化サイクル
koboriakira
0
140
実践ArchUnit ~実例による検証パターンの紹介~
ogiwarat
2
280
KotlinConf 2025 現地で感じたServer-Side Kotlin
n_takehata
1
220
Datadog RUM 本番導入までの道
shinter61
1
310
Haskell でアルゴリズムを抽象化する / 関数型言語で競技プログラミング
naoya
17
4.8k
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
340
関数型まつりレポート for JuliaTokai #22
antimon2
0
130
Featured
See All Featured
Mobile First: as difficult as doing things right
swwweet
223
9.7k
How to Think Like a Performance Engineer
csswizardry
24
1.7k
Become a Pro
speakerdeck
PRO
28
5.4k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
4
200
Designing for humans not robots
tammielis
253
25k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
4 Signs Your Business is Dying
shpigford
184
22k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
48
5.4k
Designing Experiences People Love
moore
142
24k
Transcript
Ordered List @jnunemaker RailsConf Baltimore, MD May 17, 2011 Why
You Should Never Use an ORM
You crazy man...
None
“ Albert Einstein Any intelligent fool can make things bigger,
more complex, and more violent.
Violence My Path Of
@gem
HTTParty
HappyMapper
MongoMapper
ToyStore
None
None
Three Points
1) Interface Think About Your
1) Interface Think About Your 2) Data
1) Interface Think About Your 2) Data 3) Code
Your Interface Think About
“ John Nunemaker ORMs too often lead to interface laziness.
site.memberships.create({ :user_id => user.id, :owner => true, })
site.add_owner(user)
membership.update_attributes({ :state => 1, })
membership.update_attributes({ :state => 'maximized', })
user.maximize(site)
content.to_json({ 'a crap ton': 'of options' })
ContentPresenter.new(site, date, { :page => params['page'], }).to_json
class ContentPresenter include BasePresenter def initialize(site, date, options={}) @site, @date
= site, date @options = options end def page # ... def per_page # ... def total # ... def path # ... def prev_path # ... def next_path # ... def next_page_path # ... def prev_page_path # ... def paginated # ... def content # ...
def path # ... def prev_path # ... def next_path
# ... def next_page_path # ... def prev_page_path # ... def paginated # ... def content # ... def as_json(options = nil) { 'date' => @date.to_s, 'prev_path' => prev_path, 'next_path' => next_path, 'content' => content, 'page' => page, 'per_page' => per_page, 'total' => total, 'prev_page_path' => prev_page_path, 'next_page_path' => next_page_path, } end end
Content.paginate({ :conditions => { :site_id => site.id, :date => date,
}, :page => params['page'], :per_page => 15, })
site.content_for_date(date, { :page => params['page'], })
Your Interface Think About
Your Data Think About
“ John Nunemaker ORMs sometimes hide creative ways you can
store and retrieve your data.
Failure and Triumph A Story of
{ '_id' => 'site_id:2011-03-28', '/' => {'v' => 200, 't'
=> 'Home'}, '/about/' => {'v' => 50, 't' => 'About'}, '/foo/' => {'v' => 23, 't' => 'Foo!'}, }
You say heresy! I say use case...
None
Content.get("#{site.id}:2011-03-28")
None
write data ensure_index(site_id, date, path)
read data ensure_index(site_id, date, views)
{ '_id' => BSON::ObjectId.new, 'sid' => site_id, 'p' => '/about/',
'd' => '2011-03-28', 'v' => 50, }
NewContent.for_site_and_date(site, date)
db['c.2011.5']
db['c.2011.5'] read index write index
db['c.2011.4'] => db['c.2011.5'] read index write index
None
/about/
/this/is/my/really/long/ and/descriptive/path/and/ of/course/we/need/to/ have/a/query/string? gibberish=true&yunolikesh orturls=false#DontForgetT oHashTagIt
None
Zlib.crc32('...really long path...') 762151429
Counts Every bit
Integers
Site.create(:state => 'enabled')
class Site States = { 'enabled' => 1, 'disabled' =>
2, } end Site.create({ :state => Site::States['enabled'], })
class Site def enabled? state == States['enabled'] end def disabled?
!enabled? end end
Compression
require 'rsmaz' compressed = RSmaz.compress(str) decompressed = RSmaz.decompress(compressed)
require 'zlib' compressed = Zlib::Deflate.deflate(str) decompressed = Zlib::Inflate.inflate(compressed)
require 'msgpack' ids = [1,2,3,4,5,6,7,8,9,10] compressed = MessagePack.pack(ids) decompressed =
MessagePack.unpack(compressed)
class Stylesheet class RSmazCompressor def self.compress(str) RSmaz.compress(str) end def self.decompress(str)
RSmaz.decompress(str) end end class ZlibCompressor def self.compress(str) Zlib::Deflate.deflate(str) end def self.decompress(str) Zlib::Deflate.inflate(str) end end
Compressors = { 1 => RSmazCompressor, 2 => ZlibCompressor, }
key :compressor_id, Integer key :contents, String validates_inclusion_of :compressor_id, :within => Compressors.keys def contents value = read_attribute(:contents) compressor.decompress(value) end def compressor Compressors[compressor_id] end end
Partial Updates
site.atomic_update_attributes(attrs)
Unused Fields
Counts Where
Memory/Disk/Network
class SiteMode include Scam attr_accessor :name def password_required? id ==
2 end def item_cache? id == 1 end end
SiteMode.create({ :id => 1, :name => 'live' }) SiteMode.all #
find by id or string id pp SiteMode.find(2) pp SiteMode.find('2')
class Plan include Toy::Store store(:memory, {}) attribute(:title, String) attribute(:price, Integer)
end
class Asset plugin Joint attachment :file def page_cache(version=nil) page_cache_original page_cache_version(version)
end end
current_user.sites.map do |site| Site.get(site['id']) end
ids = current_user.sites.map do |site| site['id'] end Site.all(:_id.in => ids)
Go A Long Way A Little Ruby Can
Move
Move BigintMove
Move BigintMove MakeYouWannaMove
Move BigintMove MakeYouWannaMove DaMove
Move BigintMove MakeYouWannaMove DaMove SmoothMove
Move BigintMove MakeYouWannaMove DaMove SmoothMove NightMove
Move BigintMove MakeYouWannaMove DaMove SmoothMove NightMove DanceMove
Partition.create({ :association => :moves, :model => Move, :first_id => 1,
:writer => false, })
Partition.for_writes.model.create(...)
Partition.since(since_id, last_move_id).map do |p| send(p.association).since(since_id) end
Your Data Think About
Your Code Think About
“ No code is faster than no code.
$ bx ruby performance/reads.rb Collection#find_one 0.270231008529663 Site.first 0.69925594329834
/track - no /content - no /referrers - no /sites
- yes /users - yes
class Hit def site @site ||= begin query = {'_id'
=> site_id} options = {:fields => ['tz']} collection.find_one(query, options) end end end
write code Don’t be afraid to
read code Don’t be afraid to
fail Don’t be afraid to
Site.find(id) Site.create({ :title => 'RailsTips', }) site.update_attributes(attrs) site.to_json
Your Code Think About
“ Albert Einstein It takes a touch of genius —and
a lot of courage—to move in the opposite direction.
Ordered List Thank you!
[email protected]
John Nunemaker RailsConf Baltimore, MD
May 17, 2011 @jnunemaker