Share
Embed
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
Transcript
44 slides
-
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. -
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). -
Refactoring But now you have one less reason not to
do that – recently Ruby version of Refactoring book was published. -
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. -
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. -
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. -
And our projects looks like Bad factored code leads projects
to look like this. -
Plan • Productivity • Testing • What is refactoring? •
Code smells • Let’s refactor! • How to rate our code? • Conclusion The plan. -
* 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. -
*Productivity. Self refactoring. If we decided to make our programs
better why not to begin with ourselves? -
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. -
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! -
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. -
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. -
* Testing Remember the definition of refactoring? How do we
know that we haven’t changed anything? -
Refactoring is started with tests. Want to refactor – cover
code with tests first. -
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? -
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 :) -
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. -
Always use separate server for CI. And never never never
install Jenkins or any CI on you production server. “Oh captain...” I hear :D -
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. -
* Refactoring Disciplined technique for restructuring an existing body of
code, altering its internal structure without changing its external behavior Martin Fowler Just a reminder. -
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. -
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 :) -
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. -
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 -
puts 'wait for it' ... ... ... ... ... ...
... ... ... ... puts 'dary' end long. -
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). -
Too many params Long methods definitions are bad because you
need to scroll code horizontally our it brakes the formatting so use objects. -
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. -
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. -
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. -
* 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. -
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. -
* 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? -
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. -
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. -
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.