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
61
9.7k
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
AI: The stuff that nobody shows you
jnunemaker
PRO
2
240
Atom
jnunemaker
PRO
10
4.4k
MongoDB for Analytics
jnunemaker
PRO
11
1k
Addicted to Stable
jnunemaker
PRO
32
2.8k
MongoDB for Analytics
jnunemaker
PRO
21
2.3k
MongoDB for Analytics
jnunemaker
PRO
16
30k
Why NoSQL?
jnunemaker
PRO
10
980
Don't Repeat Yourself, Repeat Others
jnunemaker
PRO
7
3.5k
I Have No Talent
jnunemaker
PRO
14
1k
Other Decks in Programming
See All in Programming
CSC307 Lecture 07
javiergs
PRO
0
550
360° Signals in Angular: Signal Forms with SignalStore & Resources @ngLondon 01/2026
manfredsteyer
PRO
0
110
AgentCoreとHuman in the Loop
har1101
5
220
疑似コードによるプロンプト記述、どのくらい正確に実行される?
kokuyouwind
0
380
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
600
20260127_試行錯誤の結晶を1冊に。著者が解説 先輩データサイエンティストからの指南書 / author's_commentary_ds_instructions_guide
nash_efp
0
890
AI Agent Tool のためのバックエンドアーキテクチャを考える #encraft
izumin5210
6
1.8k
AIと一緒にレガシーに向き合ってみた
nyafunta9858
0
160
登壇資料を作る時に意識していること #登壇資料_findy
konifar
3
920
なるべく楽してバックエンドに型をつけたい!(楽とは言ってない)
hibiki_cube
0
140
CSC307 Lecture 09
javiergs
PRO
1
830
KIKI_MBSD Cybersecurity Challenges 2025
ikema
0
1.3k
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
330
40k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
320
Agile that works and the tools we love
rasmusluckow
331
21k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
130
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
110
BBQ
matthewcrist
89
10k
Designing Powerful Visuals for Engaging Learning
tmiket
0
220
New Earth Scene 8
popppiees
1
1.5k
Site-Speed That Sticks
csswizardry
13
1.1k
Code Review Best Practice
trishagee
74
20k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.4k
GraphQLとの向き合い方2022年版
quramy
50
14k
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