Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Refactoring in Ruby

Refactoring in Ruby

This is a presentation from my talk at Minsk.Rb

It is about how I discovered and use refactoring in my daylife – what approaches and instruments I use.

Anatoli Makarevich

October 29, 2012
Tweet

More Decks by Anatoli Makarevich

Other Decks in Programming

Transcript

  1. I am a ruby developer at http://evrone.ru And I work

    for Evrone.com – russian company that is famous for hosting RailsClub and developing highload projects.
  2. I am a part of gitfm.com gistflow.com So you may

    know me if you visited Gistflow.com – open source blog platform for developers and GitFM.com – personal recommendation service for Github repos (and it is really smart, there is a big math behind the scene).
  3. Refactoring But now you have one less reason not to

    do that – recently Ruby version of Refactoring book was published.
  4. Martin Fowler, 1999 Meet the founder – Martin Fowler. Endless

    respect to this guy because he started new programming discipline and I would like to say scientific approach to work with code.
  5. The problem In the past refactoring was avoided in development

    processes. http://en.wikipedia.org/wiki/Code_refactoring#History So the problem I want to discuss today is that refactoring is already the formed technique.
  6. Problem Nowadays refactoring is still not used widely. Me But

    for couple of years of development I have heard only once that someone used this approach to factoring their code.
  7. Plan • Productivity • Testing • What is refactoring? •

    Code smells • Let’s refactor! • How to rate our code? • Conclusion The plan.
  8. * What is refactoring? Disciplined technique for restructuring an existing

    body of code, altering its internal structure without changing its external behavior Martin Fowler Just read the definition. We will build the whole philosophy on top of it.
  9. Let’s use aliases! alias s="sublime" alias g="git" alias cpd="cap production

    deploy" alias csd="cap staging deploy" p() { cd ~/Sites/$1; } _p() { _files -W ~/Sites -/; } compdef _p p Super duper captain tip – use aliases! And not only variables – write functions for example like this – navigating to project in Sites directory.
  10. Economy cap production deploy vs cpd 3 sec * 20

    a day * 30 days = 30 min/month And it can saves you some time and you can spend this time refactoring!
  11. Rails generators gem install zeus zeus init zeus start 9

    sec * 20 a day * 30 days = 90 min/month Use zeus to preload your app and not to waste time waiting.
  12. Apps from templates rails new myapp -m template.rb https://github.com/evrone/omniauth-github-bootstrap And

    if you work with Github API often create an app template and start each project from this point.
  13. * Testing Remember the definition of refactoring? How do we

    know that we haven’t changed anything?
  14. How we test? • Test::Unit • RSpec • Capybara •

    Cucumber We use a lot of tools to test our apps. But do you usually run `rspec spec` before each commit?
  15. CIs • Travis CI • CI Joe • Bamboo •

    Jenkins You may heard about Travis CI but there are a lot off tools more. Though I still think that Travis are the best :)
  16. Jenkins statistics We chose Jenkins and here is our stats

    for about a month – each step is a new feature and each red pile in the bottom stands for amount of broken tests. So as you can see we save our users from 500 pages couple of times and not deployed bad code.
  17. Always use separate server for CI. And never never never

    install Jenkins or any CI on you production server. “Oh captain...” I hear :D
  18. And how about a profiler? But how do you know

    that your code still work fast after all refactoring? You need a profiler and I don’t know anything better than NewRelic.
  19. * Refactoring Disciplined technique for restructuring an existing body of

    code, altering its internal structure without changing its external behavior Martin Fowler Just a reminder.
  20. What for? • Complexity • Readability • Maintainability • Extensibility

    So for ourselves we need to understand why do we need to refactor and also it is useful if we need to explain this to our employer. It is 100% profit.
  21. Code Smell Any symptom in the source code of a

    program that possibly indicates a deeper problem. Kent Beck So in refactoring I noticed only one term and it is Code Smell. You may have heard it a lot :)
  22. Repeated code • In different classes • In one class

    • In one method Let’s start with the most famous code smell – is repeated code and it could be repeated in many ways.
  23. Loooong methods def barny_says puts 'legen' ... ... ... ...

    ... ... ... ... ... ... puts 'wait for it' The second code smell in my list is long method. And methods could be reaaaaly
  24. puts 'wait for it' ... ... ... ... ... ...

    ... ... ... ... puts 'dary' end long.
  25. FAAAAT models Another problem is fat model. There could be

    300 methods and it is a signal that this only model do much, for example if you see methods with the same prefix it is probably time to move this methods to another class (named with prefix).
  26. Too many params Long methods definitions are bad because you

    need to scroll code horizontally our it brakes the formatting so use objects.
  27. OMG def self.reset_counters #resettings counters puts "Clean counters" Count.where(:count_type =>

    "CatalogGlobalRubric").each{ |count| count.destroy } catalogs = Catalog2.all puts "Calculation" size = catalogs.size nom = 0 catalogs.each{|catalog| nom = nom + 1 puts nom.to_s + " from " + size.to_s catalog.counters_inc if catalog.approved } return "That’s it!!!" end And here comes the bullshit – in this method you can see many code smells - ambiguous variables, obvious comments, long method, bad naming, everything.
  28. Know your tools! def mydomain? site.domain == 'mydomain' ? true

    : false end page = (@topic.replies.approved.count / Reply.per_page).to_i page += 1 if ((@topic.replies.approved.count % Reply.per_page).to_i > 0) All code smells before were about understanding the code. I mean that we READ the code and not INTERPRET it as a computer. So bad code make us interpret and it takes a lot of our energy and creativity, this is why we do less and this is why we are getting bored and tired. This is why we should refactor! Here couple of code smells which are about knowing of Ruby standard lib.
  29. Seriously, know your tools! @doc = StaticDocs.find_by_link(params[:id]) raise ActiveRecord::RecordNotFound if

    !@doc Count.where(:count_type => "CatalogGlobalRubric").each{ |count| count.destroy } Also in Rails there is its own specific and when I want to write some method I first look for in Rails API and in 60% of cases I find it.
  30. * Let’s refactor! • Extract/inline method • Replace conditional with

    method • Replace temp variable with method • Extract/inline class • ... The are quite a lot of refactoring techniques and I am quite sure you know some of them. But checkout Martin’s Fowler book to read them all and remember. As I said before this is very well structured list of refactorings.
  31. Rename method “In Computer Science there are only two problem

    – naming and cache invalidation.” Phil Karton My favorite refactoring (and the most difficult for me) is renaming. Your code should be readable besides interpretable.
  32. * How to rate our code? So you are 5

    minutes from refactoring – you just need a starter point. But since we deal with Ruby why not to use Ruby to analize our code for code smells?
  33. ruby_parser Sounds fresh so let’s look at some simple class.

    How can we analize it? We probably need a better structure - may be array or hash.
  34. S-expressions s(:class, :User, nil, s(:scope, s(:block, s(:call, nil, :attr_accessor, s(:arglist,

    s(:lit, :name))), s (:defn, :initialize, s(:args, :name), s(:scope, s (:block, s(:lasgn, :name, s(:lvar, :name))))), s (:defn, :say, s(:args), s(:scope, s(:block, s (:call, nil, :puts, s(:arglist, s(:str, "hello"))))))))) So ruby_parser gem provides necessary functionality. It converts ruby code into sexp format which could be analized.
  35. Instruments • gem ‘reek’ • gem ‘flay’ • gem ‘flog’

    • CodeClimate The most well known solutions for analizing are listed here. For me `reek` is the most useful - it shows what should be refactored, where and how. Be sure to check it.