Monday, March 30, 2009

named_scope : Real life examples from ScrumPad

I am working on ScrumPad chat refactoring now. In rails 2, the named_scope feature works really great for ActiveRecord models. Lets start with the code first-

The Source Code:

class ChatUser < ActiveRecord::Base
belongs_to :chat
belongs_to :user
belongs_to :chat_status, :foreign_key => "status_id"

named_scope :closed, lambda {|chat_id| {:conditions => ["status_id = #{ChatStatus::CLOSED} AND chat_id = ? ", chat_id]}} do
def invite()
each { |chat_user| chat_user.update_attribute(:status_id, ChatStatus::INVITED) }
end
end

named_scope :active_chats, lambda {|user_id| {:conditions => ["user_id = ? AND status_id not in (#{ChatStatus::CLOSED}, #{ChatStatus::LEFT})", user_id]}}
named_scope :with_chat, :include => :chat
end

So, you get an idea about the ChatUser class. Its a relation object between user, chat and chat_status with some additional fields.

How am I Using My named_scope?

ChatUser.closed(chat_id)

Gives me all the chat users who closed their chat windows for the chat having chat_id.

ChatUser.closed(chat_id).with_chat

Gives me the same objects as previous but eager loads the chat object. So, it saves plenty of database calls when I need to iterate through the chats!

ChatUser.closed(chat_id).invite()

Invites all users to a chat with chat_id if the buddy closed the chat window.

Why named_scope?

  1. named_scope is not just a syntactic sugar. It generates much less query using WHERE IN clause instead of WHERE = clause. So, reduces the number of calls to a single call.
  2. Chaining the named_scope will generate only a single query for the chain. So, ChatUser.closed(chat_id).with_chat will produce only one query.
  3. You get rid of looping in many cases! It will help you to write concise and clear codes.
  4. When you can divide the objects in your classes in partitions, then you may wish to write the named_scope for partitioning the data. In my example, the :closed named_scope does this. So, I can add methods to this named_scope which actually works for the closed chats. It is kind of dividing your objects into named groups. So, it increases readability.

Let me know if you have another good example of a real life named_scope in your project.

Monday, March 23, 2009

Design/Code Review: Now, It's time to realize!

Are you doing code reviews?

Thank God, you are.

Not?

Well, you are not alone. You know, most of your bugs could be killed by reviews. Most of your technical debts could be paid by reviews. Your team could collectively learn more by reviews...

Now, It's time to realize!

Start now! It's simple. I have found the following approach to be useful-

  1. Pair up with one developer. Make it explicit to the team. So, you know who reviews your code.
  2. Mix up a junior team member with a senior one, if possible.
  3. Have a fixed time, at least 30 minutes for each two weeks to do a team design/code review.
  4. Do it in small increments. We did the following-
    • Sprint#1: Review variable/method/class/file/folder names only.
    • Sprint#2: #1 + Review if/else blocks, loops.
    • Sprint#3: #2 + Review class responsibilities.
    • Sprint#4: #3 + Review test codes only.

The result is really worth

This first level feedback will help you to eliminate a lot of bugs, help in knowledge transfer and collective learning. Roughly, It takes only 10-15 minutes to review a code written in 3 days. I suggest, keep it simple.

One interesting thing is, many times I have found the developer him/herself actually found bugs/mistakes in the code before the reviewer at the time or reviewing.

A reviewer's eye will save lot of your time and money.

Update: Be constructive in your feedback! Example:-

Worst: This code is a piece of ...

Worse: This code is bad

Bad: This code is not good

Good: A better way is..

Better: We can also do it this way...

Best ?

Sunday, March 22, 2009

Juggernaut on Linux

I just installed Juggernaut on my linux box. The installation is simpler than windows. At least it gave me less pain.

Just run the following commands-

  1. gem install json
  2. gem install activemachine
  3. gem install juggernaut
  4. juggernaut –g juggernaut.yml
  5. juggernaut –c juggernaut.yml

I got a little pain regarding the g++ compiler that is required to build the activemachine. I did not have it installed in my Amazon EC2 instance and after some searches, I could install it using the following-

apt-get install g++

IMPORTANT!!

Well, it was fine if I could end here! However, I found that this installation stopped my MySQL service and changed the /etc/mysql/my.cnf file. So, an attempt to start the MySQL was successful only after I removed the # comment from the line log_bin = blah blah blah…

So, if you are using Redhat Enterprise 5.0, you may find it useful. If you are using Amazon EC2, you will find it useful too. I do not know about other distros, but may be something similar will be there (at least hopefully)!

Comet and Server Push (Reverse Ajax) technology

I am re-implementing an ajax based chat system. Presently an ajax request is polled continuously to look for any updates/messages from the user’s browser. However, the plan is to use the server to push the messages to the clients to off-load the server from a huge number of useless ajax calls.

I learned about Comet and found it interesting. You may read about comet here at WIKI.

Juggernaut is a rails plug-in that uses Flash to implement the server push technology. It is simple and it produces RJS script for the client. So, it can be used many other scenarios where a live update is required. of course, chat system is a good place for this.

The installation required a few tweaks as follows:-

  1. 1. Installed json_pure gem instead of json. (gem install json_pure)
  2. 2. Installed EventMachine gem (gem install eventmachine)
  3. 3. Installed juggernaut gem (gem install juggernaut –-ignore-dependencies)
  4. 4. Modified the C:\ruby\lib\ruby\gems\1.8\specifications\juggernaut-0.5.7.gemspec in places to the following

s.add_runtime_dependency(%q<json_pure>, [">= 1.1.1"])
s.add_development_dependency(%q<hoe>, [">= 1.3.1"])

s.add_dependency(%q<json_pure>, [">= 1.1.1"])
s.add_dependency(%q<hoe>, [">= 1.3.1"])

s.add_dependency(%q<json_pure>, [">= 1.1.1"])
s.add_dependency(%q<hoe>, [">= 1.3.1"])

since, you do not find the required versions of all the gems, you need to change this checks to get a way.

Then, this readme helped me to get started.

Will follow up this post as I work more on this. Have a good day!

Friday, March 06, 2009

The RANK() Function for Numbering on Groups/Partitions in SQL Server

Previously, I used the ROW_NUMBER() function to get the monotonically increasing row number of a result set from a SQL query. But, this time the requirement was a bit different as follows.

I have many combinations of Year, Make, Model and Trim of vehicles in my database. I also have potential profit on sale of each of the combinations. I need to produce, the top 5 trims for a Year, Make, Model combination that yields maximum profits.

So, to solve this problem, I cannot simply use ROW_NUMBER(). Basically, I need to find the row numbers starting from 1 for each group of Year, Make and Model. Then, take only those rows having a rank <= 5. Ranking based on such groups/partitions can be easily done by using the RANK() function. I am quoting the syntax from MSDN here-

RANK ( )    OVER ( [ < partition_by_clause > ] < order_by_clause > )

So, in my case the query is something like the following-


RANK ( ) OVER ( PARTITION BY Year, MAKE, MODEL ORDER BY Profit DESC, Trim )


So, the RANK() is similar to ROW_NUMBER() in the context of the PARTITION. As if, the RANK() restarts counting from 1 for each partition. I think, like me, many of you may find it new and useful in similar requirements.


Without using this function, it will be much difficult to produce the desired result set. However, if you have a nicer/alternative solution, please teach me!