Sunday, December 27, 2009

Added Crummy to generate breadcrumbs for CampZero.com

According to google's SEO guideline, its a good idea to provide breadcrumbs to your web contents. This is good in two ways: a) It helps people to find path to move up the navigation stack and b) it helps the google and other search engines to get a feel about your web content's hierarchical organization.
To add this breadcrumbs support, in my application www.campzero.com, a going to be online service marketplace for Bangladesh, I simply used the Crummy plugin. You can take a look at the Crummy plugin at github. It took me less than 10 minutes to find, learn and use this plugin! You can see the plugin in action at the campzero site.
I recommend this plugin for your Ruby on Rails breadcrumbs needs!

acts_as_permalinkable: SEO friendly rails URLs using my first RoR plugin

As a byproduct of my work on www.campzero.com, I released my first ruby on rails plugin called acts_as_permalinkable on github athttp://github.com/smsohan/acts_as_permalinkable
A comprehensive documentation is given at the github page. If you ever need to use search engine friendly urls or permalink like this blog, you may consider using the acts_as_permalinkable plugin. It takes less than 3 minutes to add the permalink feature to your rails model!
Get started by the following and you are free to contribute!
script/plugin install git://github.com/smsohan/acts_as_permalinkable.git

Thursday, December 24, 2009

Sitemap-generator for your Rails App and deployment solution

When talking about Search Engine Optimization for your public web pages, you probably try to follow the google guidelines for search engine optimization. Its a good one to get started with. For my recent project, www.campzero.com, I read the document and tried to follow the steps. Today, I worked on generating sitemap for www.campzero.com using the following:
  • Installed the site-map generator plugin following this link at Aktagon's, github link
  • For some reason, probably because of permission issues, my plugin install didn't generate the sample sitemap.yml file for me. However, I created the config/sitemap.yml file myself and put the following contents there:
domain: www.campzero.com
limit: 5000
priority: 1
change_frequency: weekly
  • Then, I put the call to the sitemap method as shown in the github documentation.
  • Finally, I ran the command rake sitemap:gerenate to generate my sitemap.xml file inside the public folder.
  • So far this went well with the local environment. However, when I deployed this code and ran the rake command in my staging environment, it said it was not finding any model with the sitemap method.
  • After some debugging, I found that the problem was with the code at the file generator.rb where they put model.methods.include?('sitemap_options') to see if the model contains a method named sitemap_options. But, at my staging environment, I found that this was returning false although there was this method inside the model. I changed the code to the following so that the include? check is done both for strings and symbols and it worked fine.
if((model.methods.include?(:sitemap_options) || model.methods.include?('sitemap_options')) && model.sitemap_options != nil)
models << model
end
  • Now, I could generate sitemap at my staging environment.
  • However, soon I found another issue with deployment, as I want my sitemap file to stay between deployments. So, I had to ensure the sitemap file is generated at a shared place other than the default public folder. I did the following changes to the sitemap_generator_task.rake file:
if defined?(SITEMAP_FILE_PATH)
SitemapGenerator::Generator.new(SITEMAP_FILE_PATH).find_models_and_generate
else
SitemapGenerator::Generator.run
end
  • I added the constant SITEMAP_FILE_PATH in my config/environments/staging.rb file to get it working.
  • Finally, I changed my deployment script to define a symlink from the public folder to the shared file path as follows:
run "ln -s #{shared_path}/sitemap/sitemap.xml #{release_path}/public/sitemap.xml"

Tuesday, December 22, 2009

How to strip html tags, truncate and highlight texts in ruby on rails

Recently, I had the following requirements as I was working on CampZero.com - the going to be service marketplace of Bangladesh.
  1. Remove all html tags other than hyperlinks and new lines from a html fragment
  2. Truncate the text to show only first 200 characters of the text and append ellipsis (...) in case the text was truncated.
  3. Highlight an array of words in the text to show the search query worlds that matched
The first one, getting rid of all but hyperlinks and new lines was achieved by the following code:

<%= sanitize my_html_text, :tags => %w(br a) %>
Next, to truncate the text, I simply used the following:

<%= truncate my_sanitized_text, :length => 200 %>
Lastly, to highlight my search query words, I did the following

#in the controller
@query_words = params[:query] ? params[:query].split(/\W/) : ''
#in the view
In reality, I chained the above thee methods as shown below:
<%= highlight(truncate(sanitize(my_html_text, :tags => %w(br a)), :length => 200), @query_words) %>
These methods and their siblings are great as time savers. Rails makes the web development fun by including this as built in methods. For reference, you can check the link at SanitizeHelper and TextHelper
Happy railing!

Friday, December 18, 2009

How is Rails plugins helping me in developing CampZero.com?

I am up to a web venture called www.CampZero.com - an online market place for you service providers in Bangladesh. This is somewhat similar in spirit to classified sites like ebay and craigslist, but the target market it consciously chosen to be the service industry. Anyway, I will go to the point why I picked rails for this project and how it is paying off.

A little background about me. I have some good background on .Net/C# and I developed several projects using this technologies. Also, I have some experience with Rails and developed almost same number of projects as that of .Net. So, I made an informed decision about choosing the Ruby on Rails framework for my project over .Net/C#. Here's the rationale:

Story#1: As a CampZero developer, I want to deploy the system as soon as I am done with a feature.
Solution: Use capistrano to automate the deployment process. It took me less than 30 minutes to setup the automatic one-click deployment. The deployment steps are at a minimum as follows:
  1. Get the latest code from the code repository.
  2. Create a link to the shared log directory.
  3. Create a link to the shared assets directory.
  4. Create a link to the full text search configuration file.
  5. Migrate the database schema.
  6. Change the link to the application to the latest code.
  7. Restart the full text search engine.
  8. Restart the web server.
  9. Rollback if any step of 1-8 results in a failure.
The whole process is triggered by a single line of command "cap staging deploy:migrations" and takes less that 3 minutes to complete on an average.

Story#2: As a guest user of CampZero, I would like to sign up for an account so that I can post an ad and/or rank the service providers.
The signup process is actually a three step process as follows:
  1. Create account, with password encrypted.
  2. Get an email with an activation link.
  3. Verify email address by clicking an activation link.
Also, there are several related works as follows:
  1. Login
  2. Logout
  3. Reset password
I used Authlogic for this purpose and it has taken care of all the aspects for me. For emailing I used ActionMailer. The whole job of authentication took no more than 4 hours! Thanks again to Authlogic.

Story#3: As a user of CampZero, I want to search for service providers using natural text.
The full text search was implemented using Sphinx and Thinking-sphinx. This also comes with default support for paginating lists. So, Thinking sphinx took care of all my search needs. I used the following features:
  1. Search by full text in the service description, title.
  2. Also search the service provider names and service categories.
  3. Rank by the ratings.
  4. Search using English morphology, for example, if searching for 'cars' it also searches for 'car'.
I spent as little as 6 hours to setup and code the whole free text search! The total coding size for search is less than even 15 lines in total!

Story#4: As a service consumer, I want to rate and write comment on my service providers so that other consumers can make informed decisions.
I used two plugins called, rate-fu and acts as commentable! These plugins are great time savers as well. All the underlying logics for handling ratings and commenting are already there and you merely plug the features in. It took me 5 hours and most of it was due to the UI part!

I am convinced that for most web applications now, Ruby on Rails is an automatic best seller. But, of course, my prior experience helped me in getting things done even faster. Lets see how this project makes a business :-)


Thursday, December 17, 2009

"Promises are meant to be broken" and my 2010 promises

"One must have a good memory to be able to keep the promises that one makes"
--Friedrich Nietzsche
"Promises are like the full moon, if they are not kept at once they diminish day by day"
--German Proverb
“Better a broken promise than none at all.”
--Mark Twain

Its always good to refer to previous experiences when you do a research. This doesn't only make you fair but also eliminates the reinventing the wheel problem! Well, this is what I learned from my graduate studies :-)
So, what is this about promises today? Well, you know its the time of the year when you have vacations and enjoy with family and friends... and start thinking about the next year. Make some rough plans probably for the upcoming year. Here is what I am promising-
  1. By January 1, find two potential MS research topics and draw an outline of each!
  2. By January 1, reduce 1kg weight!
What's next? Well, I have a vision of the future but trying to be agile here. Not doing lot of useless upfront thinking and leaving it up to the retrospect session on January 1 :-) I believe agile works and so if I can follow the spirits, I should be able to reach my vision on time.
My readers can wait till Jan 1 to get the retrospect report! I will be blatant and truthful (and this is a promise!).

Tuesday, December 15, 2009

What I learned from my first semester at University of Calgary as a Grad Student?

In a single line, the first semester has been awesome.
Some of you already know that I came to Calgary, AB, Canada this fall to start a graduate research focusing agile software development. So, to get started I tried to come up with a research idea by hunting several resources including popular publications, blogs and books. This is not yet over...
However, I took a course called Applied Machine Learning and had the opportunity to work on a project that might lead to my MS thesis. The project, Auto Tagging Emails with User Stories, targets to grab and automatically tag emails with user stories based on a project's context information. The trick is, if you see the text similarity between an email and a user story and complement with their temporal and meta data similarity, you can make a guess about their relation. I wanted to make it an automatic process so that when people share knowledge in emails they can easily make use of this knowledge for future references. The project was successful in its scope and I submitted a paper day before yesterday. Keeping my fingers crossed to see the decision on this paper!
Apart from the project, this course also offered the unique opportunity to work with Prof. Dr. Richter. He was really helpful and spent a lot of time on my project and the paper.
I also did a group project for the Interactive Tabletops and Surfaces course. This project was called "Tavolo", a surface solution for conferences where people could bring their research ideas through images/videos/pdfs and annotate/share with others. This was my first ever tabletop project. We used Microsoft Surface and I liked the hardware so far. But in the end I found that the size and low resolution of the surface limited our opportunity to implement several features of the project. But in a nutshell this project gave me the opportunity to try something around Human Computer Interaction and next generation collaboration designs.
During the last week of November, I attended the ITS2009 conference. It was a 3 day international conference people came from all continents. I liked the presentations and the fact that this research community is as if its a connected web. I must say, the Bill Buxton speech was a great one. He envisioned the next generation human computer interaction and also discussed about real life commercial applications coming out of the research. It was very inspiring!
I also submitted a grant application to iCore. I am personally convinced that this was a good proposal and I have the necessary background to make it a successful research. But according to my supervisor, its a good idea to be less optimistic with iCore fund. Anyway, composing this application helped me in finding some of the holes in my writing and thinking skills. I will happily take this lesson!
In my family life, this was an eventful time as well. My wife, Shahana, got admitted to the ECE department at University of Calgary and she will start her MS this January. This means we might be graduating at similar times and be back to Bangladesh soon thereafter. Wish we make good use of the opportunity in our graduate studies.
Well, this is a pretty much a summary! But I forgot one thing, Swimming! For the last month and half, I am going to swimming 3/4 days a week and enjoying this activity. The university swimming pool, like all other games and sports venues, is really well maintained.
I am looking for a Camera and waiting for the Boxing Day sale. Let me know if you saw a good DSLR camera around $500!
Oh! I forgot another announcement! I have taken my first web venture at www.campzero.com! If you have some time stop by and let me know if you like/dislike the idea and its presentation. I am planning to go live from Jan 1 2010!
Merry Christmas!

Friday, November 06, 2009

Lean Thinking: You will probably like to learn the essence of agile

Image taken from: http://www.leansoftwareinstitute.com/images/img_bigpicture.jpg

If you read the Poppendieck's book called, "Lean Software Development : An Agile Toolkit", you probably liked it because it managed to get the essence out of agile practices. So, what are these core principles? Well, most of you already know the phrase, "Inspect and Adapt". Now, you also know a bunch of specifications that facilitate this, for an instance, Scrum, XP etc.

Reading the book, I had a realization that, its good to talk using concrete facts as much as possible. So, doing a value stream mapping practice is worth than spending hours in discussing the process optimization. The same holds true with the Profit and Loss statement when figuring out which option to take - quality compromise, deadline shifting or feature squeezing. Being able to answer why questions, at least 5 in a succession, is something very critical - then you know the hidden junk thats causing the bad smell. I highly recommend reading this book, especially to people who are doing agile for a year or so and thinking about getting better at it.

I also had the opportunity to attend a speech by the authors on this Monday. The speech was a great one. But for my readers, I will write about an example from the speech.

Once Mary and Tom visited a company that creates hardware and software tools for real time video conferencing. They met the Boss there and asked what they were doing. The answer was, "We are working to improve the system so that our customers get better video conferencing solution for their businesses." They went to a section where people were working on hardware and asked one what he was doing. The person replied, "I am creating a component for the system, so that our customers can do better video conferencing". Then they went to a software developer and asked what she was doing. She replied, "I am working to improve a part of the software so that our customers can do better video conferencing".... (I am sure Mary used better words than mine and it was really interesting to hear the story in her voice :-))

So, the fact that she wanted to capture using this example is, although each individual is involved in a specific task, they envision the bigger picture from the customers' standpoint. This is really important. Because as soon as you start seeing the views from the customers' perspective, you will produce less bugs. In the book they mentioned, most software bugs are not results of coding/design errors, rather they arise from the difference in views among customers and developers.

Overall, it was a pleasure to read the book, although this blog post may not reflect all of my respect and take home from the book :-(



Tuesday, October 27, 2009

Now reading: Lean Software Development: An Agile Toolkit

This book by Mary and Tom Poppendieck is an awesome read. I just read the first three chapters and loving it. More on this book will come later as I read more...
I am tuned to attend the next CAMUG session by the Authors! It should be a lightning session and looking forward to Nov 2nd.

Saturday, October 17, 2009

Communicating tools for working on remote projects

Ever since I started working in the software industry, as a freelancer or representing a company, I found the most challenging part of a remote software development project is "Communication". In agile setup, collaboration plays a leading role to be effective and efficient.

By communication, I mean the following:-
  1. Getting the spec as intended by the client.
  2. Asking specific questions on time.
  3. Status update about progress, blocks and forthcoming events.
  4. Getting feedback as intended by the client.
  5. Making specific suggestions with rationale to the client.
I am listing a few tools that I used and recommend others to use.
  1. A note pad: I write down small bullet points as soon as I find a question/suggestion/idea.
  2. Voice chat/telephone call: It should be #1 preference. Its real time and most speedy after face-to-face. I use Skype for my voice calls and sometimes my phone as well.
  3. IM: I use GoogleTalk most of the time if it works with client. Otherwise, I just use the one that my client uses most frequently.
  4. Collaboration tool: I use ScrumPad.com. Post my messages, people get email notification and can directly reply on that notification. This way the collaboration is all captured in ScrumPad and we can also keep using Email.
  5. A wire framing/drawing tool: Sometimes a small sketch/piece of drawing may greatly ease the communication hurdle. I use MS Visio at times. However, I also use scanned copies of hand drawings and annotations. It works. However, I am looking for a good web based wire framing tool and I believe it will off-load a lot of decision confusions.
  6. Desktop sharing tool: Screen capture and desktop sharing also works for me. I use LogMeIn and Xing. These tools offer first class feedback capturing capability from remote clients.
I also try to follow some general rules:
  1. Always have a prioritized list of points that I want to discuss.
  2. Be on time.
  3. Never stay disconnected for more than 3 business days.
I am sure out-sourcing will keep growing in the coming days, not only for its low cost but also for the fact that they are getting smarter and equally competent as people who charge many folds compared to them. I also anticipate a lot of out-sourcing job will go to individuals or 2/3 person groups, may be not from fortune 500 companies, but there are still other unfortunate millions of companies who will need such small teams. If you plan to work remotely, I am sure you will need some of the above tools, and if you are already in the business and think you have other good tools, please share with me.

Tuesday, October 06, 2009

Web application user interface without any Menu

If you are like me, with little creativity with UI (!), on a new project you always start with a simple layout, banner followed by a row of menu and then a two column body that ends with a footer. Well, here is an example:-
----------------------------------------------------------
CampZero
zero hassle camping
----------------------------------------------------------
Home | Place a booking
----------------------------------------------------------
Welcome |
|
|
|
|
|
---------------------------------------------------------
Campzero.com, all rights reserved
---------------------------------------------------------
Well, there are other ways and you will almost always see good visual elements in most websites. However, somehow all of these beautiful sites come with some sort of menu. This post is about a site that doesn't have a menu at all.
Yes it is possible to create a web app without a menu. The application that I recently developed is designed around an intuitive workflow. The workflow itself drives the app and it does so without any menu. For example, on landing you see a dashboard with three sections. Main section shows highlights of different projects, sidebar contains the search box and top part contains profile card. Now, you can navigate the whole application from here. For example, select a project you will see main section with the project latest activities and the search box will search in the scope of the project.
The point is, if you know the users of your app will most likely follow one of a few workflows, then you can design a UI that flows naturally.

Monday, September 21, 2009

Showing unread posts/comments: An example of rails ActiveRecord 'touch'

I worked on the following story:-
"As a partner, when I visit a project's dashboard I want to see five most recently started or updated discussion threads with number of unread comments, if any. If any of these are new, I want to see them in a highlighted view. Next, if I open the thread, I want to see all new comments in a highlighted view as well. However, once seen, the threads/comments should no longer be highlighted from the rest."
I used the following steps to implement this.

Step#1: Added a model MessageReadTime (message_id, user_id, last_read_at)
class Message 
has_many :messages_read_times 
end
Step#2: Added filters in the messages_controller
after_filter :update_message_read_time, :only => [:show]
def update_message_read_time
read_time = MessageReadTime.find_or_create_by_message_id_and_user_id( params[:id], current_user.id)
read_time.last_read_at = Time.now
read_time.save!
end
Step#3: Added :touch=>true and unread? function in Comment class
class Comment
..
belongs_to :message, :touch => true
def unread?(user)
read_time = self.message.message_read_times.find_by_user_id(user_id)
return true unless(read_time)
return read_time.last_read_at < (updated_at || created_at) end end
Step#4: Added unread_comments method in Message class like this
class Message
...
def unread_comments(user)
self.comments.collect{|comment| comment.unread?(user) ? comment : nil }.compact
end

def unread?(user)
read_time = self.message_read_times.find_by_user_id(user.id)
return true unless read_time
return self.updated_at >= read_time.last_read_at
end
...
end
This is it! If you know a better way to do this, lets discuss in the comments. You are also welcome to share your thoughts/suggestions :-)

Thursday, September 17, 2009

Some useful plugins for RoR projects

Previously I used a few plugins in RoR projects including ScrumPad. On a more recent work, I found the following plugins to be really useful and easy to get started:-

1. I18n: Rails Internationalization
2. Seed-fu: Initial data loading for application  (e.g. admin user, product categories)
Tutorial http://github.com/mbleigh/seed-fu A support is now built in for Rails 2.3.4
3. Thinking-sphinx: Full text search
4. Paperclip: File and image upload made hassle free

If you looking for any of the above for features in your app, I suggest you give these plugins a try. It should be good for most of the apps unless you have some really unique needs.

Write in comments if you would like to share some other useful RoR plugins.

Wednesday, September 09, 2009

The CGI story on agile scaling success on a large project

This intro is from the presenters:-
PAS was a joint venture development initiative by 4 major oil and gas
companies and CGI. Devon, Encana, Husky and Talisman joined with CGI to
develop a new Production and Revenue Application. Each company put 3 senior
business resources on the project. The development component of the PAS
initiative cost $35M over 5 years with up to 90 people on the team. This
presentation is on how we used Agile to achieve this mammoth undertaking.

The product is currently running in production at 5 major oil and gas
companies with great reviews. It is also in production for several mid and
smaller sized companies. CGI is currently marketing the product.
This was my first ever meet with the Calgary agile methods user group, CAMUG and it was a great experience. Off late, I have been looking for my graduate research topic on agile methods, especially around scaling agile beyond a single team and this was just a perfect session for me.

I noted down a few of their discussed topics that I would like to share with my readers:
  1. The project continued in dev mode for 5 years, a $35M project.
  2. It started with only 3 members and extended to a team of 90 following Scrum+XP.
  3. The project had 5 sponsoring companies or clients.
  4. They had 6 teams working in the same sprint cycles.
  5. In each team, there were significant members from the business working full time with the team onsite and in the same open-space arrangement.
  6. They had some 3000+ unit tests and also 300+ acceptance test.
  7. They automated all repetitive tests.
  8. The had external experts visiting them from time to time. Eric Evans once visited them and helped them getting better grasp on Domain Driven Design.
  9. There had been a $800K and one month deviation from the projected cost and timeline.
They also discussed some issues related to working in a multi-team, multi-client project. I remember the following ones:-
  1. They had to balance between features/bug fixes.
  2. The deployment was taken care of by the respective sponsors, not the teams.
  3. They had issues with sprint backlog management.
They highlighted some aspects with great emphasis:-
  1. Open communication is the key to success.
  2. Onsite and full time real user availability is very important for such a big project.
  3. Automated tests, partial pair programming and continuous integration is a big plus.
  4. Staying co-located was really helpful.
What about scaling beyond?
  1. I asked them, if they felt it would still be a similar success if there had been 12 teams or even more with 200 people or so. They said, it would be challenging. But in response, they also said, following waterfall would make life much harder with such a big team, if at all it could be a success at the first place! Yes, I also believe this.
  2. One of the audiences asked if they outsourced a part of the project and the response was 'No'. CGI has a big team in India with a very high CMM ranking, but the project manager and asst. project manager said, it would be much difficult for differing time zones. Also, it would be difficult to transfer the knowledge as well as replicate the value of onsite client presence. The development manager also added that, the cultural difference between an agile and CMM setup would also been an issue if they had to go for the off-shore team.
The session was much more eventful than what I could compile. So, if you are anywhere near Calgary and interested about meeting agile practitioners from the industry, lets meet at the next meet! 

 
 

Sunday, September 06, 2009

A new home at Calgary and starting days

We relocated to the northwest section of Calgary, Alberta on the 26th August. I am new to this part of the world and traveling to this opposite time zone (GMT+6 to GMT-6) took around 33 hours. Did you ever take a flight on Qatar? Not? I recommend it. They offer best foods for your south asian delight. My route was Dhaka - Doha - London - Calgary. I enjoyed the trip (don't tell anyone, I was a bit scared when traveling over the Atlantic :-))

The city of Calgary is really eye soothing green during this season. The little homes and lawns look fabulous in my eyes. People here celebrate the summer in style, you will see large family camping vans every now and then. So far the people here are also very friendly and welcoming towards new comers. It has been a good experience and hopefully coming days will be even better!

On the 4th, I attended the graduate orientation program and met a lot of people. It was nice to know that the University of Calgary is equipped with all amenities required for an excellent graduate education. I am looking forward to use my free pass to the swimming pool! It'll be fun!

I met my supervisor, Frank, and also people at my Lab. My next duty will be to select a topic for my research by the end of this year. But the earlier it is selected, the better it is. Let me know if you have a good idea on your heads around agile software process/tools or digital tabletops.

My upcoming posts will be a mix of my graduate studies and my software related works. Also, I will be TAing and wish to share some of my teaching experience as well. Stay tuned!

Wednesday, August 19, 2009

Rambling stories from my days @ Code71 : My Takehome

Today is going to be my last day with the Code71 team and this is the last post of the series on my Code71 days.

The journey started on June 1, 2006 and now at this moment, I just wanted to summarize my takehome from the last three years' of work. I will go short, just touching the bits...
Teaming is at the core of Code71's culture. It went beyond teaming just for software development as we met outside for a movie, celebrated even the smallest of personal achievements and shared the excitement of a cricket or tennis match even at midnight from home over phone!
Planning and adapting practice. I have gone through aprroximately 70 sprint planning and 50 sprint retrospect sessions at work. But this scrum habit of inspect and adapt has been engrossed in my personal life as well. I try to maintain a written to-do list with deadlines and look back at times.
Continuous learning. As I worked on different technologies (.Net/RoR) and different domains (Financial/Vehicle dealership/Project management/Web community), I learned to grab new concepts. I developed a learning attitude towards solving a problem and realizing an opportunity.
Happy memories are great as takehome gifts and I feel blessed to have a large array of such memories. Helping the team growing and maturing towards best-practices is itself a happy feeling. And there are those great memories with seeing a start-up client making millions, getting gift card from happy clients on new year... and of course the team meets at the Code71 dining.
I will end with a few thanks note here. Thanks to Nimat and Syed for believing in my competence and giving me the opportunity to work, lead and learn. (I am really sorry that the I had to turn down the L-1 offer, it really was too late!). Thanks to all of my teammates for your ever smiling faces and support. Thanks to Omar, my first mentor at Code71, for introducing me to the basics and the pathway to continuous learning. A special thanks to Sohel, our office assistant, for his ever enthusiastic service and care. Wishing best of luck to Shaer and his team, you will take the company to the next height inshaAllah.

I am going to graduate school at University of Calgary, Canada this fall to start my MS under Prof. Frank Maurer and looking forward to it. I hope my experience at Code71 will help me in my future life and who knows, may be someday I will again be a part of the Code71 team!


Tuesday, August 11, 2009

Rambling story from my days @ Code71: My reading list

In my previous post, I got a bit nostalgic! However, ever since I posted the first one, I was looking for another post on the series. Trying to capture what I learned during the past 3 years, I found it would be really time taking for me and my readers. So, I sort of compiled the following list in this post. Hope it helps someone who is just eager to learn about software.

Books

Most visited sites

Blogs

Community

Saturday, August 08, 2009

Rambling stories from my days @ Code71 : Startup days

Sighs!

Back then, on Friday, May 26, 2006, I was a final year undergrad student at CSE, BUET. I was looking for a part-time software dev job opportunity and found a little one page advert for a student job at asha-technologies (lately renamed as Code71). Visited their website and thought it might be worth giving a try!

As usual, I was interviewed over phone and enjoyed a long 2 hour interview on premise. I found it really inspiring and gained more interest towards the job after this session. I started waiting for a response… but was pretty certain about a positive one!

Good things happen in quick successions in our lives. Agree?

I agree. Because I just started a soul-journey with my soul-mate, Shahana, on the March of 2006. Then got the job offer on the 26th of May! Couldn’t be happier. A job for me during that time was just beyond its compensation, it was an inspiration, opportunity to see the real world and being part of something bigger than myself.

Photo taken at Chhera dip (The Torn Island), St. Martins, Bangladesh. The last photograph taken with my first digital camera bought from my first month’s Salary!

I started my job on the 1st of June, 2006 at Asha-technologies. Asha-tech was still to find an office and Omar asked to meet him at his home office! That’s how it all started. We met a few times a week at Omar’s home until we moved to our office at the green building of green square at green road, Dhaka on the first of July.

Asha-tech signed up a client before it was even formed! So, once we moved into the office, we were building our first asha-tech product, an online loan financing gateway. We were enthusiastic about agile scrum/xp practices from the first day at office. The result was found in just less than 3 months. We rolled out our first release of the product. It was really a happy start. A fantastic start for a start-up. The client started generating revenue in less than 3 months of project inception!

The office setup was a small but adequate enough for our team. We installed long backup UPS (2 hours * 5 computers), A/C, IPS and dedicated internet connection with Wi-Fi. The work environment was full of fun. We were going for an outing to a team event every month and even more often going to delicious buffet places. We played table football and bowling… every time had a record breaking score and a new winner. We went swimming and believe me, Omar is as good a swimmer as he is a master in software technology. He would go to swimming with a flipper and flip like professional swimmers. He can even swim without using his hands/legs at all, lying side-on and in all such actions… I learned swimming keeping heads down and the easy way of breathing from him! Thanks!

Technologically we were maturing as well. Started using XPlanner for managing our project, attended daily standup meetings and started doing TDD. I won’t claim we got everything right at the first try… but, we were trying consistently, improving bit by bit… to this day.

For the most part, I was enjoying my job and became used to the pressure of a job + undergraduate studies. I said, good things happen in close succession. Another proof here! My first term final result with this job was a 4.0/4.0. I never scored 4.0 in a term before this nor had a 20+ hour/week job alongside my studies.

I strongly believe, my job taught me the attitude towards work, “plan, act and retrospect”. After over three years, I would suggest any new entrant in the software industry to start a career with passion. Its fun with passion. Its a win everyday with passion.

Thursday, July 16, 2009

Rails modeling guide#2: naming convention for ruby on rails model methods

Naming conventions play an important role to the software's overall architecture. It is not a rocket science, still, it may lead to unhappy consequences if not taken care of at the early stage of a project. This small best practices can make a code base significantly improved.

Rails does a good job by using the dynamic power of ruby and providing with a handful of dynamic methods with the models. ActiveRecord::Base and its included modules follow a consistent naming, which clearly represent the intended purpose of the methods. At Code71, we are working on ScrumPad, a 2nd generation agile scrum tool using ruby on rails and our model methods are named according to the following rules-

1. All boolean returning methods end with '?'

company.billable?, sprint.current?, story.in_progress?

2. Boolean methods do not start with is_ or has_ or did_ (as you might see in other popular languages)

company.is_billable? -> company.billable?
sprint.is_current? -> sprint.current?

3. find_ and find_all are used only for class (self.find or self.find_all) methods and should return a single/array of object of the class respectively.

find_* methods may return a single object of the class/nil

find_all_* methods return an array of objects of the class or [], but never a nil

4. No methods start with a get_ as other languages.

5. A method ends with ! if it alters the object itself.

sprint.close!()
story.progress!()

6. Methods that persists an object/may throw exception, should always end with ! (implied from rule 5)

invoice.update_status!(:paid)

7. Always use parentheses '()' in method names. Future versions of ruby is deprecating the support for method names without parentheses.

Following these 7 simple rules we have consistent and intuitive model method names across the whole ScrumPad. Let me know if you have any suggestion to these names to make it even better.

Rails modeling guide#1: right structure of a ruby on rails model

30MAR4U

Rails models are no exception compared to the super models! You are in the business if and only if you got a good physical structure and can stick to it for years...

At Code71, we are keeping our rails models attractive following a few guidelines. I will be posting these guidelines in a series and here goes the first one - about the physical structure of the ruby on rails models.

We keep the following order consistent in our models:-

  1. CONSTANTS
  2. has_one, has_many, belongs_to, has_and_belongs_to relations in dependency order
  3. plug-ins initialization (acts_as_tree, acts_as_state_machine etc.)
  4. validates_presence_of
  5. validates_uniqueness_of
  6. validates_numericality_of
  7. validates_format_of
  8. custom_validations
  9. named_scopes grouped by related purposes
  10. active record hooks (after_initialize, before_create, after_create, ...) in execution order in the format (after_initialize [:assign_default_state, :sanitize_content] )
  11. protected
  12. hook method implementations according to execution order
  13. public
  14. constructor
  15. class methods in alphabetic order
  16. other methods alphabetically or grouped if related
  17. protected
  18. methods alphabetically or grouped if related
  19. private
  20. self methods in alphabetic order or similar methods in a group
    other methods in alphabetic order or similar methods in a group

Rule

No method gets code real estate over 20 lines. If needed, one/more private methods are used.

How is this helping us?

  1. We are absolutely sure where to look for a method or where to write a new method.
  2. The code base is really consistent.
  3. The unit test methods also follow the same order, which makes managing the test suite easy.

More to come later this week. Stay tuned!

Tuesday, July 07, 2009

Implementing breadcrumb in rails projects – a clean approach

breadcrumb

In most web applications, breadcrumbs offer a nice way to trace back to previously visited pages. However, generating the breadcrumbs and showing them on dynamic pages sometimes need special care for the following reasons-

  1. The links of the breadcrumb may contain dynamic links.
  2. It is used in all the pages. So, changing the breadcrumb may trigger a series of changes.

In ScrumPad, we are using ruby on rails. There are a few plugins to help rails projects in managing breadcrumbs, but none seemed to satisfy our need. In fact, most projects come up with some distinctive ways to generate the breadcrumbs. However, we kept the breadcrumb clean in the following way in ScrumPad.

Step#1:

Encapsulated the breadcrumb generation logic into a single class and used it from all places.

class Breadcrumb
include ActionView::Helpers::UrlHelper
include ActionView::Helpers::TagHelper
include ApplicationHelper

attr_accessor :parts, :separator, :prefix

def initialize(separator = nil, parts = [])
self.separator = separator || "<img src="\"/images/stub_arrow_right.gif\"" />"
self.parts = parts
end

def add(title, url = nil)
self.parts << {:title => title, :url => url}
end

def set_prefix(title, url)
self.prefix = {:title => title, :url => url}
end

def to_s
if(!self.parts.nil? and !self.parts.empty?)
if(self.prefix.nil?)
parts_with_prefix = self.parts
else
parts_with_prefix = [self.prefix] + self.parts
end

breadcrumb_html = []
parts_with_prefix.each do |part|
if(part[:url].nil? or part[:url].empty?)
breadcrumb_html << "#{part[:title]}"
else
breadcrumb_html << link_to(part[:title], part[:url])
end
end
return breadcrumb_html.join(" #{self.separator} ")
end
return ''
end
end

Step#2:

A before_filter in the ActionController initializes the breadcrumb in the following way:-

def initialize_breadcrumb()
@breadcrumb = Breadcrumb.new
if(project_selected?)
@breadcrumb.prefix = {:title => "Dashboard", :url => dashboard_project_path(selected_project())}
end
end

Step#3:

Now, @breadcrumb is available to all actions. However, if the RESTful resource definition is right, the rest of the breadcrumb generation becomes really simple. We have methods like the following in our controllers-

def generate_breadcrumb(sprint, story = nil)
@breadcrumb.add(sprint.name, project_sprint_path(project.id, sprint.id))
if(!story.nil?)
@breadcrumb.add(story.display_title, story_path(story))
elsif(self.action_name != 'index')
@breadcrumb.add('Stories', stories_path())
end

current_page = self.action_name == 'index' ? 'Stories' : self.action_name.humanize
@breadcrumb.add(current_page)
end

Step#4:

Finally, in my view layout, I just use this instance variable as shown here:-

<%= @breadcrumb %>

So, the whole breadcrumb generation is encapsulated and the implementation is clean. Let me know if you liked it. I am in the process of creating a plugin so that anyone can just drop it in any rails app and start using straight away!

Monday, June 15, 2009

Lesson#2: Pace Your Sprint Rightly

In my previous post, I said about being incremental. Here come the next thing, being “ITERATIVE”. A prefer the term Sprint than Iteration.

So, once you decided to take small increments, make sure you reach the targets sprinting.

sprint

I suggest you prepare for sprinting with the right techniques and tools. A few recommendations-

  1. Never miss a daily standup meeting. Spend only 2 minutes (or less) per person answering the three questions – what did you do yesterday, what’s on the plate for today and what is blocking the race?
  2. Install visual clues for bringing the under the hood stuffs to daylight. Remember, being able to address the loopholes is the key. The solution usually follows automatically.

The key concept to internalize is, sprinting is a balance race. You need a good start and keep the momentum to reach the touch line on time. Its a small race and if you fall back, the touch line may seem too far to celebrate.

At Code71, ScrumPad, is helping us in sprinting. Our sprints are two week sprints in most projects. We found the team communication holds a key in meeting the deadline. Since, within a sprint, someone of the team may need an unplanned vacation or an issue may arise out of the blue, the team needs to step up and put extra efforts. Again, visual clues help the team in keeping everybody posted timely.

If a team finds it difficult to meet the deadline and find the sprint length to be too small, then what? Should they linger the sprint length? NO. The solution is to even shorten the length. To make sure, the team can plan for short spans with better accuracy. Lingering the sprint length addresses the wrong disease and hence may not solve the problem.

Wednesday, June 03, 2009

Lesson#1: Going Incremental is Natural!

As Scrum and Agile processes tell you, do it in small sprints, 2 weeks preferably, and go incremental. Take a small piece at a time and sprint.

human-evolution-t10176

I took this image from internet and credits to this site.

It’s easy to work out the Natural way than to defy it! If you are iterative and incremental, you are reaching towards the right hand side of the image! And to make the evolution faster, I suggest you try out Scrumming with ScrumPad. If you value “teaming” and “delivering” in sprints, ScrumPad will give you the oxygen to breathe while you sprint!

I suggest you follow a routine to iterate. At Code71, we follow the below-

Day 1: Plan for the next 9 days. Breakdown work items into smaller tasks, estimate at hours for each of the tasks and assign each task to an individual.

Day 8: Release in test server (shadow version of the real production environment) and collect customer feedback.

Day 9: Work on customer feedback and go live in production server. Always tag the version that is put in the production following the standard -

R<ProductReleaseVersion>.S<SprintNumber>.B<BuildNumber>.P<PatchNumber>

This gives us the rollback point when there is any issue in the latest production deploy. Of course, we make sure we do not need to touch on the tags too often!

How are you sprinting? Let me know if you have a suggestion.

Its easier to get lost! Would you?

I was talking to a friend of mine, who started a IT start up and working full time with a few others to foster the business. He was telling me-

“We have 13 projects running at this moment. We are working our heart out. But, we are not finding any time to do Test Driven Development, Continuous Integration and all the good things…”

Well, I understand how it feels! As the title says, “Its easier to get lost!”

maze 

Do you fancy getting stuck at this maze?

For startups, it is difficult to control the pulse. Because, you want to reach your billion dollar spot as early as possible, this week, or even earlier, today or even just in a few hours! And, as days go by, you start to feel the need for some process, to safeguard your efforts and quality, to hit the deadlines, to get in the rhythm of a sustainable pace.

But it may be really difficult to catch the ball at the first jump. We, at Code71, believe we need to be visibly competent and confident about the quality of our work. And worked hard to get the gears together in motion. Now it is cliques great. We have got the people motivated to follow the best practices, the tools to “do more with less” and the process to ensure a “sustainable pace”. I advise, you do at least the following to learn to escape the maze from tomorrow-

    • DIE for planning. Plan for short spans. We plan for two week sprints.
    • While planning, estimate honestly. Estimate all the hours necessary for following best practices. (producing automated test scripts may take 40% longer time, but bear with it)
    • Plan on your inputs. You cannot push your inputs. So, you may need to squeeze the output to match against your capacity.
    • DIE to meet the deadline according to the plan.

This is the mindset. You need to start believing to sustain. You need to plan honestly and never miss a deadline. After reaching the deadline, you retrospect. Find the loopholes and start filling those one by one. If you don’t see a loophole, find a ladder to reach higher. But do not place a ladder on a land mine!

Its not difficult if you have the preparation. To prepare, at a minimum do the following-

  • Have a Continuous Integration (CI) server up and running 24x7 or DIE. (We use CruiseControl, its free and great)
  • Make your CI server to send build, test and coverage report for you. Keep an eye on the coverage report and DIE to remain well above the the 80% line.
  • Keep track of your activities for retrospect. We use ScrumPad. It helps you to iterate, collaborate and deliver.

The keyword is “sustainable pace”. I found Scrum to address this sustainable pace really smartly. If you haven’t tried yet and looking for the loopholes to fill or the ladder to climb up, I suggest you learn about agile and Scrum, find an expert and give it a try. It’s worth than you might have expected.

If you know a better way to keep delivering better, I will appreciate for sharing your idea to me.

Wednesday, May 13, 2009

Unit/Functional Test Rails ActionController filters following DRY

At ScrumPad most of our controllers are bounded by filters for authentication/authorization. Some filters apply to all actions in a controller while others apply to only a few or leave out only a few. However, since we are following TDD, we need to test the filter is invoked before each of the desired action. This makes the test code MOIST (not DRY)!

Example of Moist Code:

The following example only captures two test methods. However, if you have 30 controllers like ours and on an average 5 filters at each, you will possibly find many such duplicates making your test code so moist that it becomes shabby!

class SomeController
before_filter :authenticate
before_filter :restrict_invalid_role
end
class SomeControllerTest
def test_index_redirects_without_login
get :index
assert_redirected_to :controller=>:login, :action=>:login
end
def test_index_redirects_without_valid_role
login_as(:invalid_role)
get :index
assert_redirected_to :controller=>:exception, :action=>:not_allowed
end
end

Example of DRY Code:
I came up with the following implementation to help us with unit testing the before filters. The assumption is, if your filter is invoked, it will work fine. And we are testing the filter only once. The following code is written at the end of the test/test_helper.rb.
class ActionController::TestCase
##example: should_apply_before_filter_to_actions(:authenticate, [:index, :new])
def should_apply_before_filter_to_actions(before_filter_name, actions)
if(actions.nil? or actions.empty?)
assert false
end
filter = find_maching_before_filter(before_filter_name)
actions.each do |action|
assert_before_filter_applied(filter, action)
end
end
##example: should_apply_before_filter_to_action(:authenticate, :index)
def should_apply_before_filter_to_action(before_filter_name, action)
filter = find_maching_before_filter(before_filter_name)
assert_before_filter_applied(filter, action)
end

##example: should_not_apply_before_filter_to_actions(:authenticate, [:index, :new])
def should_not_apply_before_filter_to_actions(before_filter_name, actions)
if(actions.nil? or actions.empty?)
assert false
end
filter = find_maching_before_filter(before_filter_name)
actions.each do |action|
assert_before_filter_not_applied(filter, action)
end
end

##example: should_not_apply_before_filter_to_action(:authenticate, :index)
def should_not_apply_before_filter_to_action(before_filter_name, action)
filter = find_maching_before_filter(before_filter_name)
assert_before_filter_not_applied(filter, action)
end

##example: should_apply_before_filters([:authenticate, :session_expiry])
def should_apply_before_filters(before_filter_names)
if(before_filter_names.nil? or before_filter_names.empty?)
assert false, "No Before Filter is Passed"
end
before_filter_names.each {|filter| should_apply_before_filter(filter)}
end

##example: should_apply_before_filter(:authenticate)
def should_apply_before_filter(before_filter_name)
filter = find_maching_before_filter(before_filter_name)
if(filter.nil?)
assert false, "no matching filter found for #{before_filter_name}"
end
assert filter.options.empty?, "the filter #{before_filter_name} has only/except options and does not apply to all actions"
end

private
#finds the matching BeforeFilter object
def find_maching_before_filter(before_filter_name)
filters = @controller.class.filter_chain()
if !filters.nil?
filters.each do |filter|
if(filter.is_a?(ActionController::Filters::BeforeFilter) and filter.method == before_filter_name)
return filter
end
end
end
return nil
end

#asserts a single BeforeFilter is applied on a single action
def assert_before_filter_applied(filter, action)
if(filter.nil? or action.nil?)
assert false
end

if(filter.options.empty?)
assert true
return
end
if(!filter.options[:only].nil?)
assert filter.options[:only].include?(action.to_s)
end
if(!filter.options[:except].nil?)
assert !filter.options[:except].include?(action.to_s)
end
end

#asserts a single BeforeFilter is not applied on a single action
def assert_before_filter_not_applied(filter, action)
if(filter.nil? or action.nil?)
assert false
end

if(filter.options.empty?)
assert false
end

if(!filter.options[:except].nil?)
assert filter.options[:except].include?(action.to_s)
end
if(!filter.options[:only].nil?)
assert !filter.options[:only].include?(action.to_s)
end
end
end
Now my test code looks like the following-
  def test_filters
should_apply_before_filters(:authenticate, :restrict_invalid_role)
end
I can use the other methods as well to get finer control if the before_filter is applied using :only or :except options. And I can use these helper methods across all my controller test classes, making the whole point of testing filters really neat and short.

If you are familiar with shoulda tests, you will find the above code following shoulda like naming conventions. I found the above code to strip a lot of your efforts, since you eliminate all test codes that safeguard your filters.

Hope it helps someone with similar need.

Sunday, April 26, 2009

Forget Me Not! Object Oriented Design in Custom Exception

When designing custom exceptions, you may forget about old school OO fundamentals. As a reminder, lets take a look into the following custom exception classes.


StorySaveError
StoryDescopeNotAllowedError
StoryCompleteError
StoryNotFoundError
StoryDeleteError
StoryDeleteNotAllowedError

These exceptions are really useful in my application. But the bad thing is, they all derive from StandardError class, whereas there should be a base class, may be StoryError, which is more meaningful and useful. So, we can have the following-


class StoryError < StandardError
end
StorySaveError < StoryError
StoryDescopeNotAllowedError < StoryError
StoryCompleteError < StoryError
StoryNotFoundError < StoryError
StoryDeleteError < StoryError
StoryDeleteNotAllowedError < StoryError

With the addition of a base class for all Story related exceptions, I can write cleaner/better code.

  • When I am not interested about the specific error, I can just use rescue StoryError to catch 'em all
  • I can place a common error handling routine for all Story related exceptions
  • I can add new exception types without altering the codes where the specific type of StoryError is insignificant

From my experience, I found that most people are not cautious about OO when desiging custom exceptions. (because they are exceptions!). Nonetheless, if you follow the OO guides, it will pay off for sure.

Tuesday, April 21, 2009

Unit Test eager loading in Rails ActiveRecord association

To avoid the n+1 problem, you need to use eager loading in ActiveRecord object associations. An easy implementation of eager loading can be done using named scope in the following way.

class User < ActiveRecord::Base
has_many :friends
named_scope :eager_load_friends, :include => :fiends
end
User.find(user_id).eager_load_friends
To unit test the named scope, you can use this following helper method (keep it in test_helper.rb, if you like) that I wrote for ScrumPad
def test_eager_loaded(model, association)
assert !model.instance_variable_get("@#{association.to_s}").nil?
end
You can then test your eager loading in the following way
def test_eager_load_friends
test_eager_loaded(User.find(1), :friends)
end
You can also use the shoulda plug-in if you like. For me, I think we should test the values returned by our named scope as opposed to shoulda approach, which tests if the code is written as expected.

Got another solution? I will appreciate if you share.

Wednesday, April 15, 2009

Implementing Template Method in Rails Controllers Using Module and Mixin

All rails controllers are subclasses of the ApplicationController class. A typical controller class declaration will look like the following-

class LoginController < ApplicationController
#the actions go here
end

With this basic information, I would like to state the problem first.


The Problem/Job in Hand

Add an action switch_project to all the controllers (> 20) of the ScrumPad code base. The implementations of the switch_project method will be same for all the controllers only other than the fact that, the switching destination will be different.


Analysis

Placing the switch_project action in the ApplicationController would be the best option. But, the methods of application controller are not accessible as actions. So, the following won’t work


class ApplicationController
def switch_project
if(is_valid_switch?)
logger.debug(“A switch is taking place”)
destination = get_destination(new_project_id)
redirect_to destination
end
end
end

if you hit http://server/login/switch_project you will get a server side error. However, if you instead place the switch_project inside the LoginController, it will work fine. But, of course at a cost. You need to copy/paste this method 20+ times as there are 20+ controllers with the same need! Horrible!


Again, as I said, the get_destination(new_project_id) is the only part that will be different for each of the controllers. So, we definitely find a template method here.


The Solution

If you need an introduction about Module and Mixin in Ruby, please read here at ruby-doc. We are going to use Mixin to implement the desired solution, efficiently.

So, I put the switch_project method in a module called, ProjectSwitchModule inside a new file at app/controllers/project_switch_module.rb like this-


module ProjectSwitchModule
def switch_project
if(is_valid_switch?)
logger.debug(“A switch is taking place”)
destination = get_destination(new_project_id)
redirect_to destination
end
end
def is_valid_switch?
#I determine if the switch is valid at this method and return boolean
end
end

To make it available to all my controllers, I include this module in just in the ApplicationController in the following way-


require ‘project_switch_module’
class ApplicationController
include ProjectSwitchModule
end

Also, to provide controller specific implementation of the get_destination(project_id) method, I am just writing this method in each of the controllers in the following way-


class LoginController
private
def get_destination(project_id)
#custom destination logic for LoginController
end
end
class MessageController
private
def get_destination(project_id)
#custom destination logic for MessageController
end
end

Now, if I invoke http://server/login/switch_project or http://server/message/switch_project I will get the result of the switch_project action. So, this gives us an elegant way to follow design patterns for efficient implementation. It will save a lot of my time in future when I need to change the switch_project method, since I just need to change at a single place instead of 20s.


Afterthoughts

If, for a controller the switch_project needs to be different from the template at the module, it is achieved simply by overriding the switch_project inside the controller. No worries!


I will appreciate any feedback on this article.

Saturday, April 11, 2009

Testing the SyntaxHighlighter Scripts

For the last few months, I am on the lookout for a really good syntax highlighter that helps me to post blogs on all the programming languages in a pretty html with syntax coloring/highlighting. This one is taken from http://alexgorbatchev.com/wiki/SyntaxHighlighter

Ruby/Rails
class TestHighlighter
def my_highlighter
return "SyntaxHighlighter"
end
end

CSharp

public class TestHighlighter
{
public string MyHighlighter
{
get {return "SyntaxHighlighter";}
}
}


What did I add to my blog?



Open Edit Html and add this just before in the blog's template



<link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" type="text/css" rel="stylesheet" />
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" type="text/css" rel="stylesheet" />
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script type='text/javascript'>
    SyntaxHighlighter.config.bloggerMode = true;
    SyntaxHighlighter.all();
</script>


Thanks to Ashraf for informing me about the Windows Live Writer Plugin! It will be useful for sure.

Thursday, April 09, 2009

Pair Programming: How am I feeling?

For an explanation of Pair Programming, please visit this wiki entry.

Good

I am pair programming on the ScrumPad project now and the feeling in general is good. I have this perception is the work quality is better than doing alone. Also, the amount of time wasted to find small issues are now much reduced. Overall, its good.

Productivity Increased

I definitely found the productivity boosted by a factor of 1.5 at least. May be this is specific to my case, as I am working on a mid scale refactoring task. We worked on two user stories so far and completed the stories in 1.5 times faster compared to the individual estimates. We are doing estimation on a regular basis and the variance between estimation and actual hours are less than 5% as we see in the last 17 sprints in this project.

Disclaimer

I am yet new to this practice and not in a position to draw a conclusion yet. However, I believe our open space set-up and strong team culture helped us a lot to start this pair programming.

Are you pairing? Please, share your feelings and suggestions.

Tuesday, April 07, 2009

assert_equal_float : assert_equal between two float objects with precision

In doing rails unit testing, sometime you need to assert the equality between two float objects in the following fashion

assert_equal 32.8, object_under_test.method_returning_float

The internal storage of float objects sometimes will contain 32.8 with additional lower precision decimal points and hence the assert may fail although the significant digits may be same. For example, the value of object_under_test.method_returning_float may be stored as 32.80000001 in memory and the above call may fail.

To solve this problem, you may wish to use the round method of Float class in the following way

assert_equal 32.8, object_under_test.method_returning_float.round(1)

The above line will evaluate true since it will round up to one decimal points. However, be careful about cases where you may have a value greater than 5 in the second decimal place! because (32.86).to_f.round(1) will become 32.9!

However, when you are talking about insignificant digits, this rounding should work fine for you.

Next step is to define a new assert_equal_float method that takes the precision as an argument. Adding this method will save you from code duplication and will improve readability.

def assert_equal_float(expected, actual, precision)
assert_equal expected.to_f.round(precision), actual.to_f.round(precision)
end

Happy float asserting!

Sunday, April 05, 2009

Looking at ASP.NET MVC

Being over-burdened by all the blog posts on MVC from the ASP.Net for the last few months, I am now looking to ASP.Net MVC. Still seeing the tutorials on asp.net/mvc site.

I have worked on a few rails projects and the ASP.Net MVC implementation is very much like Rails. Anyway, still early for me to comment!

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!

Sunday, February 22, 2009

Working on a Data Warehouse project

I have been busy for the last month as we, at Code71, rolled out the first release of the Business Intelligence project for Vuneu Media. I will give you a brief on my project here so that you can follow my coming posts.

The used vehicle dealers buy their vehicles from different Auctions across the country. When making a buy decision, they try to find answer to these questions-

  1. What vehicles are customers buying?
  2. How much it costs to get those from Auctions?
  3. How many of these are receiving cash advances and by which lenders?
  4. What is my potential gross profit if I deal a vehicle?
  5. Where can I find the vehicles in Auctions?

So, we are getting the information from data vendors. Since, the amount of data is really large (nearly 10 million rows per month in total) for human manipulation, we are adding real value to the business by providing software intelligence. We developed the technology to put the pieces together and make it handy for the dealers.

We are using the following software/technologies:-

  1. SQL Server 2008, 64 Bit, Standard Edition.
  2. SQL Server Integration Service.
  3. SQL Server Reporting Service.
  4. ASP.Net, C#, WCF.
  5. SQL Server Analysis Service (is in the pipeline, not used yet!)
  6. Windows Server 2008, 64 Bit.

I came across a number of innovations as well as issues at each step of the project. The database schema design was itself a challenge since data come from different vendors in various formats and granularities.

Here, I will start with an issue resulting from the “64 bit” SQL Server limitations-

SQL Server 64 bit versions include Integration Services, but it lacks support for some components. One such is, Microsoft Jet Driver. We use this driver to load data from Excel files.

To load Excel data using SSIS, you have the following options:-

1. Locate Program Files (x86)\Microsoft SQL Server\90\DTS\Binn\DTExec.exe. Then use this with your options. You can take a look at the command arguments by invoking DTExec –? This way you can run the SSIS packages using command line.

2. Using the SQL Server Agent Job is rather simple. Just Create/edit your job step having the Excel, then select Use 32 Bit in the Options/Execution Options tab. It will automatically use the 32 bit version of DTExec.

3. If you are using the IDE, you can turn of 64 bit by un-checking the Use 64 Bit Runtime at the Project Properties > Debugging.

More information on 64 bit SQL Server related issues are here at MSDN.

Also, I got help from Blog N-Technologies.