Monday, December 31, 2007

Refactoring: We are not alone!

http://refactormycode.com
Read this blog, it will make you smile!

I did some testing on the refactorings suggested in:
http://refactormycode.com/codes/2-ruby-simple-loop

testing.rb

def prof(t = 1, output = :puts)
starting_time = Time.now
t.times { yield }
dlta = (Time.now - starting_time).to_f/t
case output
when :ret
"### time: #{dlta.to_s}(s) . req/s: #{(1/dlta)}"
else
puts "### time: #{dlta.to_s}(s) . req/s: #{(1/dlta)}"
end
end

times = []
times << ["(1..10).each do |i|
puts i
end",
prof(1000,:ret) {
(1..10).each do |i|
puts i
end
}]

times << ["for i in (1..10)
puts i
end
",prof(1000,:ret){
for i in (1..10)
puts i
end
}]

times << ["(1..10).each { |i| puts i }",prof(1000,:ret){
(1..10).each { |i| puts i }
}]

#times << ["puts (1..10).to_a * '\n'",prof(1000,:ret){
# puts (1..10).to_a * "\n"
#}]

#times << ["puts (1..10).to_a",prof(1000,:ret){
# puts (1..10).to_a
#}]

times << ["1.upto(10) { |i| puts i }",prof(1000,:ret){
1.upto(10) { |i| puts i }
}]

times << ["puts 1,2,3,4,5,6,7,8,9,10",prof(1000,:ret){
puts 1,2,3,4,5,6,7,8,9,10
}]

times << ["10.times {|i| p i+1}",prof(1000,:ret){
10.times {|i| p i+1}
}]

puts '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
times.collect { |t|
puts t
puts '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
}

Two of the suggestions:

  • puts (1..10).to_a
  • puts (1..10).to_a * "\n"
don't really work, so I left them out of the tests)

And the results are ...

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
(1..10).each do |i|
puts i
end
### time: 0.000165467(s) . req/s: 6043.50112106946
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
for i in (1..10)
puts i
end
### time: 0.00018765(s) . req/s: 5329.07007727152
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
(1..10).each { |i| puts i }
### time: 0.00020241(s) . req/s: 4940.46736821303
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1.upto(10) { |i| puts i }
### time: 0.000216612(s) . req/s: 4616.54940631175
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
puts 1,2,3,4,5,6,7,8,9,10
### time: 0.000164026(s) . req/s: 6096.59444234451
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10.times {|i| p i+1}
### time: 0.000208756(s) . req/s: 4790.28147693958
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

4 comments:

Shai said...

so what's the final final result? better to write more code and it runs faster? death to refractoring? write more code, it's better for ya?

;)

Dor Kalev said...

I think that the thing most common for the two highest ranked results:

{ (1..10).each do |i|
puts i
end }

and
{ puts 1,2,3,4,5,6,7,8,9,10 }

is the simplicity of it's code.
my conclusions are:

1. SIMPLE = GOOD PERFORMANCE
2. SIMPLE != SHORT
3. SHORT != GOOD PERFORMANCE

hence:
* WRITE SIMPLE CODE!

stwf said...

Isn't the real lesson here to stop paying so much attention to brevity as it relates to performance?????

THe total difference between the slowest and the fastest loop is 0.00005! So write your code for readability and maintainability, super short but obscure notation won't save you performance time but will cost you maintenance time.

dor kalev said...

i totally agree.