how to rate a Rails application

4,321 views
4,238 views

Published on

Talk given at Euruko 2010: the talk describes how to quickly evaluate the quality of a Rails codebase. Ruby metrics are explained in detail.

Published in: Technology

how to rate a Rails application

  1. 1. How to rate a Rails application Elise Huard @elise_huard http://jabberwocky.eu Sunday 30 May 2010
  2. 2. Acquisition Sunday 30 May 2010
  3. 3. Maintenance Sunday 30 May 2010
  4. 4. Where to Start ? Sunday 30 May 2010
  5. 5. Try the app Björn Söderqvist on Flickr Sunday 30 May 2010
  6. 6. Rails version Sunday 30 May 2010
  7. 7. plugins and gems Photo Lex on Flickr Sunday 30 May 2010
  8. 8. Sunday 30 May 2010
  9. 9. Run Tests Sunday 30 May 2010
  10. 10. Lots of code Sunday 30 May 2010
  11. 11. config/routes.rb match ‘/’, :to => ‘root#index’ match ‘root’, :to => ‘root#index’ namespace :admin do resources :grids do resources :nodes resources :edges do collection do post :all post :update_all end end resources :walkers end end resources :nodes, :only => [:show,:new,:create,:destroy] do put :directions, :on => :collection end resources :walkers, :only => [:show,:new,:create,:destroy] do get :select, :on => :collection end resources :itineraries, :only => [:show] Sunday 30 May 2010 map.four_oh_four '*path' , :controller => 'four_oh_fours'
  12. 12. models railroad -M | dot Tpng > models.png rubymine ctrl-alt-D Sunday 30 May 2010
  13. 13. names “There are only two hard things in Computer Science: cache invalidation and naming things” Phil Karlton Sunday 30 May 2010
  14. 14. Metrics: Know thine Tools docman on flickr Sunday 30 May 2010
  15. 15. LOC rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 2702 | 2150 | 36 | 158 | 4 | 11 | | Helpers | 358 | 303 | 0 | 22 | 0 | 11 | | Models | 1358 | 1104 | 30 | 117 | 3 | 7 | | Libraries | 2286 | 1655 | 38 | 152 | 4 | 8 | | Integration tests | 0 | 0 | 0 | 0 | 0 | 0 | | Functional tests | 1687 | 1322 | 31 | 195 | 6 | 4 | | Unit tests | 1356 | 1079 | 27 | 158 | 5 | 4 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 9747 | 7613 | 162 | 802 | 4 | 7 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 5212 Test LOC: 2401 Code to Test Ratio: 1:0.5 Sunday 30 May 2010
  16. 16. RubyParser and Parsetree Ryan Davis and Eric Hodel (‘Ruby Sadists’) Sunday 30 May 2010
  17. 17. RubyParser and Parsetree Abstract syntax tree RubyParser.new.parse(File.read(‘metrics.rb’),‘metric.rb’) class Metrics s(:class,:Metrics, nil, def probe s(:scope, s(:defn,:probe, puts "good" s(:args), end s(:scope, end s(:block, s(:call, nil, :puts, s(:arglist, s(:str, "good")))))))) Symbolic Expression (Sexp) Sunday 30 May 2010
  18. 18. RubyParser and Parsetree Abstract syntax tree RubyParser.new.parse(File.read(‘metrics.rb’),‘metric.rb’) class Metrics s(:class,:Metrics, nil, def probe s(:scope, s(:defn,:probe, puts "good" s(:args), end s(:scope, end s(:block, s(:call, nil, :puts, s(:arglist, s(:str, "good")))))))) Symbolic Expression (Sexp) Ruby2Ruby Sunday 30 May 2010
  19. 19. RubyParser pure ruby Parsetree ruby and inline c < 1.9 Sunday 30 May 2010
  20. 20. rake stats size Flog Flay code complexity code similarities Roodi R_B_P Saikuro Reek cyclomatic antipatterns Rails complexity Heckle Rcov test coverage Sunday 30 May 2010
  21. 21. flog ‘the pain your code is in’ Sunday 30 May 2010
  22. 22. FLOG flog lib/flog.rb 647.8: flog total 13.8: flog/method average 87.5: Flog#output_details 58.8: Flog#process_iter 54.2: Flog#flog 48.8: Flog#parse_options 34.1: Flog#none 23.2: Flog#output_method_details 22.1: Flog#score_method 16.0: Flog#process_block_pass 15.6: Flog#report 15.2: Flog#expand_dirs_to_files 15.0: Flog#klass_name Sunday 30 May 2010
  23. 23. FLOG Assignment Branch Condition (ABC) def score_method(tally) a, b, c = 0, 0, 0 tally.each do |cat, score| case cat when :assignment then a += score when :branch then b += score else c += score end end Math.sqrt(a*a + b*b + c*c) end Sunday 30 May 2010
  24. 24. FLOG Weighing the AST with factors def process_if(exp) add_to_score :branch process exp.shift # cond penalize_by 0.1 do process exp.shift # true process exp.shift # false end s() end Sunday 30 May 2010
  25. 25. FLOG Methods Very good: < 20 All Right: < 50 Sunday 30 May 2010
  26. 26. FLAY code similarities Sunday 30 May 2010
  27. 27. FLAY flay *.rb Total score (lower is better) = 621 1) IDENTICAL code found in :defn (mass*2 = 188) channel.rb:48 clip.rb:80 2) Similar code found in :defn (mass = 93) channel.rb:150 clip.rb:110 clip.rb:116 3) Similar code found in :defs (mass = 58) contact.rb:32 contact.rb:37 Sunday 30 May 2010
  28. 28. FLAY RubyParser def mass @mass ||= self.structure.flatten.size end Hash of structure of nodes with mass > threshold self.hashes[node.structural_hash] << node analyze: if same hash = similar if same node = identical Sunday 30 May 2010
  29. 29. Saikuro cyclomatic complexity Sunday 30 May 2010
  30. 30. Saikuro Sunday 30 May 2010
  31. 31. Saikuro ruby-lex every keyword is interpreted into ‘state’ state used to calculate if, unless, while, until, for, elsif, when, rescue (blocks) Recursively Sunday 30 May 2010
  32. 32. Saikuro Good: methods < 5 Sunday 30 May 2010
  33. 33. Roodi ‘Ruby Object Oriented Design Inferometer’ nutmeg66 on flickr Sunday 30 May 2010
  34. 34. Roodi app/controllers/itineraries_controller.rb:4 - Method name "show" cyclomatic complexity is 14. It should be 8 or less. app/models/itinerary.rb:41 - Block cyclomatic complexity is 6. It should be 4 or less. app/controllers/itineraries_controller.rb:4 - Method "show" has 30 lines. It should have 20 or less. app/helpers/application_helper.rb:27 - Method "clippy" has 26 lines. It should have 20 or less. Sunday 30 May 2010
  35. 35. Roodi RubyParser visitor pattern visitor: checker (Configuration) visitable: parsed nodes = extensible Sunday 30 May 2010
  36. 36. Reek Sunday 30 May 2010
  37. 37. Reek more OO-specific checks Control Couple Data Clump Feature Envy Large Class Long Method Long Parameter List Simulated Polymorphism Uncommunicative Name Sunday 30 May 2010
  38. 38. Reek UserSessionsController has no descriptive comment (Irresponsible Module) UserSessionsController#destroy calls current_user_session twice (Duplication) app/controllers/users_controller.rb -- 5 warnings: UsersController has no descriptive comment (Irresponsible Module) UsersController tests @aid_app at least 4 times (Simulated Polymorphism) UsersController#create calls params 3 times (Duplication) UsersController#create calls params[:user] 3 times (Duplication) ... Sunday 30 May 2010
  39. 39. Reek RubyParser extends parsed nodes traverses nodes returns code after Ruby2Ruby Sunday 30 May 2010
  40. 40. rails_best_practices kamoda on Flickr Sunday 30 May 2010
  41. 41. rails_best_practices ./app/controllers/ws/vmg/aid_user_accounts_controller.rb:160 - move model logic into model (@aid_user_account called_count > 4) ./app/controllers/ws/vmg/ipt_controller.rb:102 - move model logic into model (xml called_count > 4) ./app/controllers/ws/vmg/ipt_controller.rb:102 - move model logic into model (pf called_count > 4) ./config/routes.rb:3 - overuse route customizations (customize_count > 3) ./config/routes.rb:35 - overuse route customizations (customize_count > 3) ./app/models/vmg/scenario.rb:41 - keep finders on their own model Sunday 30 May 2010
  42. 42. rails_best_practices Visitor pattern visitor : checking_visitor visitable: visitable sexp Sunday 30 May 2010
  43. 43. Churn Sunday 30 May 2010
  44. 44. Churn +-------------------------------------------------+---------------+ | file_path | times_changed | +-------------------------------------------------+---------------+ | db/schema.rb | 26 | | config/routes.rb | 24 | | app/controllers/application_controller.rb | 22 | | app/controllers/add_apps_controller.rb | 22 | | config/environment.rb | 20 | | app/views/layouts/application.html.erb | 20 | | app/models/ability.rb | 18 | ... Sunday 30 May 2010
  45. 45. Churn Not only classes but also methods (RubyParser) Version control: git, Hg, svn Locates changes in source using logs (as in git log) Sunday 30 May 2010
  46. 46. Churn common sense ... mostly useful in maintenance phase Sunday 30 May 2010
  47. 47. Rcov Sunday 30 May 2010
  48. 48. Rcov Total coverage: comments included Sunday 30 May 2010
  49. 49. Rcov Executes test keeps track of the executed lines Using C extension when possible to hook into MRI (experimental for 1.9) Sunday 30 May 2010
  50. 50. Rcov good: 100% coverage Sunday 30 May 2010
  51. 51. Heckle Sunday 30 May 2010
  52. 52. Heckle ParseTree + Ruby2Ruby mutate time-consuming: combinatorials more for small programs (gems, scripts) doesn’t work for ruby 1.9 (ParseTree) Sunday 30 May 2010
  53. 53. Heckle Initial tests pass. Let's rumble. ********************************************************************** *** AidApp#property_names loaded with 4 possible mutations ********************************************************************** 4 mutations remaining... Replacing AidApp#property_names with: --- original +++ mutation def property_names - (meta_policy and meta_policy.property_names_for(:aid_app)) + (nil and meta_policy.property_names_for(:aid_app)) end Sunday 30 May 2010
  54. 54. rake stats size Flog Flay code complexity code similarities Roodi Saikuro Reek cyclomatic antipatterns RAILS_BEST complexity _PRACTICES Heckle Rcov test coverage Sunday 30 May 2010
  55. 55. metric_fu Sunday 30 May 2010
  56. 56. check out the good stuff OrbitalJoe on flickr Sunday 30 May 2010
  57. 57. what these metrics don’t tell you Bugs Sunday 30 May 2010
  58. 58. what these metrics don’t tell you code performance Ruby Profiling Sunday 30 May 2010
  59. 59. Reads like a book Sunday 30 May 2010
  60. 60. http://railroad.rubyforge.org/ http://www.igvita.com/2008/12/11/ruby-ast-for-fun-and-profit/ http://ruby.sadi.st/Ruby_Sadist.html http://goruco2008.confreaks.com/04_davis.html http://cwd.dhemery.com/2009/11/wmaat/ http://c2.com/cgi/wiki?AbcMetric http://hissa.nist.gov/HHRFdata/Artifacts/ITLdoc/235/title.htm http://blog.rubybestpractices.com/posts/judofyr/sexp-for- rubyists.html Elise Huard @elise_huard elise@elisehuard.be http://jabberwocky.eu http://github.com/elisehuard Sunday 30 May 2010

×