Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Performance Optimization 101 for Ruby developers
Search
Nihad Abbasov
May 19, 2019
Programming
140
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Performance Optimization 101 for Ruby developers
Nihad Abbasov
May 19, 2019
More Decks by Nihad Abbasov
See All by Nihad Abbasov
Golang for Rubyists
narkoz
1
110
Other Decks in Programming
See All in Programming
SREの越境 / SRE Collaboration
y0hgi
2
310
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
130
Rでドレミ/Do-Re-Mi_with_R
florets1
0
130
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
1.1k
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
カツオ、ご期待ください
suneo3476
0
190
iOS 27でニュースアプリはどう変わる!? 〜日経電子版の新機能対応と、開発事例から〜
lynnswap
7
13k
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
390
R8 の設定見直しでアプリサイズ削減
andpad
0
220
phperだってパンチカードでコーディングしたい
o0h
PRO
0
330
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
180
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
750
Featured
See All Featured
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.2k
Building a Scalable Design System with Sketch
lauravandoore
464
34k
Are puppies a ranking factor?
jonoalderson
2
4.1k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
WENDY [Excerpt]
tessaabrams
14
40k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Ruling the World: When Life Gets Gamed
codingconduct
0
400
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
710
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
Transcript
Performance Optimization 101 for Ruby developers
whoami Nihad Abbasov github.com/narkoz
[email protected]
AGENDA - Ruby - Rails - Front-end
What is application performance indication of the time it takes
application to respond
What is performance optimization process of modifying a software system
to make some aspect of it work more efficiently or use fewer resources
Why is performance important if your application loads and runs
slowly, it is more likely to be abandoned by your users
1. Optimizing Ruby Tips and techniques for optimizing your Ruby
code
Measure code execution time Use benchmark-ips gem
Benchmark with benchmark-ips require 'benchmark/ips' Benchmark.ips do |x| x.report('addition') {
1 + 1 } x.report('addition with send') { 1.send(:+, 1) } x.compare! end
Use #sample instead of #shuffle.first # slow [*1..100].shuffle.first # fast
[*1..100].sample
Use #map instead of #each + push # slow array
= [] [*1..100].each { |e| array.push e } # fast array = [*1..100].map { |e| e }
Use #flat_map instead of #map + flatten # slow [*1..100].map
{ |e| [e, e] }.flatten # fast [*1..100].flat_map { |e| [e, e] }
Use #reverse_each instead of #reverse + each # slow [*1..100].reverse.each
{ |e| e } # fast [*1..100].reverse_each { |e| e }
Use #min_by instead of #sort_by + first # slow [*1..100].sort_by
{ |e| e.next }.first # fast [*1..100].min_by { |e| e.next }
Use #min/max instead of #sort + first/last # slow [*1..100].sort_by
{ |e| e.next }.last [*1..100].sort { |e| e.next }.first [*1..100].sort { |e| e.next }.last # fast [*1..100].max_by { |e| e.next } [*1..100].min { |e| e.next } [*1..100].max { |e| e.next }
Use #detect instead of #select + first # slow [*1..100].select
{ |e| e == 20 }.first # fast [*1..100].detect { |e| e == 20 }
Use #reverse.detect instead of #select.last # slow [*1..100].select { |e|
(e % 10).zero? }.last # fast [*1..100].reverse.detect { |e| (e % 10).zero? }
Use #each_key instead of #keys + each # slow HASH.keys.each
{ |k| k } # fast HASH.each_key { |k| k } HASH = Hash[*('aa'..'zz')]
Use #key? instead of #keys + include? # slow HASH.keys.include?
'zz' # fast HASH.key? 'zz' HASH = Hash[*('aa'..'zz')]
Use #value? instead of #values + include? # slow HASH.values.include?
'zz' # fast HASH.value? 'zz' HASH = Hash[*('aa'..'zz')]
Make objects immutable with #freeze # slow string = 'Hello'.freeze
10.times { puts string } # slow string = 'Hello' 10.times { puts string }
Use magic comment # frozen_string_literal: true # frozen_string_literal: true
Use Date.iso8601 instead of Date.parse # slow Date.parse('2018-03-19') # fast
Date.iso8601('2018-03-19')
Use Time.iso8601 instead of Time.parse # slow Time.parse('2018-03-21T1 1:26:50Z') #
fast Time.iso8601('2018-03-21T1 1:26:50Z')
Use Hash instead of OpenStruct # slow require 'ostruct' person
= OpenStruct.new person.name = 'John' person.name # fast person = {} person[:name] = 'John' person[:name]
Additional resources and tools ▪ github.com/JuanitoFatas/fast-ruby ▪ github.com/DamirSvrtan/fasterer ▪ github.com/rubocop-hq/rubocop-performance
2. Optimizing Rails Tips and techniques for optimizing your Rails
application
Benchmark your application - wrk - h2load - ab -
siege
Use application monitoring metrics - scout_apm - skylight - newrelic
Check application performance profile REQUESTS PER-MINUTE CLASSIFICATION < 50 ms
Fast < 300 ms Normal > 300 ms Slow
Use database queries to deal with records # DO: Item.order(created_at:
:desc).limit(20) # DONT: Item.all.sort_by(&:created_at).reverse.first(20)
Use database queries to deal with records Don't be afraid
to use raw SQL
Use select to get only the necessary data @users =
User.select(:name, :email).limit(20) <% @users.each do |user| %> <%= user.name %><br> <%= user.email %> <% end %>
Use size on relation instead of count @messages = current_user.messages.unread
<% @messages.each do |message| %> <%= message.body %> <% end %> <h2>Unread Messages: <%= @messages.size %></h2>
Use database indexes correctly User.where(email: '
[email protected]
') # migration: add_index :users,
:email, unique: true
Indexes for polymorphic associations class Comment belongs_to :commentable, polymorphic: true
belongs_to :user end class Post has_many :comments, as: :commentable has_one :user end
Indexes for polymorphic associations add_index :comments, :user_id add_index :comments, %i[commentable_type
commentable_id]
Order records by ID User.order(id: :desc) # faster alternative to
User.order(created_at: :desc)
Use subqueries with ActiveRecord # 2 separate queries Ad.where(id: current_user.bookmarks.pluck(:ad_id))
# 1 query with subquery Ad.where(id: current_user.bookmarks.select(:ad_id))
Eliminate N+1 queries @user = User.first <% @user.comments.each %> <%=
comment.body %> <% end %>
Eliminate N+1 queries Use AR#includes @user = User.includes(:comments).first
Use materialized database views *PostgreSQL only. use scenic gem
Use limit in queries User.limit(10) Use pagination: @pagy, @records =
pagy(Post.published)
Use explain when in doubt User.where(id: [1, 2]).comments.explain
Use background processing UserMailer.welcome(@user).deliver_later VideoImportJob.perform_later(current_user)
Avoid rendering with loops <% @users.each do |user| %> <%=
render 'users/profile_card', user: user %> <% end %>
Use collection rendering <%= render partial: 'users/profile_card', collection: @users %>
Use collection caching <%= render @post.comments, cached: true %>
Minimize or suppress HTTP redirects Use HTTP Strict Transport Security
(HSTS)
Enable HSTS preload config.force_ssl = true config.ssl_options = { hsts:
{ preload: true } }
Use libvips for image processing config.active_storage.variant_processor = :vips
Reduce log writes Use gems: ▪ rails_semantic_logger ▪ lograge
Use faster gems ▪ github.com/SamSaffron/fast_blank ▪ github.com/ohler55/oj ▪ github.com/ohler55/ox ▪
github.com/redis/hiredis-rb ▪ github.com/ddnexus/pagy
Use a faster language ▪ Go ▪ Elixir ▪ C
Additional resources and tools ▪ github.com/MiniProfiler/rack-mini-profiler ▪ github.com/gregnavis/active_record_doctor ▪ github.com/tmm1/stackprof
▪ github.com/schneems/derailed_benchmarks ▪ github.com/plentz/lol_dba ▪ github.com/flyerhzm/bullet
3. Optimizing Front-end Tips and techniques for optimizing front-end of
your application
Serve compressed assets Nginx example with gzip: location ~ ^/(assets|packs)/
{ ... gzip_static on; }
Use better compression Use Brotli compression format: location ~ ^/(assets|packs)/
{ ... gzip_static on; brotli_static on; }
Use modern cache control Add immutable to Cache-Control headers: location
~ ^/(assets|packs)/ { ... add_header Cache-Control public,immutable; }
Use resource hints <link rel="dns-prefetch" href="https://assets.example.com">
Use WEBP for images Supported by: ▪ Google Chrome (desktop)
17+ ▪ Google Chrome for Android version 25+ ▪ Microsoft Edge 18+ ▪ Firefox 65+ ▪ Opera 11.10+ ▪ Native web browser, Android 4.0+ (ICS)
Use Turbolinks Or: ▪ Vuejs ▪ React ▪ Stimulus
Use with caution HTTP/2 Push path = view_context.asset_path('application.css', host: '',
protocol: :relative) response.set_header('Link', "<#{path}>; rel=preload; as=style")
Questions? github.com/narkoz
[email protected]