Slide 1

Slide 1 text

最佳實踐如何變成了最慢實踐 ⼗十個你不知道會導致效能低落的設計 12年11月18⽇日星期⽇日

Slide 2

Slide 2 text

Me • http://blog.xdite.net • Rails Developer ( 2007~ ) • ROCO Inc. Founder • Facebook World Hack 世界⾸首獎 12年11月18⽇日星期⽇日

Slide 3

Slide 3 text

why this topic? 12年11月18⽇日星期⽇日

Slide 4

Slide 4 text

We follow • Convention over configuration • Best Practices • Default • Instinct!!! 12年11月18⽇日星期⽇日

Slide 5

Slide 5 text

效能越來越差 12年11月18⽇日星期⽇日

Slide 6

Slide 6 text

New Relic 抓不出來 12年11月18⽇日星期⽇日

Slide 7

Slide 7 text

抓不到的地⽅方 • Deployment • Asset Compiling • Loading Environment • ActiveRecord (MySQL) convention • View 12年11月18⽇日星期⽇日

Slide 8

Slide 8 text

Deployment 12年11月18⽇日星期⽇日

Slide 9

Slide 9 text

Bundler desc "Run bundle install" task :install_bundle_gems do run "cd #{deploy_to}/current; RAILS_ENV=#{rails_env} bundle install" end Wrong & Slow 12年11月18⽇日星期⽇日

Slide 10

Slide 10 text

Bundler load ‘bundler/capistrano’ bundle install --gemfile /home/apps/project/releases/20121114191908/Gemfile --path /home/apps/d4dpr/shared/ bundle --deployment --quiet --without development test Solution 12年11月18⽇日星期⽇日

Slide 11

Slide 11 text

Deploy with Asset precompile rake RAILS_ENV=production assets:precompile Wrong & Slow 12年11月18⽇日星期⽇日

Slide 12

Slide 12 text

Deploy with Asset precompile load 'deploy/assets' rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile Solution 12年11月18⽇日星期⽇日

Slide 13

Slide 13 text

Deploy with Asset precompile set :assets_dependencies, %w(app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb) namespace :deploy do namespace :assets do desc <<-DESC Run the asset precompilation rake task. You can specify the full path \ to the rake executable by setting the rake variable. You can also \ specify additional environment variables to pass to rake via the \ asset_env variable. The defaults are: set :rake, "rake" set :rails_env, "production" set :asset_env, "RAILS_GROUPS=assets" set :assets_dependencies, fetch(:assets_dependencies) + %w(config/locales/js) DESC task :precompile, :roles => :web, :except => { :no_release => true } do from = source.next_revision(current_revision) if capture("cd #{latest_release} && #{source.local.log(from)} #{assets_dependencies.join ' '} | wc -l").to_i > 0 run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile} else logger.info "Skipping asset pre-compilation because there were no asset changes" end end end end Solution 12年11月18⽇日星期⽇日

Slide 14

Slide 14 text

Deploy with Asset precompile https://github.com/ndbroadbent/turbo-sprockets-rails3 only recompiling changed assets Solution 12年11月18⽇日星期⽇日

Slide 15

Slide 15 text

Asset Pipeline 12年11月18⽇日星期⽇日

Slide 16

Slide 16 text

Asset Pipeline(require_tree) • good for split controller specific logic • posts.js.coffee 12年11月18⽇日星期⽇日

Slide 17

Slide 17 text

Asset Pipeline(require_tree) • require_tree • users.js.coffee • posts.js.coffee • products.js.coffee • ..... Default & Slow 12年11月18⽇日星期⽇日

Slide 18

Slide 18 text

Asset Pipeline(require_tree) # posts.js.coffee # Place all the behaviors and hooks related to the matching controller here. # All this logic will automatically be available in application.js. # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ empty_assets still cost compile time ~250ms Wrong & Slow 12年11月18⽇日星期⽇日

Slide 19

Slide 19 text

Asset Pipeline(require_tree) • remove *.js.coffee (empty) • only require what you need Solution 12年11月18⽇日星期⽇日

Slide 20

Slide 20 text

Asset Pipeline(@import) • @import is awesome • Web have “compass” 12年11月18⽇日星期⽇日

Slide 21

Slide 21 text

Asset Pipeline(@import) • import “compass” • @import "compass/utilities"; • @import "utilities/color"; • @import "utilities/general"; • @import "utilities/sprites"; • @import "utilities/tables"; • @import "compass/typography"; • @import "compass/css3"; recursive @import Slow 12年11月18⽇日星期⽇日

Slide 22

Slide 22 text

Asset Pipeline(@import) • Only @import specific SCSS @import "compass/typography/links/link-colors"; Solution 12年11月18⽇日星期⽇日

Slide 23

Slide 23 text

Loading Environment 12年11月18⽇日星期⽇日

Slide 24

Slide 24 text

Bundler Group matters • import all gems without grouping gem "capistrano" gem "capistrano-ext" gem "cape" gem "magic_encoding" gem "annotate" gem “rspec” gem “capybara” Wrong & Slow 12年11月18⽇日星期⽇日

Slide 25

Slide 25 text

Bundler Group matters • group by environment group :development do gem "capistrano" gem "capistrano-ext" gem "cape" gem "magic_encoding" gem "annotate" end group :test do gem “rspec” gem “capybara” end Solution 12年11月18⽇日星期⽇日

Slide 26

Slide 26 text

ActiveRecord with MySQL 12年11月18⽇日星期⽇日

Slide 27

Slide 27 text

Order by String • state machine • published • draft • rejected 12年11月18⽇日星期⽇日

Slide 28

Slide 28 text

Order by String # current_state :string(255) add_column :posts,: current_state, :string Wrong & Slow 12年11月18⽇日星期⽇日

Slide 29

Slide 29 text

Order by String add_column :posts,: current_state, :string , :limit => 11 Solution Optimal index size for variable text in MySQL http://www.xarg.org/2012/07/optimal-index-size- for-variable-text-in-mysql/ 12年11月18⽇日星期⽇日

Slide 30

Slide 30 text

map(&:id) <%= posts.map(&:id) %> ( SELECT * from `posts` ) [1,3,5,8,13,21] Wrong & Slow 12年11月18⽇日星期⽇日

Slide 31

Slide 31 text

map(&:id) <%= posts.select(:id).map(&:id) %> ( SELECT id from `posts` ) [1,3,5,8,13,21] Solution 12年11月18⽇日星期⽇日

Slide 32

Slide 32 text

timestamp create_table :invoices do |t| t.integer :user_id t.datetime :paid_at t.timestamps end scope :recent_paid, order(“paid_at DESC”) Default & Slow Slow Slow 12年11月18⽇日星期⽇日

Slide 33

Slide 33 text

timestamp add_column :invoices, :paid_at, :integer Time.to_i DateTime.strptime("1318996912",'%s') Solution 12年11月18⽇日星期⽇日

Slide 34

Slide 34 text

View 12年11月18⽇日星期⽇日

Slide 35

Slide 35 text

Logic in View • ERB with eval <% if current_user.is_admin? %> admin panel <% else %> user panel <% end %> Wrong & Slow 12年11月18⽇日星期⽇日

Slide 36

Slide 36 text

Logic in View • ERB with eval <%= render_panel_for(current_user %> Solution 12年11月18⽇日星期⽇日

Slide 37

Slide 37 text

Query in View/Helper • Query in view doesn’t have cache <%= post.user.name %> Wrong & Slow 12年11月18⽇日星期⽇日

Slide 38

Slide 38 text

Query in View/Helper class Post < ActiveRecord::Base def author_name user.try(:name) end end Solution <%= post.author_name %> 12年11月18⽇日星期⽇日

Slide 39

Slide 39 text

for each <% for post in @posts %>
”> <%= post.user_name %>
<% end %> Wrong & Slow 12年11月18⽇日星期⽇日

Slide 40

Slide 40 text

for each <%= div_for(@posts, :class => “posts”) do |post| %> <%= post.user_name %> <% end %> Solution 12年11月18⽇日星期⽇日

Slide 41

Slide 41 text

complex link_to <% if current_user %> ”> <%= current_user.name %> <% end %> Wrong & Slow 12年11月18⽇日星期⽇日

Slide 42

Slide 42 text

complex link_to <%= link_to_if(current_user, user_path(current_user) ) do content_tag(:i, :class => “icon icon-user”) + content_tag(:span, current_user. name) end %> Solution 12年11月18⽇日星期⽇日

Slide 43

Slide 43 text

Conclusion 12年11月18⽇日星期⽇日

Slide 44

Slide 44 text

use convention carefully 12年11月18⽇日星期⽇日

Slide 45

Slide 45 text

dig deep 12年11月18⽇日星期⽇日

Slide 46

Slide 46 text

back to basic 12年11月18⽇日星期⽇日

Slide 47

Slide 47 text

Thanks for listening 12年11月18⽇日星期⽇日

Slide 48

Slide 48 text

Q&A 12年11月18⽇日星期⽇日