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
250
Atom
jnunemaker
PRO
10
4.5k
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
Patterns of Patterns
denyspoltorak
0
1.4k
[KNOTS 2026登壇資料]AIで拡張‧交差する プロダクト開発のプロセス および携わるメンバーの役割
hisatake
0
280
開発者から情シスまで - 多様なユーザー層に届けるAPI提供戦略 / Postman API Night Okinawa 2026 Winter
tasshi
0
200
QAフローを最適化し、品質水準を満たしながらリリースまでの期間を最短化する #RSGT2026
shibayu36
2
4.4k
CSC307 Lecture 04
javiergs
PRO
0
660
Grafana:建立系統全知視角的捷徑
blueswen
0
330
0→1 フロントエンド開発 Tips🚀 #レバテックMeetup
bengo4com
0
560
Smart Handoff/Pickup ガイド - Claude Code セッション管理
yukiigarashi
0
130
FOSDEM 2026: STUNMESH-go: Building P2P WireGuard Mesh Without Self-Hosted Infrastructure
tjjh89017
0
160
Fragmented Architectures
denyspoltorak
0
150
AI前提で考えるiOSアプリのモダナイズ設計
yuukiw00w
0
230
Basic Architectures
denyspoltorak
0
670
Featured
See All Featured
Agile that works and the tools we love
rasmusluckow
331
21k
Discover your Explorer Soul
emna__ayadi
2
1.1k
GraphQLとの向き合い方2022年版
quramy
50
14k
Ethics towards AI in product and experience design
skipperchong
2
190
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.4k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
0
140
Typedesign – Prime Four
hannesfritz
42
2.9k
Believing is Seeing
oripsolob
1
54
Marketing to machines
jonoalderson
1
4.6k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
430
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
200
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
57
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