Without Nate, the number of programmers in the company is odd number, which means that there is always one person having to do solo programming. This misfortune fell on me since last Friday. I programmed alone for the most of the on last Friday and Yesterday, writing Selenium test. With no one to review my code all the times, every typo and misuse can only be found at run time, because there's no compiler to check my source code. Sometime such errors were very hard to find out all by myself and I wasted a lot of time on even very silly mistakes. Once I try to run Selenium tests, it reported errors. Then I tried very hard to understand the error message, until I found it impossible for me to figure it out, and I called Philip for help, only to find that I forgot to start the web server!
With no one on site to discuss, it was not easy to come up with a solution when I experienced some difficulties. Meanwhile, with no one to switch the keyboard back and forth, thinking and typing the code alone for 8 hours a day, I fell very tired. I drank a lot of coffee, and sometimes I had to put some cold water on my face to keep a clear mind.
After spending last 3 hours on Selenium tests, I finally completed that task. With Philip's pairing for about one hour, we eventually found out how to test the element generated by Ajax using XPath, which had been pending through the weekend. Two people working together is so full of ideas!
Then I moved to pair with Paul on the task about velocity tracking. After we implemented the functionality and passed all the tests, we started to refactor. There is a piece of code which can well exhibit the benefit of pair programming.
I am still not quite familiar with Rails, comparing I am with SQL, so I wrote that code like this (Let's called it code portion 1):
task_sessons = TaskSession.find_by_sql("select ts.work_date, ts.user_id from task_sessions ts, tasks t, stories s where ts.work_date between '#{start_date.to_time.to_s :db}' and '#{target_date.to_time.to_s :db}' and ts.task_id = t.id and t.story_id = s.id and s.project_id = #{project_id})
And followed by another piece of code which had been written by Paul (code portion 2):
unique_entry = Hash.new
for x in task_sessions do
unique_entry[[x.work_date, x.user_id]] = 'A'
end
puts "using hash: "+unique_entry.length.to_s
return unique_entry.length
It worked. And I was about to commit it. Because Paul had some errands, Philip came to pair with me instead. He thought that it was not good to put such a long SQL inside Rails. And I was eager to know how to rewrite it in Rails way. Then he showed me:
task_sessions = TaskSession.find(:all,
:select => "task_sessions.work_date, task_sessions.user_id",
:joins => "join tasks t on task_id = t.id join stories s on t.story_id = s.id",
:conditions => "work_date between '#{start_date.to_time.to_s :db}' and '#{target_date.to_time.to_s :db}' and s.project_id = #{project_id}")
And he also think code portion 2 smelled not good enough. So he suggested to use the class Set instead. Then he went away for some errands. I did some investigation on Set API, and rewrite the code portion 2 using Set. But it failed. Then Jordan came. He said that we did not need to use Set; Array had already had a method uniq to delete those duplicated element. Then we tried, it also failed. At this time, if he left, I might have continue to investigate Set and Array API to find out the problem. But then he suddenly came with a great idea. This is the result of code portion 1 & 2:
task_sessions = TaskSession.find(:all,
:select => "distinct task_sessions.work_date, task_sessions.user_id",
:joins => "join tasks t on task_id = t.id join stories s on t.story_id = s.id",
:conditions => "work_date between '#{start_date.to_time.to_s :db}' and '#{target_date.to_time.to_s :db}' and s.project_id = #{project_id}")
return task_sessions.size
It is much shorter then before, and it is more clear now.
With no one on site to discuss, it was not easy to come up with a solution when I experienced some difficulties. Meanwhile, with no one to switch the keyboard back and forth, thinking and typing the code alone for 8 hours a day, I fell very tired. I drank a lot of coffee, and sometimes I had to put some cold water on my face to keep a clear mind.
After spending last 3 hours on Selenium tests, I finally completed that task. With Philip's pairing for about one hour, we eventually found out how to test the element generated by Ajax using XPath, which had been pending through the weekend. Two people working together is so full of ideas!
Then I moved to pair with Paul on the task about velocity tracking. After we implemented the functionality and passed all the tests, we started to refactor. There is a piece of code which can well exhibit the benefit of pair programming.
I am still not quite familiar with Rails, comparing I am with SQL, so I wrote that code like this (Let's called it code portion 1):
task_sessons = TaskSession.find_by_sql("select ts.work_date, ts.user_id from task_sessions ts, tasks t, stories s where ts.work_date between '#{start_date.to_time.to_s :db}' and '#{target_date.to_time.to_s :db}' and ts.task_id = t.id and t.story_id = s.id and s.project_id = #{project_id})
And followed by another piece of code which had been written by Paul (code portion 2):
unique_entry = Hash.new
for x in task_sessions do
unique_entry[[x.work_date, x.user_id]] = 'A'
end
puts "using hash: "+unique_entry.length.to_s
return unique_entry.length
It worked. And I was about to commit it. Because Paul had some errands, Philip came to pair with me instead. He thought that it was not good to put such a long SQL inside Rails. And I was eager to know how to rewrite it in Rails way. Then he showed me:
task_sessions = TaskSession.find(:all,
:select => "task_sessions.work_date, task_sessions.user_id",
:joins => "join tasks t on task_id = t.id join stories s on t.story_id = s.id",
:conditions => "work_date between '#{start_date.to_time.to_s :db}' and '#{target_date.to_time.to_s :db}' and s.project_id = #{project_id}")
And he also think code portion 2 smelled not good enough. So he suggested to use the class Set instead. Then he went away for some errands. I did some investigation on Set API, and rewrite the code portion 2 using Set. But it failed. Then Jordan came. He said that we did not need to use Set; Array had already had a method uniq to delete those duplicated element. Then we tried, it also failed. At this time, if he left, I might have continue to investigate Set and Array API to find out the problem. But then he suddenly came with a great idea. This is the result of code portion 1 & 2:
task_sessions = TaskSession.find(:all,
:select => "distinct task_sessions.work_date, task_sessions.user_id",
:joins => "join tasks t on task_id = t.id join stories s on t.story_id = s.id",
:conditions => "work_date between '#{start_date.to_time.to_s :db}' and '#{target_date.to_time.to_s :db}' and s.project_id = #{project_id}")
return task_sessions.size
It is much shorter then before, and it is more clear now.
没有评论:
发表评论