<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-34526917</id><updated>2012-01-22T20:15:54.453-08:00</updated><category term='LINQ'/><category term='Lean'/><category term='Continuous Integration'/><category term='other'/><category term='Architecture'/><category term='MVC'/><category term='SQL'/><category term='Javascript'/><category term='Rails'/><category term='.Net'/><category term='SQL Server'/><category term='UX'/><category term='Calgary'/><category term='C#'/><category term='TDD'/><category term='.Net 3.5'/><category term='Graduate'/><category term='css'/><category term='scrum'/><category term='agile'/><category term='Ruby'/><category term='Database'/><category term='html'/><category term='Unit test'/><category term='ASP.Net'/><category term='Book'/><category term='Object Oriented Design'/><title type='text'>Sohan - on software artisanship</title><subtitle type='html'>&lt;pre&gt;while I.am_alive? do
  read.think.innovate.share
  I.wannabe_alive += 1
end&lt;/pre&gt;</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.smsohan.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default?start-index=101&amp;max-results=100'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>144</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-34526917.post-9101412129143810286</id><published>2012-01-22T20:15:00.000-08:00</published><updated>2012-01-22T20:15:54.468-08:00</updated><title type='text'>Are You Still Parsing HTML Element Ids?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;To render a list, often times we use repeated HTML elements with a similar template. For example, the search results in ebay.com is a list of divs, each containing different data in the same template. In a server side, this rendering code is somewhat similar to this:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1660430.js"&gt;&lt;/script&gt;&lt;br /&gt;If you noticed, a product with it's database id = 123 will be rendered inside a div with id="product_123", and similarly div id="product_456" will contain the product with id = 456.&lt;br /&gt;&lt;br /&gt;With such ids, we can write JavaScript code that can extract the database id of a selected product to do interesting things, for example:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1660456.js"&gt; &lt;/script&gt;&lt;br /&gt;This is a useful and a common technique. However, in this era of &lt;a href="http://dev.w3.org/html5/spec/Overview.html#embedding-custom-non-visible-data-with-the-data-attributes"&gt;HTML5&lt;/a&gt;, we can make use of its custom attributes feature to write a clean JavaScript event handler without the help of parsing. Here's an example:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1660524.js"&gt; &lt;/script&gt;&lt;br /&gt;I will never parse my HTML element Id again. What about you?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-9101412129143810286?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/9101412129143810286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2012/01/are-you-still-parsing-html-element-ids.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/9101412129143810286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/9101412129143810286'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2012/01/are-you-still-parsing-html-element-ids.html' title='Are You Still Parsing HTML Element Ids?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6986733362084478682</id><published>2012-01-17T21:20:00.000-08:00</published><updated>2012-01-17T21:20:57.012-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Database'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Object Versioning is an Open Design Problem</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://farm3.staticflickr.com/2517/3874492115_e69defd351.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="213" src="http://farm3.staticflickr.com/2517/3874492115_e69defd351.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;This unsolvable maze is a local food from Bangladesh, known as Jilapi&lt;br /&gt;Photo credits to&amp;nbsp;&lt;span style="background-color: #fefefe; color: blue; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 18px; text-align: left; text-decoration: none;"&gt;&lt;a href="http://www.flickr.com/photos/udvranto_pothik/" style="background-color: #fefefe; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 18px; text-align: left; text-decoration: none;"&gt;udvranto pothik&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Object Versioning is often required by a business rule, for example, to maintain an audit trail or to be able to revert to a previous version, etc. This is the 3rd time in my career where this Object Versioning requirement made me think like -&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;There's gotta be an easier solution!&amp;nbsp;&lt;/blockquote&gt;But, I am yet to find one. So, I am thinking it's one of those open design problems, may be.&lt;br /&gt;&lt;br /&gt;To clarify the requirement with an example, let's consider the following scenario:&lt;br /&gt;&lt;br /&gt;A lawyer is preparing a document for one of her clients using a software. On January 17th, she needs to take a look at the version of the same document from May last year so that she can backtrace some changes that took place during these months.&lt;br /&gt;&lt;br /&gt;Lets assume the lawyer is using a software that stores the documents in a relational database with the following schema.&lt;br /&gt;&lt;pre&gt;A Document has many Evidences, each provided by an EvidenceProvider&lt;br /&gt;&lt;br /&gt;Document (id, client_id, case_id, name)&lt;br /&gt;Evidence (id, document_id, evidence_provider_id, details)&lt;br /&gt;EvidenceProvider(id, name)&lt;br /&gt;&lt;/pre&gt;Now, given the versioning requirement how would you design your data model?&lt;br /&gt;&lt;br /&gt;Here's a couple of points that your design should address at a minimum:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;Going back to a version means a complete snapshot of the old version of the document. So, the version of May 1st should only bring the evidences that were there on that very day.&lt;/li&gt;&lt;li&gt;As a new version is created, it should inherit all previous evidences.&lt;/li&gt;&lt;/ul&gt;As I have mentioned earlier, I am yet to find a good data model that can take care of these concerns without over-complicating everything. Let me know if you got a beautiful solution to this problem.&lt;br /&gt;&lt;br /&gt;However, in my latest project, the requirement is even harder. It's somewhat like this:&lt;br /&gt;&lt;br /&gt;The lawyer may have some documents in the "work in progress version". This means, if she needs to print a document for the court, she only wants to print the last "good version", skipping the "work in progress version".&lt;br /&gt;&lt;br /&gt;Also, when there is such a "work in progress version", she needs to attach any new Evidence to both the last "good version" as well as to the "work in progress version".&lt;br /&gt;&lt;br /&gt;Well, now you see the design of a data model for Object Versioning becomes really messy and unintuitive.&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;So, here's my question to you - how would you design a solution for this?&lt;/blockquote&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6986733362084478682?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6986733362084478682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2012/01/object-versioning-is-open-design.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6986733362084478682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6986733362084478682'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2012/01/object-versioning-is-open-design.html' title='Object Versioning is an Open Design Problem'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8598435855850790840</id><published>2011-11-20T17:54:00.001-08:00</published><updated>2011-11-20T18:56:28.419-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><title type='text'>Care Driven Development: Javascript</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;There &lt;a href="http://blankdd.com/"&gt;is * Driven Development&lt;/a&gt;, where they listed "all possible thing" driven development and dedicated a whole website to it! Well, I am adding one more to the list, "Care Driven Development", with an emphasis to Javascript coding.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;Javascript coding, do you care enough?&lt;/blockquote&gt;CSS is the most hairy spagetti piece of almost any web project. And its not leading by a far distance to it's first cousin; Javascript. But, the good thing is, it just takes a little care to clean the bush out of Javascript and make it pretty.&lt;br /&gt;&lt;br /&gt;Do you care enough not to use the following ever again?&lt;br /&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;$('#deep_under_the_ocean')&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;.parent().parent()&lt;/span&gt;.hide()?&lt;/li&gt;&lt;li&gt;$.ajax(&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;url: 'bank_accounts/transfer_money'&lt;/span&gt;, amount: 500...)&lt;/li&gt;&lt;li&gt;$('#eiffel_tower').height(&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;$('#paris').height() + &amp;nbsp;$('#eiffel_tower base').height() +&amp;nbsp;$('#eiffel_tower tower').height()&amp;nbsp;+&lt;/span&gt; ...)&lt;/li&gt;&lt;li&gt;populateNewYork(&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;'east', 'north', 50, 100, 23, ...&lt;/span&gt;)&lt;/li&gt;&lt;li&gt;$('.shark').click(function()&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;{$('.small_fish').attacked(function(){...})}&lt;/span&gt;)&lt;/li&gt;&lt;li&gt;parseInt(&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;$('.selected').id().split('-').last()&lt;/span&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I am compiling a list of such careless JS coding examples and this is just a start. If you have a few to add to this list, please keep sending!&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8598435855850790840?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8598435855850790840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/11/care-driven-development-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8598435855850790840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8598435855850790840'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/11/care-driven-development-javascript.html' title='Care Driven Development: Javascript'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5768314193940306727</id><published>2011-11-18T21:32:00.001-08:00</published><updated>2011-11-18T23:57:55.627-08:00</updated><title type='text'>Enterprise Software Projects: oh, yeah!</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I just rolled off my first ever enterprise software project couple of weeks ago. After staying six months on the project and while the memory is still fresh, I thought I would write a retrospect on the project and on my role.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5wSfo6UY1JE/TsdJk-YQvzI/AAAAAAAAAXk/Xy4XWTycW0U/s1600/Screen+shot+2011-11-18+at+11.15.16+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-5wSfo6UY1JE/TsdJk-YQvzI/AAAAAAAAAXk/Xy4XWTycW0U/s1600/Screen+shot+2011-11-18+at+11.15.16+PM.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The program is rather big, I guess it had ~300 people for the last couple or so years. I joined late for the program. So, by the time I went there, a massive amount of work has already been done, meaning a huge learning curve for me. On retrospect, I think I did well :)&lt;br /&gt;&lt;br /&gt;My team was small, 4-5 people including 3 devs. But we were responsible for really high value enterprise integration work, especially, linking the two most important applications in the program. This was a great place to learn some of the core business domain specific knowledge and I loved it!&lt;br /&gt;&lt;br /&gt;However, enterprise integration stuff is full of XML messaging and translation. While XSLT works when it works, in our situation we had too much logic and stateful data involved in the translation. So, we had to write a hell lot of custom code for all the XML messaging... and it sucks! Why?&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;Service APIs change all the time!&amp;nbsp;&lt;/blockquote&gt;I was mostly writing Java at work in this project for the first time in my professional career. This was a big change as well as a good exposure, considering my recent work mostly being in C# and Ruby. &amp;nbsp;In retrospect, I would say, I would rather not use Java, its a great platform but offers your an aging language.&lt;br /&gt;&lt;br /&gt;Being in the enterprise world means dealing with enterprise service buses, queues, oracle database, weblogic, load balancers, risk and compliance and you name it... sometimes the complexity of these things seemed to be&amp;nbsp;unnecessarily&amp;nbsp;troublesome, but then again, at times they made sense as well.&lt;br /&gt;&lt;br /&gt;People factors matter way greater than any other factor in such a big project. In retrospect, I think a hierarchical system often leads to longer meetings, useless communication and less ownership for most people.&lt;br /&gt;&lt;br /&gt;I will continue this post to a second episode where I will talk about development practices, challenges with multi-project communication, politics and power relations etc. Stay tuned!&amp;nbsp;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5768314193940306727?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5768314193940306727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/11/enterprise-software-projects-oh-yeah.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5768314193940306727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5768314193940306727'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/11/enterprise-software-projects-oh-yeah.html' title='Enterprise Software Projects: oh, yeah!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-5wSfo6UY1JE/TsdJk-YQvzI/AAAAAAAAAXk/Xy4XWTycW0U/s72-c/Screen+shot+2011-11-18+at+11.15.16+PM.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4628433952981672788</id><published>2011-11-13T15:57:00.001-08:00</published><updated>2011-11-13T16:19:27.877-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='html'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Aligning an HTML DIV Inside Another One</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Across different projects, I have found people taking CSS shortcuts for translating the Photoshopped design templates into HTML. Back in the days, layout used to be all Table based and it was kind of straight forward to fit everything into grid cells. However, with CSS styling the extra flexibility to put elements in any arbitrary layout came extra responsibility - to make sure things still align nicely while being fluid to accommodate different screen resolutions and form factors.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-21-12O0-QHA/TsBacV3pq_I/AAAAAAAAAXM/aUOql7Yjy8k/s1600/Screen+shot+2011-11-13+at+5.01.16+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="34" src="http://3.bp.blogspot.com/-21-12O0-QHA/TsBacV3pq_I/AAAAAAAAAXM/aUOql7Yjy8k/s320/Screen+shot+2011-11-13+at+5.01.16+PM.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-AEiJnBUw8wA/TsBackj_N-I/AAAAAAAAAXQ/nGFX0AnYL-I/s1600/Screen+shot+2011-11-13+at+5.01.27+PM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="43" src="http://3.bp.blogspot.com/-AEiJnBUw8wA/TsBackj_N-I/AAAAAAAAAXQ/nGFX0AnYL-I/s320/Screen+shot+2011-11-13+at+5.01.27+PM.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Aligning the child div in red inside a parent div in green using CSS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Here's a quick and dead simple example to create CSS alignment for a div inside another one!&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;Pro Tip: Use position:relative for the parent div and position:absolute for the child div.&lt;/blockquote&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1362939.js"&gt; &lt;/script&gt;This will make sure the parent is positioned relatively to other elements in the page. However, the absolutely positioned child can be positioned anywhere inside the parent without making the whole layout fixed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4628433952981672788?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4628433952981672788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/11/aligning-html-div-inside-another-one.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4628433952981672788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4628433952981672788'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/11/aligning-html-div-inside-another-one.html' title='Aligning an HTML DIV Inside Another One'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-21-12O0-QHA/TsBacV3pq_I/AAAAAAAAAXM/aUOql7Yjy8k/s72-c/Screen+shot+2011-11-13+at+5.01.16+PM.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3141369502197511397</id><published>2011-11-01T19:04:00.000-07:00</published><updated>2011-11-01T19:04:40.060-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Using instanceof is mostly a Code Smell</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;When using static programming languages such as Java, often time I have seen people writing methods that accept Object as a parameter. These methods typically don't really work on any Object, but works with multiple types of classes that don't have any common base class. Here's an example of such a method:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1332622.js"&gt;&lt;/script&gt;As you can see in this example, the &lt;code&gt;process&lt;/code&gt; method actually expects one of &lt;code&gt;CleanFloor&lt;/code&gt; or &lt;code&gt;LaunchRocket&lt;/code&gt; instances. However, since the two don't have a common subclass, it falls back to an Object type. And that results in the smelly code as you see in the example.&lt;br /&gt;&lt;br /&gt;An ideal solution would be to change the design of the classes so that you can either use a common base class or a generic method. But if you can't just do that&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="tr_bq"&gt;Get rid of the instanceof anyway!&lt;/blockquote&gt;&lt;br /&gt;However, this doesn't need to be smelly. Turning to basics of OO programming concepts, you will recall that there's this thing called method overloading that is specifically there to solve this very problem.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1332647.js"&gt; &lt;/script&gt;It seems so obvious in this example that you might question, why someone would use the former code? Well, I have seen quite a few of them and if you search for instanceof in your Java project, I won't be surprised if you see a few code fragments that match the former example.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3141369502197511397?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3141369502197511397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/11/using-instanceof-is-mostly-code-smell.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3141369502197511397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3141369502197511397'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/11/using-instanceof-is-mostly-code-smell.html' title='Using instanceof is mostly a Code Smell'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7167744481634191593</id><published>2011-10-04T15:32:00.000-07:00</published><updated>2011-10-04T15:36:52.880-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Nightly Build is a Warning (or Horror)</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://farm7.static.flickr.com/6167/6175859290_ebca7ae0e3.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="225" src="http://farm7.static.flickr.com/6167/6175859290_ebca7ae0e3.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Photo credits:&amp;nbsp;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;a href="http://www.flickr.com/photos/insidethemagic/" style="color: #0063dc; text-decoration: none;"&gt;insidethemagic&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;I think, Nightly build is an anti-pattern for Continuous Integration. If you are integrating continuously, then you shouldn't need a nightly build, that would be too discrete :(&lt;br /&gt;&lt;br /&gt;If you already have a per-commit continuous integration setup, you shouldn't need the so called nightly build unless there's something bad about the code.&lt;br /&gt;&lt;br /&gt;Often times, builds taking &amp;gt;10 minutes are put in the bucket of nightly builds.&lt;br /&gt;Some people put batch processing related tests under such nightly builds. A colleague told me they used nightly build to clean up resources (disk space, recreate the database etc.) on a nightly build - to ensure the apps worked fine on a fresh state.&lt;br /&gt;&lt;blockquote&gt;Under most circumstances, a nighly build means something long running. That in itself can be an indication of poor performance.&lt;/blockquote&gt;But what I have seen is, when such nightly builds are broken - they are rarely looked after or cared for. Because, first thing in the morning, who the hell wants to look at that broken nightly build? Even if someone takes a look, since its long running, it might well eat up all morning to actually try/fix/commit changes and see it go green again! Since it takes longer to make the build green, people keep delaying it for later... meaning&lt;br /&gt;&lt;blockquote&gt;it becomes generally acceptable to let the nightly build stay in RED.&amp;nbsp;&lt;/blockquote&gt;And once people get used the redness of the nightly build, they start ignoring it, inevitably.&lt;br /&gt;&lt;br /&gt;So, here's what I would do:&lt;br /&gt;&lt;blockquote&gt;Avoid nightly builds altogether.&lt;br /&gt;Avoid nightly builds altogether.&lt;br /&gt;Avoid nightly builds altogether.&lt;br /&gt;Otherwise, make one person from the team responsible for the build (rotate people).&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7167744481634191593?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7167744481634191593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/10/nightly-build-is-warning-or-horror.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7167744481634191593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7167744481634191593'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/10/nightly-build-is-warning-or-horror.html' title='Nightly Build is a Warning (or Horror)'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm7.static.flickr.com/6167/6175859290_ebca7ae0e3_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1533298980429589442</id><published>2011-09-28T14:23:00.000-07:00</published><updated>2011-09-28T14:29:56.341-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Database'/><title type='text'>The Perils of Soft Delete</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Often times, applications cannot get rid of the database records for business rules. For example, if you are a cable TV provider, you might have a customer calling you to stop the National Geographic Channel subscription from next month.&amp;nbsp;Ideally you would like to delete this record, but you can't do it until the effective date:( If you delete it, the next invoice will not be able to charge for this channel, although it's still being used.&lt;br /&gt;&lt;br /&gt;In such scenarios, its common to fall back to a soft delete model. As an example, here's a little code:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1249283.js"&gt; &lt;/script&gt;&lt;br /&gt;This code looks simple and harmless at a first sight. But, as you develop your app, you'll run into a lot of issues from this. Here's a short list:&lt;br /&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;You need to take care of cascading soft delete, for example, cancelling a customer's subscription needs to cascade down to all channels and other objects under it.&lt;/li&gt;&lt;li&gt;Whenever, you are listing the current subscriptions of a customer, you need to filter out the ended ones.&lt;/li&gt;&lt;li&gt;You need to figure out a strategy to periodically clean the ended subscriptions so that your database is not filled with outdated data.&lt;/li&gt;&lt;li&gt;If you have a business key used as a primary key as well, you will be in trouble if an ended subscription is restarted.&lt;/li&gt;&lt;li&gt;Your code will eventually have a lot of if-else blocks to apply changes to only on active objects.&lt;/li&gt;&lt;/ol&gt;So, what is the solution? Its best to avoid them as much as possible. Richard Dingwall has &lt;a href="http://richarddingwall.name/2009/11/20/the-trouble-with-soft-delete/"&gt;a detailed blog post&lt;/a&gt; on some alternative techniques to avoid soft-delete. But if you have to have soft delete, as shown in the example, its worth remembering the aforementioned points.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1533298980429589442?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1533298980429589442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/09/perils-of-soft-delete.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1533298980429589442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1533298980429589442'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/09/perils-of-soft-delete.html' title='The Perils of Soft Delete'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3863233929896167531</id><published>2011-09-23T10:47:00.000-07:00</published><updated>2011-09-23T10:49:55.911-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><title type='text'>Hardcoded URLs in Javascript are too Slippery</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2728/4182189627_ba036b02c8.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="448" src="http://farm3.static.flickr.com/2728/4182189627_ba036b02c8.jpg" width="500" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Photo credits to&amp;nbsp;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;a href="http://www.flickr.com/photos/36179943@N00/" style="color: #0063dc; text-decoration: none;"&gt;Esteban Cavrico&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;I was working on a web project that lets you delete some records using Ajax. The following is just an example, but you might be familiar with a similar code already:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1237981.js"&gt; &lt;/script&gt;&lt;br /&gt;This code used to work when the DELETE endpoint was indeed under '/blog/posts'. However, at some point a developer wants to remove the '/blog' from all the endpoints to put them directly under '/posts'! You can see, in such cases it is very hard to catch the bug that would be caused by the faulty JS code.&lt;br /&gt;&lt;br /&gt;Here's a quick recommendation:&lt;br /&gt;&lt;blockquote&gt;Don't hardcode the URLs (or anything that is actually a server configuration) inside your JS.&amp;nbsp;&lt;/blockquote&gt;This is a code smell, as its duplicating code. But its also dangerous, because its hard to catch/fix these defects since they can be buried deep under an untested Javascript file. Instead feed this data from your server side code and you'll mitigate risk that way.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3863233929896167531?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3863233929896167531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/09/hardcoded-urls-in-javascript-are-too.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3863233929896167531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3863233929896167531'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/09/hardcoded-urls-in-javascript-are-too.html' title='Hardcoded URLs in Javascript are too Slippery'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2728/4182189627_ba036b02c8_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1460660085633527740</id><published>2011-09-20T08:55:00.000-07:00</published><updated>2011-09-20T09:13:43.844-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Excess of Private Methods is a Code Smell</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Private methods, when used meaningfully, are a great tool for writing beautiful object oriented code. But as many other things in life, excess of private methods is bad, too!&lt;br /&gt;&lt;br /&gt;In my opinion, we use private methods to:&lt;br /&gt;&lt;br /&gt;1. &amp;nbsp;isolate a block of code to be reused inside the class.&lt;br /&gt;2. &amp;nbsp;extract code from another method for code readability.&lt;br /&gt;&lt;br /&gt;Now, taking these two use cases in mind, here's an easy conclusion:&lt;br /&gt;&lt;blockquote&gt;The lower the ratio of public to private methods, the harder it is to write unit tests since the "units" are potentially larger.&lt;/blockquote&gt;I don't know if there is any rule of thumb, but you will smell it when you see your unit tests require a lot of setup and assertions. Here's a code example from the Play! framework, an MVC franework for Java developers.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/playframework/play/blob/925a0676148f6cb149350f899a60d934544ab61a/framework/src/play/mvc/ActionInvoker.java"&gt;ActionInvoker.java &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You will see there are public methods with 100+ lines. I hope you agree with me:&lt;br /&gt;&lt;blockquote&gt;"The ActionInvoker.java code is not readable"&lt;/blockquote&gt;For the sake of readability, introducing private methods with good names would help. However, that doesn't eliminate any of&amp;nbsp;the possible code paths from the public methods. So, if you are lucky, you will see really long unit tests with complex setup conditions and mock expectations. Otherwise, there will be no tests at all! Without any tests for such long and complex methods, use them at your own risk. I won't :(&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;Disclaimer: I like the play! framework a lot. However, if you take a look at their code and if you think unit testing is important, you'll see they have a lot of rooms for improvement with simple&lt;/span&gt; &lt;a href="http://books.google.ca/books?id=1MsETFPD3I0C&amp;amp;pg=PA110&amp;amp;lpg=PA110&amp;amp;dq=extract+method+martin+fowler&amp;amp;source=bl&amp;amp;ots=pLM4p0UCef&amp;amp;sig=5nCPhEPwBkNULvuHiOF1jiW1qqk&amp;amp;hl=en&amp;amp;ei=Jrt4TqjZCoK80AG4nbDlDA&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;ct=result&amp;amp;resnum=6&amp;amp;ved=0CEUQ6AEwBQ#v=onepage&amp;amp;q=extract%20method%20martin%20fowler&amp;amp;f=false"&gt;extract method&lt;/a&gt; &lt;span class="Apple-style-span" style="color: #666666;"&gt;refactoring.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1460660085633527740?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1460660085633527740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/09/code-smell-private-vs-public-method.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1460660085633527740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1460660085633527740'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/09/code-smell-private-vs-public-method.html' title='Excess of Private Methods is a Code Smell'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4426474509061722287</id><published>2011-09-16T15:15:00.000-07:00</published><updated>2011-09-16T15:15:03.952-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Quiz: C# Async and Await. What is the Output of this Code?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;C# 5.0 (CTP version at this point) has support for async and await to allow clean implementation of non-blocking IO using a task-continuation model. I was just playing with it and here's the sample code to tease your brain. Tell me what is the output of this program?&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1223284.js"&gt; &lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4426474509061722287?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4426474509061722287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/09/quiz-c-async-and-await-what-is-output.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4426474509061722287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4426474509061722287'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/09/quiz-c-async-and-await-what-is-output.html' title='Quiz: C# Async and Await. What is the Output of this Code?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2707411555118132877</id><published>2011-09-16T15:07:00.000-07:00</published><updated>2011-09-16T15:07:55.530-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>How to Extend a Ruby Module?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Modules in Ruby are like classes with a few important differences. One of the differences is, a module cannot inherit from another module using the same syntax as class inheritance. However, its pretty easy to inherit a module's method into another module, by just using the include ModuleToInclude syntax. Here's an example if you are looking for one:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1223271.js"&gt; &lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2707411555118132877?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2707411555118132877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/09/how-to-extend-ruby-module.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2707411555118132877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2707411555118132877'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/09/how-to-extend-ruby-module.html' title='How to Extend a Ruby Module?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3563737773334748813</id><published>2011-08-15T10:18:00.000-07:00</published><updated>2011-08-15T10:18:08.101-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Should You Unit Test Interaction with Static Methods?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;No. You should not. Here's an example:&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1147225.js"&gt; &lt;/script&gt;&lt;/div&gt;&lt;br /&gt;If you are somehow mocking this static method, you are potentially making it dangerous for other places where this static method is used. Eventually, this will create red test results that are hard to find and make your tests dependent on each other.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3563737773334748813?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3563737773334748813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/08/should-you-unit-test-interaction-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3563737773334748813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3563737773334748813'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/08/should-you-unit-test-interaction-with.html' title='Should You Unit Test Interaction with Static Methods?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5261133862076252650</id><published>2011-08-12T08:03:00.001-07:00</published><updated>2011-08-12T08:03:17.299-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>How to list all classes that include a module?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Here's the code:&lt;/div&gt;&lt;script src="https://gist.github.com/1142228.js"&gt; &lt;/script&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5261133862076252650?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5261133862076252650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/08/how-to-list-all-classes-that-include.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5261133862076252650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5261133862076252650'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/08/how-to-list-all-classes-that-include.html' title='How to list all classes that include a module?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2266021561349368583</id><published>2011-08-09T22:38:00.000-07:00</published><updated>2011-08-09T22:40:22.024-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Should you unit test methods with a lot of mocking?</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Well, anytime you have a lot of mocking, it is probably a smell. Particularly, a first smell is violation of the &lt;a href="http://en.wikipedia.org/wiki/Law_of_Demeter"&gt;law of demeter&lt;/a&gt;. However, we were having discussion about whether or not we should write unit test for something like the following example:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1136189.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;As you can see, this method actually does a quite important task. It invokes the search method with specific parameters that will determine your search results. Now, we were debating whether or not the example unit test actually brings any value.&lt;br /&gt;&lt;br /&gt;Here's what we have discussed:&lt;br /&gt;&lt;b&gt;Pros:&lt;/b&gt;&lt;br /&gt;It confirms that you are actually calling the third party method with the right parameter.&lt;br /&gt;&lt;b&gt;Cons:&lt;/b&gt;&lt;br /&gt;The test is too tightly coupled with the implementation, so it will break if something changes inside the method irrespective of its actual output.&lt;br /&gt;&lt;br /&gt;But we failed to come to an unanimous decision on its usefulness. We all agreed on the point that it definitely needed some integration tests to make sure the search had actually worked.&lt;br /&gt;&lt;br /&gt;Here are two questions for you:&lt;br /&gt;&lt;br /&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;Would you skip the unit test altogether for this method and rely completely on an integration test? Why/Why not?&lt;/li&gt;&lt;li&gt;If you are to rewrite this code, how would you write this using TDD?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Looking forward to see your input on this!&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2266021561349368583?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2266021561349368583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/08/should-you-unit-test-methods-with-lot.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2266021561349368583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2266021561349368583'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/08/should-you-unit-test-methods-with-lot.html' title='Should you unit test methods with a lot of mocking?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1781896902637821722</id><published>2011-08-05T22:12:00.000-07:00</published><updated>2011-08-05T22:12:32.901-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Ruby present? Method</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Ruby has a nice little keyword called unless, that checks the opposite of if. So, you are probably used to a code like this:&lt;br /&gt;&lt;br /&gt;&lt;pre lang="ruby"&gt;return customer.first_name unless customer.nil?&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you haven't used present? before, you can in fact turn the above unless into a more familiar and easy to understand if statement:&lt;br /&gt;&lt;br /&gt;&lt;pre lang="ruby"&gt;return customer.first_name if customer.present?&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So, in most cases when you are using unless with a negative condition, you can use present? and if instead. I find it way easier to read.&lt;br /&gt;&lt;br /&gt;present? does the opposite of blank?. So, you will get the following:&lt;br /&gt;&lt;br /&gt;&lt;pre lang="ruby"&gt;nil.present? #=&amp;gt; false&lt;br /&gt;[].present? #=&amp;gt; false&lt;br /&gt;"hello".present? =&amp;gt; true&lt;br /&gt;["a"].present? #=&amp;gt; true&lt;br /&gt;&lt;/pre&gt;Hope it helps!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1781896902637821722?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1781896902637821722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/08/ruby-present-method-with-unless.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1781896902637821722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1781896902637821722'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/08/ruby-present-method-with-unless.html' title='Ruby present? Method'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4892732944175459844</id><published>2011-07-26T10:52:00.000-07:00</published><updated>2011-07-26T10:54:45.105-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Constructors Are Methods, too!</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;Yes, if your constructor does something meaningful. This is just like another method and should be treated equally for unit testsing purpose. Here's an example that should need unit test:&lt;br /&gt;&lt;script src="https://gist.github.com/1107355.js"&gt; &lt;/script&gt;&lt;br /&gt;It looks simple, so testing it should be simple, too. I would only skip the default constuctors, as long as they don't do anything interesting.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4892732944175459844?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4892732944175459844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/07/should-you-write-unit-tests-for.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4892732944175459844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4892732944175459844'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/07/should-you-write-unit-tests-for.html' title='Constructors Are Methods, too!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4667517555874970708</id><published>2011-07-22T12:24:00.000-07:00</published><updated>2011-07-22T12:38:39.311-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UX'/><title type='text'>How to Annoy Your Customers? Learn from GoDaddy Account Status Email</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-0DN9O0Y4w3I/TinJW3lhP5I/AAAAAAAAAVw/Xn2pmjJjXbE/s1600/Screenshot-1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="560" src="http://3.bp.blogspot.com/-0DN9O0Y4w3I/TinJW3lhP5I/AAAAAAAAAVw/Xn2pmjJjXbE/s640/Screenshot-1.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Just looking at this screenshot alone, what do you think it is?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;I have a few domains registered with GoDaddy. I went with them, because at that time, I didn't know of another renowned provider. But they have always been the best of producing the most confusing ever user interface. The account status email is one step ahead in that same direction.&lt;br /&gt;&lt;br /&gt;This is how it starts:&lt;br /&gt;&lt;br /&gt;At the top right corner, it says July 2011, in grayed out font! A deliberate attempt to de-emphasize the statement period!&lt;br /&gt;&lt;br /&gt;Just below the date, there is a fake input box and a button labeled Go. This is an image and if you click it, it will actually open a new page instead of asking for user input right inside the search box. This is just following the theory of most surprise (as opposed to &lt;a href="http://en.wikipedia.org/wiki/Principle_of_least_astonishment"&gt;principle of least surprise&lt;/a&gt;)!&lt;br /&gt;&lt;br /&gt;Next, in red background, they welcome me by saying, Welcome, S. M. Sohan! Customer Number: ### wtf? Customer Number? Do I give a shit what my customer number is? Why is the welcome grouped together with search and contact? How are these related?&lt;br /&gt;&lt;br /&gt;Then it says, Log in to your account on &lt;b&gt;our secure website&lt;/b&gt; to view &lt;b&gt;your most recent account&lt;/b&gt; statement. What does this mean? Does it mean, this statement is not recent? Is this not secure?&lt;br /&gt;&lt;br /&gt;Then it says, Summary of your account as of 7/21/2011&lt;b&gt;**&lt;/b&gt;. That f'ing footnote will tell you that, the information may not reflect recent changes! What? Is this good enough till 7/21? If not, why do you even send this bullshit to me?&lt;br /&gt;&lt;br /&gt;Then it has 4 boxes side by side. The first one, &lt;b&gt;Messages&lt;/b&gt; has Alerts: No, Notification(s): Yes. &lt;b&gt;View now&lt;/b&gt; is a button to their site. How stupid is this? Why bother saying alerts "No"? If you know I have notifications, why not put it right here? Why are you confused about notification"(s)" - you should know if its just one (notification) or more (notifications). How lazy is that?&lt;br /&gt;&lt;br /&gt;Items Expiring is the other funny one. It says, Domain names: No. Then it says renew now. What? You're saying nothing is expiring. Why on earth I would renew something?&lt;br /&gt;&lt;br /&gt;Then it takes almost 50% of the screen for asking me to contact with them through a number of channels including Facebook. Really? Facebook fan of GoDaddy? Crazy people!&lt;br /&gt;&lt;br /&gt;In the end, they don't care putting a note of thanks, let alone personalize it with the name of an actual person. Isn't it rude to end an email this way?&lt;br /&gt;&lt;br /&gt;Now, with all these hammerings - as if it fell short of creating enough fun, it says, More for You: followed by tens of fine print links to things that don't matter at all to me. Oh boy! you are awesome!&lt;br /&gt;&lt;br /&gt;I am not a designer by any means. However, I think, even I can design a better version than this crap. Here's my version in a screen mockup.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-T-ySiJT4c-s/TinOUi2YfRI/AAAAAAAAAV0/zXKeZxR2wIM/s1600/Screenshot-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="330" src="http://2.bp.blogspot.com/-T-ySiJT4c-s/TinOUi2YfRI/AAAAAAAAAV0/zXKeZxR2wIM/s400/Screenshot-2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4667517555874970708?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4667517555874970708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/07/how-to-annoy-your-customer-learn-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4667517555874970708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4667517555874970708'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/07/how-to-annoy-your-customer-learn-from.html' title='How to Annoy Your Customers? Learn from GoDaddy Account Status Email'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-0DN9O0Y4w3I/TinJW3lhP5I/AAAAAAAAAVw/Xn2pmjJjXbE/s72-c/Screenshot-1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2179846596306874080</id><published>2011-07-11T12:21:00.000-07:00</published><updated>2011-07-11T12:21:41.593-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Avoid Duplication in Config Files</title><content type='html'>Any kind of configuration file, be it an ugly xml file or a prettier yml or properties file, its been a source of frustration to me. Here's a list of few such pain points:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There are two config keys that point to the same value. e.g. db_username=master, data_source_user=master&lt;/li&gt;&lt;li&gt;There are two config keys for urls that point to the same domain, but different paths. e.g. market.com/cameras and market.com/undies&lt;/li&gt;&lt;li&gt;Config entries with placeholders. e.g. weather_url= weather.com/%s or weather_url= weather.com/%s/hourly&lt;/li&gt;&lt;li&gt;Config entries with default values that should not default to anything.&lt;/li&gt;&lt;li&gt;Config entries that are required but don't fail the application deployment when not set.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Are you having to deal with similar pain points? Some more?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2179846596306874080?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2179846596306874080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/07/avoid-duplication-in-config-files.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2179846596306874080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2179846596306874080'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/07/avoid-duplication-in-config-files.html' title='Avoid Duplication in Config Files'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2200747760057310528</id><published>2011-06-25T09:30:00.000-07:00</published><updated>2011-06-25T09:30:04.509-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>How Not To Provide Feedback When Doing Code Review</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;Code review, as any other review process, can often be an attack on someone's ego and incite anger and frustration. Being both on sending and receiving end of such code reviews for years, I have learned a few how-not-to-do-it, or as one might say, anti-patterns of providing code review feedback. Let me know if you agree/disagree with me on the following:&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;You are always reviewing Adam's code while Adam is never reviewing yours.&lt;/li&gt;&lt;li&gt;Your feedback is like "Adam, &lt;b&gt;you should&lt;/b&gt; break down part of this method into a private method" instead of "&lt;b&gt;we can probably&lt;/b&gt; extract a part of..."&lt;/li&gt;&lt;li&gt;You are always suggesting, for example "&lt;b&gt;we should do&lt;/b&gt; x and y and z", instead of asking interesting questions "&lt;b&gt;can we&lt;/b&gt; do x? &lt;b&gt;what if&lt;/b&gt; we did y?" &lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2200747760057310528?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2200747760057310528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/06/how-not-to-provide-feedback-when-doing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2200747760057310528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2200747760057310528'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/06/how-not-to-provide-feedback-when-doing.html' title='How Not To Provide Feedback When Doing Code Review'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6133726199057097274</id><published>2011-06-22T12:58:00.000-07:00</published><updated>2011-06-22T12:59:58.981-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><title type='text'>Service API and Exceptions</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;Too often I see I am using a REST/SOAP API to talk to a third party system that frustrates me because of poor error messaging. Here's an example to illustrate a typical frustration:&lt;br /&gt;&lt;br /&gt;Call: city_service.update_residence_address(city_dueler, new_address)&lt;br /&gt;Response: &amp;lt;status&amp;gt;Failed&amp;lt;/status&amp;gt;&amp;lt;error&amp;gt;Invalid address&amp;lt;/error&amp;gt;&lt;br /&gt;&lt;br /&gt;But the address just seems right to me. So, I need to know specific reason about why the address is wrong. The error message leaves this critical detail. What happens next is, I look for the log files created by the city_service, conceptually supposed to be a third party hosted service. To do this, I SSH to the server, then cd to the logs folder and get lost in many of the cryptic log files. Then eventually I find a log and if I am lucky, I find something like the following:&lt;br /&gt;&lt;br /&gt;InvalidAddressException at:...&lt;br /&gt;...&lt;br /&gt;Street number is not listed..&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Now, I know I had an issue with the streer number. But I can see this only after I looked into the log of the thirdparty server. In an ideal case, I don't have an access to their server. Even if I have it, I cannot easily understand their logs and stack traces! In most API calls to third party applications I have had this&amp;nbsp;frustration&amp;nbsp;to varying degrees.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Here's a lesson learned:&lt;/b&gt;&lt;br /&gt;Next time you expose an API for another app, expose error messages as specific as possible - so that, no details is left buried into your log files.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6133726199057097274?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6133726199057097274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/06/service-api-and-exceptions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6133726199057097274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6133726199057097274'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/06/service-api-and-exceptions.html' title='Service API and Exceptions'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2179532162547209091</id><published>2011-03-17T12:56:00.000-07:00</published><updated>2011-03-17T12:56:38.178-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>NuGet - Why Should You Care?</title><content type='html'>Traditionally the .NET community, or more appropriately the users of .NET framework relied on products from Microsoft - so, in a product stack you are likely to see almost everything coming from Microsoft. However, some community contribution made its way into the main stream - for example, NUnit or Log4Net. But you can literally count the number of such main stream non-Microsoft products in your development stacks with your fingers (sparing a few)!&lt;br /&gt;&lt;blockquote&gt;NuGet makes it easy to share your reusable library/utility code to the community. So, if you've done something cool that you wanna share, you should utilize the platform.&lt;/blockquote&gt;One important difference between your and Microsoft's contribution is, whatever you are contributing is likely to be a piece of software extracted from one of your real world projects. On the other hand, Microsoft attempts to produce something based on public interest and their imagination - often missing the real pain that you or I have. So, this mismatch between the designer and the actual consumer of the product often leaves a lot of opportunity for you. If you did something to solve your own pain on a project, its likely you're not alone. So, share it with us.&lt;br /&gt;&lt;blockquote&gt;NuGet official feed and website is a great place to get feedback.&lt;/blockquote&gt;Did something cool? Well, you should feel good as people will use and appreciate your work. More importantly, they will provide you with interesting ideas and reviews that you haven't thought about. Does this sound useful to you? People will go even further - they will directly contribute to the project with code!&lt;br /&gt;&lt;blockquote&gt;NuGet will challenge you with competition from other contributors.&lt;/blockquote&gt;A healthy competition is a great way of learning from others too. You'll see other contributors attacking the same pain you are solving in a different approach, often directly challenging you! You love challenge, don't you?&lt;br /&gt;&lt;blockquote&gt;If you need hard numbers to get motivated, here's some data from my MvcMailer project:&lt;ul&gt;&lt;li&gt;Downloaded 600+ times in less than 2 months.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Received 60+ emails from people using MvcMailer, mostly encouraging feedback.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;300%+ increase in my blog traffic.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;div&gt;Bottom line is, you should publish your NuGet package if there's any cool project you have done. Or, look out for what others are doing and possibly contribute with your code/suggestions. If you need an idea, look for StackOverflow questions, you'll see there are solvable problems that people are fighting against time and again.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2179532162547209091?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2179532162547209091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/03/nuget-why-should-you-care.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2179532162547209091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2179532162547209091'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/03/nuget-why-should-you-care.html' title='NuGet - Why Should You Care?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5050143991561186956</id><published>2011-03-14T08:56:00.000-07:00</published><updated>2011-03-14T08:58:19.161-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>My 2011 Q1 developer roadmap</title><content type='html'>For me, 2011 Q1 has so far been a good exposure to new techniques, tools, articles and books, thanks to ThoughtWorks book allowance! However, if you are interested, here's what's keeping me busy:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="color: #38761d; font-size: large;"&gt;User Experience:&lt;/span&gt; I find a good user experience is THE thing that you want in anything you design, and if you are writing a software, its even more important. After I read a few books, I have a feeling that its not just a common sense approach, it takes some education and a deep care to produce something usable. Check out my reading list at &lt;a href="http://smsohan.com/"&gt;http://smsohan.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="color: #274e13; font-size: large;"&gt;HTML5&lt;/span&gt;&lt;span style="color: #274e13;"&gt;:&lt;/span&gt; HTML5 is so more than just knowing How To Meet Ladies (HTML)! The popular browsers are all way ahead of the official HTML5 release date, so if you are building something on the web, its time you give it a real shot. Again, I shared my reading list on my website.&lt;/li&gt;&lt;li&gt;&lt;span style="color: #38761d; font-size: large;"&gt;.NET NuGet&lt;/span&gt;&lt;span style="color: #38761d;"&gt;: &lt;/span&gt;Microsoft .NET just got a major component, NuGet package manager, that greatly simplifies the sharing and consuming of reusable libraries. Already there are tens of thousands of downloads for the popular .NET libraries and I believe its just a start. So, if you've done something cool in your project and want that to share with the .NET crowd, you should consider NuGet as a distribution channel and get some traction on it.&lt;/li&gt;&lt;li&gt;&lt;span style="color: #38761d; font-size: large;"&gt;MvcMailer&lt;/span&gt;&lt;span style="color: #38761d;"&gt;:&lt;/span&gt; MvcMailer has got all my developer attention in the recent past. If you haven't checked already, I highly encourage you take a look at its features &lt;a href="https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide"&gt;at this page&lt;/a&gt; and you'll see its a full stack elegant emailing solution that you need in your ASP.NET MVC projects. However, while working on this, I got familiar with the internals of the ASP.NET MVC source code and I consider this as a good experience.&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="color: #38761d; font-size: large;"&gt;Functional Programming&lt;/span&gt;&lt;span style="color: #38761d;"&gt;:&lt;/span&gt; Did you learn one? Which one? Please suggest me your favorite functional language. In the remaining of this Q1, I want to spend some time on a functional programming language, probably F#.&lt;/li&gt;&lt;/ol&gt;Its inspiring to see Calgary getting warmer these days - hope we get some outdoor soccer by the end of 2011 Q1, that would be awesome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5050143991561186956?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5050143991561186956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/03/my-2011-q1-developer-roadmap.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5050143991561186956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5050143991561186956'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/03/my-2011-q1-developer-roadmap.html' title='My 2011 Q1 developer roadmap'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1843109098925814548</id><published>2011-03-07T09:03:00.000-08:00</published><updated>2011-03-07T09:03:35.887-08:00</updated><title type='text'>MvcMailer 1.0 Released</title><content type='html'>Just released MvcMailer 1.0 as promised in my &lt;a href="http://smsohan.blogspot.com/2011/03/whats-coming-in-mvcmailer-nuget-10.html"&gt;previous post&lt;/a&gt;.&amp;nbsp;Download your copy using the following:&lt;br /&gt;&lt;blockquote&gt;Install-Package MvcMailer&lt;/blockquote&gt;Of course, you will find a comprehensive tutorial at: &lt;a href="https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide"&gt;this github wiki&lt;/a&gt; page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1843109098925814548?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1843109098925814548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/03/mvcmailer-10-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1843109098925814548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1843109098925814548'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/03/mvcmailer-10-released.html' title='MvcMailer 1.0 Released'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8033597683665584444</id><published>2011-03-04T12:17:00.000-08:00</published><updated>2011-03-04T12:19:57.160-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Whats Coming in MvcMailer NuGet 1.0?</title><content type='html'>Thanks to 365+ downloads of the MvcMailer NuGet before it hit version 1.0 and now its time to wrap up the NuGet package for an official first release. I got several encouraging feedback on this package and here's what you get from this first release:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Use Scaffold Mailer to generate your mailers with views. &lt;/li&gt;&lt;li&gt;Compose rich emails using your favorite ASP.NET MVC view engine.&lt;/li&gt;&lt;li&gt;Use master pages and pass data using ViewData/ViewBag.&lt;/li&gt;&lt;li&gt;Send multi-part emails for both text and html email readers.&lt;/li&gt;&lt;li&gt;Put images inline so that they are visible even when email client is offline.&lt;/li&gt;&lt;li&gt;Write unit test for your mailers and controllers that use the mailers.&lt;/li&gt;&lt;li&gt;Send attachments.&lt;/li&gt;&lt;li&gt;Send emails asynchronously.&lt;/li&gt;&lt;/ol&gt;To my knowledge, MvcMailer is gonna be the first full stack ActionMailer like Emailing library for ASP.NET MVC 3. If you are an ASP.Net MVC programmer who deeply care about high quality work and maximizing efficiency - you gotta try MvcMailer 1.0 for writing pretty email sending code.&lt;br /&gt;The &lt;a href="https://github.com/smsohan/MvcMailer/wiki/MvcMailer-Step-by-Step-Guide"&gt;github wiki page&lt;/a&gt; has everything you will need to know about MvcMailer. Version 1.0 comes out on Monday. Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8033597683665584444?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8033597683665584444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/03/whats-coming-in-mvcmailer-nuget-10.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8033597683665584444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8033597683665584444'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/03/whats-coming-in-mvcmailer-nuget-10.html' title='Whats Coming in MvcMailer NuGet 1.0?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1148137720037832091</id><published>2011-01-28T09:04:00.000-08:00</published><updated>2011-01-28T09:04:18.418-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>ActionMailer 3 - why do you call instance methods as class/self methods?</title><content type='html'>I didn't even notice this little trick! As long as I didn't have to call deliver_welcome_message (or deliver_*) methods that would magically call welcome_message, I was happy that now the magic is gone. Things are transparent!&lt;br /&gt;Here's an example showing the change: Say you have the following mailer:&lt;br /&gt;&lt;pre class="ruby"&gt;class Notifier &amp;lt; ActionMailer::Base&lt;br /&gt;  def welcome_message(new_user)&lt;br /&gt;    #a warm welcome message&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;Now, prior to Rails 3, or ActionMailer 3, you would write the following to actually call this method to get the benefits of ActionMailer magics, such as finding the view based on method name and so on:&lt;br /&gt;&lt;pre class="ruby"&gt;Notifier.deliver_welcome_message(new_user_instance)  &lt;/pre&gt;I am sure this deliver_* was a clever design decision to solve a hard problem, that is, finding the view name based on the method name. However, in ActionMailer 3, this is gone. Now the question is, if this trick is gone, how come it still finds the view name from the method name? Who sets the view name? To know the answer, first, let's take a look at how we call the welcome_message now.&lt;br /&gt;&lt;pre class="ruby"&gt;Notifier.welcome_message(new_user_instance).send&lt;/pre&gt;&lt;pre class="ruby"&gt;Instead of&lt;/pre&gt;&lt;br /&gt;&lt;pre class="ruby" style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Notifier.&lt;b&gt;new&lt;/b&gt;.welcome_message(new_user_instance).send&lt;/pre&gt;&lt;br /&gt;So, the magic deliver_ prefix is gone. But, did you see the new trick? Well, its a clever design again. The trick this time is, you call your instance method, welcome_message as if it was a class method. But there is no class method called welcome_message, so it instead goes to method_missing and thats how it sets up the view name from this call. Here's the code that does this little trick!&lt;br /&gt;&lt;pre class="ruby"&gt;def method_missing(method, *args) #:nodoc:&lt;br /&gt;    return super unless respond_to?(method)&lt;br /&gt;    new(method, *args).message&lt;br /&gt;  end&lt;/pre&gt;All it does is, instantiates the mailer with the method name!&lt;br /&gt;&lt;br /&gt;However, this design decision has interesting side effects as well. Or may be not side effects, but rather core effects. For example, since you are calling your mailer methods as class methods, you cannot use a single mailer instance to send out multiple emails at the same time. In fact, every mailer has only one instance of message. So, it cannot store two messages at the same time. This is as if, you can have multiple methods in a class, but you cannot call more than one class or you will mess up the class's state!&lt;br /&gt;&lt;br /&gt;Wonder why? Well, this is rooted in another key design choice: ActionMailer::Base is a subclass of AbstractController::Base. Now, if you look at controllers, you will notice that at any given point of time, a controller instance is only responsible for responding to a single action. This is logical for controllers. But how about mailers? I see a mismatch in my mental model and the actual implementation model. I don't see a reason why a mailer is a controller! For the sake of code reuse? But that could be done via delegation anyway.&lt;br /&gt;&lt;br /&gt;I will end this post with one question: &lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #073763;"&gt;Do you think mailer is a controller?&lt;/span&gt;&lt;/b&gt; hints: think about LSP.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1148137720037832091?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1148137720037832091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/01/actionmailer-3-why-do-you-call-instance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1148137720037832091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1148137720037832091'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/01/actionmailer-3-why-do-you-call-instance.html' title='ActionMailer 3 - why do you call instance methods as class/self methods?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3433718449275289819</id><published>2011-01-14T10:13:00.001-08:00</published><updated>2011-01-14T10:14:15.005-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.Net'/><title type='text'>Social Helpers in ASP.Net MVC3 (Facebook, Twitter, Gravatar etc.)</title><content type='html'>This site shows the examples!&lt;br /&gt;&lt;a href="http://www.asp.net/webmatrix/tutorials/13-adding-social-networking-to-your-web-site"&gt;http://www.asp.net/webmatrix/tutorials/13-adding-social-networking-to-your-web-site&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now, the social links and buttons are no longer from a third-party source, its straight from Microsoft. I don't know if this is first-party or second-party :p&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3433718449275289819?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3433718449275289819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/01/social-helpers-in-aspnet-mvc3-facebook.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3433718449275289819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3433718449275289819'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/01/social-helpers-in-aspnet-mvc3-facebook.html' title='Social Helpers in ASP.Net MVC3 (Facebook, Twitter, Gravatar etc.)'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2960811328452399049</id><published>2011-01-13T10:24:00.000-08:00</published><updated>2011-01-13T10:24:09.702-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>My Article at CodeProject: MvcMailer</title><content type='html'>I just released a .Net NuGet package called MvcMailer and to get people super easily started, put an article at CodeProject.com. You are most welcome to the article at&amp;nbsp;&lt;a href="http://www.codeproject.com/KB/aspnet/MvcMailerNuGet.aspx"&gt;http://www.codeproject.com/KB/aspnet/MvcMailerNuGet.aspx&lt;/a&gt;&lt;br /&gt;I welcome your comments and suggestions!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2960811328452399049?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2960811328452399049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/01/my-article-at-codeproject-mvcmailer.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2960811328452399049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2960811328452399049'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/01/my-article-at-codeproject-mvcmailer.html' title='My Article at CodeProject: MvcMailer'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1376939722656777677</id><published>2011-01-07T11:12:00.000-08:00</published><updated>2011-01-07T11:12:50.980-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>C# Named Parameters Can be Very Useful</title><content type='html'>Think about the following code example:&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue; font-family: 'Courier New', Courier, monospace;"&gt;htmlHelper.InputHelper(InputType.CheckBox, name, "true", true /* useViewData */, false /* isChecked */, true /* setId */, false /* isExplicitValue */, htmlAttributes);&lt;/span&gt;&lt;br /&gt;This line is taken from the source code of ASP.NET MVC, or to be more specific its a line from the InputExtension class. I think the intent of the original developer is clear:&lt;br /&gt;Add comment next to arguments so that one can easily read the method call without getting lost in a who's who since there are quite some arguments to pass.&lt;br /&gt;To learn more about named parameters using C#, you can visit &lt;a href="http://weblogs.asp.net/scottgu/archive/2010/04/02/optional-parameters-and-named-arguments-in-c-4-and-a-cool-scenario-w-asp-net-mvc-2.aspx"&gt;this post&lt;/a&gt; by ScottGu.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1376939722656777677?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1376939722656777677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/01/c-named-parameters-can-be-very-useful.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1376939722656777677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1376939722656777677'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/01/c-named-parameters-can-be-very-useful.html' title='C# Named Parameters Can be Very Useful'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8211603062185412710</id><published>2011-01-02T09:28:00.000-08:00</published><updated>2011-01-02T09:28:38.692-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>2011: Yet Another New Year</title><content type='html'>Dear Readers:&lt;br /&gt;Happy 2011. 2010 was a great year. Why?&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Defended my&amp;nbsp;&lt;a href="http://smsohan.com/Email_Auto_Tagging_Sohan.pdf"&gt;MSc thesis&lt;/a&gt;&amp;nbsp;after a moderate 16 months of grad school life.&lt;/li&gt;&lt;li&gt;Published &lt;a href="http://people.ucalgary.ca/~smsohan/#research"&gt;3 papers&lt;/a&gt; in 3 international conferences.&lt;/li&gt;&lt;li&gt;Visited 4 new countries - &lt;a href="http://en.wikipedia.org/wiki/Netherlands"&gt;Netherlands&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Sweden"&gt;Sweden&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Finland"&gt;Finland&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Norway"&gt;Norway&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Visited a few interesting cities - &lt;a href="http://en.wikipedia.org/wiki/Vancouver"&gt;Vancouver&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Victoria"&gt;Victoria&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Edmonton"&gt;Edmonton&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;100+ posts on &lt;a href="http://DrinkRails.com/"&gt;DrinkRails.com&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;25,000+ visits to my two blogs from all over the world.&lt;/li&gt;&lt;li&gt;Developed a fresh new app, Plexina Central, for &lt;a href="http://www.wairever.ca/"&gt;Wairever Inc&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Lived a healthy life.&lt;/li&gt;&lt;li&gt;Bought my first (98 Corolla) and second (2000 CR-V) cars (also sold my first car)!&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;To live up to this standard, 2011 is surely challenged by 2010. Let's see how 2011 rolls: To give you a heads up, I am joining &lt;a href="http://www.ThoughtWorks.com/"&gt;ThoughtWorks&lt;/a&gt; as a Consultant on January 4th!&lt;/div&gt;&lt;div&gt;However, 2010 was the only year in my life when I didn't see my parents and siblings. I hope, 2011 does a better job in this regard. It is getting essential now.&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_Gr1ozXzBWpM/TSC1Pk04TbI/AAAAAAAAAS4/zp7sCUrzofo/s1600/IMG_0109.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="239" src="http://1.bp.blogspot.com/_Gr1ozXzBWpM/TSC1Pk04TbI/AAAAAAAAAS4/zp7sCUrzofo/s320/IMG_0109.JPG" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;This is how I look at the close of 2010&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div&gt;And I want to look leaner at the close of 2011 or even before that :(&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8211603062185412710?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8211603062185412710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2011/01/2011-yet-another-new-year.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8211603062185412710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8211603062185412710'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2011/01/2011-yet-another-new-year.html' title='2011: Yet Another New Year'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_Gr1ozXzBWpM/TSC1Pk04TbI/AAAAAAAAAS4/zp7sCUrzofo/s72-c/IMG_0109.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5960208520945649203</id><published>2010-12-13T12:38:00.000-08:00</published><updated>2010-12-13T12:38:57.456-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.Net'/><title type='text'>DRY - Total 161 Duplicate ArgumentNullException calls in ASP.Net MVC Source Code</title><content type='html'>There are 161 occurrences of the following code pattern inside the ASP.Net MVC source code: See details of which class and which line at&amp;nbsp;&lt;a href="https://gist.github.com/739523"&gt;https://gist.github.com/739523&lt;/a&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;method(type argument)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;if(argument == null){&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;throw new ArgumentNullException("argument")&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;So, in total this pattern introduces 312 lines of duplicate code without whitespaces and 644 lines of duplicate code including whitespaces. And the pattern is simple, just check a condition and throw exception if its true. Not to mention, there are numerous other duplications where &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;string.IsNullOrEmpty&lt;/span&gt;&lt;/span&gt; is used to check for string arguments.&lt;br /&gt;This observation is interesting to me. Since, I think it adds a lot of noise to the code. In fact, if you randomly look at any of the methods - you have a good chance of seeing the first few lines doing this exactly similar thing. And this adds noise to me. Not to mention that, the developer needs to write the code, write tests for this code and if one needs to use this method, somehow should know this in advance that passing a null will result in an exception. But of course, this is not explicit from the method signature unless the developer also takes the pain to put a documentation styled comment and mention about this ArgumentNullException.&lt;br /&gt;To remove this clutter, I think C# can introduce a few language keywords such as the follows:&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;public void Authenticate(&lt;b&gt;required&lt;/b&gt; User user)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;public void AddNewUser(&lt;b&gt;nonblank&lt;/b&gt; string userName)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;A compiler can very easily compile the code and put the exception throwing logic based on these keywords. Call it a syntactic sugar or a language keyword, this is the kind of translation that seems to be perfect for the compilers. And I can foresee it being used in almost all methods we write, since if the methods require an argument they do it for a purpose and most of the time null is not expected anyway!&lt;br /&gt;I don't know if this will reach the people responsible for developing C#, but if it does, I think the community will really love this new language feature.&lt;br /&gt;I know about workarounds using AOP or other hyped-but-seldom-used tricks to solve this problem. But these tricks often make life harder by introducing a learning curve and then punishing the learning by slowing down the application. So, its best to put in as a core language feature. What do you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5960208520945649203?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5960208520945649203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/12/dry-total-161-duplicate.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5960208520945649203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5960208520945649203'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/12/dry-total-161-duplicate.html' title='DRY - Total 161 Duplicate ArgumentNullException calls in ASP.Net MVC Source Code'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8534808707828352230</id><published>2010-12-10T14:41:00.000-08:00</published><updated>2010-12-10T14:51:07.708-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Book Review: Jose Valim's Crafting Rails Applications</title><content type='html'>&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://shared2.pragprog.com/images/covers/190x228/betas/jvrails.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://shared2.pragprog.com/images/covers/190x228/betas/jvrails.jpg" width="266" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Have you already read this?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;The following excerpt &amp;nbsp;by Jose Valim at the end of the book nicely summarizes it:&lt;br /&gt;&lt;blockquote&gt;Finally, you understand Rails better. You can explore other areas of the source code, study other Action Controller and Active Models modules, check other generators implementations or read the source of Railties, Engines and Applications with detail! - Jose Valim&lt;/blockquote&gt;For the impatient readers, this is the best in-depth Ruby on Rails related book I have ever read and you should read this (only 172 pages). Buy the book &lt;a href="http://pragprog.com/titles/jvrails/crafting-rails-applications"&gt;here&lt;/a&gt;. But wait, you could get 40% discount and get the book for $13. I will tell you how, continue reading!&lt;br /&gt;This book literally opens up the Ruby on Rails framework for the readers. So, now I am crystal clear about Metal, Rack, ActiveModel, Rendering, Templating, Migrations, Gems, Engines and so many core concepts. If you are like me, you have cloned &lt;a href="https://github.com/rails/rails"&gt;the Ruby on Rails code&lt;/a&gt; and took a peek into the code to understand, patch some code or just to &lt;a href="http://smsohan.blogspot.com/2010/11/ruby-some-mysterious-language-features.html"&gt;learn some hidden treasures of Ruby&lt;/a&gt;, but had tough time getting hold of the big picture. Well, this book will show you some highways and also some other useful alleys - you can find the rest by yourself!&lt;br /&gt;This book embraces Test Driven Design, so all code examples, and hell yes there's a lot of them, are test driven. So, its unit test, functional test and integration test that drives the show. The topics cover customization of key Ruby on Rails components such as: models, controllers, views, mailers, generators and rack integrations. But the examples are really good as it shows:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Responding to pdf requests so that the server responds with on-the-fly PDF responses&lt;/li&gt;&lt;li&gt;Using Markdown templates for producing HTML&amp;nbsp;and Text multipart emails from a single source template&lt;/li&gt;&lt;li&gt;Rendering views that are stored in a database to work as a simple CMS&lt;/li&gt;&lt;li&gt;Publishing and subscribing to Rails internal event such as SQL queries&lt;/li&gt;&lt;li&gt;Creating a simple rack application&lt;/li&gt;&lt;li&gt;Creating a Rails Engine&lt;/li&gt;&lt;li&gt;Creating custom responders so that you can DRY up your controllers that use exactly same lines for respond_to do |format|...&lt;/li&gt;&lt;li&gt;I18n translations using Redis key-value store and caching&lt;/li&gt;&lt;li&gt;Combining Sinatra with Rails in a single Rails app&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;To ease the process of trying out the DIY code, Jose Valim created an excellent gem called &lt;a href="https://github.com/josevalim/enginex"&gt;enginex&lt;/a&gt;. This gem gives you an incubator to try out the example code while building your own gem and using it from an embedded dummy application, writing tests and even browsing the app. The whole experience of trying out the code is awesome. Before this, I have never read a book that shipped with a gem just so that the readers could easily use the source code. Awesome idea and even better execution.&lt;/div&gt;&lt;div&gt;While explaining the inner workings of Ruby on Rails framework the book also discussed about a few useful gems:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="https://github.com/plataformatec/devise"&gt;devise&lt;/a&gt; - authentication gem.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/josevalim/enginex"&gt;enginex&lt;/a&gt; - produces incubator for gem development and makes it a breeze.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/jnicklas/capybara"&gt;capybara&lt;/a&gt;&amp;nbsp;- drives integrations tests and also works with browsers through selenium etc.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/rtomayko/rdiscount"&gt;rdiscount&lt;/a&gt; -&amp;nbsp;Discount is an implementation of John Gruber's Markdown markup language in C&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/plataformatec/responders"&gt;responders&lt;/a&gt; - DRY up your Ruby on Rails application with a number of handy responders.&lt;/li&gt;&lt;li&gt;&lt;a href="http://rubygems.org/gems/redis"&gt;redis&lt;/a&gt; - an easy to use Key Value store.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/sandal/prawn"&gt;prawn&lt;/a&gt; - Ruby PDF library.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;This book also shows a number of cool tricks. Its overall a fun read. I would say, the final version will be &amp;nbsp;more eye-soothing, but don't wait for that. Grab your ebook now and you will get the updates as they come!&lt;/div&gt;&lt;/div&gt;&lt;div&gt;I would like the book more if Jose Valim could reorganize some of the content. For an example, the text about Generators appear in different places. I think it would be easier to follow if it was in a separate chapter. The same applies for Engine.&lt;/div&gt;&lt;div&gt;I have another observation: the book is written for pro developers with substantial Ruby/Rails application. But I think the topics discussed here could also be equally useful to beginners. The later can be achieved by going a bit slow about some of the topics. Jose Valim, can you add little explanations at places for beginners?&lt;/div&gt;&lt;div&gt;&lt;b&gt;The bottom line is, buy this book and read&lt;/b&gt;. To receive 40% discount, sign up at&amp;nbsp;&lt;a href="http://pragprog.com/"&gt;http://pragprog.com&lt;/a&gt; and refer to a friend and ask her to complete signup. You both get 40% discount. To claim, go to your account and you will find this as soon as your friend completes the signup.&lt;/div&gt;&lt;div&gt;Thank you!&lt;/div&gt;&lt;div&gt;--&lt;/div&gt;&lt;div&gt;This review is not sponsored and contains my opinion only.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8534808707828352230?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8534808707828352230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/12/book-review-jose-valims-crafting-rails.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8534808707828352230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8534808707828352230'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/12/book-review-jose-valims-crafting-rails.html' title='Book Review: Jose Valim&apos;s Crafting Rails Applications'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6130164709513709360</id><published>2010-11-11T21:52:00.000-08:00</published><updated>2010-11-11T21:52:00.758-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Ruby - some mysterious language features</title><content type='html'>Here I will share some of the interesting ruby features that you will notice when looking into mature ruby code by advanced level coders.&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/673781.js?file=RubyAdvancedFeatures"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6130164709513709360?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6130164709513709360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/11/ruby-some-mysterious-language-features.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6130164709513709360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6130164709513709360'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/11/ruby-some-mysterious-language-features.html' title='Ruby - some mysterious language features'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-795360062199708500</id><published>2010-11-10T12:36:00.000-08:00</published><updated>2010-11-10T12:36:36.399-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Upgrading to Ruby on Rails 3 - beware!</title><content type='html'>Ryan Bates had a series of posts (&lt;a href="http://railscasts.com/episodes/225-upgrading-to-rails-3-part-1"&gt;1&lt;/a&gt;, &lt;a href="http://railscasts.com/episodes/226-upgrading-to-rails-3-part-2"&gt;2&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="http://railscasts.com/episodes/227-upgrading-to-rails-3-part-3"&gt;3&lt;/a&gt;) on upgrading your Rails 2.3.x apps to Rails 3.x and sure they are useful. But if you are really doing that, beware of the following changes that you will need to do. It will take a lot of time for sure if you you have a moderate sized app.&lt;br /&gt;&lt;br /&gt;Upgrading your models:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Get rid of all validates_xxx_of with appropriate validates&lt;/li&gt;&lt;li&gt;Get rid of all def validate ... end methods with custom validator&lt;/li&gt;&lt;li&gt;Find out all occurrences of :conditions, :limit, :order and use new active record methods instead&lt;/li&gt;&lt;li&gt;Replace all named_scope with scope&lt;/li&gt;&lt;li&gt;Make sure your acts_as_xxxx plugins are all updated to use Ruby on Rails 3. I had troubles with Authlogic as it shows Based.named_scope is DEPRICATED. Still looking for a solution.&lt;/li&gt;&lt;li&gt;Ruby 1.9.2 doesn't work with soap42 wsdl driver. Haven't found a solution yet as it keeps reporting an error regarding "XML processor module" missing.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Upgrading your controllers:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Find out all occurrences of find method and replace with where.&lt;/li&gt;&lt;li&gt;Find out all calls to Mailer that looks like deliver_xxx and make it xxx.deliver&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;Upgrading your views:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;All erb blocks must start with a   has to be changed to&amp;nbsp; . Do the same for all such erb blocks with a do.&lt;/li&gt;&lt;li&gt;All link_to_remote or remote_form_for or other remote form helpers need to be changed to their non-remote counterparts with a param :remote =&amp;gt; true.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Upgrading your mailers:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;body method is gone, instead of the hashed params to this method, just define instance variables.&lt;/li&gt;&lt;li&gt;All xxx.text.html.erb now becomes xxx.html.erb in the mailer views.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Upgrading the config files:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;The best way is to crate a new rails app and then copy the config folder into yours.&lt;/li&gt;&lt;li&gt;Look at the initializers and clean up any required initializers.&lt;/li&gt;&lt;li&gt;Make sure you have autoload_paths setup to include the lib folder. It is not included by default, so your code from the lib folder won't be accessible.&lt;/li&gt;&lt;li&gt;Look at deprecation warning and you will see lots of config.action_controller.* need to changed to config.*&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Plugins:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;All plugin/lib/rails/tasks/*.rake needs to be copied in to plugin/lib/tasks/*.rake&lt;/li&gt;&lt;li&gt;Make sure your plugins don't use named_scope, if you find any, replace with scope.&lt;/li&gt;&lt;li&gt;Whatever applies to your models should also be applied to your plugins that act on models.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Testing:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Check you have updated shoulda, rspec or whatever lib you use.&lt;/li&gt;&lt;li&gt;Update test codes according to your new lib.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;Upgrading IDE to use RVM:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Your IDE is not smart enough to use RVM. However &lt;a href="http://blendedmusings.blogspot.com/2010/10/getting-rvm-textmate-ruby-187-and-192.html"&gt;use this&lt;/a&gt; to get TextMate ready.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-795360062199708500?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/795360062199708500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/11/upgrading-to-ruby-on-rails-3-beware.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/795360062199708500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/795360062199708500'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/11/upgrading-to-ruby-on-rails-3-beware.html' title='Upgrading to Ruby on Rails 3 - beware!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6385133827587424206</id><published>2010-09-29T16:37:00.000-07:00</published><updated>2010-09-29T16:37:47.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Using nil.to_a or whatever.to_a in ruby</title><content type='html'>Ruby is a programming language for developer happiness and productivity for customers. Here is a quick happiness and productivity tip:&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/603762.js"&gt; &lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6385133827587424206?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6385133827587424206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/09/using-niltoa-or-whatevertoa-in-ruby.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6385133827587424206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6385133827587424206'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/09/using-niltoa-or-whatevertoa-in-ruby.html' title='Using nil.to_a or whatever.to_a in ruby'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6710135981440096615</id><published>2010-09-18T23:18:00.000-07:00</published><updated>2010-09-18T23:18:58.479-07:00</updated><title type='text'>4 design principles</title><content type='html'>Simplicity favors regularity.&lt;br /&gt;Smaller is faster.&lt;br /&gt;Good design demands compromise.&lt;br /&gt;Make the common case fast.&lt;br /&gt;&lt;br /&gt;The four principles of MIPS design that applies to most design jobs we do, even with our personal lives. Agree?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6710135981440096615?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6710135981440096615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/09/4-design-principles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6710135981440096615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6710135981440096615'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/09/4-design-principles.html' title='4 design principles'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-408185538366944107</id><published>2010-09-15T15:39:00.000-07:00</published><updated>2010-09-15T15:42:45.570-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><title type='text'>OO Design Dilemma: Auditing Changes Across Hierarchical Objects</title><content type='html'>Here is a sample UML class diagram of the situation that posed me the OO design dilemma a few days ago.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_Gr1ozXzBWpM/TJFBU_9fSvI/AAAAAAAAAR4/P_vohuF54gQ/s1600/Picture+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://2.bp.blogspot.com/_Gr1ozXzBWpM/TJFBU_9fSvI/AAAAAAAAAR4/P_vohuF54gQ/s640/Picture+1.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;Let me explain with an example,&lt;br /&gt;&lt;blockquote&gt;The &lt;b&gt;Electronic Items&lt;/b&gt; catalog has many &lt;b&gt;Televisions&lt;/b&gt;. The Sony Televisions come with different &lt;b&gt;specifications&lt;/b&gt;, such as refresh rate of 240 Hz, 120 Hz and 60 Hz. However, the 240 Hz ones also comes in different &lt;b&gt;colors&lt;/b&gt; - Black and Grey.&lt;/blockquote&gt;Now, a store manager needs to see the recent changes across all catalogs, such as electronic items, musical instruments and so on. So, if someone added a new Sony 240 Hz color of Dark Black or removed the Grey one, the store manager needs to see this. However, a department manager may need to see changes at all levels, for example whenever one of her Catalog, Product, Specification or its Property is changed. So, if she needs to see all changes under Sony Television, you know, she needs to see changes in the name and value of underlying specifications and their properties as well as changes at the higher level, say, the price.&lt;br /&gt;&lt;br /&gt;Now, the above design looks good from OO perspective. However, since we need to persist the data into a relational database, we will end up with one table per class and foreign keys to interlink. If you are doing Ruby on Rails, you will possibly use polymorphic association between Auditable and the subclasses. For an example, lets consider the following E-R design (not showing all relations):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Gr1ozXzBWpM/TJFE56rQeUI/AAAAAAAAASA/DuAVnIfhJ74/s1600/Picture+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="http://3.bp.blogspot.com/_Gr1ozXzBWpM/TJFE56rQeUI/AAAAAAAAASA/DuAVnIfhJ74/s400/Picture+2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now, given this schema, if you need to find out the latest 50 Log Messages with Author and Associated objects for the Electronics Catalog, how would you write a simple query?&lt;br /&gt;&lt;br /&gt;Look, here is an expected outcome of the query:&lt;br /&gt;Sep 15, 2010&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Jane added new Color : Dark Black for Sony 240 Hz TV&lt;/li&gt;&lt;li&gt;Shon changed the Sony TV Price from $700 to $600&lt;/li&gt;&lt;li&gt;Jakie added a new Specification for Panasonic TV: Aspect Ratio -&amp;gt; 16:9&lt;/li&gt;&lt;/ol&gt;Sep 14, 2010&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;...&lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Now, you see, the date wise grouping can be done once the latest audit logs from all across the Catalog hierarchy is found. But how do you find it given a CatalogID to start with? The following query wont work:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;SELECT TOP 50 * FROM Auditables WHERE AuditableTypeName='Catalog' and AuditableID=my_catalog_id ORDER BY Timestamp DESC&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Because it will only produce the audit logs for the Catalog Object, whereas we are expecting to see all the recent audits for this Catalog and underlying products down to the Specification Property level.&lt;br /&gt;&lt;br /&gt;However, one work around is to query for the Audit Logs for the Catalog. Next, find all the Products of this Catalog and query for the audits for all these products. However, if we are to select top 50 audits for the catalog and its whole hierarchy, how many should we select here? And the problem gets even worse, &amp;nbsp;when you have to repeat the above steps for Specifications and Specification Properties. When you have to take the latest 50 audit logs after you run a few queries, say 10, you have to take 50 audit logs for each &amp;nbsp;of them. Because, the latest 50 results can be from a single query :-(&lt;br /&gt;&lt;br /&gt;Looks like the Auditable class and corresponding design doesn't work well for this situation. So, what is a possible solution?&lt;br /&gt;&lt;br /&gt;It's hard. I don't readily see a great solution. However, workarounds are there. For example, we can change the Audiable class to hold references to all levels of the Catalog object hierarchy. So, in that case the Auditables table will look like the following:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Gr1ozXzBWpM/TJFJLW-zqpI/AAAAAAAAASI/-daGa5FRXTI/s1600/Picture+3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_Gr1ozXzBWpM/TJFJLW-zqpI/AAAAAAAAASI/-daGa5FRXTI/s320/Picture+3.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;With such a schema, we need to ensure if the Audit Log corresponds to a SpecificationProperty, we put references to all its higher level objects. So, the query will be simple. With this assumption, the following query will be able to fetch all audit logs for Catalog and its descendants.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;SELECT TOP 50 * FROM Auditables WHERE CatalogID=my_catalog_id&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Similarly, the following query will produce the audit logs for a single project and its descendents:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;SELECT TOP 50 * FROM Auditables WHERE ProductID=my_product_id&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;However, it has its downsides as well. The Auditables is no longer a general purpose Auditable. If we add a new type of Auditable, we cannot use it unless we alter its properties! High Coupling! Less Reuse. Also, a lot of if-else will be required to show the Audit logs, as it can belong to multiple parents!&lt;br /&gt;&lt;br /&gt;How would you solve this design dilemma? Comments welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-408185538366944107?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/408185538366944107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/09/oo-design-dilemma-auditing-changes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/408185538366944107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/408185538366944107'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/09/oo-design-dilemma-auditing-changes.html' title='OO Design Dilemma: Auditing Changes Across Hierarchical Objects'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_Gr1ozXzBWpM/TJFBU_9fSvI/AAAAAAAAAR4/P_vohuF54gQ/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3218103616149181967</id><published>2010-07-19T13:50:00.000-07:00</published><updated>2010-07-19T13:50:34.937-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Know Your Enemies Before They Kill You!</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2147/2476084336_b3aca1cffc.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://farm3.static.flickr.com/2147/2476084336_b3aca1cffc.jpg" width="300" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;From &lt;a href="http://www.flickr.com/photos/derekb/"&gt;darekb&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;You know what, this is a political world. So, enemies will seemingly look like your friends until the moment when.. well, its time for the kill! My dear readers, its time to know the enemies!&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;I have met with a few enemies off late. I will go one by one here.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;If you are a software developer like me, you will often see this enemy, camouflaged variables, methods, classes and namespaces. For example, I have recently seen a Stack camouflaged as Visitor! I really mean this. I found a class called Visitor, so I was expecting a Visitor Design Pattern implementation or something similar, but what I got was a Stack under the hood with two methods Push and Pop! This enemies are very bad for your health, as they will keep you guessing all the time... you never know what they do from looking at their names!&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Another enemy you will often see are the very skinny ones, to skinny to have any meat in them. I met some enemies like this as well. What happens when you do over engineering with interface explosion and a lot of one method classes? Is it really that difficult? Is it really a class? Is it really a package? I don't think so! You can spoil a piece of code by introducing a class/package for a single method. This enemy often surfaces because of the fact that, the design pattern book only shows classes with one/two key methods in them... which is of course not intended. But this is life... you gotta balance between class explosion and God classes... really, or this enemy will kill you someday.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;I have just touched two common enemies... but there is another enemy we all are aware of, CMD+c (OS X) or Ctrl + C (Win). Its such a pain to copy a code fragment and use it in a different class... this is exactly the form of reuse that kills everything. Make sure you don't let this germ to grow, or it will outgrow you and leave you crying.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Have you reviewed your code by someone else today? If yes, keep up the good work. If not, beware of the enemies before they get you. Best of luck!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3218103616149181967?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3218103616149181967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/07/know-your-enemies-before-they-kill-you.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3218103616149181967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3218103616149181967'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/07/know-your-enemies-before-they-kill-you.html' title='Know Your Enemies Before They Kill You!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2147/2476084336_b3aca1cffc_t.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2311485400333805854</id><published>2010-07-07T15:19:00.000-07:00</published><updated>2010-07-07T15:22:18.678-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>The Greatest Show on Earth and What Else?</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.fifa.com/mm/photo/tournament/competition/01/26/98/56/1269856%5ffull-lnd.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="216" src="http://www.fifa.com/mm/photo/tournament/competition/01/26/98/56/1269856%5ffull-lnd.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;FIFA world cup 2010 is almost coming to an end. This is definitely the greatest show on earth and I have been all occupied with the matches...&lt;br /&gt;&lt;br /&gt;However, the show started almost immediately after I was back from Europe. It was a nice tour, starting a day at Amsterdam. Then to Trondheim (Norway), Stockholm and the best part was the night long sea cruise to Helsinki. An experience to remember for the rest of my life.&lt;br /&gt;&lt;br /&gt;The days were eventful to say the least. At XP 2010, I presented my paper. Here is the presentation for my caring readers :-)&lt;br /&gt;&lt;br /&gt;&lt;iframe frameborder="0" height="342" src="http://docs.google.com/present/embed?id=dghx8mpb_98czd8pcgm" width="410"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;But XP 2010 was also a great place to meet people from around the world who care about software, its crafts and of course impacts. In very short, I found people to be very interested and starting to explore the possibilities with Lean and Kanban. This was a little surprising, because until now it has almost always been Scrum and XP to have a covering meaning of Agile. But, the industry seems to be leaning towards Lean. This is the beauty of being agile, to be able to adapt with time!&lt;br /&gt;However, Norway seemed to be an expensive place even compared to Calgary. But, don't shy away from Norway for this reason, they have spectacular beauty in their landscape. Serene and soothing. While staying in Trondheim, I visited a cathedral from early 1000's. It was amazing to see the cathedral still standing firmly after so many years... extreme engineering! The city was full of historical buildings... if you haven't heard, the Harry Potter building is actually the main academic building at NTNU. (kidding! but the locals really call it by Harry Potter building)&lt;br /&gt;This is me and my wife in front of the Harry Potter Building!&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Gr1ozXzBWpM/TDT4pdKwpgI/AAAAAAAAAQE/hYe-ssiFtpY/s1600/DSC00668.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_Gr1ozXzBWpM/TDT4pdKwpgI/AAAAAAAAAQE/hYe-ssiFtpY/s320/DSC00668.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The city tour and canal cruise at Amsterdam was also a pleasant experience. It was nice to see the centuries old bridges and roads still serving the people so well. It is indeed a bicycle city, everyone in the city seemed to have a bicycle... believe me, they have multi-storied parking facilities only for bicycles! No wonder, why they are so healthy as a nation.&lt;br /&gt;&lt;br /&gt;Next, Stockholm is a city full of life. You will see people dancing, having a drink and enjoying their times with friends everywhere. Especially for people like me, who barely see any crowd in Calgary, will find the place to be very exciting and inspiring.&lt;br /&gt;&lt;br /&gt;Our Stockholm stay was rather short as we went to Helsinki on a sea cruise with Viking line. This was very eventful. Firstly because me and my wife lost each other when I was rushing into the ship as it was just about to start... then I stepped out of the ship, rushing back to the checkin counter and heard her crying like a baby... she was so upset and so scared! But we eventually managed to get into the ship may be 1 min before the doors were locked!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Gr1ozXzBWpM/TDT610TZ9yI/AAAAAAAAAQM/mLayVi4eP5g/s1600/DSC00798.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/_Gr1ozXzBWpM/TDT610TZ9yI/AAAAAAAAAQM/mLayVi4eP5g/s320/DSC00798.JPG" width="303" /&gt;&lt;/a&gt;&lt;/div&gt;But this late entrance came with a surprise! We were given a window side cabin although we didn't get one while booking... and the awesome journey began. It was around 5:30 in the evening and the view from the deck was so nice. And there were live music and dance uptill midnight, nice romantic trip altogether. When we landed at the Helsinki city, we roamed around the tourist hotspots and I slept on the grass. Really! I took the following photo before I fell asleep..&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Gr1ozXzBWpM/TDT7skUCdDI/AAAAAAAAAQU/CFEObS_Fi3c/s1600/DSC00851.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_Gr1ozXzBWpM/TDT7skUCdDI/AAAAAAAAAQU/CFEObS_Fi3c/s320/DSC00851.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;However, back to normal life and the greatest show on earth started! At office, I have kind of wrapped up the application that I was working on for the last 3 months and now heading towards another project. This time its gonna be Java after a looong time... At the lab, trying to wrap my thesis related implementations by the summer. Discovering lot of things as I am working with Lucene, Solr, Tika, Acts as Solr and these full text search engine related stuffs. Hope to push a post about these things when I get some time!&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;But, this is summer in Calgary. And I attended the Canada Day fireworks at the City hall. Here is a photo of the event for my reader:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;a href="http://4.bp.blogspot.com/_Gr1ozXzBWpM/TDT8yE-tK1I/AAAAAAAAAQc/qBoCmechLcY/s1600/DSC00951.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_Gr1ozXzBWpM/TDT8yE-tK1I/AAAAAAAAAQc/qBoCmechLcY/s320/DSC00951.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;This is pretty much it. Looking forward to the events at Calgary Stampedes. Hopefully this will also be a wonderful time pass. I will see if I can be back with some real "meat" in this blog shortly!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2311485400333805854?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2311485400333805854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/07/greatest-show-on-earth-and-what-else.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2311485400333805854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2311485400333805854'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/07/greatest-show-on-earth-and-what-else.html' title='The Greatest Show on Earth and What Else?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Gr1ozXzBWpM/TDT4pdKwpgI/AAAAAAAAAQE/hYe-ssiFtpY/s72-c/DSC00668.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6171837443143372204</id><published>2010-05-03T13:32:00.000-07:00</published><updated>2010-05-03T13:32:29.686-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Calgary'/><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Summer of 2010! Europe, here we come!</title><content type='html'>I just completed my Winter 2010 semester at school. It was so far a good one. I pushed my papers and presentations on the courses of this semester at &lt;a href="http://smsohan.com/#courses"&gt;http://smsohan.com/#courses&lt;/a&gt;&amp;nbsp;If you are interested to read my paper about &lt;b&gt;Tabletop Application Testing&lt;/b&gt; or &lt;b&gt;Communication Challenges with Distributed Agile Teams&lt;/b&gt;, you are most welcome at my site.&lt;br /&gt;&lt;br /&gt;However, its time to look ahead to the summer. And I hope this will be a good one! I just received my driving license after a wonderful training from Drashko and Gordana at the &lt;a href="http://www.yellowpages.ca/bus/Alberta/Calgary/Green-Light-Driving-School/5369272.html"&gt;Green Light Driving School&lt;/a&gt;. If you are looking for a caring and professional driving school in Calgary, I highly recommend them. They will make it easy for you.&lt;br /&gt;&lt;br /&gt;Well, driving license comes with an obligation to buy a car :-) I am right now looking for one used car, probably from Toyota, Honda or Nissan, as people told me these are more reliable than others. I am not sure if I will be buying a car soon, but I already got visa for a Europe trip, my first ever. Its gonna be our second honeymoon in the European land :-) We will be going to Norway for attending the XP 2010 conference where I will be presenting my research paper on &lt;b&gt;Email Auto-Tagging with User Stories&lt;/b&gt;. However, we are planning to see a part of Amsterdam and Stockholm alongside Norway. I have heard all the good things about these sites during summer... staying tuned to that!&lt;br /&gt;&lt;br /&gt;I will also be working on my research project as well as my job at &lt;a href="http://www.Wairever.com/"&gt;Wairever Inc&lt;/a&gt;. This summer will be a busy one. But I am hoping the summer in Calgary will be a lot of fun with friends and at work...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;One little realization:&lt;/b&gt; I figured out that there are two crowds in the software world. One crowd has lot of respect for open source stuffs like &lt;b&gt;Ruby on Rails&lt;/b&gt; and another crowd has that for "established" big players like &lt;b&gt;.Net or Java&lt;/b&gt;. With this realization, I am focusing on getting my .Net knowledge in sync with recent developments as of &lt;b&gt;.Net 4.0 and VS 2010&lt;/b&gt;. I am always reading the blogs and MSDN... but this time I will look into one/few books that give(s) a complete and detailed picture about the deltas in .Net 4.0. &amp;nbsp;However, I will keep posting on my &lt;a href="http://www.DrinkRails.com/"&gt;Drink Rails blog&lt;/a&gt; as usual, almost daily.&lt;br /&gt;&lt;br /&gt;Do you have any recommended book for .Net 4.0? Please use the comments area for that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6171837443143372204?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6171837443143372204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/05/summer-of-2010-europe-here-we-come.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6171837443143372204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6171837443143372204'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/05/summer-of-2010-europe-here-we-come.html' title='Summer of 2010! Europe, here we come!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7315303048681700116</id><published>2010-04-26T08:38:00.001-07:00</published><updated>2010-04-26T08:38:29.228-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Using Authlogic and single access token for API access</title><content type='html'>&lt;a href="http://github.com/binarylogic/authlogic"&gt;Bynarylogic's authlogic&lt;/a&gt; has gained much popularity for its out of the box solution to ruby on rails authentication. Yesterday, I was working on giving API access to my ruby on rails application so that other apps can use my RESTful services. The authenticated API access usually involves the following steps:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;API_KEY or a token to identify/authenticate an API call.&lt;/li&gt;&lt;li&gt;Authentication of an API caller using the API_KEY.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Authlogic comes with in-built support for this. The following steps will do it for you:&lt;/div&gt;&lt;div&gt;&lt;script src="http://gist.github.com/379478.js"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7315303048681700116?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7315303048681700116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/04/using-authlogic-and-single-access-token.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7315303048681700116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7315303048681700116'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/04/using-authlogic-and-single-access-token.html' title='Using Authlogic and single access token for API access'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1703706026329814409</id><published>2010-03-31T23:10:00.000-07:00</published><updated>2010-04-07T16:08:06.751-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>flash.now - did you know?</title><content type='html'>Well, I didn't know this until late. If you are like me, you have often wondered when you saw those unwanted flash messages appearing after a request, sometimes after ajax requests when you do a redirect, all on a sudden that flash shows up!&lt;br /&gt;Well, as you have thought, the Ruby on Rails people have solved this problem way before now. The solution is to wisely use flash.now[] and flash[]. Here are a few tips:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Use flash.now[] when you are flashing:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;on ajax requests&lt;/li&gt;&lt;li&gt;before a call to render :action =&amp;gt; :my_action, as often found in failure cases of create and update actions&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Use flash[] when you are flashing:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;before a redirect_to, often found in the success cases of create and update actions&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;In general, use flash.now[] when you don't want to carry over the flash to the next http request and flash[] otherwise. The FlashHash class has more detail on this&lt;a href="http://api.rubyonrails.org/classes/ActionController/Flash/FlashHash.html"&gt; at the ruby on rails API page&lt;/a&gt;. Hope this helps you to get rid of those annoying and often embarrassing out-of-context flash messages!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1703706026329814409?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1703706026329814409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/03/flashnow-did-you-know.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1703706026329814409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1703706026329814409'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/03/flashnow-did-you-know.html' title='flash.now - did you know?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8312887872726871433</id><published>2010-03-23T10:33:00.000-07:00</published><updated>2010-03-23T10:33:33.680-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>What's up next?</title><content type='html'>Hello Readers:&lt;br /&gt;Wish you all are doing great as the Spring already started :-)&lt;br /&gt;Recently my grad courses are keeping me busy with assignments and projects as the term comes close to an end. So, I haven't had much time to spend on blogging other than posting the Ruby on Rails link blog called &lt;a href="http://www.DrinkRails.com/"&gt;www.DrinkRails.com&lt;/a&gt;. However, for my readers, I thought I would post the recent presentation that I put for the Agile course here:&lt;br /&gt;&lt;iframe frameborder="0" height="342" src="http://docs.google.com/present/embed?id=dghx8mpb_59chmh48hh" width="410"&gt;&lt;/iframe&gt;&lt;br /&gt;But I am looking forward to start a new project with Wairever (&lt;a href="http://www.Wairever.com/"&gt;www.Wairever.com&lt;/a&gt;), a Calgary based health care IT solution vendor. I hope that will fuel me with a lot of new concepts and as always, I will try to keep my learning posted here at my blog. Stay tuned! BTW, if you are Ruby on Rails developer or wanna be so, please let me know your feedback about the DrinkRails.com link blog.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8312887872726871433?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8312887872726871433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/03/whats-up-next.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8312887872726871433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8312887872726871433'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/03/whats-up-next.html' title='What&apos;s up next?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2752787172405931222</id><published>2010-03-11T08:48:00.000-08:00</published><updated>2010-03-11T08:54:30.360-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Ruby on Rails Security Review: An Experience Report</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3359/3244476512_5fbe80a529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="341" src="http://farm4.static.flickr.com/3359/3244476512_5fbe80a529.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;Image credits to &lt;a href="http://www.flickr.com/photos/intherough/"&gt;Wink&lt;/a&gt;&amp;nbsp;on Flickr (creative commons)&lt;/div&gt;&lt;br /&gt;I was reviewing a Ruby on Rails source code to see the security implementations they have so far. They are about to launch their product for the first release and wanted to ensure they have the most obvious things checked. So, in a sense it was not supposed to be a hacking job for me, rather to check if the most well known security measures are in place. This is what I looked into so far:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Password:&lt;/b&gt; Password was encrypted using a salt. However, the default logger would log the password as they didn't use the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;filter_paramerer_logging&lt;/span&gt; method.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Cross-Site Scripting&lt;/b&gt;&lt;b&gt;: &lt;/b&gt;I was able to easily inject a script by just entering &amp;lt;script&amp;gt;alert('Script')&amp;lt;/script&amp;gt; when I signed up to the system and every time it would open an alert window whenever I navigated to a new page! So, I recommended them to use &amp;lt;%= h %&amp;gt;. However, Rails 3 does a good job of making this a default.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Authorization: &lt;/b&gt;I found the weakest measure in the implementation of Authorization. For an example, there is a calendar in the web app where one can add/remove events. I found that any logged in user, not necessarily the event owner, could change/remove any calendar event. This was a shocker. Next, I found this same thing happening to the core models as well. The catch here is, they had a filter that checked if a user was logged in, but they didn't check if a user has rights to modify an instance of the object. For example, there is a project model, that can only be modified by the project owner. However, this per object ownership was not authorized and it was a huge potential security bug in my opinion.&lt;/li&gt;&lt;li&gt;&lt;b&gt;File uploads: &lt;/b&gt;The app was designed to upload the files to a folder underneath the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;public&lt;/span&gt; folder. Which means, if the rails server was down, apache would serve the files directly to the user bypassing whatever security measure was taken inside the app.&lt;/li&gt;&lt;li&gt;&lt;b&gt;PRG violation: &lt;/b&gt;This is a good idea to follow a post-redirect-get pattern when an object is modified through &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;post/delete/put&lt;/span&gt; to ensure pressing the browser refresh button doesn't re-invoke the change. This wasn't done at some places which might end in multiple payments and such severe risks.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Direct public release: &lt;/b&gt;I was a bit concerned that they wanted to go public release with their first ever release, even before having an alpha or at least in-house user. This is important because this application deals with money and credit cards. Trust is very important for such apps. So, I advised them to try this for some real works at home other than the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;"asdf asdf asdf...."(!)&lt;/span&gt;&amp;nbsp;kind inputs. This will help them spotting some of the odd behaviors early and cause less embarrassment.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;It was only a 4 hour assignment for me. Also, I was only limited to the source code and the test deployment that they have now. However, it seemed to me that, they might spend a few hours to fix the obvious errors and do some in-house real use before going to a public release.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2752787172405931222?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2752787172405931222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/03/ruby-on-rails-security-review.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2752787172405931222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2752787172405931222'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/03/ruby-on-rails-security-review.html' title='Ruby on Rails Security Review: An Experience Report'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3359/3244476512_5fbe80a529_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6106813180816254473</id><published>2010-03-09T21:01:00.000-08:00</published><updated>2010-03-09T21:02:05.285-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Ruby on Rails or Rails on Ruby?</title><content type='html'>All on a sudden, this thing popped up in my mind. What we are calling Ruby on Rails, is this actually "Ruby" on "Rails" or the other way around? Is this upside down? Here's my mental picture of the RoR framework:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm1.static.flickr.com/86/239456671_8eb4cc1e15.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="480" src="http://farm1.static.flickr.com/86/239456671_8eb4cc1e15.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;Image credits to &lt;a href="http://www.flickr.com/photos/thefoologs/"&gt;Foo Fighter&lt;/a&gt;&amp;nbsp;on Flickr(creative commons)&lt;/div&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Ruby is a self-sustained language. As a language this is completely ignorant of the Rails Framework. So, I think there is no dependency from Ruby to Rails.&lt;/li&gt;&lt;li&gt;Rails is a framework built using Ruby as a language. So, there is a strict dependency from Rails to Ruby.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;What do you think? Would you call it "Rails on Ruby" or "Ruby on Rails"? I see a point of agreement for the ones who want to call it RoR, no damage done :-)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Lets see how this "on" preposition works for other language/platform pairs:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Java on Struts vs&amp;nbsp;Struts on Java&lt;/li&gt;&lt;li&gt;PHP on Cake vs&amp;nbsp;Cake on PHP&lt;/li&gt;&lt;li&gt;C# on .Net vs&amp;nbsp;.Net on C#&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Confused? Well, then you can use RoR for now!&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6106813180816254473?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6106813180816254473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/03/ruby-on-rails-or-rails-on-ruby.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6106813180816254473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6106813180816254473'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/03/ruby-on-rails-or-rails-on-ruby.html' title='Ruby on Rails or Rails on Ruby?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm1.static.flickr.com/86/239456671_8eb4cc1e15_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7091055763423973692</id><published>2010-02-26T11:24:00.000-08:00</published><updated>2010-02-26T11:28:13.147-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails Source Code Walkthrough #1: the ActiveModel Module</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 11px;"&gt;&lt;span class="Apple-style-span" style="font-family: Times;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande'; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 11px;"&gt;&lt;span class="Apple-style-span" style="font-family: Times;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;I was taking a look into the fresh ActiveModel module of Rails 3 as of github revision #100644. Here is what I learned:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Learned about new feature called &lt;a href="http://github.com/rails/rails/blob/c1304098cca8a9247a9ad1461a1a343354650843/activesupport/lib/active_support/dependencies/autoload.rb"&gt;autoload&lt;/a&gt;. Rails Inside has a small yet &lt;a href="http://www.rubyinside.com/ruby-techniques-revealed-autoload-1652.html"&gt;useful autoload example here&lt;/a&gt;. It is a mechanism to lazy load your modules, so delaying the load unless the module methods are actually called. A call to autoload simply marks it as a potential include, but the actual include takes place only when you first use something on that module. I has a syntax like the following:&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 17px; white-space: pre;"&gt;&lt;span class="nb" style="color: #0086b3; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;autoload&lt;/span&gt; &lt;span class="ss" style="color: #990073; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;:Callbacks&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Using autoload, the ActiveModel module loads a number of other modules such as: &lt;span class="Apple-style-span" style="color: #990073; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 17px; white-space: pre;"&gt;AttributeMethods, Callbacks, Dirty, Observer, Observing etc.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Also, it initializes the &lt;a href="http://guides.rubyonrails.org/i18n.html"&gt;I18n&lt;/a&gt; Internationalization with the default en locale.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;What's inside AttributeMethods?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;This module defines class methods that lets you define attribute methods for the objects. I learned that you can have prefix, suffix and affix appended to your attributes that go to to a default method. For example, consider the following example right from the code:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; font-weight: normal; line-height: 14px; white-space: normal;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; font-weight: normal; line-height: 14px; white-space: normal;"&gt;&lt;pre style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font: normal normal normal 115%/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;div class="line" id="LC152" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;      #   class Person&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC153" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# &lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC154" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     include ActiveModel::AttributeMethods&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC155" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     attr_accessor :name&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC156" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     &lt;/span&gt;&lt;span class="c1" style="font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;attribute_method_suffix '_short?'&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC157" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     &lt;/span&gt;&lt;span class="c1" style="font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;define_attribute_methods [:name]&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC158" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC159" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     private&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC160" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# &lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC161" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     def &lt;b&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;attribute_short?&lt;/span&gt;&lt;/b&gt;(attr)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC162" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#       send(attr).length &amp;lt; 5&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC163" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#     end&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC164" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   end&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC165" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC166" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   person = Person.new&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC167" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   person.name = "Bob"&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC168" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   person.name          # =&amp;gt; "Bob"&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC169" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   &lt;b&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;person.name_short?&lt;/span&gt;&lt;/b&gt;   # =&amp;gt; true&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Isn't this amazing?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside callbacks?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Callbacks module is responsible for firing your before, after and around callbacks on ActiveModel models.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside Conversion?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Conversion module only has 3 methods, to_model, to_key and to_param . These methods can be overriden to allow custom conversion of the ActiveModel objects.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside Dirty?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;The dirty module is all about dirty tracking methods of your ActiveModels. It has methods like changes, changed?, changed, reset_attr! etc. that you can use to track changes  of your model objects. Thinks like history tracking or audition on changes can be done using this module methods.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside Errors module?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;This module has everything that deals with generating errors on ActiveModel validations. One ruby feature I learned from this module that I didn't know before. Its something like an indexer in C#. Here is an example from the source code:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; line-height: 14px; white-space: normal;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; line-height: 14px; white-space: normal;"&gt;&lt;pre style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font: normal normal normal 115%/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;div class="line" id="LC73" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# When passed a symbol or a name of a method, returns an array of errors for the method.&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC74" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# &lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC75" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   p.errors[:name]   #=&amp;gt; ["can not be nil"]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC76" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   p.errors['name']  #=&amp;gt; ["can not be nil"]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC77" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;def&lt;/span&gt; &lt;span class="nf" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;[]&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;attribute&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC78" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;if&lt;/span&gt; &lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;errors&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;=&lt;/span&gt; &lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;get&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;attribute&lt;/span&gt;&lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;to_sym&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC79" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;errors&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC80" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;else&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC81" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;set&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;attribute&lt;/span&gt;&lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;to_sym&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;,&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;[]&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC82" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC83" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC84" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;/div&gt;&lt;div class="line" id="LC85" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# Adds to the supplied attribute the supplied error message.&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC86" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# &lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC87" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   p.errors[:name] = "must be set"&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC88" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;#   p.errors[:name] #=&amp;gt; ['must be set']&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC89" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;def&lt;/span&gt; &lt;span class="nf" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;[]=&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;attribute&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;,&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;error&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC90" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nb" style="color: #0086b3; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;self&lt;/span&gt;&lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;[&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;attribute&lt;/span&gt;&lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;.&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;to_sym&lt;/span&gt;&lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;]&lt;/span&gt; &lt;span class="o" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;error&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC91" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside the Naming module?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Naming module is all about singular, plural, human and such names for your models! This methods are used to define the routes as well as in views. You can override such methods to provide a custom pluralized name for your model.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside observing?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Rails Observers provide you a clean implementation of the &lt;a href="http://en.wikipedia.org/wiki/Observer_pattern"&gt;Observer design pattern&lt;/a&gt;. It extends on top of the &lt;a href="http://ruby-doc.org/docs/ProgrammingRuby/html/lib_patterns.html"&gt;default observer module from Ruby&lt;/a&gt;. These observers are often use for implementing Aspect oriented programming as well as the code that are neither part of models or controllers, rather fall in between the two. Email notification is an useful example from &lt;a href="http://guides.rubyonrails.org/action_mailer_basics.html"&gt;Rails Guides&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside the Railtie module?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Well, not much! But it glues up ActiveModel with Rails! Just two lines of code as folllows:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; line-height: 14px; white-space: normal;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; line-height: 14px; white-space: normal;"&gt;&lt;pre style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font: normal normal normal 115%/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;div class="line" id="LC1" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="nb" style="color: #0086b3; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;require&lt;/span&gt; &lt;span class="s2" style="color: #dd1144; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;"active_model"&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="nb" style="color: #0086b3; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;require&lt;/span&gt; &lt;span class="s2" style="color: #dd1144; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;"rails"&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's up with Serialization?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;It has only one method that generates a hash based on the serializable attributes with :only and :except filter!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside Serializers?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;It has two serializers, one for json and another for xml. This two works great out of the box. However, if you need to tweak it, it should be very simply done by subclassing this classes.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;What's inside translation?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;It translates your model attribute names to match your locale using I18n. The default skim looks for the following naming in your local yml file when called through the method &lt;span class="Apple-style-span" style="color: #990000; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font-weight: bold;"&gt;human_attribute_name&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;b&gt;activemodel.attributes.underscore_model_name.attribute_name&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;Whats inside Validations?&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;This is a freshly renovated module for Rails 3, as it merged the validates_presence like methods into a single method validate that lets you keep all your validations for a model with a single call. Also you can easily reuse custom validators through out your models.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;But this forked a few more modules, one per kind of validation. All these validations and your potential custom validators will probably be descendent of the Validator class that has the following method:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #990000; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 12px; line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: black; font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; font-weight: normal; line-height: 14px; white-space: normal;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #990000; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 12px; line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: black; font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; font-weight: normal; line-height: 14px; white-space: normal;"&gt;&lt;pre style="font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; font: normal normal normal 115%/normal Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;&lt;div class="line" id="LC114" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# Override this method in subclasses with validation logic, adding errors&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC115" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="c1" style="color: #999988; font-style: italic; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;# to the records +errors+ array where necessary.&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC116" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;def&lt;/span&gt; &lt;span class="nf" style="color: #990000; font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;validate&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;(&lt;/span&gt;&lt;span class="n" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;record&lt;/span&gt;&lt;span class="p" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC117" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;raise&lt;/span&gt; &lt;span class="no" style="color: teal; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC118" style="line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="k" style="font-weight: bold; line-height: 1.4em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Some in-built implementation of this validator are acceptance, confirmation, exclusion etc. I learned something new here, the&amp;nbsp;&lt;span class="Apple-style-span" style="color: teal; font-family: 'Bitstream Vera Sans Mono', Courier, monospace; font-size: 12px; line-height: 16px;"&gt;NotImplementedError &lt;span class="Apple-style-span" style="color: black; font-family: Times; font-size: medium; line-height: 17px;"&gt;exception.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;So, what's the big learning here?&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;I will use Modules to modularize my ruby code. This perfectly makes sense and also this is how one can come up with plugins out of their code base. Having the small bits in a module also facilitates reusability inside a project.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;The source of ActiveModel is very simple and completely ignorant of its underlying database. This is the big change of liberating Rails from ActiveRecord, which I think is not a matter for most rails developer anyway! But its a good lesson learned.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Once I see some time, I would like to jump in to the development of Rails, at least make some initial contribution.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 17px; white-space: pre;"&gt;Stay tuned for more posts on Rails 3 source code.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7091055763423973692?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7091055763423973692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/02/rails-source-code-walkthrough-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7091055763423973692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7091055763423973692'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/02/rails-source-code-walkthrough-1.html' title='Rails Source Code Walkthrough #1: the ActiveModel Module'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8459188019702118312</id><published>2010-02-25T12:05:00.000-08:00</published><updated>2010-02-25T12:05:31.213-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Why would you spend $10 to learn to use Basecamp?</title><content type='html'>This is sounding very strange to me indeed! 37Signals is very much known for creating the simplest of interfaces and I really found people finding it very intuitive. But this is strange... now they are asking people to buy a book for $10 to learn how to use Basecamp! Can you believe it? See the sales post (!) here at&amp;nbsp;&lt;a href="http://feedproxy.google.com/~r/typepad/37signals/products/~3/jK7OxAFFZ84/sams-teach-yourself-basecamp-in-10-minutes-is-a-comprehensive-guide-to-basecamp.html"&gt;"Sams Teach Yourself Basecamp in 10 Minutes" is a comprehensive guide to Basecamp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8459188019702118312?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8459188019702118312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/02/why-would-you-spend-10-to-learn-to-use.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8459188019702118312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8459188019702118312'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/02/why-would-you-spend-10-to-learn-to-use.html' title='Why would you spend $10 to learn to use Basecamp?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-717056429180573994</id><published>2010-02-23T19:17:00.000-08:00</published><updated>2010-02-23T19:17:31.467-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Ruby on Rails Interview Questions: Advanced</title><content type='html'>In my previous post, I listed a few &lt;a href="http://smsohan.blogspot.com/2010/02/ruby-on-rails-interview-questions.html"&gt;general interview questions for Ruby on Rails&lt;/a&gt; jobs. This one is intended to be more of an advanced level, not for the rookies :-)&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;What is Rack?&lt;/li&gt;&lt;li&gt;Sketch out a deployment architecture of a Ruby on Rails application utilizing multiple servers.&lt;/li&gt;&lt;li&gt;How can you secure a rails application to counter for Session Fixation?&lt;/li&gt;&lt;li&gt;Where can I get the core rails framework source code?&lt;/li&gt;&lt;li&gt;How can you reuse the models from one rails project into another?&lt;/li&gt;&lt;li&gt;Explain one plugin that you extracted out of your source code.&lt;/li&gt;&lt;li&gt;What is the difference between pre-initializers and initializers?&lt;/li&gt;&lt;li&gt;How can you easily switch your logger to use Log4r?&lt;/li&gt;&lt;li&gt;How would you design the logging standard for your rails application?&lt;/li&gt;&lt;li&gt;How can you implement asynchronous messaging in Rails?&lt;/li&gt;&lt;li&gt;What will you do to look for a possible memory leak in Rails application?&lt;/li&gt;&lt;li&gt;How can you run a profiler?&lt;/li&gt;&lt;li&gt;What is lambda?&lt;/li&gt;&lt;li&gt;What is Proc? When did you use this?&lt;/li&gt;&lt;li&gt;How can you use before and after callbacks of your rails methods to halt a database insert/update/delete?&lt;/li&gt;&lt;li&gt;How can you reuse your before and after callback methods across multiple models?&lt;/li&gt;&lt;li&gt;Define an architecture to store files uploaded to an application so that they are only accessible to valid users.&lt;/li&gt;&lt;li&gt;How would you change your asset storage to use a static server?&lt;/li&gt;&lt;li&gt;Explain one situation when you used rails caching.&lt;/li&gt;&lt;li&gt;What kinds of caching comes in-built with Rails?&lt;/li&gt;&lt;li&gt;Can you explain the use of 'dynamic' features of Ruby on the core Rails framework?&lt;/li&gt;&lt;li&gt;How can you call a SOAP web service from a rails application?&lt;/li&gt;&lt;li&gt;Your application needs to send a lot of email notifications. How would you design the notification so that the end user doesn't get stuck for email sending delays?&lt;/li&gt;&lt;li&gt;What is a mongrel cluster?&lt;/li&gt;&lt;li&gt;Can you explain if the clusters share a same memory? Can one cluster handle a request from a client that was handled by another?&lt;/li&gt;&lt;li&gt;How would you internationalize your application interface?&lt;/li&gt;&lt;li&gt;How can you create a rails generator?&lt;/li&gt;&lt;li&gt;Have you ever used a polymorphic association?&lt;/li&gt;&lt;li&gt;How can you define a plugin that adds a new class method to ActiveRecord::Base?&lt;/li&gt;&lt;li&gt;What are the three most significant changes in Rails 3 in your eyes?&lt;/li&gt;&lt;li&gt;How can you implement complex reporting using ruby on rails?&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;I am sure this list will go on and on. But I have found most people asking questions about scalability, deployment issues, security and such architectural level questions to extract out the in-depth understanding of such core concepts. Where to learn more on such advanced stuffs?&amp;nbsp;&lt;a href="http://guides.rubyonrails.org/"&gt;Ruby on Rails Guides&lt;/a&gt; and &lt;a href="http://stackoverflow.com/questions/tagged/ruby-on-rails"&gt;Stack Overflow&lt;/a&gt; are my favorite places. However, its good to keep an eye on the edge rails to see what's happening today!&amp;nbsp;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-717056429180573994?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/717056429180573994/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/02/ruby-on-rails-interview-questions_23.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/717056429180573994'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/717056429180573994'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/02/ruby-on-rails-interview-questions_23.html' title='Ruby on Rails Interview Questions: Advanced'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3299396765789538442</id><published>2010-02-22T23:12:00.000-08:00</published><updated>2010-02-22T23:24:00.253-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Ruby on Rails Interview Questions</title><content type='html'>&lt;b&gt;Ruby Specific Questions&lt;/b&gt;&lt;br /&gt;The best place for learning ruby is to get started with the &lt;a href="http://ruby-doc.org/docs/ProgrammingRuby/"&gt;programming-ruby&lt;/a&gt;. It fairly covers the important bits in a very readable language. Here are a few quick questions on ruby:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;What is rubygems?&lt;/li&gt;&lt;li&gt;What is a Symbol?&lt;/li&gt;&lt;li&gt;What is the difference between a Symbol and String?&lt;/li&gt;&lt;li&gt;What is the purpose of yield?&lt;/li&gt;&lt;li&gt;How do you define class variables?&lt;/li&gt;&lt;li&gt;How do you define instance variables?&lt;/li&gt;&lt;li&gt;How do you define global variables?&lt;/li&gt;&lt;li&gt;How can you dynamically define a method body?&lt;/li&gt;&lt;li&gt;What is a Range?&lt;/li&gt;&lt;li&gt;How can you implement method overloading?&lt;/li&gt;&lt;li&gt;What is the difference between '&amp;amp;&amp;amp;' and 'and' operators?&lt;/li&gt;&lt;li&gt;What is the convention for using '!' at the end of a method name?&lt;/li&gt;&lt;li&gt;What is a module?&lt;/li&gt;&lt;li&gt;What is mixin?&lt;/li&gt;&lt;li&gt;How will you implement a singleton pattern?&lt;/li&gt;&lt;li&gt;How will you implement a observer pattern?&lt;/li&gt;&lt;li&gt;How can you define a constant?&lt;/li&gt;&lt;li&gt;How can you define a custom Exception?&lt;/li&gt;&lt;li&gt;How can you fire a method when a module is included inside a class?&lt;/li&gt;&lt;li&gt;What is the default access modifier (public/protected/private) for a method?&lt;/li&gt;&lt;li&gt;How can you call the base class method from inside of its overriden method?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Rails Specific Questions&lt;/span&gt;&lt;br /&gt;A thorough reading of the articles at&amp;nbsp;&lt;a href="http://guides.rubyonrails.org/"&gt;Ruby on Rails Guides&lt;/a&gt;&amp;nbsp;can be very useful for starters as well as a refresher for veterans. The following bunch of questions are specific to rails, in no particular order. The &lt;a href="http://www.pragprog.com/"&gt;Pragmatic Bookshelf&lt;/a&gt; has a fantastic book for beginners called&amp;nbsp;&lt;a href="http://www.pragprog.com/frequently-asked-questions/ebooks"&gt;Agile Web Development Using Ruby on Rails&lt;/a&gt;.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Define the Rails MVC implementation using an example.&lt;/li&gt;&lt;li&gt;What is a named scope? (or Scope in Rails 3).&lt;/li&gt;&lt;li&gt;Can you give an example of a class that should be inside the lib folder?&lt;/li&gt;&lt;li&gt;Where should you put code that is supposed to run when your application launches?&lt;/li&gt;&lt;li&gt;What deployment tool do you use?&lt;/li&gt;&lt;li&gt;How can you migrate your database schema one level down?&lt;/li&gt;&lt;li&gt;What is an observer?&lt;/li&gt;&lt;li&gt;What is a sweeper?&lt;/li&gt;&lt;li&gt;How can you implement caching in Rails?&lt;/li&gt;&lt;li&gt;What is a filter? When it is called?&lt;/li&gt;&lt;li&gt;How can you divide your controllers into separate modules?&lt;/li&gt;&lt;li&gt;What is RESTful routing?&lt;/li&gt;&lt;li&gt;How can you list all routes for an application?&lt;/li&gt;&lt;li&gt;How can you send a multi-part email?&lt;/li&gt;&lt;li&gt;Is it possible to embed partial views inside layouts? How?&lt;/li&gt;&lt;li&gt;What is the purpose of RJS?&lt;/li&gt;&lt;li&gt;How can you create a REST API for your application?&lt;/li&gt;&lt;li&gt;How can you define a new environment called 'staging'?&lt;/li&gt;&lt;li&gt;What is Rake?&lt;/li&gt;&lt;li&gt;What is Capistrano?&lt;/li&gt;&lt;li&gt;What is a polymorophic association?&lt;/li&gt;&lt;li&gt;How can you implement a polymorphic association?&lt;/li&gt;&lt;li&gt;What is a has and belongs to many association?&lt;/li&gt;&lt;li&gt;What is the difference between has_one and belongs_to?&lt;/li&gt;&lt;li&gt;How can you implement single table inheritance?&lt;/li&gt;&lt;li&gt;What is eager loading?&lt;/li&gt;&lt;li&gt;How can you eager load associated objects?&lt;/li&gt;&lt;li&gt;How can you add a custom validation on your model?&lt;/li&gt;&lt;li&gt;How can you implement a custom theme for your forms?&lt;/li&gt;&lt;li&gt;Why is fields_for used for?&lt;/li&gt;&lt;li&gt;What is the purpose of a helper method?&lt;/li&gt;&lt;li&gt;What is flash?&lt;/li&gt;&lt;li&gt;How can you install the missing gems that are required by your application in the simplest way?&lt;/li&gt;&lt;li&gt;How can you implement internationalization?&lt;/li&gt;&lt;li&gt;How can you show search user friendly urls instead of using only numeric ids?&lt;/li&gt;&lt;li&gt;How can you configure your application for different environments?&lt;/li&gt;&lt;li&gt;How can you instruct rails logger to ignore passwords and such fields while logging?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;Test Frameworks&lt;/b&gt;&lt;br /&gt;Ruby on Rails has a number of built-in and a few other third-party test frameworks. Here are a few sample questions on such frameworks:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Are you familiar with unit testing?&lt;/li&gt;&lt;li&gt;How does functional testing differ from unit testing?&lt;/li&gt;&lt;li&gt;Have you ever used a mocking framework?&lt;/li&gt;&lt;li&gt;Are you familiar with BDD using RSpec or Cucumber?&lt;/li&gt;&lt;li&gt;What is an alternative to using test fixtures?&lt;/li&gt;&lt;li&gt;How can you reuse part of a text fixture?&lt;/li&gt;&lt;li&gt;How do you specify associations in the test fixture yml files?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;Plugins&lt;/b&gt;&lt;br /&gt;Plugins are the principal mechanism to reuse code. The open-source community is at full-bloom when it comes about plugins. The &lt;a href="http://railsplugins.org/plugins"&gt;Rails Plugins site&lt;/a&gt; has a really good list of such plugins from the community.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;What plugin would you recommend for user authentication and authorization?&lt;/li&gt;&lt;li&gt;What plugin do you use for full-text search?&lt;/li&gt;&lt;li&gt;How can you implement a state machine?&lt;/li&gt;&lt;li&gt;What is the difference between a plugin and a gem?&lt;/li&gt;&lt;li&gt;How can you create a plugin?&lt;/li&gt;&lt;li&gt;Can you please name a few useful plugins?&lt;/li&gt;&lt;li&gt;How can you implement a search feature that searches for multiple models?&lt;/li&gt;&lt;li&gt;How can you upload a flie to a server?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;Architecture Related Questions&lt;/b&gt;&lt;br /&gt;This questions can be from different angles like: quality, security, scalability, manageability, interoperability, reusability and all the other ilities you name! Here are a few example questions:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Is Rails scalable?&lt;/li&gt;&lt;li&gt;What are the key deployment challenges?&lt;/li&gt;&lt;li&gt;How can you safeguard a rails application from SQL injection attack?&lt;/li&gt;&lt;li&gt;How can you secure a rails application?&lt;/li&gt;&lt;li&gt;How can rails engage with a SOA platform?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;Community Related Questions&lt;/b&gt;&lt;br /&gt;I see a fairly large community on &lt;a href="http://github.com/languages/Ruby"&gt;Github&lt;/a&gt;, &lt;a href="http://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;, &lt;a href="http://railscasts.com/"&gt;RailsCasts&lt;/a&gt;, &lt;a href="http://weblog.rubyonrails.org/"&gt;The Riding Rails Blog&lt;/a&gt;&amp;nbsp;and many more. Some interviewers may want to see if you are connected to the community. The following questions may help you prepare :-)&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Can you tell me a few good community resources for Rails?&lt;/li&gt;&lt;li&gt;Where would you reach out to get the community to answer your questions?&lt;/li&gt;&lt;li&gt;What's new in Rails 3.0?&lt;/li&gt;&lt;li&gt;Which famous applications are built using ruby on rails?&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;I plan to polish this document on a later revision. But in the meanwhile, if you feel like contributing, you can start commenting with the answers, more questions or suggestions. I believe this will not only help people getting ready for their next Rails job, but also for everyone to see what knowledge we are missing...&lt;br /&gt;Disclaimer: This is not a shortcut, rather its kind of a check list that may help you with an interview.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3299396765789538442?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3299396765789538442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/02/ruby-on-rails-interview-questions.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3299396765789538442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3299396765789538442'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/02/ruby-on-rails-interview-questions.html' title='Ruby on Rails Interview Questions'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4246132462568362133</id><published>2010-01-21T07:48:00.000-08:00</published><updated>2010-01-21T07:48:08.477-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Uploading files with blog post</title><content type='html'>At times I wanted to push some files with my blog so that people can download and check something locally. Up until now, it was not a straight-forward way. I either uploaded the file to my own server or google pages or somewhere. Then linked it on the blog.&lt;br /&gt;However, you can now publish files from &lt;a href="http://skydrive.live.com/"&gt;Windows Live SkyDrive&lt;/a&gt;&amp;nbsp;(total free space of 25 GB)&amp;nbsp;or &lt;a href="http://docs.google.com/"&gt;Google Docs&lt;/a&gt; (Total free space 1GB). If you haven't checked already, google now offers you the opportunity to upload any kind of file without conversion. I know there are other services like this, but these two should be reliable.&lt;br /&gt;I took some information from this &lt;a href="http://www.itwriting.com/blog/2082-store-any-type-of-file-in-google-apps-in-effect-gdrive.html"&gt;Tim Anderson's ITWriting blog&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4246132462568362133?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4246132462568362133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/01/uploading-files-with-blog-post.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4246132462568362133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4246132462568362133'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/01/uploading-files-with-blog-post.html' title='Uploading files with blog post'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-780479413308966090</id><published>2010-01-20T09:28:00.000-08:00</published><updated>2010-01-20T09:35:52.773-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Experience notes from a RoR code review job</title><content type='html'>Recently I had the opportunity to review a ruby on rails code. The project aims to create an online market place for experts, with a similar model to some other freelancing/outsourcing sites. Here is how and what I reviewed:&lt;br /&gt;I had a read-only access to the code and no download was allowed locally. So, I didn't get to run the code, tests or any tool to auto-generate some reports on the code. Also, it was supposed to be a high level review and I was supposed to take 5 hours to take a look into the code and write a report on the various aspects of it. In the end, it took me 6 hours and I came up with a 14 page report. I liked this job for a few reasons:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;When I was working at &lt;a href="http://www.ScrumPad.com/"&gt;www.ScrumPad.com&lt;/a&gt;&amp;nbsp;project, we got our code reviewed by Gregg Pollack of &lt;a href="http://railsenvy.com/"&gt;RailsEnvy&lt;/a&gt;. During those days we had little experience on RoR before we started the project. So, we ended up with something that was working well, but wasn't the best one in terms of confidence and reliability. I remember the review was very well-thought and presented by Gregg and that to a great extent shaped the later works on the project.&lt;/li&gt;&lt;li&gt;This was my first official assignment as a reviewer.&lt;/li&gt;&lt;li&gt;I was excited to see how other people were approaching their RoR projects.&lt;/li&gt;&lt;/ol&gt;&amp;nbsp;Now coming to my review approach, here you go:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;After some googling about reviewing RoR applications, I didn't find any comprehensive suggestion and decided to go my own way.&lt;/li&gt;&lt;li&gt;To get started, I took a look into the &lt;b&gt;config/routes.rb&lt;/b&gt; file. I had the impression that, routes.rb would help me understand the resources and their relationships. But soon I discovered one potential issue as there were almost no nesting of resources and some resources had tens of actions apart from the standard RESTful methods.&lt;/li&gt;&lt;li&gt;Next, I picked the resource with most number of methods and found that, it was actually taking the responsibility of 5 different resources. Although these resources were somewhat related, it made little sense to me to have such FAT controllers.&lt;/li&gt;&lt;li&gt;I was also looking for &lt;b&gt;logging, exception handling, ruby coding style, naming&lt;/b&gt; and came up with some suggestions to improve on these aspects.&lt;/li&gt;&lt;li&gt;I also suggested them to &lt;b&gt;modularize their controllers&lt;/b&gt;. They already had an admin module, but they could introduce more to clean up things.&lt;/li&gt;&lt;li&gt;After controllers, I went to the &lt;b&gt;models&lt;/b&gt;. By the time I found a few &lt;b&gt;natural inheritance relations&lt;/b&gt; among the models. But the relations were not found in the models that ended up with a number of &lt;b&gt;code duplications&lt;/b&gt; and similar looking branches at several places. So, I suggested them to install the relations using &lt;b&gt;single table inheritance&lt;/b&gt; and cleanup the stuffs.&lt;/li&gt;&lt;li&gt;Apart from the relations, I also found a number of &lt;b&gt;self or class methods&lt;/b&gt; floating here and there. While ActiveRecord models themselves offer a number of such methods, its not always wise to create one without thinking. In the code I found self methods resulted in method duplication and &lt;b&gt;wrong method placement&lt;/b&gt; at several places.&lt;/li&gt;&lt;li&gt;Next coming to views, I found they did a good job with the helpers and partials. Views were better organized. But also, I found &lt;b&gt;a lot, I mean a lot, of partials&lt;/b&gt;. Such an explosion of partials often makes it hard to find the right ones, especially for new comers.&lt;/li&gt;&lt;li&gt;Going to test code, I found they had a test suite with unit, functional and integration tests. But the amount of test was a concern for me. I believe test codes are there to help good design practices and managing changes over time. I suggested them to &lt;b&gt;target 80% test coverage&lt;/b&gt; at a minimum.&lt;/li&gt;&lt;li&gt;Coming about &lt;b&gt;deployment&lt;/b&gt;, I found they were using manual deployment techniques. I suggested them to use &lt;a href="http://www.capify.org/"&gt;capistrano&lt;/a&gt;&amp;nbsp;for deployment.&lt;/li&gt;&lt;li&gt;Overall I found a lot of reinventing the wheel scenario as they could get rid of lots of code by just using commonly known and free &lt;b&gt;plugins&lt;/b&gt;. I suggested some plugins in this regard.&lt;/li&gt;&lt;li&gt;I suggested them to use &lt;b&gt;named_scopes&lt;/b&gt; to get rid of some self methods here and there.&lt;/li&gt;&lt;/ol&gt;After the review, I felt such patterns in RoR code is expected to surface in most new to RoR teams. Although experienced and smart people often read articles and consult experts as an on going basis to get things right at the first place. I suggest every team, if they haven't already gone through, to take some time and study the resources at &lt;a href="http://guides.rubyonrails.org/"&gt;http://guides.rubyonrails.org&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="http://wiki.rubyonrails.org/"&gt;http://wiki.rubyonrails.org/&lt;/a&gt;&lt;br /&gt;Also, its a good idea to know the Ruby language fluently to make use of the power of the language. A good learning resource comes with ruby installation named &lt;b&gt;Programming Ruby&lt;/b&gt;, also available in the internet at &lt;a href="http://ruby-doc.org/"&gt;http://ruby-doc.org&lt;/a&gt;&lt;br /&gt;&lt;a href="http://ruby-doc.org/"&gt;&lt;/a&gt;As a continuous learning tool, I also suggest keeping an eye on &lt;a href="http://railscasts.com/"&gt;http://railscasts.com&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="http://stackoverflow.com/questions/tagged/ruby-on-rails"&gt;http://stackoverflow.com/questions/tagged/ruby-on-rails&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-780479413308966090?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/780479413308966090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/01/experience-notes-from-ror-code-review.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/780479413308966090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/780479413308966090'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/01/experience-notes-from-ror-code-review.html' title='Experience notes from a RoR code review job'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7534944460796401174</id><published>2010-01-01T12:31:00.000-08:00</published><updated>2010-01-26T14:52:49.004-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Home/End key in Mac ( MacBook Pro ) Windows on Bootcamp</title><content type='html'>If you are anything like me, you love using the home and end key to quickly move to the start/end of a line of text. But, in Apple MacBook Pro, there is no default home/end key! I searched the internet and found Command + Left/Right to the rescue on OS X.&lt;br /&gt;&lt;div&gt;But, then I installed windows 7 on my Mac and it was nightmare to edit without the home/end keys. Today I just found that you can use&lt;b&gt;&lt;span style="color: red;"&gt; fn+ Left/Right&lt;/span&gt;&lt;/b&gt; for this purpose! Hurray! It makes my time with Microsoft office and Visual studio much happier, again :-)&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7534944460796401174?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7534944460796401174/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2010/01/homeend-key-in-macbook-pro-windows.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7534944460796401174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7534944460796401174'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2010/01/homeend-key-in-macbook-pro-windows.html' title='Home/End key in Mac ( MacBook Pro ) Windows on Bootcamp'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6664686548439602745</id><published>2009-12-27T20:30:00.000-08:00</published><updated>2010-01-03T14:28:04.627-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Added Crummy to generate breadcrumbs for CampZero.com</title><content type='html'>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.&lt;div&gt;To add this breadcrumbs support, in my application &lt;a href="http://www.campzero.com/"&gt;www.campzero.com&lt;/a&gt;, a going to be online service marketplace for Bangladesh, I simply used the Crummy plugin. You can take a look at the &lt;a href="http://github.com/zachinglis/crummy/"&gt;Crummy plugin at github&lt;/a&gt;. It took me less than 10 minutes to find, learn and use this plugin! You can see the plugin in action at the &lt;a href="http://www.campzero.com/service_categories/3-Catering-service-Bangladesh/services"&gt;campzero site&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;I recommend this plugin for your Ruby on Rails breadcrumbs needs!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6664686548439602745?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6664686548439602745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/added-crummy-to-generate-breadcrumbs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6664686548439602745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6664686548439602745'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/added-crummy-to-generate-breadcrumbs.html' title='Added Crummy to generate breadcrumbs for CampZero.com'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5248403503503806456</id><published>2009-12-27T10:38:00.002-08:00</published><updated>2009-12-27T10:42:36.434-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>acts_as_permalinkable: SEO friendly rails URLs using my first RoR plugin</title><content type='html'>&lt;span class="Apple-style-span"   style="font-family:'Lucida Grande', serif;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style=" white-space: pre;font-size:11px;"&gt;&lt;span class="Apple-style-span"   style="  white-space: normal; font-family:Georgia, serif;font-size:16px;"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;As a byproduct of my work on &lt;/span&gt;&lt;a href="http://www.campzero.com/"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;www.campzero.com&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;, I released my first ruby on rails plugin called acts_as_permalinkable on github at&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;a href="http://github.com/smsohan/acts_as_permalinkable"&gt;http://github.com/smsohan/acts_as_permalinkable&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;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!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Get started by the following and you are free to contribute!&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;span class="Apple-style-span"  style=" color: rgb(68, 68, 68); line-height: 67px; white-space: pre; font-family:Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;"&gt;script/plugin install git://github.com/smsohan/acts_as_permalinkable.git&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5248403503503806456?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5248403503503806456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/acts-as-permalinkable-seo-friendly.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5248403503503806456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5248403503503806456'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/acts-as-permalinkable-seo-friendly.html' title='acts_as_permalinkable: SEO friendly rails URLs using my first RoR plugin'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2911767778823578597</id><published>2009-12-24T17:20:00.000-08:00</published><updated>2009-12-24T17:52:13.534-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Sitemap-generator for your Rails App and deployment solution</title><content type='html'>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, &lt;a href="http://www.campzero.com/"&gt;www.campzero.com&lt;/a&gt;, I read the document and tried to follow the steps. Today, I worked on generating sitemap for www.campzero.com using the following:&lt;ul&gt;&lt;li&gt;Installed the site-map generator plugin following this link at &lt;a href="http://aktagon.com/projects/rails/sitemap-generator"&gt;Aktagon's&lt;/a&gt;, &lt;a href="http://github.com/christianhellsten/sitemap-generator"&gt;github link&lt;/a&gt;&lt;/li&gt;&lt;li&gt;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:&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush: rails"&gt;domain: www.campzero.com&lt;br /&gt;limit: 5000&lt;br /&gt;priority: 1&lt;br /&gt;change_frequency: weekly&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Then, I put the call to the sitemap method as shown in the github documentation. &lt;/li&gt;&lt;li&gt;Finally, I ran the command &lt;b&gt;rake sitemap:gerenate&lt;/b&gt; to generate my sitemap.xml file inside the public folder.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;After some debugging, I found that the problem was with the code at the file generator.rb where they put &lt;b&gt;model.methods.include?('sitemap_options') &lt;/b&gt;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.&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush: rails"&gt;if((model.methods.include?(:sitemap_options) || model.methods.include?('sitemap_options')) &amp;amp;&amp;amp; model.sitemap_options != nil)&lt;br /&gt;models &amp;lt;&amp;lt; model&lt;br /&gt;end&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Now, I could generate sitemap at my staging environment.&lt;/li&gt;&lt;li&gt;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:&lt;/li&gt;&lt;/ul&gt;&lt;pre class="brush: rails"&gt;if defined?(SITEMAP_FILE_PATH)&lt;br /&gt;SitemapGenerator::Generator.new(SITEMAP_FILE_PATH).find_models_and_generate&lt;br /&gt;else&lt;br /&gt;SitemapGenerator::Generator.run&lt;br /&gt;end&lt;/pre&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I added the constant SITEMAP_FILE_PATH in my config/environments/staging.rb file to get it working.&lt;/li&gt;&lt;li&gt;Finally, I changed my deployment script to define a symlink from the public folder to the shared file path as follows:&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;run "ln -s #{shared_path}/sitemap/sitemap.xml #{release_path}/public/sitemap.xml"&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2911767778823578597?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2911767778823578597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/sitemap-generator-for-your-rails-app.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2911767778823578597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2911767778823578597'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/sitemap-generator-for-your-rails-app.html' title='Sitemap-generator for your Rails App and deployment solution'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1353895714339100017</id><published>2009-12-22T13:50:00.000-08:00</published><updated>2009-12-22T14:12:12.865-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>How to strip html tags, truncate and highlight texts in ruby on rails</title><content type='html'>Recently, I had the following requirements as I was working on CampZero.com - the going to be service marketplace of Bangladesh.&lt;div&gt;&lt;ol&gt;&lt;li&gt;Remove all html tags other than hyperlinks and new lines from a html fragment&lt;/li&gt;&lt;li&gt;Truncate the text to show only first 200 characters of the text and append ellipsis (...) in case the text was truncated.&lt;/li&gt;&lt;li&gt;Highlight an array of words in the text to show the search query worlds that matched&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The first one, getting rid of all but hyperlinks and new lines was achieved by the following code:&lt;/div&gt;&lt;pre class="brush: rails"&gt;&lt;br /&gt;&amp;lt;%= sanitize my_html_text, :tags =&gt; %w(br a) %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;Next, to truncate the text, I simply used the following:&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: rails"&gt;&lt;br /&gt;&amp;lt;%= truncate my_sanitized_text, :length =&gt; 200 %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Lastly, to highlight my search query words, I did the following&lt;/div&gt;&lt;pre class="brush: rails"&gt;&lt;br /&gt;#in the controller&lt;br /&gt;@query_words = params[:query] ? params[:query].split(/\W/) : ''&lt;br /&gt;#in the view&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;In reality, I chained the above thee methods as shown below:&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: rails"&gt;&amp;lt;%= highlight(truncate(sanitize(my_html_text, :tags =&gt; %w(br a)), :length =&gt; 200), @query_words) %&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;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 &lt;a href="http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html#M001620"&gt;SanitizeHelper&lt;/a&gt; and &lt;a href="http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html"&gt;TextHelper&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Happy railing!&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1353895714339100017?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1353895714339100017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/how-to-strip-html-tags-truncate-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1353895714339100017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1353895714339100017'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/how-to-strip-html-tags-truncate-and.html' title='How to strip html tags, truncate and highlight texts in ruby on rails'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7535798069366068819</id><published>2009-12-18T15:24:00.000-08:00</published><updated>2009-12-18T22:32:49.298-08:00</updated><title type='text'>How is Rails plugins helping me in developing CampZero.com?</title><content type='html'>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.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Story#1: As a CampZero developer, I want to deploy the system as soon as I am done with a feature.&lt;/b&gt;&lt;/div&gt;&lt;div&gt;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:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Get the latest code from the code repository.&lt;/li&gt;&lt;li&gt;Create a link to the shared log directory.&lt;/li&gt;&lt;li&gt;Create a link to the shared assets directory.&lt;/li&gt;&lt;li&gt;Create a link to the full text search configuration file.&lt;/li&gt;&lt;li&gt;Migrate the database schema.&lt;/li&gt;&lt;li&gt;Change the link to the application to the latest code.&lt;/li&gt;&lt;li&gt;Restart the full text search engine.&lt;/li&gt;&lt;li&gt;Restart the web server.&lt;/li&gt;&lt;li&gt;Rollback if any step of 1-8 results in a failure.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The whole process is triggered by a single line of command "&lt;b&gt;cap staging deploy:migrations&lt;/b&gt;" and takes less that 3 minutes to complete on an average.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;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.&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;The signup process is actually a three step process as follows:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Create account, with password encrypted.&lt;/li&gt;&lt;li&gt;Get an email with an activation link.&lt;/li&gt;&lt;li&gt;Verify email address by clicking an activation link.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Also, there are several related works as follows:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Login&lt;/li&gt;&lt;li&gt;Logout&lt;/li&gt;&lt;li&gt;Reset password&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;Story#3: As a user of CampZero, I want to search for service providers using natural text.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;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:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Search by full text in the service description, title.&lt;/li&gt;&lt;li&gt;Also search the service provider names and service categories.&lt;/li&gt;&lt;li&gt;Rank by the ratings.&lt;/li&gt;&lt;li&gt;Search using English morphology, for example, if searching for 'cars' it also searches for 'car'.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;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.&lt;/b&gt;&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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 :-)&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7535798069366068819?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7535798069366068819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/how-is-rails-plugins-helping-me-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7535798069366068819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7535798069366068819'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/how-is-rails-plugins-helping-me-in.html' title='How is Rails plugins helping me in developing CampZero.com?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5585772298234253084</id><published>2009-12-17T00:45:00.000-08:00</published><updated>2009-12-17T01:01:03.441-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>"Promises are meant to be broken" and my 2010 promises</title><content type='html'>&lt;b&gt;"One must have a good memory to be able to keep the promises that one makes"&lt;/b&gt;&lt;div&gt;--Friedrich Nietzsche&lt;/div&gt;&lt;div&gt;&lt;b&gt;"Promises are like the full moon, if they are not kept at once they diminish day by day"&lt;/b&gt; &lt;/div&gt;&lt;div&gt;--German Proverb&lt;/div&gt;&lt;div&gt;&lt;b&gt;“Better a broken promise than none at all.”&lt;/b&gt; &lt;/div&gt;&lt;div&gt;--Mark Twain&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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 :-)&lt;/div&gt;&lt;div&gt;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-&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;By January 1, find two potential MS research topics and draw an outline of each!&lt;/li&gt;&lt;li&gt;By January 1, reduce 1kg weight!&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;My readers can wait till Jan 1 to get the retrospect report! I will be blatant and truthful (and this is a promise!).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5585772298234253084?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5585772298234253084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/promises-are-meant-to-be-broken-and-my.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5585772298234253084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5585772298234253084'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/promises-are-meant-to-be-broken-and-my.html' title='&quot;Promises are meant to be broken&quot; and my 2010 promises'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7320056770834700568</id><published>2009-12-15T11:20:00.000-08:00</published><updated>2009-12-16T14:14:27.275-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Graduate'/><title type='text'>What I learned from my first semester at University of Calgary as a Grad Student?</title><content type='html'>In a single line, the first semester has been awesome.&lt;div&gt;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...&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;object width="400" height="265"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=7942838&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1"&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=7942838&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="265"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;&lt;a href="http://vimeo.com/7942838"&gt;Tavolo: A Tabletop Application for Conferences&lt;/a&gt; from &lt;a href="http://vimeo.com/user2731498"&gt;Chris Luce&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;Oh! I forgot another announcement! I have taken my first web venture at&lt;span class="Apple-style-span"  style="font-size:large;"&gt; &lt;/span&gt;&lt;a href="http://www.campzero.com/"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;www.campzero.com&lt;/span&gt;&lt;/a&gt;! 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! &lt;/div&gt;&lt;div&gt;Merry Christmas! &lt;/div&gt;&lt;div&gt;  &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7320056770834700568?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7320056770834700568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/12/what-i-learned-from-my-first-semester.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7320056770834700568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7320056770834700568'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/12/what-i-learned-from-my-first-semester.html' title='What I learned from my first semester at University of Calgary as a Grad Student?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3080387140806009830</id><published>2009-11-06T14:05:00.000-08:00</published><updated>2009-11-06T14:37:11.690-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Lean'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>Lean Thinking: You will probably like to learn the essence of agile</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_Gr1ozXzBWpM/SvSed__DWtI/AAAAAAAAAJw/zjcCAiIzQMQ/s1600-h/img_bigpicture.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://1.bp.blogspot.com/_Gr1ozXzBWpM/SvSed__DWtI/AAAAAAAAAJw/zjcCAiIzQMQ/s320/img_bigpicture.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5401116091353357010" /&gt;&lt;/a&gt;Image taken from: http://www.leansoftwareinstitute.com/images/img_bigpicture.jpg&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Reading the book, I had a realization that, its good to talk using concrete facts as much as possible. So, doing a &lt;b&gt;value stream mapping&lt;/b&gt; practice is worth than spending hours in discussing the process optimization. The same holds true with the &lt;b&gt;Profit and Loss &lt;/b&gt;statement when figuring out which option to take - quality compromise, deadline shifting or feature squeezing. Being able to answer &lt;b&gt;why &lt;/b&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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 :-))&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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 :-(  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3080387140806009830?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3080387140806009830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/11/lean-thinking-you-will-probably-like-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3080387140806009830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3080387140806009830'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/11/lean-thinking-you-will-probably-like-to.html' title='Lean Thinking: You will probably like to learn the essence of agile'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_Gr1ozXzBWpM/SvSed__DWtI/AAAAAAAAAJw/zjcCAiIzQMQ/s72-c/img_bigpicture.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2939795876376805017</id><published>2009-10-27T22:55:00.000-07:00</published><updated>2009-10-27T22:59:39.627-07:00</updated><title type='text'>Now reading: Lean Software Development: An Agile Toolkit</title><content type='html'>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...&lt;div&gt;I am tuned to attend the next CAMUG session by the Authors! It should be a lightning session and looking forward to Nov 2nd.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2939795876376805017?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2939795876376805017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/10/now-reading-lean-software-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2939795876376805017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2939795876376805017'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/10/now-reading-lean-software-development.html' title='Now reading: Lean Software Development: An Agile Toolkit'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6560920346145265491</id><published>2009-10-17T23:27:00.000-07:00</published><updated>2009-10-18T00:05:21.804-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Communicating tools for working on remote projects</title><content type='html'>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.&lt;div&gt;&lt;br /&gt;&lt;div&gt;By communication, I mean the following:-&lt;div&gt;&lt;ol&gt;&lt;li&gt;Getting the spec as intended by the client.&lt;/li&gt;&lt;li&gt;Asking specific questions on time.&lt;/li&gt;&lt;li&gt;Status update about progress, blocks and forthcoming events.&lt;/li&gt;&lt;li&gt;Getting feedback as intended by the client.&lt;/li&gt;&lt;li&gt;Making specific suggestions with rationale to the client.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;I am listing a few tools that I used and recommend others to use.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;A note pad:&lt;/b&gt; I write down small bullet points as soon as I find a question/suggestion/idea.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Voice chat/telephone call:&lt;/b&gt; 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.&lt;/li&gt;&lt;li&gt;&lt;b&gt;IM&lt;/b&gt;: I use GoogleTalk most of the time if it works with client. Otherwise, I just use the one that my client uses most frequently.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Collaboration tool: &lt;/b&gt;I use &lt;a href="http://scrumpad.com/"&gt;ScrumPad.com&lt;/a&gt;. 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.&lt;/li&gt;&lt;li&gt;&lt;b&gt;A wire framing/drawing tool: &lt;/b&gt;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.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Desktop sharing tool: &lt;/b&gt;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.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;I also try to follow some general rules:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Always have a prioritized list of points that I want to discuss.&lt;/li&gt;&lt;li&gt;Be on time.&lt;/li&gt;&lt;li&gt;Never stay disconnected for more than 3 business days.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;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.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6560920346145265491?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6560920346145265491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/10/communicating-tools-for-working-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6560920346145265491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6560920346145265491'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/10/communicating-tools-for-working-on.html' title='Communicating tools for working on remote projects'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3574655172335702280</id><published>2009-10-06T15:42:00.000-07:00</published><updated>2009-10-06T16:11:23.457-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Web application user interface without any Menu</title><content type='html'>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:-&lt;div&gt;----------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span" style="white-space: normal; color: rgb(0, 153, 0); "&gt;CampZero&lt;span class="Apple-tab-span" style="white-space:pre"&gt;     &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="color:#006600;"&gt;zero hassle camping&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;----------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="color:#3366FF;"&gt;Home &lt;/span&gt;| &lt;span class="Apple-style-span"  style="color:#3366FF;"&gt;Place a booking&lt;/span&gt;&lt;/div&gt;&lt;div&gt;----------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span"  style="color:#003333;"&gt;Welcome&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt; &lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;span class="Apple-tab-span" style="white-space:pre"&gt;       &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;|&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;        &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;        &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;|&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;        &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;        &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;|&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;        &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;        &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;|&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;        &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;        &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;|&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;        &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;        &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;|&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;---------------------------------------------------------&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;Campzero.com, all rights reserved&lt;/span&gt;&lt;/div&gt;&lt;div&gt;---------------------------------------------------------&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;b&gt;Yes it is possible to create a web app without a menu. &lt;/b&gt;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.&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3574655172335702280?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3574655172335702280/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/10/web-application-user-interface-without.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3574655172335702280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3574655172335702280'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/10/web-application-user-interface-without.html' title='Web application user interface without any Menu'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6931754076393822245</id><published>2009-09-21T14:47:00.000-07:00</published><updated>2009-09-21T15:41:25.832-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Showing unread posts/comments: An example of rails ActiveRecord 'touch'</title><content type='html'>I worked on the following story:-&lt;blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;"As a&lt;/span&gt; partner, &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;when&lt;/span&gt; I visit a project's dashboard I &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;want&lt;/span&gt; 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."&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;I used the following steps to implement this.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step#1: Added a model MessageReadTime (message_id, user_id, last_read_at)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: rails"&gt;class Message &lt;br /&gt;has_many :messages_read_times &lt;br /&gt;end&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step#2: Added filters in the messages_controller&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: rails"&gt;after_filter :update_message_read_time, :only =&gt; [:show]&lt;br /&gt;def update_message_read_time&lt;br /&gt;read_time = MessageReadTime.find_or_create_by_message_id_and_user_id( params[:id], current_user.id)&lt;br /&gt;read_time.last_read_at = Time.now&lt;br /&gt;read_time.save!&lt;br /&gt;end&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step#3: Added :touch=&gt;true and unread? function in Comment class&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class="brush: rails"&gt;class Comment&lt;br /&gt;..&lt;br /&gt;belongs_to :message, :touch =&gt; true&lt;br /&gt;def unread?(user)&lt;br /&gt; read_time = self.message.message_read_times.find_by_user_id(user_id)&lt;br /&gt; return true unless(read_time)&lt;br /&gt; return read_time.last_read_at &lt; (updated_at || created_at)       end   end&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Step#4: Added unread_comments method in Message class like this&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre class="brush:rails"&gt;class Message&lt;br /&gt;...&lt;br /&gt;def unread_comments(user)&lt;br /&gt;self.comments.collect{|comment| comment.unread?(user) ? comment : nil }.compact&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def unread?(user)&lt;br /&gt;read_time = self.message_read_times.find_by_user_id(user.id)&lt;br /&gt;return true unless read_time&lt;br /&gt;return self.updated_at &gt;= read_time.last_read_at&lt;br /&gt;end&lt;br /&gt;...&lt;br /&gt;end&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;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 :-)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6931754076393822245?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6931754076393822245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/09/showing-unread-postscomments-example-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6931754076393822245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6931754076393822245'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/09/showing-unread-postscomments-example-of.html' title='Showing unread posts/comments: An example of rails ActiveRecord &apos;touch&apos;'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2670791038582860765</id><published>2009-09-17T08:16:00.000-07:00</published><updated>2009-09-17T08:29:45.043-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Some useful plugins for RoR projects</title><content type='html'>Previously I used a few plugins in RoR projects including &lt;a href="http://scrumpad.com/"&gt;ScrumPad&lt;/a&gt;. On a more recent work, I found the following plugins to be really useful and easy to get started:-&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;1. I18n: Rails Internationalization&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;RailsCast at &lt;a href="http://railscasts.com/episodes/138-i18n"&gt;http://railscasts.com/episodes/138-i18n&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Guides post at &lt;a href="http://guides.rubyonrails.org/i18n.html"&gt;http://guides.rubyonrails.org/i18n.html&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;2. Seed-fu: Initial data loading for application  (e.g. admin user, product categories)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Tutorial&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;a href="http://github.com/mbleigh/seed-fu"&gt;http://github.com/mbleigh/seed-fu&lt;/a&gt; A support is now built in for Rails 2.3.4&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;3. Thinking-sphinx: Full text search&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;RailsCast &lt;a href="http://railscasts.com/episodes/120-thinking-sphinx"&gt;http://railscasts.com/episodes/120-thinking-sphinx&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Tutorial &lt;a href="http://freelancing-god.github.com/ts/en/"&gt;http://freelancing-god.github.com/ts/en/&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;4. Paperclip: File and image upload made hassle free&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;RailsCast &lt;a href="http://railscasts.com/episodes/134-paperclip"&gt;http://railscasts.com/episodes/134-paperclip&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Thoughtbot wiki &lt;a href="http://wiki.github.com/thoughtbot/paperclip"&gt;http://wiki.github.com/thoughtbot/paperclip&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Write in comments if you would like to share some other useful RoR plugins.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2670791038582860765?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2670791038582860765/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/09/some-useful-plugins-for-ror-projects.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2670791038582860765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2670791038582860765'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/09/some-useful-plugins-for-ror-projects.html' title='Some useful plugins for RoR projects'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-745189126209951137</id><published>2009-09-09T11:17:00.000-07:00</published><updated>2009-09-09T13:07:30.213-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>The CGI story on agile scaling success on a large project</title><content type='html'>&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px; "&gt;This intro is from the presenters:-&lt;br /&gt;&lt;blockquote&gt;PAS was a joint venture development initiative by 4 major oil and gas&lt;br /&gt;companies and CGI. Devon, Encana, Husky and Talisman joined with CGI to&lt;br /&gt;develop a new Production and Revenue Application. Each company put 3 senior&lt;br /&gt;business resources on the project. The development component of the PAS&lt;br /&gt;initiative cost $35M over 5 years with up to 90 people on the team. This&lt;br /&gt;presentation is on how we used Agile to achieve this mammoth undertaking.&lt;br /&gt;&lt;br /&gt;The product is currently running in production at 5 major oil and gas&lt;br /&gt;companies with great reviews. It is also in production for several mid and&lt;br /&gt;smaller sized companies. CGI is currently marketing the product.&lt;/blockquote&gt;This was my first ever meet with the &lt;a href="http://www.calgaryagile.com/"&gt;Calgary agile methods user group, CAMUG&lt;/a&gt; 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.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;I noted down a few of their discussed topics that I would like to share with my readers:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px; "&gt;The project continued in dev mode for 5 years, a $35M project.&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px; "&gt;It started with only 3 members and extended to a team of 90 following Scrum+XP.&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;The project had 5 sponsoring companies or clients.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;They had 6 teams working in the same sprint cycles.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;In each team, there were significant members from the business working full time with the team onsite and in the same open-space arrangement.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;They had some 3000+ unit tests and also 300+ acceptance test.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;They automated all repetitive tests.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;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.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt;There had been a $800K and one month deviation from the projected cost and timeline.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px; "&gt;They also discussed some issues related to working in a multi-team, multi-client project. I remember the following ones:-&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;They had to balance between features/bug fixes.&lt;/li&gt;&lt;li&gt;The deployment was taken care of by the respective sponsors, not the teams.&lt;/li&gt;&lt;li&gt;They had issues with sprint backlog management.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;They highlighted some aspects with great emphasis:-&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Open communication is the key to success.&lt;/li&gt;&lt;li&gt;Onsite and full time real user availability is very important for such a big project.&lt;/li&gt;&lt;li&gt;Automated tests, partial pair programming and continuous integration is a big plus.&lt;/li&gt;&lt;li&gt;Staying co-located was really helpful.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;What about scaling beyond?&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;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.&lt;/span&gt; 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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;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! &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px; "&gt; &lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial; font-size: 13px;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-745189126209951137?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/745189126209951137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/09/cgi-story-on-agile-scaling-success-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/745189126209951137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/745189126209951137'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/09/cgi-story-on-agile-scaling-success-on.html' title='The CGI story on agile scaling success on a large project'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-7873719432635529294</id><published>2009-09-06T20:58:00.000-07:00</published><updated>2009-09-22T23:58:46.050-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Calgary'/><category scheme='http://www.blogger.com/atom/ns#' term='Graduate'/><title type='text'>A new home at Calgary and starting days</title><content type='html'>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 :-))&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-7873719432635529294?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/7873719432635529294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/09/new-home-at-calgary-and-starting-days.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7873719432635529294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/7873719432635529294'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/09/new-home-at-calgary-and-starting-days.html' title='A new home at Calgary and starting days'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1042328163533027733</id><published>2009-08-19T19:44:00.000-07:00</published><updated>2009-09-23T00:00:43.060-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Rambling stories from my days @ Code71 : My Takehome</title><content type='html'>Today is going to be my last day with the Code71 team and this is the last post of &lt;a href="http://smsohan.blogspot.com/search/label/Code71"&gt;the series&lt;/a&gt; on my Code71 days.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;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...&lt;/div&gt;&lt;div&gt;&lt;b&gt;Teaming &lt;/b&gt;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!&lt;/div&gt;&lt;div&gt;&lt;b&gt;Planning and adapting &lt;/b&gt;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.&lt;/div&gt;&lt;div&gt;&lt;b&gt;Continuous learning. &lt;/b&gt;As I worked on different technologies (&lt;b&gt;.Net/RoR&lt;/b&gt;) and different domains (&lt;b&gt;Financial/Vehicle dealership/Project management/Web community&lt;/b&gt;), I learned to grab new concepts. I developed a learning attitude towards solving a problem and realizing an opportunity.&lt;/div&gt;&lt;div&gt;&lt;b&gt;Happy memories &lt;/b&gt;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.&lt;/div&gt;&lt;div&gt;I will end with &lt;b&gt;a few thanks note &lt;/b&gt;here. Thanks to &lt;a href="http://code71.com/AboutCode71/OurTeam/tabid/57/Default.aspx"&gt;Nimat&lt;/a&gt; and &lt;a href="http://blog.syedrayhan.com/"&gt;Syed &lt;/a&gt;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 &lt;a href="http://syedraihan.com/"&gt;Omar&lt;/a&gt;, 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.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I am going to graduate school at &lt;a href="http://ucalgary.ca/"&gt;University of Calgary&lt;/a&gt;, Canada this fall to start my MS under &lt;a href="http://ebe.cpsc.ucalgary.ca/Frank.Maurer/"&gt;Prof. Frank Maurer&lt;/a&gt; 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!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1042328163533027733?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1042328163533027733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/08/rambling-stories-from-my-days-code71-my.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1042328163533027733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1042328163533027733'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/08/rambling-stories-from-my-days-code71-my.html' title='Rambling stories from my days @ Code71 : My Takehome'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-390999091341540904</id><published>2009-08-11T22:30:00.001-07:00</published><updated>2009-09-23T00:01:05.932-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Rambling story from my days @ Code71: My reading list</title><content type='html'>&lt;p&gt;In my &lt;a href="http://smsohan.blogspot.com/2009/08/rambling-stories-from-my-days-code71.html" target="_blank"&gt;previous post&lt;/a&gt;, 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.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Books&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.foundersatwork.com/" target="_blank"&gt;Founders at work&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.amazon.com/Enterprise-Application-Architecture-Addison-Wesley-Signature/dp/0321127420"&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0201485672"&gt;Refactoring: Improving the Design of Existing Code - By Martin Fowler&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.codeplex.com/AppArchGuide" target="_blank"&gt;Patterns &amp;amp; practices Application Architecture Guide 2.0&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.pragprog.com/titles/rails3/agile-web-development-with-rails-third-edition" target="_blank"&gt;Agile web development with Rails&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://oreilly.com/catalog/9780596008673/" target="_blank"&gt;Head first Object-Oriented analysis and design&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.goodagile.com/scrumprimer/scrumprimer.pdf" target="_blank"&gt;The scrum primer&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.cc2e.com/" target="_blank"&gt;Code complete&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;strong&gt;Most visited sites&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://google.com/" target="_blank"&gt;Google&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.msdn.com/" target="_blank"&gt;MSDN&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;span style="color:#336699;"&gt;&lt;a href="http://api.rubyonrails.org/" target="_blank"&gt;Rails API&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;    &lt;li&gt;&lt;span style="color:#336699;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Main_Page" target="_blank"&gt;Wikipedia&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;    &lt;li&gt;&lt;span style="color:#336699;"&gt;&lt;a href="http://guides.rubyonrails.org/" target="_blank"&gt;Rails guides&lt;/a&gt;&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;span style="font-size:130%;color:#000000;"&gt;&lt;strong&gt;Blogs&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;span style="color:#000000;"&gt;&lt;a href="http://jasonhaley.com/blog/" target="_blank"&gt;Jason Haley’s link blog&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;    &lt;li&gt;&lt;span style="color:#000000;"&gt;&lt;a href="http://blog.cwa.me.uk/" target="_blank"&gt;Chris Alcocks’s reflective perspective&lt;/a&gt;&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;span style="font-size:130%;color:#000000;"&gt;&lt;strong&gt;Community&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;span style="color:#000000;"&gt;&lt;a href="http://forums.asp.net/" target="_blank"&gt;ASP.Net forum&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;    &lt;li&gt;&lt;span style="color:#000000;"&gt;&lt;a href="http://railsforum.com/" target="_blank"&gt;Rails forum&lt;/a&gt;&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-390999091341540904?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/390999091341540904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/08/rambling-story-from-my-days-code71-my.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/390999091341540904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/390999091341540904'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/08/rambling-story-from-my-days-code71-my.html' title='Rambling story from my days @ Code71: My reading list'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3284685461064541138</id><published>2009-08-08T22:04:00.001-07:00</published><updated>2009-09-23T00:03:47.435-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Rambling stories from my days @ Code71 : Startup days</title><content type='html'>&lt;p&gt;Sighs!&lt;/p&gt;  &lt;p&gt;Back then, on Friday, May 26, 2006, I was a final year undergrad student at &lt;a href="http://www.buet.ac.bd/cse"&gt;CSE, BUET&lt;/a&gt;. 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 &lt;a href="http://code71.com/" target="_blank"&gt;Code71&lt;/a&gt;). Visited their website and thought it might be worth giving a try!&lt;/p&gt;  &lt;p&gt;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!&lt;/p&gt;  &lt;p&gt;Good things happen in quick successions in our lives. Agree?&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&lt;img height="214" src="http://photos-g.ak.fbcdn.net/photos-ak-snc1/v3755/201/25/559702037/n559702037_2367230_3471408.jpg" width="222" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;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!&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;I started my job on the 1st of June, 2006 at Asha-technologies. Asha-tech was still to find an office and &lt;a href="http://syedraihan.com/" target="_blank"&gt;Omar&lt;/a&gt; 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.&lt;/p&gt;  &lt;p&gt;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!&lt;/p&gt;  &lt;p&gt;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, &lt;a href="http://syedraihan.com/" target="_blank"&gt;Omar&lt;/a&gt; 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!&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3284685461064541138?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3284685461064541138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/08/rambling-stories-from-my-days-code71.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3284685461064541138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3284685461064541138'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/08/rambling-stories-from-my-days-code71.html' title='Rambling stories from my days @ Code71 : Startup days'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2064904725135285846</id><published>2009-07-16T19:15:00.001-07:00</published><updated>2009-07-18T20:53:43.599-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails modeling guide#2: naming convention for ruby on rails model methods</title><content type='html'>&lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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 &lt;a href="http://www.code71.com/" target="_blank"&gt;Code71&lt;/a&gt;, we are working on &lt;a href="http://www.scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt;, a 2nd generation agile scrum tool using ruby on rails and our model methods are named according to the following rules-&lt;/p&gt; &lt;p&gt;1. All boolean returning methods end with '?'&lt;/p&gt;&lt;pre class="brush: rails"&gt;company.billable?, sprint.current?, story.in_progress?&lt;/pre&gt;&lt;p&gt;2. Boolean methods do not start with is_ or has_ or did_ (as you might see in other popular languages)&lt;/p&gt;&lt;pre class="brush: rails"&gt;company.is_billable? -&amp;gt; company.billable?&lt;br /&gt;sprint.is_current? -&amp;gt; sprint.current?&lt;/pre&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;find_* methods may return a single object of the class/nil&lt;/p&gt;&lt;p&gt;find_all_* methods return an array of objects of the class or [], but never a nil&lt;/p&gt;&lt;p&gt;4. No methods start with a get_ as other languages.&lt;/p&gt;&lt;p&gt;5. A method ends with ! if it alters the object itself.&lt;/p&gt;&lt;pre class="brush: rails"&gt;sprint.close!()&lt;br /&gt;story.progress!()&lt;/pre&gt;&lt;p&gt;6. Methods that persists an object/may throw exception, should always end with ! (implied from rule 5)&lt;/p&gt;&lt;pre class="brush: rails"&gt;invoice.update_status!(:paid)&lt;/pre&gt;&lt;p&gt;7. Always use parentheses '()' in method names. Future versions of ruby is deprecating the support for method names without parentheses.&lt;/p&gt;&lt;p&gt;Following these 7 simple rules we have consistent and intuitive model method names across the whole &lt;a href="http://www.scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt;. Let me know if you have any suggestion to these names to make it even better.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2064904725135285846?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2064904725135285846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/07/rails-modeling-guide2-naming-ruby-on.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2064904725135285846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2064904725135285846'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/07/rails-modeling-guide2-naming-ruby-on.html' title='Rails modeling guide#2: naming convention for ruby on rails model methods'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5228401575766343122</id><published>2009-07-16T07:52:00.000-07:00</published><updated>2009-07-16T20:17:29.591-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Rails modeling guide#1: right structure of a ruby on rails model</title><content type='html'>&lt;p&gt; &lt;/p&gt; &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Gr1ozXzBWpM/Sl8_GY9tjZI/AAAAAAAAAF4/mXyyvZf0TqE/s1600-h/30MAR4U%5B3%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="273" alt="30MAR4U" src="http://lh4.ggpht.com/_Gr1ozXzBWpM/Sl8_KZGni7I/AAAAAAAAAF8/iPeKlLA9_j8/30MAR4U_thumb%5B1%5D.jpg?imgmax=800" width="105" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;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...&lt;/p&gt; &lt;p&gt;At &lt;a href="http://www.code71.com/" target="_blank"&gt;Code71&lt;/a&gt;, 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.&lt;/p&gt; &lt;p&gt;We keep the following order consistent in our models:- &lt;/p&gt;&lt;ol&gt; &lt;li&gt;CONSTANTS&lt;/li&gt; &lt;li&gt;has_one, has_many, belongs_to, has_and_belongs_to relations in dependency order&lt;/li&gt; &lt;li&gt;plug-ins initialization (acts_as_tree, acts_as_state_machine etc.)&lt;/li&gt; &lt;li&gt;validates_presence_of&lt;/li&gt; &lt;li&gt;validates_uniqueness_of &lt;/li&gt; &lt;li&gt;validates_numericality_of&lt;/li&gt; &lt;li&gt;validates_format_of&lt;/li&gt; &lt;li&gt;custom_validations&lt;/li&gt; &lt;li&gt;named_scopes grouped by related purposes&lt;/li&gt; &lt;li&gt;active record hooks (after_initialize, before_create, after_create, ...) in execution order in the format (after_initialize [:assign_default_state, :sanitize_content] )&lt;/li&gt; &lt;li&gt;&lt;strong&gt;protected&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;hook method implementations according to execution order&lt;/li&gt; &lt;li&gt;&lt;strong&gt;public&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;constructor&lt;/li&gt; &lt;li&gt;class methods in alphabetic order&lt;/li&gt; &lt;li&gt;other methods alphabetically or grouped if related&lt;/li&gt; &lt;li&gt;&lt;strong&gt;protected&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;methods alphabetically or grouped if related&lt;/li&gt; &lt;li&gt;&lt;strong&gt;private&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;self methods in alphabetic order or similar methods in a group&lt;br /&gt;other methods in alphabetic order or similar methods in a group&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;strong&gt;&lt;span style="color:#004000;"&gt;Rule&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;No method gets code real estate over 20 lines. If needed, one/more private methods are used.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;span style="color:#004000;"&gt;How is this helping us?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;ol&gt; &lt;li&gt;We are absolutely sure where to look for a method or where to write a new method.&lt;/li&gt; &lt;li&gt;The code base is really consistent.&lt;/li&gt; &lt;li&gt;The unit test methods also follow the same order, which makes managing the test suite easy.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;More to come later this week. Stay tuned!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5228401575766343122?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5228401575766343122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/07/rails-modeling-guide1-right-structure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5228401575766343122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5228401575766343122'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/07/rails-modeling-guide1-right-structure.html' title='Rails modeling guide#1: right structure of a ruby on rails model'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Gr1ozXzBWpM/Sl8_KZGni7I/AAAAAAAAAF8/iPeKlLA9_j8/s72-c/30MAR4U_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5830813756489405476</id><published>2009-07-07T22:23:00.001-07:00</published><updated>2009-07-07T22:31:55.230-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Implementing breadcrumb in rails projects – a clean approach</title><content type='html'>&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Gr1ozXzBWpM/SlQtUMgYMWI/AAAAAAAAAFw/T6ETdg1_psY/s1600-h/breadcrumb%5B3%5D.png"&gt;&lt;img title="breadcrumb" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="132" alt="breadcrumb" src="http://lh3.ggpht.com/_Gr1ozXzBWpM/SlQtVVnNvKI/AAAAAAAAAF0/WGq_a6xKgTk/breadcrumb_thumb%5B1%5D.png?imgmax=800" width="571" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;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-&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The links of the breadcrumb may contain dynamic links. &lt;/li&gt;    &lt;li&gt;It is used in all the pages. So, changing the breadcrumb may trigger a series of changes. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;In &lt;a href="http://scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt;, 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 &lt;a href="http://scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Step#1:&lt;/p&gt;  &lt;p&gt;Encapsulated the breadcrumb generation logic into a single class and used it from all places.&lt;/p&gt;  &lt;pre class="brush: rails"&gt;class Breadcrumb&lt;br /&gt;include ActionView::Helpers::UrlHelper&lt;br /&gt;include ActionView::Helpers::TagHelper&lt;br /&gt;include ApplicationHelper&lt;br /&gt;&lt;br /&gt;attr_accessor :parts, :separator, :prefix&lt;br /&gt;&lt;br /&gt;def initialize(separator = nil, parts = [])&lt;br /&gt;  self.separator = separator || "&amp;lt;img src="\"/images/stub_arrow_right.gif\"" /&amp;gt;"&lt;br /&gt;  self.parts = parts&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def add(title, url = nil)&lt;br /&gt;  self.parts &amp;lt;&amp;lt; {:title =&amp;gt; title, :url =&amp;gt; url}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def set_prefix(title, url)&lt;br /&gt;  self.prefix = {:title =&amp;gt; title, :url =&amp;gt; url}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def to_s&lt;br /&gt;  if(!self.parts.nil? and !self.parts.empty?)&lt;br /&gt;    if(self.prefix.nil?)&lt;br /&gt;      parts_with_prefix = self.parts&lt;br /&gt;    else&lt;br /&gt;      parts_with_prefix = [self.prefix] + self.parts&lt;br /&gt;    end&lt;br /&gt;  &lt;br /&gt;    breadcrumb_html = []&lt;br /&gt;    parts_with_prefix.each do |part|&lt;br /&gt;      if(part[:url].nil? or part[:url].empty?)&lt;br /&gt;        breadcrumb_html &amp;lt;&amp;lt; "&lt;span&gt;#{part[:title]}&lt;/span&gt;"&lt;br /&gt;      else&lt;br /&gt;        breadcrumb_html &amp;lt;&amp;lt; link_to(part[:title], part[:url])&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    return breadcrumb_html.join(" #{self.separator} ")&lt;br /&gt;  end&lt;br /&gt;  return ''&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Step#2:&lt;/p&gt;&lt;p&gt;A before_filter in the ActionController initializes the breadcrumb in the following way:-&lt;/p&gt;&lt;pre class="brush: rails"&gt;def initialize_breadcrumb()&lt;br /&gt;  @breadcrumb = Breadcrumb.new&lt;br /&gt;  if(project_selected?)&lt;br /&gt;    @breadcrumb.prefix = {:title =&amp;gt; "Dashboard", :url =&amp;gt; dashboard_project_path(selected_project())}&lt;br /&gt;  end&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Step#3:&lt;/p&gt;&lt;p&gt;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-&lt;/p&gt;&lt;pre class="brush: rails"&gt;def generate_breadcrumb(sprint, story = nil)&lt;br /&gt;  @breadcrumb.add(sprint.name, project_sprint_path(project.id, sprint.id))&lt;br /&gt;  if(!story.nil?)&lt;br /&gt;    @breadcrumb.add(story.display_title, story_path(story))&lt;br /&gt;  elsif(self.action_name != 'index')&lt;br /&gt;    @breadcrumb.add('Stories', stories_path())&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  current_page = self.action_name == 'index' ? 'Stories' : self.action_name.humanize&lt;br /&gt;  @breadcrumb.add(current_page)&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Step#4:&lt;/p&gt;&lt;p&gt;Finally, in my view layout, I just use this instance variable as shown here:-&lt;/p&gt;&lt;pre class="brush: rails"&gt;&amp;lt;%= @breadcrumb %&amp;gt;&lt;/pre&gt;&lt;p&gt;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!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5830813756489405476?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5830813756489405476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/07/implementing-breadcrumb-in-rails.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5830813756489405476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5830813756489405476'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/07/implementing-breadcrumb-in-rails.html' title='Implementing breadcrumb in rails projects – a clean approach'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Gr1ozXzBWpM/SlQtVVnNvKI/AAAAAAAAAF0/WGq_a6xKgTk/s72-c/breadcrumb_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3058272347640117</id><published>2009-06-15T00:58:00.001-07:00</published><updated>2009-06-15T00:58:15.612-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>Lesson#2: Pace Your Sprint Rightly</title><content type='html'>&lt;p&gt;In my &lt;a href="http://smsohan.blogspot.com/2009/06/lesson1-going-incremental-is-natural.html" target="_blank"&gt;previous post&lt;/a&gt;, I said about being incremental. Here come the next thing, being “ITERATIVE”. A prefer the term Sprint than Iteration.&lt;/p&gt;  &lt;p&gt;So, once you decided to take small increments, make sure you reach the targets sprinting.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Gr1ozXzBWpM/SjX_DmKLDgI/AAAAAAAAAFo/xYRbI8rsbVI/s1600-h/sprint%5B3%5D.jpg"&gt;&lt;img title="sprint" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="260" alt="sprint" src="http://lh3.ggpht.com/_Gr1ozXzBWpM/SjX_EyH2GEI/AAAAAAAAAFs/c7e42WMAbEI/sprint_thumb%5B1%5D.jpg?imgmax=800" width="347" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;I suggest you prepare for sprinting with the right techniques and tools. A few recommendations-&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;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?&lt;/li&gt;    &lt;li&gt;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.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;At Code71, &lt;a href="http://scrumpad.com" target="_blank"&gt;ScrumPad&lt;/a&gt;, 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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3058272347640117?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3058272347640117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/06/lesson2-pace-your-sprint-rightly.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3058272347640117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3058272347640117'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/06/lesson2-pace-your-sprint-rightly.html' title='Lesson#2: Pace Your Sprint Rightly'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Gr1ozXzBWpM/SjX_EyH2GEI/AAAAAAAAAFs/c7e42WMAbEI/s72-c/sprint_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4309435714032682579</id><published>2009-06-03T21:25:00.001-07:00</published><updated>2009-09-22T23:38:07.699-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>Lesson#1: Going Incremental is Natural!</title><content type='html'>&lt;p&gt;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. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Gr1ozXzBWpM/SidMvX7yttI/AAAAAAAAAFc/HvBvxUoFJdY/s1600-h/human-evolution-t10176%5B3%5D.jpg"&gt;&lt;img title="human-evolution-t10176" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="293" alt="human-evolution-t10176" src="http://lh4.ggpht.com/_Gr1ozXzBWpM/SidMx5T5PoI/AAAAAAAAAFg/0U5KZOhlt7c/human-evolution-t10176_thumb%5B1%5D.jpg?imgmax=800" width="407" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;I took this image from internet and credits to &lt;/em&gt;&lt;a href="http://blogs.houstonpress.com/" target="_blank"&gt;&lt;em&gt;this site.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;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 &lt;a href="http://scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt;. If you value “teaming” and “delivering” in sprints, &lt;a href="http://scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt; will give you the oxygen to breathe while you sprint!&lt;/p&gt;  &lt;p&gt;I suggest you follow a routine to iterate. At &lt;a href="http://code71.com/" target="_blank"&gt;Code71&lt;/a&gt;, we follow the below-&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Day 1:&lt;/strong&gt; 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.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Day 8: &lt;/strong&gt;Release in test server (shadow version of the real production environment) and collect customer feedback.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Day 9: &lt;/strong&gt;Work on customer feedback and go live in production server. Always tag the version that is put in the production following the standard -&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;R&amp;lt;ProductReleaseVersion&amp;gt;.S&amp;lt;SprintNumber&amp;gt;.B&amp;lt;BuildNumber&amp;gt;.P&amp;lt;PatchNumber&amp;gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;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!&lt;/p&gt;  &lt;p&gt;How are you sprinting? Let me know if you have a suggestion.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4309435714032682579?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4309435714032682579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/06/lesson1-going-incremental-is-natural.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4309435714032682579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4309435714032682579'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/06/lesson1-going-incremental-is-natural.html' title='Lesson#1: Going Incremental is Natural!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Gr1ozXzBWpM/SidMx5T5PoI/AAAAAAAAAFg/0U5KZOhlt7c/s72-c/human-evolution-t10176_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-213871350631224849</id><published>2009-06-03T02:27:00.001-07:00</published><updated>2009-06-03T02:34:58.822-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Its easier to get lost! Would you?</title><content type='html'>&lt;p&gt;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-&lt;/p&gt;  &lt;blockquote&gt;   &lt;p style="background-color: #fff200"&gt;&lt;em&gt;“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…”&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Well, I understand how it feels! As the title says, “Its easier to get lost!”&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Gr1ozXzBWpM/SiZB7nxv4hI/AAAAAAAAAFU/5Ye5BRK3vsE/s1600-h/maze%5B3%5D.jpg"&gt;&lt;img title="maze" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="338" alt="maze" src="http://lh5.ggpht.com/_Gr1ozXzBWpM/SiZB9jKM9iI/AAAAAAAAAFY/IUmlB7qh55o/maze_thumb%5B1%5D.jpg?imgmax=800" width="338" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Do you fancy getting stuck at this maze?&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;But it may be really difficult to catch the ball at the first jump. We, at &lt;a href="http://Code71.com" target="_blank"&gt;Code71&lt;/a&gt;, 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-&lt;/p&gt;  &lt;ul&gt;   &lt;ul&gt;     &lt;li&gt;&lt;strong&gt;DIE&lt;/strong&gt; for planning. Plan for short spans. We plan for two week sprints. &lt;/li&gt;      &lt;li&gt;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) &lt;/li&gt;      &lt;li&gt;Plan on your inputs. You cannot push your inputs. So, you may need to squeeze the output to match against your capacity. &lt;/li&gt;      &lt;li&gt;&lt;strong&gt;DIE&lt;/strong&gt; to meet the deadline according to the plan. &lt;/li&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;p&gt;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!&lt;/p&gt;  &lt;p&gt;Its not difficult if you have the preparation. To prepare, at a minimum do the following-&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Have a Continuous Integration (CI) server up and running 24x7 or &lt;strong&gt;DIE&lt;/strong&gt;. (We use &lt;a href="http://cruisecontrol.sourceforge.net/" target="_blank"&gt;CruiseControl&lt;/a&gt;, its free and great) &lt;/li&gt;    &lt;li&gt;Make your CI server to send build, test and coverage report for you. Keep an eye on the coverage report and &lt;strong&gt;DIE&lt;/strong&gt; to remain well above the the 80% line. &lt;/li&gt;    &lt;li&gt;Keep track of your activities for retrospect. We use &lt;a href="http://scrumpad.com" target="_blank"&gt;ScrumPad&lt;/a&gt;. It helps you to iterate, collaborate and deliver. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The keyword is &lt;strong&gt;“sustainable pace”&lt;/strong&gt;. 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 &lt;a href="http://www.goodagile.com/scrumprimer/index.html" target="_blank"&gt;Scrum&lt;/a&gt;, find an expert and give it a try. It’s worth than you might have expected.&lt;/p&gt;  &lt;p&gt;If you know a better way to keep delivering better, I will appreciate for sharing your idea to me. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-213871350631224849?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/213871350631224849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/06/its-easier-to-get-lost-would-you.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/213871350631224849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/213871350631224849'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/06/its-easier-to-get-lost-would-you.html' title='Its easier to get lost! Would you?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Gr1ozXzBWpM/SiZB9jKM9iI/AAAAAAAAAFY/IUmlB7qh55o/s72-c/maze_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-512867889907619965</id><published>2009-05-13T00:49:00.001-07:00</published><updated>2009-05-13T20:25:29.337-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Unit/Functional Test Rails ActionController filters following DRY</title><content type='html'>&lt;p&gt;At &lt;a href="http://scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt; 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)!&lt;/p&gt;&lt;p&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;&lt;strong&gt;Example of Moist Code:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;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!&lt;/span&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;pre class="brush: rails"&gt;class SomeController&lt;br /&gt;before_filter :authenticate&lt;br /&gt;before_filter :restrict_invalid_role&lt;br /&gt;end&lt;br /&gt;class SomeControllerTest&lt;br /&gt;def test_index_redirects_without_login&lt;br /&gt;get :index&lt;br /&gt;assert_redirected_to :controller=&amp;gt;:login, :action=&amp;gt;:login&lt;br /&gt;end&lt;br /&gt;def test_index_redirects_without_valid_role&lt;br /&gt;login_as(:invalid_role)&lt;br /&gt;get :index&lt;br /&gt;assert_redirected_to :controller=&amp;gt;:exception, :action=&amp;gt;:not_allowed&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;Example of DRY Code:&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;pre class="brush: rails"&gt;class ActionController::TestCase&lt;br /&gt;##example: should_apply_before_filter_to_actions(:authenticate, [:index, :new])&lt;br /&gt;def should_apply_before_filter_to_actions(before_filter_name, actions)&lt;br /&gt;if(actions.nil? or actions.empty?)&lt;br /&gt;  assert false&lt;br /&gt;end&lt;br /&gt;filter = find_maching_before_filter(before_filter_name)&lt;br /&gt;actions.each do |action|&lt;br /&gt;  assert_before_filter_applied(filter, action)&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;##example: should_apply_before_filter_to_action(:authenticate, :index)&lt;br /&gt;def should_apply_before_filter_to_action(before_filter_name, action)&lt;br /&gt;filter = find_maching_before_filter(before_filter_name)&lt;br /&gt;assert_before_filter_applied(filter, action)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;##example: should_not_apply_before_filter_to_actions(:authenticate, [:index, :new])&lt;br /&gt;def should_not_apply_before_filter_to_actions(before_filter_name, actions)&lt;br /&gt;if(actions.nil? or actions.empty?)&lt;br /&gt;  assert false&lt;br /&gt;end&lt;br /&gt;filter = find_maching_before_filter(before_filter_name)&lt;br /&gt;actions.each do |action|&lt;br /&gt;  assert_before_filter_not_applied(filter, action)&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;##example: should_not_apply_before_filter_to_action(:authenticate, :index)&lt;br /&gt;def should_not_apply_before_filter_to_action(before_filter_name, action)&lt;br /&gt;filter = find_maching_before_filter(before_filter_name)&lt;br /&gt;assert_before_filter_not_applied(filter, action)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;##example: should_apply_before_filters([:authenticate, :session_expiry])&lt;br /&gt;def should_apply_before_filters(before_filter_names)&lt;br /&gt;if(before_filter_names.nil? or before_filter_names.empty?)&lt;br /&gt;  assert false, "No Before Filter is Passed"&lt;br /&gt;end&lt;br /&gt;before_filter_names.each {|filter| should_apply_before_filter(filter)}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;##example: should_apply_before_filter(:authenticate)&lt;br /&gt;def should_apply_before_filter(before_filter_name)&lt;br /&gt;filter = find_maching_before_filter(before_filter_name)&lt;br /&gt;if(filter.nil?)&lt;br /&gt;  assert false, "no matching filter found for #{before_filter_name}"&lt;br /&gt;end&lt;br /&gt;assert filter.options.empty?, "the filter #{before_filter_name} has only/except options and does not apply to all actions"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;private&lt;br /&gt;#finds the matching BeforeFilter object&lt;br /&gt;def find_maching_before_filter(before_filter_name)&lt;br /&gt;filters = @controller.class.filter_chain()&lt;br /&gt;if !filters.nil?&lt;br /&gt;  filters.each do |filter|&lt;br /&gt;    if(filter.is_a?(ActionController::Filters::BeforeFilter) and filter.method == before_filter_name)&lt;br /&gt;      return filter&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;return nil&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#asserts a single BeforeFilter is applied on a single action&lt;br /&gt;def assert_before_filter_applied(filter, action)&lt;br /&gt;if(filter.nil? or action.nil?)&lt;br /&gt;  assert false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if(filter.options.empty?)&lt;br /&gt;  assert true&lt;br /&gt;  return&lt;br /&gt;end&lt;br /&gt;if(!filter.options[:only].nil?)&lt;br /&gt;  assert filter.options[:only].include?(action.to_s)&lt;br /&gt;end&lt;br /&gt;if(!filter.options[:except].nil?)&lt;br /&gt;  assert !filter.options[:except].include?(action.to_s)&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;#asserts a single BeforeFilter is not applied on a single action&lt;br /&gt;def assert_before_filter_not_applied(filter, action)&lt;br /&gt;if(filter.nil? or action.nil?)&lt;br /&gt;  assert false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if(filter.options.empty?)&lt;br /&gt;  assert false&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;if(!filter.options[:except].nil?)&lt;br /&gt;  assert filter.options[:except].include?(action.to_s)&lt;br /&gt;end&lt;br /&gt;if(!filter.options[:only].nil?)&lt;br /&gt;  assert !filter.options[:only].include?(action.to_s)&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;Now my test code looks like the following-&lt;br /&gt;&lt;pre class="brush: rails"&gt;  def test_filters&lt;br /&gt;should_apply_before_filters(:authenticate, :restrict_invalid_role)&lt;br /&gt;end &lt;/pre&gt;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.&lt;br /&gt;&lt;p&gt;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.&lt;/p&gt;Hope it helps someone with similar need.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-512867889907619965?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/512867889907619965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/05/unit-test-actioncontroller-filters.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/512867889907619965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/512867889907619965'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/05/unit-test-actioncontroller-filters.html' title='Unit/Functional Test Rails ActionController filters following DRY'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-1228199762907373935</id><published>2009-04-26T03:59:00.001-07:00</published><updated>2009-04-26T04:04:02.845-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Forget Me Not! Object Oriented Design in Custom Exception</title><content type='html'>&lt;p&gt;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.&lt;/p&gt; &lt;pre class="brush: rails"&gt;&lt;br /&gt;StorySaveError&lt;br /&gt;StoryDescopeNotAllowedError&lt;br /&gt;StoryCompleteError&lt;br /&gt;StoryNotFoundError&lt;br /&gt;StoryDeleteError&lt;br /&gt;StoryDeleteNotAllowedError&lt;/pre&gt;&lt;p&gt;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-&lt;/p&gt;&lt;pre class="brush: rails"&gt;&lt;br /&gt;class StoryError &lt; StandardError&lt;br /&gt;end&lt;br /&gt;StorySaveError &lt; StoryError&lt;br /&gt;StoryDescopeNotAllowedError &lt; StoryError&lt;br /&gt;StoryCompleteError &lt; StoryError&lt;br /&gt;StoryNotFoundError &lt; StoryError&lt;br /&gt;StoryDeleteError &lt; StoryError&lt;br /&gt;StoryDeleteNotAllowedError &lt; StoryError&lt;/pre&gt;&lt;p&gt;With the addition of a base class for all Story related exceptions, I can write cleaner/better code.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;When I am not interested about the specific error, I can just use &lt;code&gt;rescue StoryError&lt;/code&gt; to catch 'em all&lt;/li&gt;&lt;li&gt;I can place a common error handling routine for all Story related exceptions&lt;/li&gt;&lt;li&gt;I can add new exception types without altering the codes where the specific type of StoryError is insignificant&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;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.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-1228199762907373935?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/1228199762907373935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/object-oriented-design-in-custom.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1228199762907373935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/1228199762907373935'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/object-oriented-design-in-custom.html' title='Forget Me Not! Object Oriented Design in Custom Exception'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4590116532388723880</id><published>2009-04-21T20:44:00.001-07:00</published><updated>2009-04-21T20:45:16.675-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Unit Test eager loading in Rails ActiveRecord association</title><content type='html'>&lt;p&gt;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.&lt;/p&gt; &lt;pre class="brush: rails"&gt;class User &amp;lt; ActiveRecord::Base&lt;br /&gt; has_many :friends&lt;br /&gt; named_scope :eager_load_friends, :include =&amp;gt; :fiends&lt;br /&gt;end&lt;br /&gt;User.find(user_id).eager_load_friends&lt;/pre&gt;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 &lt;a href="http://www.scrumpad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt;&lt;br /&gt;&lt;pre class="brush: rails"&gt;def test_eager_loaded(model, association)&lt;br /&gt; assert !model.instance_variable_get("@#{association.to_s}").nil?&lt;br /&gt;end&lt;/pre&gt;You can then test your eager loading in the following way&lt;br /&gt;&lt;pre class="brush: rails"&gt;def test_eager_load_friends&lt;br /&gt; test_eager_loaded(User.find(1), :friends)&lt;br /&gt;end&lt;/pre&gt;You can also use the &lt;a href="http://tammersaleh.com/posts/testing-named_scope" target="_blank"&gt;shoulda plug-in&lt;/a&gt; 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.&lt;br /&gt;&lt;p&gt;Got another solution? I will appreciate if you share.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4590116532388723880?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4590116532388723880/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/unit-test-eager-loading-in-rails.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4590116532388723880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4590116532388723880'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/unit-test-eager-loading-in-rails.html' title='Unit Test eager loading in Rails ActiveRecord association'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5148878371550064957</id><published>2009-04-15T01:44:00.001-07:00</published><updated>2009-09-22T23:39:21.339-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Object Oriented Design'/><title type='text'>Implementing Template Method in Rails Controllers Using Module and Mixin</title><content type='html'>&lt;p&gt;All rails controllers are subclasses of the ApplicationController class. A typical controller class declaration will look like the following-&lt;/p&gt; &lt;pre class="brush: ruby;"&gt;class LoginController &amp;lt; ApplicationController&lt;br /&gt;#the actions go here&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;With this basic information, I would like to state the problem first.&lt;/p&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;The Problem/Job in Hand&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;p&gt;Add an action switch_project to all the controllers (&amp;gt; 20) of the &lt;a href="http://www.ScrumPad.com/" target="_blank"&gt;ScrumPad&lt;/a&gt; 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.&lt;/p&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;Analysis&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;p&gt;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&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: rails"&gt;class ApplicationController&lt;br /&gt; def switch_project&lt;br /&gt;   if(is_valid_switch?)&lt;br /&gt;     logger.debug(“A switch is taking place”)&lt;br /&gt;     destination = get_destination(new_project_id)&lt;br /&gt;     redirect_to destination&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;if you hit http://server/login/switch_project you will get a server side error. However, if you instead place the &lt;code&gt;switch_project&lt;/code&gt; inside the &lt;code&gt;LoginController&lt;/code&gt;, 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!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Again, as I said, the &lt;code&gt;get_destination(new_project_id)&lt;/code&gt; is the only part that will be different for each of the controllers. So, we definitely find a template method here.&lt;/p&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;The Solution&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;p&gt;If you need an introduction about Module and Mixin in Ruby, please read &lt;a href="http://www.rubycentral.com/pickaxe/tut_modules.html" target="_blank"&gt;here at ruby-doc&lt;/a&gt;. We are going to use Mixin to implement the desired solution, efficiently.&lt;br /&gt;&lt;br /&gt;So, I put the &lt;code&gt;switch_project&lt;/code&gt; method in a module called, &lt;code&gt;ProjectSwitchModule&lt;/code&gt; inside a new file at app/controllers/project_switch_module.rb like this-&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: rails;"&gt;module ProjectSwitchModule&lt;br /&gt; def switch_project&lt;br /&gt;   if(is_valid_switch?)&lt;br /&gt;     logger.debug(“A switch is taking place”)&lt;br /&gt;     destination = get_destination(new_project_id)&lt;br /&gt;     redirect_to destination&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt; def is_valid_switch?&lt;br /&gt;   #I determine if the switch is valid at this method and return boolean&lt;br /&gt; end&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;To make it available to all my controllers, I include this module in just in the &lt;code&gt;ApplicationController&lt;/code&gt; in the following way-&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: rails;"&gt;require ‘project_switch_module’&lt;br /&gt;class ApplicationController&lt;br /&gt; include ProjectSwitchModule&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;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-&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: rails"&gt;class LoginController&lt;br /&gt; private&lt;br /&gt; def get_destination(project_id)&lt;br /&gt;   #custom destination logic for LoginController&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;class MessageController&lt;br /&gt; private&lt;br /&gt; def get_destination(project_id)&lt;br /&gt;   #custom destination logic for MessageController&lt;br /&gt; end&lt;br /&gt;end&lt;/pre&gt;&lt;p&gt;Now, if I invoke &lt;a href="http://server/login/switch_project"&gt;http://server/login/switch_project&lt;/a&gt; or &lt;a href="http://server/message/switch_project"&gt;http://server/message/switch_project&lt;/a&gt; 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.&lt;/p&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;Afterthoughts&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;p&gt;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!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I will appreciate any feedback on this article.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5148878371550064957?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5148878371550064957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/implementing-template-method-in-rails.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5148878371550064957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5148878371550064957'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/implementing-template-method-in-rails.html' title='Implementing Template Method in Rails Controllers Using Module and Mixin'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3959506268407646446</id><published>2009-04-11T20:58:00.001-07:00</published><updated>2009-09-23T00:03:06.462-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='other'/><title type='text'>Testing the SyntaxHighlighter Scripts</title><content type='html'>&lt;p&gt;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 &lt;a title="http://alexgorbatchev.com/wiki/SyntaxHighlighter" href="http://alexgorbatchev.com/wiki/SyntaxHighlighter"&gt;http://alexgorbatchev.com/wiki/SyntaxHighlighter&lt;/a&gt;&lt;/p&gt; &lt;strong&gt;&lt;span style="color:#008000;"&gt;Ruby/Rails&lt;/span&gt;&lt;/strong&gt;   &lt;pre class="brush: rails;"&gt;class TestHighlighter&lt;br /&gt;def my_highlighter&lt;br /&gt;  return "SyntaxHighlighter"&lt;br /&gt;end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;CSharp&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: csharp;"&gt;public class TestHighlighter&lt;br /&gt;{&lt;br /&gt;public string MyHighlighter&lt;br /&gt;{&lt;br /&gt;  get {return "SyntaxHighlighter";}&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;W&lt;/span&gt;&lt;/strong&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;hat did I add to my blog?&lt;/span&gt;&lt;/strong&gt; &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Open Edit Html and add this just before in the blog's template &lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush :html;"&gt;&amp;lt;link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" type="text/css" rel="stylesheet" /&amp;gt;&lt;br /&gt;&amp;lt;link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" type="text/css" rel="stylesheet" /&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/&amp;gt;&lt;br /&gt;&amp;lt;script type='text/javascript'&amp;gt;&lt;br /&gt;    SyntaxHighlighter.config.bloggerMode = true;&lt;br /&gt;    SyntaxHighlighter.all();&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Thanks to &lt;a href="http://jitu-blog.blogspot.com/" target="_blank"&gt;Ashraf&lt;/a&gt; for informing me about the &lt;a href="http://www.codeplex.com/wlwSyntaxHighlighter" target="_blank"&gt;Windows Live Writer Plugin&lt;/a&gt;! It will be useful for sure.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3959506268407646446?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3959506268407646446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/testing-syntaxhighlighter-scripts.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3959506268407646446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3959506268407646446'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/testing-syntaxhighlighter-scripts.html' title='Testing the SyntaxHighlighter Scripts'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4393241021383777650</id><published>2009-04-09T04:51:00.001-07:00</published><updated>2009-09-22T23:55:57.433-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>Pair Programming: How am I feeling?</title><content type='html'>&lt;p&gt;&lt;strong&gt;For an explanation of Pair Programming, please visit &lt;a href="http://en.wikipedia.org/wiki/Pair_programming" target="_blank"&gt;this wiki entry&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;Good&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;Productivity Increased&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color:#008000;"&gt;Disclaimer&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Are you pairing? Please, share your feelings and suggestions.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4393241021383777650?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4393241021383777650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/pair-programming-how-am-i-feeling.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4393241021383777650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4393241021383777650'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/pair-programming-how-am-i-feeling.html' title='Pair Programming: How am I feeling?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4968278805115506366</id><published>2009-04-07T20:17:00.001-07:00</published><updated>2009-04-20T20:48:43.887-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>assert_equal_float : assert_equal between two float objects with precision</title><content type='html'>&lt;p&gt;In doing rails unit testing, sometime you need to assert the equality between two float objects in the following fashion&lt;/p&gt;  &lt;div class="code_div"&gt;   &lt;p&gt;&lt;strong&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#000080;"&gt;assert_equal&lt;/span&gt; 32.8, object_under_test.method_returning_float&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;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 &lt;strong&gt;object_under_test.method_returning_float&lt;/strong&gt; may be stored as 32.80000001 in memory and the above call may fail.&lt;/p&gt;  &lt;p&gt;To solve this problem, you may wish to use the &lt;a href="http://www.ruby-doc.org/core-1.9/classes/Float.html" target="_blank"&gt;round method of Float class&lt;/a&gt; in the following way&lt;/p&gt;  &lt;div class="code_div"&gt;   &lt;p&gt;&lt;strong&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color:#000080;"&gt;assert_equal&lt;/span&gt; 32.8, object_under_test.method_returning_float&lt;span style="color:#008000;"&gt;.round(1)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;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!&lt;/p&gt;  &lt;p&gt;However, when you are talking about insignificant digits, this rounding should work fine for you.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;div class="code_div"&gt;   &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;strong&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="color:#000080;"&gt;def&lt;/span&gt; &lt;span style="color:#800080;"&gt;assert_equal_float&lt;/span&gt;(expected, actual, precision)            &lt;br /&gt;    &lt;span style="color:#008080;"&gt;assert_equal&lt;/span&gt; expected.to_f.round(precision), actual.to_f.round(precision)            &lt;br /&gt;&lt;span style="color:#000080;"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color:#000080;"&gt; &lt;/span&gt;   &lt;/span&gt;&lt;/p&gt;    &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Happy float asserting!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4968278805115506366?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4968278805115506366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/assertequalfloat-assertequal-between.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4968278805115506366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4968278805115506366'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/assertequalfloat-assertequal-between.html' title='assert_equal_float : assert_equal between two float objects with precision'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8115167267493921684</id><published>2009-04-05T20:25:00.001-07:00</published><updated>2009-09-22T23:42:58.420-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.Net'/><title type='text'>Looking at ASP.NET MVC</title><content type='html'>&lt;p&gt;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 &lt;a href="http://asp.net/mvc" target="_blank"&gt;asp.net/mvc&lt;/a&gt; site.&lt;/p&gt;  &lt;p&gt;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!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8115167267493921684?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8115167267493921684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/04/looking-at-aspnet-mvc.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8115167267493921684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8115167267493921684'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/04/looking-at-aspnet-mvc.html' title='Looking at ASP.NET MVC'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5557812724454673612</id><published>2009-03-30T21:09:00.001-07:00</published><updated>2009-09-22T23:43:52.520-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>named_scope : Real life examples from ScrumPad</title><content type='html'>&lt;p&gt;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-&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;The Source Code:&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;div class="code_div"&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;class&lt;/span&gt; &lt;strong&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;ChatUser&lt;/span&gt;&lt;/strong&gt; &amp;lt; ActiveRecord::Base    &lt;br /&gt;belongs_to &lt;span style="color: rgb(128, 0, 0);"&gt;:chat&lt;/span&gt;    &lt;br /&gt;belongs_to &lt;span style="color: rgb(128, 0, 0);"&gt;:user&lt;/span&gt;    &lt;br /&gt;belongs_to &lt;span style="color: rgb(128, 0, 0);"&gt;:chat_status, :foreign_key&lt;/span&gt; =&amp;gt; "status_id" &lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;  named_scope &lt;span style="color: rgb(128, 0, 0);"&gt;:closed&lt;/span&gt;, lambda {|chat_id| {&lt;span style="color: rgb(128, 0, 0);"&gt;:conditions&lt;/span&gt; =&amp;gt; ["status_id = #{ChatStatus::CLOSED} AND chat_id = ? ", chat_id]}} do    &lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;def&lt;/span&gt; invite()    &lt;br /&gt;    each { |chat_user| chat_user.update_attribute(&lt;span style="color: rgb(128, 0, 0);"&gt;:status_id&lt;/span&gt;, ChatStatus::INVITED) }    &lt;br /&gt;  &lt;span style="color: rgb(0, 0, 128);"&gt;end&lt;/span&gt;    &lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;end&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;   &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;  named_scope &lt;span style="color: rgb(128, 0, 0);"&gt;:active_chats&lt;/span&gt;, lambda {|user_id| {&lt;span style="color: rgb(128, 0, 0);"&gt;:conditions &lt;/span&gt;=&amp;gt; ["user_id = ? AND status_id not in (#{ChatStatus::CLOSED}, #{ChatStatus::LEFT})", user_id]}}    &lt;br /&gt;named_scope &lt;span style="color: rgb(128, 0, 0);"&gt;:with_chat&lt;/span&gt;, &lt;span style="color: rgb(128, 0, 0);"&gt;:include&lt;/span&gt; =&amp;gt; &lt;span style="color: rgb(128, 0, 0);"&gt;:chat&lt;/span&gt;    &lt;br /&gt;&lt;span style="color: rgb(0, 0, 128);"&gt;end&lt;/span&gt;&lt;/span&gt;  &lt;/p&gt; &lt;/div&gt; &lt;p&gt;So, you get an idea about the &lt;span style="font-family:Courier New;"&gt;ChatUser&lt;/span&gt; class. Its a relation object between user, chat and chat_status with some additional fields.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;How am I Using My named_scope?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;ChatUser.closed(chat_id)&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;Gives me all the chat users who closed their chat windows for the chat having chat_id.&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;ChatUser.closed(chat_id).with_chat&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;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!&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;ChatUser.closed(chat_id).invite()&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;Invites all users to a chat with chat_id if the buddy closed the chat window.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;Why named_scope?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt;    &lt;li&gt;You get rid of looping in many cases! It will help you to write concise and clear codes. &lt;/li&gt;    &lt;li&gt;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. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Let me know if you have another good example of a real life named_scope in your project.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5557812724454673612?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5557812724454673612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/03/namedscope-real-life-examples-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5557812724454673612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5557812724454673612'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/03/namedscope-real-life-examples-from.html' title='named_scope : Real life examples from ScrumPad'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-689684145100573788</id><published>2009-03-23T10:14:00.001-07:00</published><updated>2009-04-20T20:49:06.856-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Design/Code Review: Now, It's time to realize!</title><content type='html'>&lt;p&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;Are you doing code reviews?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Thank God, you are. &lt;/p&gt; &lt;p&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;Not?&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt; &lt;p&gt;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...&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;Now, It's time to realize!&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Start now! It's simple. I have found the following approach to be useful-&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Pair up with one developer. Make it explicit to the team. So, you know who reviews your code.&lt;/li&gt; &lt;li&gt;Mix up a junior team member with a senior one, if possible.&lt;/li&gt; &lt;li&gt;Have a fixed time, at least 30 minutes for each two weeks to do a team design/code review.&lt;/li&gt; &lt;li&gt;Do it in small increments. We did the following-&lt;/li&gt;&lt;/ol&gt; &lt;ul&gt; &lt;ul&gt; &lt;li&gt;Sprint#1: Review variable/method/class/file/folder names only.&lt;/li&gt; &lt;li&gt;Sprint#2: #1 + Review if/else blocks, loops.&lt;/li&gt; &lt;li&gt;Sprint#3: #2 + Review class responsibilities.&lt;/li&gt; &lt;li&gt;Sprint#4: #3 + Review test codes only.&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;p&gt;&lt;strong&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;The result is really worth&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;&lt;strong&gt;A reviewer's eye will save lot of your time and money.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;&lt;strong&gt;Update: Be constructive in your feedback! Example:-&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;Worst: This code is a piece of ...&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;Worse: This code is bad&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;Bad: This code is not good&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;Good: A better way is..&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;Better: We can also do it this way...&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: rgb(0, 128, 0);"&gt;&lt;strong&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Best ?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-689684145100573788?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/689684145100573788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/03/designcode-review-now-it-time-to.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/689684145100573788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/689684145100573788'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/03/designcode-review-now-it-time-to.html' title='Design/Code Review: Now, It&amp;#39;s time to realize!'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-3691679674343283915</id><published>2009-03-22T23:03:00.001-07:00</published><updated>2009-09-22T23:44:59.318-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Juggernaut on Linux</title><content type='html'>&lt;p&gt;I just installed Juggernaut on my linux box. The installation is simpler than windows. At least it gave me less pain.&lt;/p&gt;  &lt;p&gt;Just run the following commands-&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;gem install json&lt;/li&gt;    &lt;li&gt;gem install activemachine&lt;/li&gt;    &lt;li&gt;gem install juggernaut&lt;/li&gt;    &lt;li&gt;juggernaut –g juggernaut.yml&lt;/li&gt;    &lt;li&gt;juggernaut –c juggernaut.yml&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I got a little pain regarding the g++ compiler that is required to build the &lt;strong&gt;activemachine&lt;/strong&gt;. I did not have it installed in my Amazon EC2 instance and after some searches, I could install it using the following-&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;apt-get install g++&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;span style="color:#ff0000;"&gt;IMPORTANT!!&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Well, it was fine if I could end here! However, I found that this installation stopped my MySQL service and changed the &lt;strong&gt;/etc/mysql/my.cnf&lt;/strong&gt; file. So, an attempt to start the MySQL was successful only after I removed the # comment from the line log_bin = blah blah blah…&lt;/p&gt;  &lt;p&gt;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)!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-3691679674343283915?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/3691679674343283915/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/03/juggernaut-on-linux.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3691679674343283915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/3691679674343283915'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/03/juggernaut-on-linux.html' title='Juggernaut on Linux'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4179276949349906632</id><published>2009-03-22T03:34:00.001-07:00</published><updated>2009-09-22T23:45:14.583-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>Comet and Server Push (Reverse Ajax) technology</title><content type='html'>&lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;I learned about Comet and found it interesting. You may read about comet &lt;a href="http://en.wikipedia.org/wiki/Comet_%28programming%29" target="_blank"&gt;here&lt;/a&gt; at WIKI.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://juggernaut.rubyforge.org/" target="_blank"&gt;Juggernaut&lt;/a&gt; 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.&lt;/p&gt;  &lt;p&gt;The installation required a few tweaks as follows:-&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;1. Installed &lt;strong&gt;json_pure&lt;/strong&gt; gem instead of json. (gem install json_pure)&lt;/li&gt;    &lt;li&gt;2. Installed &lt;strong&gt;EventMachine&lt;/strong&gt; gem (gem install eventmachine)&lt;/li&gt;    &lt;li&gt;3. Installed juggernaut gem (gem install juggernaut &lt;strong&gt;–-ignore-dependencies&lt;/strong&gt;)&lt;/li&gt;    &lt;li&gt;4. Modified the C:\ruby\lib\ruby\gems\1.8\specifications\juggernaut-0.5.7.gemspec in places to the following&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;strong&gt;s.add_runtime_dependency(%q&amp;lt;json_pure&amp;gt;, ["&amp;gt;= 1.1.1"])      &lt;br /&gt;s.add_development_dependency(%q&amp;lt;hoe&amp;gt;, ["&amp;gt;= 1.3.1"])&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;strong&gt;s.add_dependency(%q&amp;lt;json_pure&amp;gt;, ["&amp;gt;= 1.1.1"])      &lt;br /&gt;s.add_dependency(%q&amp;lt;hoe&amp;gt;, ["&amp;gt;= 1.3.1"])&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;strong&gt;s.add_dependency(%q&amp;lt;json_pure&amp;gt;, ["&amp;gt;= 1.1.1"])      &lt;br /&gt;s.add_dependency(%q&amp;lt;hoe&amp;gt;, ["&amp;gt;= 1.3.1"])&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;since, you do not find the required versions of all the gems, you need to change this checks to get a way.&lt;/p&gt;  &lt;p&gt;Then, &lt;a href="http://github.com/maccman/juggernaut_plugin/blob/c3e07a812341f93bb1f90c00b7a125524b07b80a/README" target="_blank"&gt;this readme&lt;/a&gt; helped me to get started.&lt;/p&gt;  &lt;p&gt;Will follow up this post as I work more on this. Have a good day!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4179276949349906632?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4179276949349906632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/03/coment-and-server-push-reverse-ajax.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4179276949349906632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4179276949349906632'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/03/coment-and-server-push-reverse-ajax.html' title='Comet and Server Push (Reverse Ajax) technology'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8921021037244419991</id><published>2009-03-06T10:40:00.001-08:00</published><updated>2009-04-20T20:50:33.577-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>The RANK() Function for Numbering on Groups/Partitions in SQL Server</title><content type='html'>&lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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.&lt;/p&gt; &lt;p&gt;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 &amp;lt;= 5. Ranking based on such groups/partitions can be easily done by using the RANK() function. I am quoting the syntax &lt;a href="http://msdn.microsoft.com/en-us/library/ms176102.aspx" target="_blank"&gt;from MSDN&lt;/a&gt; here-&lt;/p&gt;&lt;pre&gt;RANK ( )    OVER ( [ &amp;lt; partition_by_clause &amp;gt; ] &amp;lt; order_by_clause &amp;gt; )&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;So, in my case the query is something like the following-&lt;/p&gt;&lt;br /&gt;&lt;p&gt;RANK ( )    OVER ( &lt;strong&gt;PARTITION BY&lt;/strong&gt; Year, MAKE, MODEL &lt;strong&gt;ORDER BY&lt;/strong&gt; Profit DESC, Trim )&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;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!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8921021037244419991?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8921021037244419991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/03/rank-function-for-numbering-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8921021037244419991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8921021037244419991'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/03/rank-function-for-numbering-on.html' title='The RANK() Function for Numbering on Groups/Partitions in SQL Server'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-608476663380562665</id><published>2009-02-22T21:58:00.001-08:00</published><updated>2009-09-22T23:56:27.694-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Database'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server'/><title type='text'>Working on a Data Warehouse project</title><content type='html'>&lt;p&gt;I have been busy for the last month as we, at &lt;a href="http://code71.com/" target="_blank"&gt;Code71&lt;/a&gt;, rolled out the first release of the Business Intelligence project for &lt;a href="http://www.vuenu.com/" target="_blank"&gt;Vuneu Media&lt;/a&gt;. I will give you a brief on my project here so that you can follow my coming posts.&lt;/p&gt;  &lt;p&gt;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-&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;What vehicles are customers buying?&lt;/li&gt;    &lt;li&gt;How much it costs to get those from Auctions?&lt;/li&gt;    &lt;li&gt;How many of these are receiving cash advances and by which lenders?&lt;/li&gt;    &lt;li&gt;What is my potential gross profit if I deal a vehicle?&lt;/li&gt;    &lt;li&gt;Where can I find the vehicles in Auctions?&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;We are using the following software/technologies:-&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;SQL Server 2008, 64 Bit, Standard Edition.&lt;/li&gt;    &lt;li&gt;SQL Server Integration Service.&lt;/li&gt;    &lt;li&gt;SQL Server Reporting Service.&lt;/li&gt;    &lt;li&gt;ASP.Net, C#, WCF.&lt;/li&gt;    &lt;li&gt;SQL Server Analysis Service (is in the pipeline, not used yet!)&lt;/li&gt;    &lt;li&gt;Windows Server 2008, 64 Bit.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;Here, I will start with an issue resulting from the &lt;strong&gt;“64 bit”&lt;/strong&gt; SQL Server limitations-&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;To load Excel data using SSIS, you have the following options:-&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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.&lt;/p&gt;  &lt;p&gt;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 &amp;gt; Debugging.&lt;/p&gt;  &lt;p&gt;More information on 64 bit SQL Server related issues are &lt;a href="http://msdn.microsoft.com/en-us/library/ms141766%28SQL.90%29.aspx" target="_blank"&gt;here at MSDN.&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Also, I got help from &lt;a href="http://blog.n-technologies.be/post/2008/08/26/Import-Excel-files-with-SQL-Server-Integration-Services-on-a-64-bit-server.aspx" target="_blank"&gt;Blog N-Technologies&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-608476663380562665?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/608476663380562665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/02/working-on-data-warehouse-project.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/608476663380562665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/608476663380562665'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/02/working-on-data-warehouse-project.html' title='Working on a Data Warehouse project'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-4033652367610842807</id><published>2009-01-21T08:25:00.001-08:00</published><updated>2009-09-22T23:57:04.852-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>A good example of C# Regular Expression: Implementing InitCap or Titleize/TitleCase using C# and Regular Expression</title><content type='html'>&lt;p&gt;Ever since I first learned about the regular expressions, I have always been fascinated by its magical capability. When I first learned about DFA/NFA, I figured out how it is possible to evaluate a regular expression and eventually, during my Undergrad at BUET, I implemented a regular expression evaluator for the Compiler Lab.&lt;/p&gt; &lt;p&gt;Now, given this history, here is a simple code that I wrote today. Let me know if you liked it-&lt;/p&gt; &lt;div style="background: white none repeat scroll 0% 0%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"&gt; &lt;p style="margin: 0px;"&gt;        Program()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.WriteLine(Titleize(&lt;span style="color: rgb(163, 21, 21);"&gt;"hello! This is a sample string for titleize!"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color: rgb(43, 145, 175);"&gt;Console&lt;/span&gt;.Read();&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        }&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt; Titleize(&lt;span style="color:blue;"&gt;string&lt;/span&gt; input)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;Regex&lt;/span&gt;.Replace(input.ToLower(), &lt;span style="color: rgb(163, 21, 21);"&gt;@"(?&amp;lt;space&amp;gt;\s*)(?&amp;lt;first&amp;gt;.)(?&amp;lt;rest&amp;gt;\S*)"&lt;/span&gt;, &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;MatchEvaluator&lt;/span&gt;(OnMatch));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        }&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt; OnMatch(&lt;span style="color: rgb(43, 145, 175);"&gt;Match&lt;/span&gt; match)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt;.Format(&lt;span style="color: rgb(163, 21, 21);"&gt;"{0}{1}{2}"&lt;/span&gt;, match.Groups[&lt;span style="color: rgb(163, 21, 21);"&gt;"space"&lt;/span&gt;].Value, match.Groups[&lt;span style="color: rgb(163, 21, 21);"&gt;"first"&lt;/span&gt;].Value.ToUpper(), match.Groups[&lt;span style="color: rgb(163, 21, 21);"&gt;"rest"&lt;/span&gt;].Value);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        }&lt;/p&gt;&lt;/div&gt; &lt;p style="margin: 0px;"&gt;For a little explanation, the pattern &lt;span style="color: rgb(163, 21, 21);"&gt;@"(?&amp;lt;space&amp;gt;\s*)(?&amp;lt;first&amp;gt;.)(?&amp;lt;rest&amp;gt;\S*)"&lt;/span&gt; matches to a series of space followed by a word. The word is further divided into two parts, the first one is just the first character and the rest understandably captures the "rest" part of the word.&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;Next the OnMatch method takes each occurrence of a match of the above pattern and as shown, simply regroups the word as previous but just takes the Upper case of the first letter!&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;Simple? You got another good example of Regular Expression? Share with me.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-4033652367610842807?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/4033652367610842807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2009/01/good-example-of-c-regular-expression.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4033652367610842807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/4033652367610842807'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2009/01/good-example-of-c-regular-expression.html' title='A good example of C# Regular Expression: Implementing InitCap or Titleize/TitleCase using C# and Regular Expression'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-531053863278252582</id><published>2008-12-23T22:12:00.001-08:00</published><updated>2009-04-20T21:55:37.965-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.Net'/><title type='text'>Solution to JavaScript File Include Problem From ASP.Net MasterPage</title><content type='html'>&lt;p&gt;You can include javascript files using a simple script tag. However, you will soon discover that, when you are using this master page from content pages that are at different levels in folder hierarchy then the script files will be missing at some cases. This is due to the fact that, script file paths are referenced relative to the content page and NOT to the master page. As a result, despite having the correct include wrt the master page, your content pages may still miss the scripts!&lt;/p&gt;  &lt;p&gt;The solution is simple. Add this following line (of course, replacing the sample values with your own ones) to your master page's page load method to add the script tag through code instead of through markup.&lt;/p&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 this\cf0 .Page.ClientScript.RegisterClientScriptInclude(\cf4 "YourKey"\cf0 , ResolveUrl(\cf4 "~/Scripts/myscript.js"\cf0 );} --&gt;  &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:courier new;font-size:10pt;color:black;"&gt;   &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   &lt;/span&gt;&lt;span style="color:blue;"&gt;this&lt;/span&gt;.Page.ClientScript.RegisterClientScriptInclude(&lt;span style="color: rgb(163, 21, 21);"&gt;"YourKey"&lt;/span&gt;, ResolveUrl(&lt;span style="color: rgb(163, 21, 21);"&gt;"~/Scripts/myscript.js"&lt;/span&gt;);&lt;/p&gt;    &lt;p style="margin: 0px;"&gt; &lt;/p&gt;    &lt;p style="margin: 0px;"&gt;Hope it saves you from the pain of adding a common js file into each of your content pages.&lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-531053863278252582?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/531053863278252582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/12/solution-to-javascript-file-include.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/531053863278252582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/531053863278252582'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/12/solution-to-javascript-file-include.html' title='Solution to JavaScript File Include Problem From ASP.Net MasterPage'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5474403990311753228</id><published>2008-12-23T21:56:00.001-08:00</published><updated>2009-09-22T23:54:37.758-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Asp.Net Membership: How to change a user's password from an admin account without knowing the current password?</title><content type='html'>&lt;p&gt;Like mine, you may also need to change a user's password from an admin account. By default, when you are using ASP.Net authentication and storing the password in the hashed format, you will not be able to see the existing password in its decrypted form. Also, to change a password using the Membership API, you will need to know the existing password. However, here is a simple solution to the problem -&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Gr1ozXzBWpM/SVHO80nP0PI/AAAAAAAAAEg/dwiTndV7ajM/s1600-h/AspNetChangePassword%5B4%5D.png"&gt;&lt;img style="border: 0px none ;" alt="AspNetChangePassword" src="http://lh5.ggpht.com/_Gr1ozXzBWpM/SVHO-soxcqI/AAAAAAAAAEk/f7_FTsN04wU/AspNetChangePassword_thumb%5B2%5D.png?imgmax=800" width="692" border="0" height="87" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The idea is, you can reset the password of a user using the following code-&lt;/p&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \cf1 string\cf0  tempPass = \cf4 Membership\cf0 .Provider.ResetPassword(\cf5 "username"\cf0 , \cf1 string\cf0 .Empty)} --&gt;  &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:courier new;font-size:10pt;color:black;"&gt;   &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   &lt;/span&gt;&lt;span style="color:blue;"&gt;string&lt;/span&gt; tempPass = &lt;span style="color: rgb(43, 145, 175);"&gt;Membership&lt;/span&gt;.Provider.ResetPassword(&lt;span style="color: rgb(163, 21, 21);"&gt;"username"&lt;/span&gt;, &lt;span style="color:blue;"&gt;string&lt;/span&gt;.Empty)&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Make sure you have the config that allows you to change password without an answer to the security question. Now, you can invoke the ChangePassword method using this tempPass as the existing pass and your custom password as the new password. Refer to the following line for a compact implementation-&lt;/p&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red43\green145\blue175;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;\red0\green0\blue255;}??\fs20 \cf1 Membership\cf0 .Provider.ChangePassword(\cf4 "username"\cf0 , \cf1 Membership\cf0 .Provider.ResetPassword(\cf4 "username"\cf0 , \cf5 string\cf0 .Empty), \cf4 "custompass"\cf0 )} --&gt;  &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:courier new;font-size:10pt;color:black;"&gt;   &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   &lt;/span&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;Membership&lt;/span&gt;.Provider.ChangePassword(&lt;span style="color: rgb(163, 21, 21);"&gt;"username"&lt;/span&gt;, &lt;span style="color: rgb(43, 145, 175);"&gt;Membership&lt;/span&gt;.Provider.ResetPassword(&lt;span style="color: rgb(163, 21, 21);"&gt;"username"&lt;/span&gt;, &lt;span style="color:blue;"&gt;string&lt;/span&gt;.Empty), &lt;span style="color: rgb(163, 21, 21);"&gt;"custompass"&lt;/span&gt;)&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;I believe this will save your time with a similar need.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5474403990311753228?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5474403990311753228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/12/aspnet-membership-how-to-change-user.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5474403990311753228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5474403990311753228'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/12/aspnet-membership-how-to-change-user.html' title='Asp.Net Membership: How to change a user&amp;#39;s password from an admin account without knowing the current password?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Gr1ozXzBWpM/SVHO-soxcqI/AAAAAAAAAEk/f7_FTsN04wU/s72-c/AspNetChangePassword_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2037809886620187947</id><published>2008-11-26T20:42:00.001-08:00</published><updated>2009-04-20T20:47:15.719-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Part 1: How am I IMPACTing following Scrum?</title><content type='html'>&lt;p&gt;In a previous post in this blog, I introduced the nice little acronym &lt;a href="http://smsohan.blogspot.com/2008/11/impact-of-agile-software-development.html"&gt;IMPACT for agile&lt;/a&gt;. To recap, here is what &lt;strong&gt;IMPACT&lt;/strong&gt; stands f&lt;em&gt;or -&lt;/em&gt;&lt;/p&gt;  &lt;blockquote style="background-color: rgb(0, 128, 192);"&gt;   &lt;p&gt;&lt;span style="color: rgb(253, 253, 253);"&gt;&lt;em&gt;&lt;strong&gt;"I&lt;/strong&gt;terative and Incremental development of a software by means of &lt;strong&gt;M&lt;/strong&gt;erciless refactoring, &lt;strong&gt;P&lt;/strong&gt;eer reviews, &lt;strong&gt;A&lt;/strong&gt;utomated acceptance testing, &lt;strong&gt;C&lt;/strong&gt;ontinuous integration and of course, &lt;strong&gt;T&lt;/strong&gt;est driven development"&lt;/em&gt;&lt;/span&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;To give you a little background around my story, let me tell you about a project that I am working since June 2006. The project is a micro-finance loan application automation server for the US financial industry. It acts as a mediator between a loan seeking customer and one of over 50 lenders in an attempt to get a loan for the customer. So, the server adds value by taking a single application to 50 odd lenders from a single submission unless no lender is left untried or some lender says 'yes' to it. This is done in real time, the processing time in average is less than 3 minutes.&lt;/p&gt;  &lt;p&gt;Now that you have the background, let me introduce the the challenges associated with this project. The bullet points are-&lt;/p&gt;  &lt;ul style="background-color: rgb(211, 249, 118);"&gt;   &lt;li&gt;Since this involves real dollars, there is nearly no margin for an error. &lt;/li&gt;    &lt;li&gt;It processes more than a thousand loan applications per hour, so a high availability is a must. &lt;/li&gt;    &lt;li&gt;This is done following agile Scrum and each two week one/two new lending partners need to be integrated. &lt;/li&gt;    &lt;li&gt;The lending partners change their integration API from time to time and we need to accommodate the changes ASAP. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To address these challenges this is how we are responding-&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Iterative and Incremental development (IID)&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;We are following Scrum and using &lt;a href="http://www.scrumpad.com/"&gt;ScrumPad&lt;/a&gt; to manage the IID. Basically, our clients/product owners put new requirements in terms of user stories in the product backlog at ScrumPad. So, with the prioritized product backlog we, the team, pick items to a sprint's backlog. Then as usual, we break it down to tasks and do everything that it takes to meet the deadline of two weeks. Within a sprint the following are the milestones-&lt;/p&gt;  &lt;table style="color: rgb(255, 255, 255); background-color: rgb(0, 128, 192);" width="612" border="1" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="66"&gt;Day 1&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 2&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 3&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 4&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 5&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 6&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 7&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Day 8&lt;/td&gt;        &lt;td valign="top" width="63"&gt;Day 9&lt;/td&gt;        &lt;td valign="top" width="82"&gt;Day 10&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="font-weight: bold;" valign="top" width="68"&gt;Sprint Planning&lt;/td&gt;        &lt;td valign="top" width="56"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td valign="top" width="56"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td valign="top" width="56"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td valign="top" width="57"&gt;Dev &amp;amp; Test&lt;/td&gt;        &lt;td style="font-weight: bold;" valign="top" width="66"&gt;Test Release&lt;/td&gt;        &lt;td style="font-weight: bold;" valign="top" width="82"&gt;Production Release&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;ul style="background-color: rgb(211, 249, 118);"&gt;   &lt;li&gt;8th day - Sprint works are completed. &lt;/li&gt;    &lt;li&gt;9th day - Test delivery at a near production environment and feedback gathering from product owner. &lt;/li&gt;    &lt;li&gt;10th day - Incorporate feedbacks and release in production. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Note that, we generally produce a number of test releases within the first 8 days. That gives us an earlier chance to gather client feedbacks.&lt;/p&gt;  &lt;p&gt;The beauty if this approach is, with this model in place we can release as early as in 8 working days, if not earlier. So, this helps us meeting the last two challenges as mentioned above.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Merciless refactoring&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Developing incrementally offers much challenge in attaining the longevity of the product. Because, naturally as new features come in, we need to make room for that in the existing implementation.To ensure the quality and life of the product, we do merciless refactoring as we go. We have over 90% unit test coverage, which helps us in doing this continuous refactoring. So, the idea is-&lt;/p&gt;  &lt;ul style="background-color: rgb(211, 249, 118);"&gt;   &lt;li&gt;Writing unit test and acceptance test. &lt;/li&gt;    &lt;li&gt;Refactoring our code/design and validating against automated tests. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Peer reviews&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This is probably the most important practice that I recommend. Because, as we had new members in the team, we found that the quality was somewhat degrading. Once, we started peer reviews, it was very helpful to the new comers as well as the veterans to keep the code quality up to the mark. We review the following things-&lt;/p&gt;  &lt;ul style="background-color: rgb(211, 249, 118);"&gt;   &lt;li&gt;Naming of variables, methods, classes, files, namespaces etc. &lt;/li&gt;    &lt;li&gt;Use of private methods for increased readability. &lt;/li&gt;    &lt;li&gt;Hard coded string literals or constants. &lt;/li&gt;    &lt;li&gt;Long/nested loops and long running if-else blocks. &lt;/li&gt;    &lt;li&gt;Code commenting. &lt;/li&gt;    &lt;li&gt;Quality of coding. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I would suggest you to try Microsoft's Stylecop, it will give you a great head start to ensure the first level code quality by enforcing the common rules. This practice is allowing us to continue the good quality over time.&lt;/p&gt;  &lt;p&gt;I have always been shy of reading extra large text in the web. So, I thought I could better post this in two parts! I assure, next post will contain more images than texts, So, you better stay tuned for the next one...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2037809886620187947?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2037809886620187947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/11/part-1-how-am-i-impacting.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2037809886620187947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2037809886620187947'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/11/part-1-how-am-i-impacting.html' title='Part 1: How am I IMPACTing following Scrum?'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6384169799761684903</id><published>2008-11-18T20:43:00.001-08:00</published><updated>2008-11-19T00:12:03.293-08:00</updated><title type='text'>Delving into client side capabilities of ASP.Net Ajax</title><content type='html'>&lt;p&gt;I believe the client side scripting capabilities of ASP.Net Ajax is not utilized by many ASP.Net developers. This is most probably due to the fact that, not many people are aware of it at the first place. Also, since most of the javascripts are rendered secretly (read, not blatantly, which is good), most developers don't even feel the existence of the underlying javascript at all.&lt;/p&gt;  &lt;p&gt;Two very simple examples of the client side library are given here as examples -&lt;/p&gt;  &lt;p&gt;1. Did you know, if you have the following javascript method, it will be automatically called when your page's DOM is finished loading?&lt;/p&gt;  &lt;pre&gt;function pageLoad(sender, args) {&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;2. Do you know the following javascript code will add an event handler to catch whenever an asynchronous post back is completed?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Sys.WebForms.PageRequestManager.instance.add_endRequest(endRequestHandler)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;These are just very little glimpses of the big scenario. To uncover more, visit the official MSDN documentation at &lt;a title="http://msdn.microsoft.com/en-au/library/bb398822.aspx" href="http://msdn.microsoft.com/en-au/library/bb398822.aspx"&gt;http://msdn.microsoft.com/en-au/library/bb398822.aspx&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;If you are new to this, I assure, you will have a much better knowledge about ASP.Net Ajax scripting than ever before and can produce better quality javascript for your ASP.Net websites. &lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;Happy digging!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6384169799761684903?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6384169799761684903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/11/delving-into-client-side-capabilities.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6384169799761684903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6384169799761684903'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/11/delving-into-client-side-capabilities.html' title='Delving into client side capabilities of ASP.Net Ajax'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5823665672043885351</id><published>2008-11-18T01:40:00.001-08:00</published><updated>2008-11-26T21:12:39.445-08:00</updated><title type='text'>IMPACTing for agile software development</title><content type='html'>&lt;p&gt;Well, next time on a dev job interview when someone asks you the question, &lt;em&gt;"&lt;span style="color:#5b2fdf;"&gt;Can you give us a brief idea on agile software development engineering practices?"&lt;/span&gt;,&lt;/em&gt; you are probably gonna laugh on your mind and just answer, &lt;strong&gt;&lt;span style="color:#355abd;"&gt;"IMPACT!"&lt;/span&gt;&lt;/strong&gt;. Yes, this is it, compact and right on target!&lt;/p&gt;  &lt;p&gt;Today, I came up with this acronym about agile engineering practices and I think its a nice one :-)&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="color:#404040;"&gt;&lt;strong&gt;IMPACT&lt;/strong&gt; can be elaborated as follows-&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;  &lt;table width="659" border="0" cellpadding="2" cellspacing="0"&gt;&lt;tbody&gt;     &lt;tr style="background-color: rgb(153, 62, 60);"&gt;       &lt;td valign="top" width="49"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;I&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="58"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;&lt;em&gt;for&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="541"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;Iterative and Incremental Development&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr style="background-color: rgb(192, 80, 77);"&gt;       &lt;td valign="top" width="52"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;M&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="58"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;&lt;em&gt;for&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="541"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;Merciless Continuous Refactoring&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr style="background-color: rgb(153, 62, 60);"&gt;       &lt;td valign="top" width="54"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;P&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="58"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;&lt;em&gt;for&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="541"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;Peer Code Reviews&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr style="background-color: rgb(192, 80, 77);"&gt;       &lt;td valign="top" width="57"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;A&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="58"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;&lt;em&gt;for&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="541"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;Automated Acceptance Tests&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr style="background-color: rgb(153, 62, 60);"&gt;       &lt;td valign="top" width="59"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;C&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="58"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;&lt;em&gt;for&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="541"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;Continuous Integration&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr style="background-color: rgb(192, 80, 77);"&gt;       &lt;td valign="top" width="61"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;T&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="58"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;&lt;em&gt;for&lt;/em&gt;&lt;/span&gt;&lt;/td&gt;        &lt;td valign="top" width="541"&gt;&lt;span style="font-size:130%;color:#ffffff;"&gt;Test Driven Development&lt;/span&gt;&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;For all you agile folks out there, I hope this &lt;strong&gt;IMPACT&lt;/strong&gt; makes sense to you! I have found many people to take agile as a panacea and start getting skeptical as soon as they feel the heat in real life. Well, we all know, there is no free lunch! So, lets get our feet on track and do the first things first. &lt;/p&gt;  &lt;p&gt;What are the first things? The answer is, IMPACT, if you really want to create a positive impact out of agile methods.&lt;/p&gt;  &lt;p&gt;Comments are welcome!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5823665672043885351?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5823665672043885351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/11/impact-of-agile-software-development.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5823665672043885351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5823665672043885351'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/11/impact-of-agile-software-development.html' title='IMPACTing for agile software development'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-5679911442546787143</id><published>2008-11-10T00:58:00.001-08:00</published><updated>2009-09-22T23:57:35.401-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unit test'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>RowTest Extension for NUnit</title><content type='html'>&lt;p&gt;Well, I was just about to implement it myself! However, its good to see that the NUnit addin named RowTest actually allows us to do the data driven unit test through declarative programming and adding parameters to the dumb test methods!&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.andreas-schlapsi.com/projects/rowtest-extension-for-nunit/" href="http://www.andreas-schlapsi.com/projects/rowtest-extension-for-nunit/"&gt;http://www.andreas-schlapsi.com/projects/rowtest-extension-for-nunit/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Check out this website for an example and get started with RowTest.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-5679911442546787143?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/5679911442546787143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/11/rowtest-extension-for-nunit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5679911442546787143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/5679911442546787143'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/11/rowtest-extension-for-nunit.html' title='RowTest Extension for NUnit'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-2862129569753813203</id><published>2008-11-03T01:04:00.001-08:00</published><updated>2009-04-20T20:46:24.937-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Iterative and Incremental implementation of Code Reviews</title><content type='html'>&lt;p&gt;Extreme Programming (XP) advocates for a pair-programming, taking the code review to its extreme. I have also found that pair programming generates a lot of speed and also helps producing better quality product in the first time. But, at the same time it's difficult to impress the management or prove return on investment  associated with pair programming to the business people. So, what is the best possible solution? I believe, we can implement frequent peer code reviews to mimic the pair programming to some extent and get the benefit out of it.&lt;/p&gt;  &lt;p&gt;In our team, we started implementing code reviews as we now recognize that there is no way to live without it. As usual, our approach is an iterative and incremental approach. So, we are taking small steps and eventually embracing the best practices in the team. I would like to share our plan here in this blog. The review process goes on the following work flow-&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;span style="color:#8080ff;"&gt;"When I am done with my work on task, I commit the code with the reviewer's name on the svn comment. CCNet automatically builds and sends a mail to the reviewer. The reviewer gets the review email through a filter and reviews the code and sends his feedback to me via IM/email."&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="color:#0000ff;"&gt;&lt;strong&gt;Sprint #1:&lt;/strong&gt;&lt;/span&gt; Review all the names or classes, files, methods, variables and so on. So, the reviewer emphasizes on the names and provides feedback on the following things-&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;1. Is the naming standard correctly followed?&lt;/p&gt;    &lt;p&gt;2. Is this a meaningful identifier?&lt;/p&gt;    &lt;p&gt;3. Does the name conform to the conventions used elsewhere in the code?&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;span style="color:#0000ff;"&gt;&lt;strong&gt;Sprint#2:&lt;/strong&gt;&lt;/span&gt; Review the use of private methods and code structure. The to-do list is -&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;1. Would it make more sense to put some code into the private method for readability and/or reusability?&lt;/p&gt;    &lt;p&gt;2. Is there any hard-coded constant directly used without referring to a const/readonly data type?&lt;/p&gt;    &lt;p&gt;3. For all the methods, is it possible to reduce the dependency by using a simple parameter instead of a whole object?&lt;/p&gt;    &lt;p&gt;4. Learn from sprint#1 and use the common learning.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;span style="color:#0000ff;"&gt;&lt;strong&gt;Sprint#3:&lt;/strong&gt;&lt;/span&gt; Review the use of loops, if-else blocks. At this iteration, the to-do is-&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;1. Is it possible to eliminate a loop?&lt;/p&gt;    &lt;p&gt;2. Is it possible to avoid the nested loops?&lt;/p&gt;    &lt;p&gt;3. Is there a large if-else-if-else block? Why is it required? Is this large conditional block a possible candidate for future change?&lt;/p&gt;    &lt;p&gt;4. Learn from sprint#2 and use the common learning.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Well, this is pretty much it. The idea is, we feel its not practical to go with an overnight policy for implementing peer code reviews. But, its very much possible that we do it in small increments and at each sprint's retrospective we bring this point. So, we are all informed that we need to do reviews, which, eventually should sustain as a best practice!&lt;/p&gt;  &lt;p&gt;If you think you have some ideas regarding this, please share it with me/my readers.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-2862129569753813203?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/2862129569753813203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/11/iterative-and-incremental.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2862129569753813203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/2862129569753813203'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/11/iterative-and-incremental.html' title='Iterative and Incremental implementation of Code Reviews'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-8588676059596018871</id><published>2008-09-06T20:50:00.001-07:00</published><updated>2009-09-22T23:57:58.684-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>CruiseControl.Net (CCNet) configuration example for NCover</title><content type='html'>&lt;p&gt;&lt;a href="http://ccnet.thoughtworks.com/"&gt;CruiseControl.Net&lt;/a&gt; is a great continuous integration tool for .Net projects. It not only continuously builds your software but provides some really helpful reports to monitor your project's progress.&lt;/p&gt;  &lt;p&gt;In agile world, we all speak of self-testing code or test driven development (TDD). If we really want to ensure our code has enough test coverage, we need to use some tool to ease our lives and NCover is a good one for this purpose. To learn more about NCover, please visit &lt;a href="http://www.ncover.com/"&gt;this&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;When integrating to CCNet, you can use a similar configuration in ccnet.config as shown below to show NCover reports for your project-&lt;/p&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red163\green21\blue21;\red0\green128\blue0;\red0\green0\blue0;}??\fs20 \cf1 &lt;\cf3 tasks\cf1 &gt;\par ??    &lt;!--\cf4  Task for MSBuild \cf1 --&gt;\par ??    &lt;\cf3 msbuild\cf1 &gt;\par ??      &lt;\cf3 executable\cf1 &gt;\cf0 C:\\WINDOWS\\Microsoft.NET\\Framework\\v3.5\\MSBuild.exe\cf1 \par ??      &lt;\cf3 projectFile\cf1 &gt;\cf0 CISample.sln\cf1 \par ??      &lt;\cf3 buildArgs\cf1 &gt;\cf0 /p:Configuration=Debug\cf1 \par ??      &lt;\cf3 targets\cf1 &gt;\cf0 Rebuild\cf1 \par ??      &lt;\cf3 timeout\cf1 &gt;\cf0 300\cf1 \par ??      &lt;\cf3 logger\cf1 &gt;\cf0 C:\\Program Files\\CruiseControl.NET\\server\\ThoughtWorks.CruiseControl.MsBuild.dll\cf1 \par ??    \par ??\par ??    &lt;!--\cf4  Task for NUnit \cf1 --&gt;\par ??    &lt;\cf3 nunit\cf1 &gt;\par ??      &lt;\cf3 path\cf1 &gt;\cf0 C:\\Program Files\\NUnit 2.4.1\\bin\\nunit-console.exe\cf1 \par ??      &lt;\cf3 assemblies\cf1 &gt;\par ??        &lt;\cf3 assembly\cf1 &gt;\cf0 CISample\\bin\\Debug\\CISample.dll\cf1 \par ??      \par ??    \par ??\par ??    &lt;!--\cf4  Task for NCover \cf1 --&gt;\par ??    &lt;\cf3 exec\cf1 &gt;\par ??      &lt;\cf3 executable\cf1 &gt;\cf0 ncover.console.exe\cf1 \par ??      &lt;\cf3 baseDirectory\cf1 &gt;\cf0 CISample\\bin\\Debug\\\cf1 \par ??      &lt;\cf3 buildArgs\cf1 &gt;\cf0 nunit-console CISample.dll //xml coverage.xml //ea NUnit.Framework.TestFixtureAttribute\cf1 \par ??    \par ??\par ??    &lt;!--\cf4  Task for NCoverExplorer \cf1 --&gt;\par ??    &lt;\cf3 exec\cf1 &gt;\par ??      &lt;\cf3 executable\cf1 &gt;\cf0 NCoverExplorer.Console.exe\cf1 \par ??      &lt;\cf3 baseDirectory\cf1 &gt;\cf0 CISample\\bin\\Debug\\\cf1 \par ??      &lt;\cf3 buildArgs\cf1 &gt;\cf0 coverage.xml /xml /r:ModuleMethodFunctionSummary\cf1 \par ??    \par ??\par ??  } --&gt;  &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:courier new;font-size:10pt;color:black;"&gt;   &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;tasks&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;!--&lt;/span&gt;&lt;span style="color:green;"&gt; Task for MSBuild &lt;/span&gt;&lt;span style="color:blue;"&gt;--&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;msbuild&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;executable&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;executable&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;projectFile&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;CISample.sln&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;projectFile&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;buildArgs&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;/p:Configuration=Debug&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;buildArgs&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;targets&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;Rebuild&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;targets&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;timeout&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;300&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;timeout&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;logger&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;logger&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;msbuild&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   20&lt;/span&gt; &lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   21&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;!--&lt;/span&gt;&lt;span style="color:green;"&gt; Task for NUnit &lt;/span&gt;&lt;span style="color:blue;"&gt;--&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   22&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;nunit&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   23&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;path&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\NUnit 2.4.1\bin\nunit-console.exe&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;path&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   24&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;assemblies&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   25&lt;/span&gt; &lt;span style="color:blue;"&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;assembly&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;CISample\bin\Debug\CISample.dll&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;assembly&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   26&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;assemblies&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   27&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;nunit&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   28&lt;/span&gt; &lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   29&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;!--&lt;/span&gt;&lt;span style="color:green;"&gt; Task for NCover &lt;/span&gt;&lt;span style="color:blue;"&gt;--&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   30&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;exec&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   31&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;executable&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;ncover.console.exe&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;executable&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   32&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;baseDirectory&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;CISample\bin\Debug\&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;baseDirectory&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   33&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;buildArgs&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;nunit-console CISample.dll //xml coverage.xml //ea NUnit.Framework.TestFixtureAttribute&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;buildArgs&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   34&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;exec&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   35&lt;/span&gt; &lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   36&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;!--&lt;/span&gt;&lt;span style="color:green;"&gt; Task for NCoverExplorer &lt;/span&gt;&lt;span style="color:blue;"&gt;--&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   37&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;exec&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   38&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;executable&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;NCoverExplorer.Console.exe&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;executable&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   39&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;baseDirectory&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;CISample\bin\Debug\&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;baseDirectory&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   40&lt;/span&gt; &lt;span style="color:blue;"&gt;      &amp;lt;&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;buildArgs&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;coverage.xml /xml /r:ModuleMethodFunctionSummary&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;buildArgs&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   41&lt;/span&gt; &lt;span style="color:blue;"&gt;    &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;exec&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   42&lt;/span&gt; &lt;/p&gt;    &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   43&lt;/span&gt; &lt;span style="color:blue;"&gt;  &amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(163, 21, 21);"&gt;tasks&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;You see that there are two NCover related &amp;lt;exec&amp;gt; nodes. The first one generates the coverage.xml. Then using this first one you can create actual report to present specifying the desired level of details of the report.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-8588676059596018871?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/8588676059596018871/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/09/cruisecontrolnet-ccnet-configuration.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8588676059596018871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/8588676059596018871'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/09/cruisecontrolnet-ccnet-configuration.html' title='CruiseControl.Net (CCNet) configuration example for NCover'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34526917.post-6370029949466918913</id><published>2008-09-01T22:04:00.001-07:00</published><updated>2009-04-20T20:45:35.337-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Set and Compile using C# Language Version 2.0 in Visual Studio 2008</title><content type='html'>&lt;p&gt;I know, while most of you are very happy with the new features in Visual Studio 2008, its sad that not all your deployment environments are upgraded to .Net framework 3.5. I had a similar situation as well on one of my projects.&lt;/p&gt;  &lt;p&gt;Its great that you can just navigate to a VS 2008 project file properties and from the Application Tab select the Target .Net Framework version to use one of .Net 2.0, 3.0 and 3.5. But this doesn't solve all the problems. You will soon discover that, your application doesn't show an error when you write C# 3.0 code with the target framework set to 2.0. This is because, the IDE by default uses the latest language version by default.&lt;/p&gt;  &lt;p&gt;To solve this problem, Navigate to &lt;span style="color:#8080ff;"&gt;&lt;strong&gt;project properties &amp;gt; Build &amp;gt; Advanced &amp;gt; Language Version and choose ISO-2 (or ISO-1).&lt;/strong&gt;&lt;/span&gt; Now with this information, the VS 2008 will start showing compiler errors for features that don't comply to the version specification!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34526917-6370029949466918913?l=blog.smsohan.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.smsohan.com/feeds/6370029949466918913/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.smsohan.com/2008/09/set-and-compile-using-c-language.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6370029949466918913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34526917/posts/default/6370029949466918913'/><link rel='alternate' type='text/html' href='http://blog.smsohan.com/2008/09/set-and-compile-using-c-language.html' title='Set and Compile using C# Language Version 2.0 in Visual Studio 2008'/><author><name>SM Sohan</name><uri>https://profiles.google.com/109651092608768339580</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-2TyoUH290eI/AAAAAAAAAAI/AAAAAAAAAW0/_2OovUGLzaQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry></feed>
