<?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-20359354</id><updated>2011-07-20T09:46:13.652-04:00</updated><title type='text'>Aaron Feng</title><subtitle type='html'>Agile Software Development (XP), Test Driven Development, .NET, etc.....</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>56</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-20359354.post-115008471695211166</id><published>2006-06-11T23:56:00.000-04:00</published><updated>2006-06-12T09:56:37.533-04:00</updated><title type='text'>Closed</title><content type='html'>I have been having a lot of problems with blogger, so I decided to move my blog.  My new home can be found &lt;a href="http://geekswithblogs.net/afeng"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-115008471695211166?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/115008471695211166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=115008471695211166' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/115008471695211166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/115008471695211166'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/06/closed.html' title='Closed'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114974234974379076</id><published>2006-06-08T00:52:00.000-04:00</published><updated>2006-06-10T01:07:28.346-04:00</updated><title type='text'>Agile Transition</title><content type='html'>&lt;span style="font-size:85%;"&gt;One of the reasons  my current job is so pleasant to work for is that everyone on the team has made the Agile transition seamlessly.  Making the Agile transition requires change of mind set, and sometimes that is not the easiest thing to do.  &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://blogs.msdn.com/mpuleio/"&gt;Michael Puleio&lt;/a&gt; described the changes he has made in his &lt;a href="http://blogs.msdn.com/mpuleio/comments/606561.aspx"&gt;post&lt;/a&gt; since he joind &lt;a href="http://msdn.microsoft.com/practices/default.aspx"&gt;Microsoft patterns &amp;amp; practices&lt;/a&gt;.  A lot of the changes he made I am sure a lot of us on the team have also experienced, so I will not try to duplicate here.  Just read his posts :)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114974234974379076?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114974234974379076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114974234974379076' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114974234974379076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114974234974379076'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/06/agile-transition.html' title='Agile Transition'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114900706133574774</id><published>2006-06-03T12:37:00.000-04:00</published><updated>2006-06-03T10:46:27.946-04:00</updated><title type='text'>Random Thoughts</title><content type='html'>&lt;span style="font-size:85%;"&gt;Nowadays people think Agile development is a substitute for success.  As &lt;a href="http://alistair.cockburn.us/"&gt;Alistair Cockburn&lt;/a&gt; found out during his researching years at IBM, a team can succeed when there is no process at all.  A process will not change the team or make them super developers.  The purpose of Agile development is to minimize the risks for the business people and developers.  In the Agile world we put down our psychic prediction hat and react to changes.  After all, no two pieces of software are alike.  With that said, there is no guarantee a project will not fail.  People usually associate failed projects with projects that are cancelled.  A project can still be considered some what of a success if it gets cancelled before all the money gets drained away.   A win for the business.&lt;br /&gt;&lt;br /&gt;Managers tend to jump on the process ban wagon before looking at the team.  Ultimately a well defined process will not write the software, your developers will.  Team chemistry is very important, in my opinion, because you could have all-star players, but if no one can work together, it is very hard to ship a product.  I think it is very important to have a variable skill level team.  In that type of environment, people will tend to explorer other possibilities.  Modern software is too complicated to make text book assumptions.  On top of that, as the saying goes, a team does not need too many chefs in the kitchen.&lt;br /&gt;&lt;br /&gt;Many companies are obsessed with assembling the ultimate dream team based on skill set, but having great skills does not equal a great team player.  A very important ingredient in the recipe to create a dream team is to find people who love doing what they do, but this tends to be over looked.  When everyone on the team is working as one, the variable skill levels tends to disappear. &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114900706133574774?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114900706133574774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114900706133574774' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114900706133574774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114900706133574774'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/06/random-thoughts.html' title='Random Thoughts'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114887114417482770</id><published>2006-05-28T22:52:00.000-04:00</published><updated>2006-05-28T22:53:52.090-04:00</updated><title type='text'>Indigo Security with AzMan</title><content type='html'>In the &lt;a href="http://aaronfeng.blogspot.com/2006/05/declarative-security-with-azman-and.html"&gt;previous post&lt;/a&gt;, I mentioned how client side security can be accomplished by using .NET attributes with AzMan.  Here are a couple of good posts on server side security using Indigo with AzMan:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://steve.emxsoftware.com/Indigo-WCF/WCF+Extensibility+Behaviors+and+Inspectors"&gt;WCF Extensibility: Behaviors and Inspectors&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://codebetter.com/blogs/sam.gentile/archive/2006/05/26/145540.aspx"&gt;How To: STS/Windows Authentication with ADAM/AD, Roles in AzMan with WCF&lt;/a&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/20359354-114887114417482770?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114887114417482770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114887114417482770' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114887114417482770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114887114417482770'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/indigo-security-with-azman.html' title='Indigo Security with AzMan'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114867028054455606</id><published>2006-05-27T09:02:00.000-04:00</published><updated>2006-05-27T00:54:08.533-04:00</updated><title type='text'>Declarative Security with AzMan and CAB</title><content type='html'>&lt;a href="http://aaronfeng.blogspot.com/2006/05/dynamically-disable-controls-on-fly.html"&gt;&lt;span style="font-size:85%;"&gt;In a &lt;/span&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://aaronfeng.blogspot.com/2006/05/dynamically-disable-controls-on-fly.html"&gt;previous post&lt;/a&gt;, I mentioned Controls can be dynamically disabled based on users' permission by using .NET attribute with &lt;a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/"&gt;AzMan&lt;/a&gt; and &lt;a href="http://practices.gotdotnet.com/projects/cab"&gt;CAB&lt;/a&gt;.  This week is our security iteration, so we are able to test the concept described in this &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html/Attbasauth.asp"&gt;MSDN article&lt;/a&gt;.  The article suggested modifying the &lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;RootWorkItemInitializationStrategy.cs&lt;/span&gt;&lt;span style="font-size:85%;"&gt;, so when each objects are built up, it will be disabled based on the attribute declared on the Controls and users' permission.  I personally do not like the idea of modifying 3rd party code when it can be avoided.  There is another way to accomplish the same thing by creating a custom &lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;BuilderStrategy&lt;/span&gt;&lt;span style="font-size:85%;"&gt; then overiding &lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;AddBuilderStrategies &lt;/span&gt;&lt;span style="font-size:85%;"&gt;method in the shell, so you can add the strategy during run time.  It will look something like this:&lt;br /&gt;&lt;/span&gt;&lt;pre&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; YourShell &lt;span style="color: rgb(128, 128, 48);"&gt;:&lt;/span&gt; FormShellApplication &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;protected&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;override&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; AddBuilderStrategies&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;Builder builder&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;base&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;AddBuilderStrategies&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;builder&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; builder&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Strategies&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;AddNew&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;BuilderStage&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Initialization&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;span style="font-size:85%;"&gt;&lt;workitem, yourform=""&gt;&lt;authorizationbuilderstrategy&gt;Here are some pitch falls we ran across when we tried to implement security with attributes.&lt;br /&gt;&lt;/authorizationbuilderstrategy&gt;&lt;/workitem,&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Dynamically created controls cannot be applied.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Literal strings are used in the declaration of attributes, so if anything changes with the security or Control, it will result in runtime rather than compile time.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;The declaration of Controls cannot be in the designer file because the designer file will get overwritten.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Performance penalty during startup of the application.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Explicit logic already exists to enable or disable the UI based on the state of the system will override the attribute.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;In that article, XML file is used on the client side to map the &lt;a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/"&gt;AzMan&lt;/a&gt; operations.  The configuration file can be completely removed if the list of valid operations is retrieved from a service layer based on the user's identity.  This is recommended so all the operations can be retrieved from a central location.  The article mentioned the source code is "demo" quality,  and he really means it.  Overall, it was pretty painless to implement the concept described in the article.&lt;br /&gt;&lt;br /&gt;Client side security is for eye candy, but the real security comes when you secure your service layer.  Service layer can be secured using declarative approach too, but that is for another time.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114867028054455606?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114867028054455606/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114867028054455606' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114867028054455606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114867028054455606'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/declarative-security-with-azman-and.html' title='Declarative Security with AzMan and CAB'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114653305679780698</id><published>2006-05-26T15:35:00.000-04:00</published><updated>2006-05-26T15:37:39.303-04:00</updated><title type='text'>Invisible Leadership</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;I have been trying to write this article for weeks now, and I cannot seem to fix the article to the point where I would like.  I am going to post it anyways, just as a caution some thoughts might not be well formulated.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;For the past week we have been talking a lot about leadership at work. We bounced around ideas on what leadership means to us. We decided that in order for leadership to exist, there must be a leader. So the next natural question for us is what is a leader?&lt;br /&gt;&lt;br /&gt;Fundamentally there are two types of leaders: institutionally defined or defined by your peers. Often this can be the same person, but it does not have to be. In this post I will talk more about non-institutionally defined leaders because it seems more interesting and unconventional. From this point on, I will just refer to a non-institutionally defined leader just as leader.&lt;br /&gt;&lt;br /&gt;This type of leader can exist in any profession where people have to work together, not exclusively in software development. What are some characteristics of this type of leader? Since he or she is pretty much invisible from the corporate point of view, below I list some common attributes of a leader: &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;ul type="disc"&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Enjoys and cares about the      type of work being produced.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Strong problem solver.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Approachable personality.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Shares ideas with others.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Assumes good faith of others.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Shares a common goal with other      members on the team.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Exhibits patience with others.&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;Works well with others.&lt;/span&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;"&gt;Strong  Communication skills.&lt;/span&gt; &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;In order for one to be a leader, he or she must have followers right? How can an "invisible" person lead? I believe this person is only invisible to outsiders, but in reality, other members of the team know who this person is. This person leads by examples, and will set the bar high &lt;span style="font-weight: bold;"&gt;(I know this is a cliche, but it is true)&lt;/span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;So far I have been talking about this magical person called the leader in a singular form. I believe there could be multiple leaders on a team, and a leader usuahlly emerges when he is able to provide insights to the problem.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;So far I have described what a leader is, but why would anyone want to follow a leader instead of leading themselves?  I think the most important attribute of a leader is the ability to solve a problem and convey the idea to the team.  It is unlikely that everyone on the team can solve all the problems, assuming the problem is non-trivial.  The person that is able to solve the problem with the best solution would be the leader in this case.  Others would want to follow because we are all working towards a common goal, and would like to learn how the problem is being solved.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size:85%;"&gt;Having a leader is important to any team situation.   Sometimes leaders inspire their team members to work harder so that they may too lead in some areas.  Ultimately, this is&lt;/span&gt;&lt;span style="font-size:10;"&gt;&lt;/span&gt;&lt;span style="font-size:10;"&gt;&lt;span style="font-size:85%;"&gt; &lt;span style="font-weight: bold;"&gt;beneficial&lt;/span&gt;&lt;o:p style="font-weight: bold;"&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt; to the entire team.&lt;br /&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/20359354-114653305679780698?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114653305679780698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114653305679780698' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114653305679780698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114653305679780698'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/invisible-leadership.html' title='Invisible Leadership'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114782986299543750</id><published>2006-05-16T20:59:00.000-04:00</published><updated>2006-05-16T23:47:11.306-04:00</updated><title type='text'>CoolCommands</title><content type='html'>&lt;span style="font-size:85%;"&gt;Yesterday I found a really cool Visual Studio 2005 Addin.  It adds many useful commands to the context menu.  I will just list some of the features I like, but I will let you be the judge.&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Open Explorer browser by right clicking on a file.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Automatically resolves missing references.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Locate item in Solution Explorer on demand when active tracking is turned off.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Copy and paste references from one project to another.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Add multiple projects at once.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Collapse all projects.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt; Visual Studio Command prompt here.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;Since we use Subversion it is very useful to be able to open the selected file in Explorer from Visual Studio.  However, on my machine it was a little bit slow (my machine is known to be slow at times).  I have the Solution Explorer active tracking turned off because it gets annoying when you are jumping from one file to another.  With the addin, I can tell Visual Studio when to do the active tracking.  Try it, let me know what you think.&lt;br /&gt;&lt;br /&gt;The latest version can be found &lt;a href="http://weblogs.asp.net/gmilano/archive/2006/05/10/446010.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114782986299543750?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114782986299543750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114782986299543750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114782986299543750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114782986299543750'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/coolcommands.html' title='CoolCommands'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114765440489810743</id><published>2006-05-14T19:46:00.000-04:00</published><updated>2006-05-15T20:54:44.170-04:00</updated><title type='text'>Refactoring from Active Record to Repository</title><content type='html'>&lt;span style="font-size:85%;"&gt;In the begining of our project, we started with a &lt;a href="http://www.martinfowler.com/eaaCatalog/repository.html"&gt;Repository&lt;/a&gt; like pattern for retrieving our entity objects.  Our repositories were muddled, and at times, contained a lot of our business logic.  We followed the basic pattern to create a repository for each entity object.  It produced a lot of duplication because many repositories shared many very similar operations.  The result was a confusing system, and made retrieving entity objects harder than it has to be.  We decided to refactor to Active Record because we thought that will solve all our problems.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.martinfowler.com/eaaCatalog/activeRecord.html"&gt;Active Record&lt;/a&gt; pattern made testing harder because static methods can not be polymorphic.  Recently, we are leaning more towards repository pattern again, but we want to design it right this time.  Repository will definitely alleviate testing.  On top that, it will also allow us to cache data in a simple and centralized manner.&lt;br /&gt;&lt;br /&gt;One thing that is not clear to us is which entity object receives a repository.   Ideally, we do not want to create a repository for every entity in our system.  In &lt;a href="http://www.bookpool.com/sm/0321125215"&gt;Domain-Driven Design&lt;/a&gt; by Eric Evan, he talks about using Aggregate to eliminate the need for creating a repository for each entity object.  Aggregate is a group of associated objects that will be treated as a single unit.  The root aggregate is an object that will encapsulate all associated objects.  The client will have to retrieve the root in order to communicate with any objects inside of the root.  Only entity objects will receive a repository is the root.&lt;br /&gt;&lt;br /&gt;I think we are on the right path, but more disscusion is required to fully understand the implication of moving toward a full blown repository pattern.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114765440489810743?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114765440489810743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114765440489810743' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114765440489810743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114765440489810743'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/refactoring-from-active-record-to.html' title='Refactoring from Active Record to Repository'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114765002694425528</id><published>2006-05-14T19:40:00.000-04:00</published><updated>2006-05-14T21:06:36.530-04:00</updated><title type='text'>Popup Advertisement</title><content type='html'>&lt;span style="font-size:85%;"&gt;Recently someone mentioned that there was a popup advertisement on my blog.  I was unaware of it at the time, and it should be removed by now.  I believe the popup was caused by some JavaScript I added for traffic statistics.  If the popup is still occurring, please let me know.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114765002694425528?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114765002694425528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114765002694425528' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114765002694425528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114765002694425528'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/popup-advertisement.html' title='Popup Advertisement'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114697656294896411</id><published>2006-05-06T23:28:00.000-04:00</published><updated>2006-05-07T01:05:00.643-04:00</updated><title type='text'>Dynamically Disable Controls on the Fly</title><content type='html'>&lt;span style="font-size:85%;"&gt;In an earlier &lt;a href="http://aaronfeng.blogspot.com/2006/05/role-based-command-authentication-with.html"&gt;post&lt;/a&gt;, I mentioned we are starting to look at how to implement role based security in our Smart Client application.  Since we are using CAB, it allows us to dynamically load modules on the fly without much effort.  We need more control of the UI than just preventing users to see certain parts of the software.  Ideally we would want to be able to restrict the UI at a more granular level, the control level.  Traditionally, people accomplished this by adding if/else statements to the UI.  This method can get messy very fast, and it is very hard to maintain.  Before I go on, I would like to thank &lt;a href="http://www.chrisholmesonline.com/"&gt;Chris Holmes&lt;/a&gt; (the guy who wrote the first version of the Outlook Explorer bar before &lt;a href="http://staff.southworks.net/blogs/matiaswoloski/default.aspx"&gt;Matias Woloski&lt;/a&gt;) on sending me so many userful links and ideas regarding this issue.&lt;br /&gt;&lt;br /&gt;Irena Kennedy has a great article on how role based security can be accomplished at the control level using attributes.  The article can be found &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html/Attbasauth.asp"&gt;here&lt;/a&gt;.  The article assumes that you are using CAB and AzMan, but the concept is not exclusive to these technologies (It is worth to note that AzMan requires &lt;span style="font-weight: bold;"&gt;COM interop&lt;/span&gt;, so the performance hit has to be considered).  It works by decorating the control you want to behavor differently based on user's role.   For example, if you want only the manager to have the ability to delete users, you would declare the following attribute on the button:&lt;br /&gt;&lt;br /&gt;[Authorization("DeleteUser", "Enabled", False)]&lt;br /&gt;&lt;br /&gt;DeleteUser is the operation that is defined in AzMan, and in this case the operation will be associted with the manager role.  If the user is not in the role, the button will appear disabled.  The code that is acutally doing all the work lives inside of CAB in the RootWorkItemInitializationStrategy.cs.  The good thing about this is the logic is isolated in one place, but the down side is we will have to remember to modify CAB code whenever a new version is released.&lt;/span&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;/pre&gt;&lt;pre class="code"&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114697656294896411?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114697656294896411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114697656294896411' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114697656294896411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114697656294896411'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/dynamically-disable-controls-on-fly.html' title='Dynamically Disable Controls on the Fly'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114688060835001010</id><published>2006-05-05T20:24:00.000-04:00</published><updated>2006-05-05T22:54:14.563-04:00</updated><title type='text'>Databinding is EVIL</title><content type='html'>&lt;span style="font-size:85%;"&gt;Ok, I am &lt;span style="font-weight: bold;"&gt;officially&lt;/span&gt; done with databinding.  Today I was working with &lt;a href="http://steve.emxsoftware.com/"&gt;Steve&lt;/a&gt; on a piece of fairly trivial code, all we wanted to do was dirty checking on a few controls and provide the ability to roll back on a simple form. We poked around in the designer, and clicked here and there, then changed a couple lines of code. Overall it was very annoying, and very repetitive work because the databinding was acting flaky. Eventually we got the dirty checking on a modal form to work correctly. Before we checked in, we smoked the application real fast just to make sure everything was still working. We clicked around for a few seconds, we noticed the dirty checking was not working correctly sometimes, but we could not pin point the exact cause. By chance, we figured out the problem. If we move the modal form around on the screen after changing a value in a combo box, databinding goes nuts which breaks the dirty checking. For the most part of the day, I thought I was high because one second databinding was working, next it was blowing up.&lt;br /&gt;&lt;br /&gt;We have been feeling the pain on databinding for a while now. I even wrote databinding on our house of pain white board, when I thought I understood databinding.  We decided to stick with it because datatbinding makes things "&lt;span style="font-weight: bold;"&gt;look&lt;/span&gt;" so easy. It is like magic. The problem with databinding is it makes something that is very comoplex under the covers to appear stupid simple. Almost every example found in any book or on the Internet uses databinding.  It seems databinding is the way to go. Databinding works fine if you have very simple UI that does nothing but display data in a primitive way. Soon as you introduce complex and rich UI, databinding makes things much harder. If databinding is so easy to use, why is &lt;a href="http://www.softinsight.com/bnoyes/"&gt;Brian Noyes&lt;/a&gt;' book "&lt;a href="http://www.bookpool.com/sm/032126892X"&gt;Data Binding with Windows Forms 2.0&lt;/a&gt;" 696 pages? There is a lot more to databinding than what meets the eye, which can lead to some serious disconnect between team members. This can often lead to dangerous situations when the wrong assumptions are made. Before you know it, you are adding hacks, so databinding would work correctly as you would expect.&lt;br /&gt;&lt;br /&gt;The predictibility of databinding is very low because not all controls behave the same way when databinding is used.  Duplication is one of the worst things you can do in any program.  The concept of what value the control is displaying is duplicated.  For example, if you want to retrieve data in a combo box, do you get it from the binding source or from the control it's self?  The worst part of  all is the value displayed in the control can be out of sync with the underlying binding source.&lt;br /&gt;&lt;br /&gt;I hope this does not sound like I am ranting, because I am not. Maybe I am old fashioned, but manually populating the controls will be much easier and more understandable. On top of that, the code will be more testable. Less magic is a good thing.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114688060835001010?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114688060835001010/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114688060835001010' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114688060835001010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114688060835001010'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/databinding-is-evil.html' title='Databinding is EVIL'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114670971298845448</id><published>2006-05-04T08:55:00.000-04:00</published><updated>2006-05-03T22:28:37.630-04:00</updated><title type='text'>Role Based Command Authentication With CAB</title><content type='html'>&lt;span style="font-size:85%;"&gt;At work, we've been having some conversations about the security architecture for our Smart Client.  Specifically, we talked about using &lt;a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/"&gt;Authorization Manager&lt;/a&gt; (&lt;a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/"&gt;AzMan&lt;/a&gt;) to define roles within our application.  I personally have no experience with AzMan, so I decided to google it.  I found a couple of useful articles on &lt;a href="http://staff.southworks.net/blogs/mariano"&gt;Mariano Szklanny&lt;/a&gt; blog on CAB role based authentication.  One of them is using &lt;a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/"&gt;AzMan&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://staff.southworks.net/blogs/mariano/archive/2006/03/15/260.aspx"&gt;CAB - Adding Command-level security to applications&lt;/a&gt;&lt;br /&gt;&lt;a href="http://staff.southworks.net/blogs/mariano/archive/2006/03/16/262.aspx"&gt;CAB - CommandAuthorization AzMan Sample Application&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114670971298845448?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114670971298845448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114670971298845448' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114670971298845448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114670971298845448'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/role-based-command-authentication-with.html' title='Role Based Command Authentication With CAB'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114654355793657437</id><published>2006-05-03T08:38:00.000-04:00</published><updated>2006-05-03T08:38:43.946-04:00</updated><title type='text'>.NET BigInteger and BigDecimal</title><content type='html'>I always wondered why there are no classes that represent big integers and decimals in the .NET API like the classes found in Java.  Apparantly, as &lt;a href="http://geekswithblogs.net/gyoung/"&gt;Greg&lt;/a&gt; pointed out in his &lt;a href="http://geekswithblogs.net/gyoung/archive/2006/05/01/76869.aspx"&gt;post&lt;/a&gt;, the BigInteger and BigDecimal exists in the J# redistributables.  It lives inside vjslib.dll.  I guess my question is why does it lives in J# redistributables, and is it safe to use in &lt;span style="font-weight: bold;"&gt;any&lt;/span&gt; .NET application?  BigInteger or BigDecimal can be very useful to any financial or mathematical application.  You would think they would not hide it in the J# redistributables.  Who uses J# anyways?  ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114654355793657437?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114654355793657437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114654355793657437' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114654355793657437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114654355793657437'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/net-biginteger-and-bigdecimal.html' title='.NET BigInteger and BigDecimal'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114662771817953155</id><published>2006-05-02T23:16:00.000-04:00</published><updated>2006-05-02T23:41:58.760-04:00</updated><title type='text'>Aardvark'd</title><content type='html'>We all know &lt;a href="http://www.joelonsoftware.com/"&gt;Joel&lt;/a&gt; has a great blog, published a couple of great books, but on top of that, he owns a great company.  What else can a geek do after these accomplishments?  How about an indenpendent film?  &lt;a href="http://www.projectaardvark.com/movie/"&gt;Aardvark'd&lt;/a&gt; is a documentary on last summer's interns at his company, &lt;a href="http://www.fogcreek.com/"&gt;Fog Creek&lt;/a&gt;.  I checked out the &lt;a href="http://www.projectaardvark.com/movie/aardvarkdtrailersmall.mov"&gt;trailer&lt;/a&gt;, it looked interesting, but it is a little short in my opinion.  What will Joel do next?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114662771817953155?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114662771817953155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114662771817953155' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114662771817953155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114662771817953155'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/05/aardvarkd.html' title='Aardvark&apos;d'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114645253946695064</id><published>2006-04-30T22:46:00.000-04:00</published><updated>2006-04-30T23:02:20.036-04:00</updated><title type='text'>Rethrowing Exceptions</title><content type='html'>It is very common to see code that catches an exception then rethrows it without doing anything.  &lt;a href="http://kinnie.blogspot.com/2006/03/bad-exceptionhandling.html"&gt;Pieter Gheysens&lt;/a&gt; has a post on why you should not just rethrow the exception.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114645253946695064?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114645253946695064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114645253946695064' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114645253946695064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114645253946695064'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/rethrowing-exceptions.html' title='Rethrowing Exceptions'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114593376075582597</id><published>2006-04-25T22:53:00.000-04:00</published><updated>2006-04-26T14:40:12.740-04:00</updated><title type='text'>Lazy User Interface Part III</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2772/2038/1600/solution.1.gif"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://photos1.blogger.com/blogger/2772/2038/320/solution.1.gif" alt="" border="0" /&gt;&lt;/a&gt;Lets start with our fictitious application from the &lt;a href="http://www.testdriven.com/modules/news/"&gt;TDD &lt;/a&gt;approach; write the tests first, and let the tests drive our design.  This time I will start from the presenter level to ensure all the UI functionalities are testable.  Before we start I would like to share the overall structure of the application, then I will touch more in depth in necessary areas.  Let take a look at all the files listed in the solution explorer.  All the files requiring the application to run are in the RealtorApplication project, and the other project is only for automated testing.  Each view implements a specific interface.  For example, CustomerView will  implement ICustomerView.  Each view has a property for the presenter to be injected as such:&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold; color: rgb(128, 0, 0);"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; CustomerViewPresenter Presenter &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; get &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;presenter&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt; set &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;presenter &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; value&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;View &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;The RealtorPresenter takes in an IRealtorService because when the button is pressed on the NavigationView, the RealtorPresenter needs to retreive data from the service.  You can think of the service as a facade for where the data should be retrieved in this case.  I am going to use DataBinding, so CustomerView and RealtorView will have their own BindingSource and it will be exposed as a property.&lt;br /&gt;&lt;br /&gt;In the test project you will notice there is a folder for all the mocks. I am only interested in making the view testable, so it is safe to mock everything else.  Lets start with the NavigationView because that is where the user interaction will happen first.&lt;pre&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;namespace&lt;/span&gt; RealtorApplicationTest &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;TestFixture&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; NavigationViewPresenterTest &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; NavigationViewPresenter presenter&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;SetUp&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; SetUp&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;     presenter &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; NavigationViewPresenter&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;Test&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; CanNotifyNavigationViewWhenButtonIsClicked&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;     EventSubscriber subscriber &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; EventSubscriber&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;LoadData &lt;span style="color: rgb(128, 128, 48);"&gt;+&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; EventHandler&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;subscriber&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Handler&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;NotifyNavigationView&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     Assert&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;IsTrue&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;subscriber&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;HasBeenCalled&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;Test&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; NotifyNavigationWithNoHandler&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;     EventSubscriber subscriber &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; EventSubscriber&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;NotifyNavigationView&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;We start with these two simple tests. The first test ensures that the presenter will fire an event when the button is clicked .  The second test makes sure no exception are thrown when the event is not being handled.  EventSubscriber is just a helper class that allows me to test if the event gets fired.&lt;br /&gt;&lt;br /&gt;When practicing &lt;a href="http://www.testdriven.com/modules/news/"&gt;TDD&lt;/a&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;, it is very important to make the test fail before you make the test pass.  Since all the tests are passing, we can wire up the event to fire when the button is envoked in the NavigationView.&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; loadButton_Click&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;object&lt;/span&gt; sender&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; EventArgs e&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;NotifyNavigationView&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;Lets move on to the RealtorViewPresenter and write a test before we run the application.&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;namespace&lt;/span&gt; RealtorApplicationTest &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;TestFixture&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; RealtorViewPresenterTest &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; RealtorViewPresenter presenter&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; MockRealtorView view&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;private&lt;/span&gt; MockRealtorService service&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;SetUp&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; SetUp&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;     service &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; MockRealtorService&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     view &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; MockRealtorView&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     presenter &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; RealtorViewPresenter&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;service&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;View &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; view&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;Test&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; HasTheServiceBeenCalled&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;     presenter&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;OnLoadData&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; EventArgs&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Empty&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     Assert&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;IsTrue&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;service&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;HasFindAllRealtorsBeenCalled&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     Assert&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;IsTrue&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;view&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;HasBindingSourceBeenCalled&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;When the RealtorViewPresenter receives the event it should call FindAllRealtors() and set the databinding on it.  The two asserts ensure that happens.  The LoadData event should be wired to RealtorViewPresenter.OnLoadData().  Everything so far has been very basic.    I will continue with the rest in the next few days.&lt;br /&gt;&lt;br /&gt;&lt;!-- ***** BEGIN LICENSE BLOCK *****    - Version: MPL 1.1/GPL 2.0/LGPL 2.1    -    - The contents of this file are subject to the Mozilla Public License Version    - 1.1 (the "License"); you may not use this file except in compliance with    - the License. You may obtain a copy of the License at    - http://www.mozilla.org/MPL/    -    - Software distributed under the License is distributed on an "AS IS" basis,    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    - for the specific language governing rights and limitations under the    - License.    -    - The Original Code is the Colorer Library.    -    - The Initial Developer of the Original Code is    - Cail Lomecb &lt;cail@nm.ru&gt;.    - Portions created by the Initial Developer are Copyright (C) 1999-2005    - the Initial Developer. All Rights Reserved.    -    - Contributor(s):    -    - Alternatively, the contents of this file may be used under the terms of    - either the GNU General Public License Version 2 or later (the "GPL"), or    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),    - in which case the provisions of the GPL or the LGPL are applicable instead    - of those above. If you wish to allow use of your version of this file only    - under the terms of either the GPL or the LGPL, and not to allow others to    - use your version of this file under the terms of the MPL, indicate your    - decision by deleting the provisions above and replace them with the notice    - and other provisions required by the LGPL or the GPL. If you do not delete    - the provisions above, a recipient may use your version of this file under    - the terms of any one of the MPL, the GPL or the LGPL.    -    - ***** END LICENSE BLOCK ***** --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114593376075582597?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114593376075582597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114593376075582597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114593376075582597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114593376075582597'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/lazy-user-interface-part-iii.html' title='Lazy User Interface Part III'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114584781242886126</id><published>2006-04-23T22:49:00.000-04:00</published><updated>2006-04-25T14:15:32.960-04:00</updated><title type='text'>Lazy User Interface Part II</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2772/2038/1600/LazyApplication.1.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://photos1.blogger.com/blogger/2772/2038/320/LazyApplication.1.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;In order to make the application testable, proper separation is required.  I will be using &lt;a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;MVP &lt;/a&gt;pattern to separate out the tiers.  &lt;a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;MVP&lt;/a&gt; is a derivitive of &lt;a href="http://www.martinfowler.com/eaaCatalog/modelViewController.html"&gt;MVC&lt;/a&gt;, the only difference is the View only communicates with the Presenter, and the Model only knows about the Presenter, not the View.  I personally like &lt;a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;MVP&lt;/a&gt; better because I think it is a little cleaner when the Model does not know about the View.&lt;br /&gt;&lt;br /&gt;Since I have been shopping around for a house, I decided to make this superficial real estate application.  The actual structure of the application and the data it holds are irrelevant, that is why they are over simplified.  The import thing here is the interactions between objects to make the code testable.  I might update the UI to make it more "realistic" later if it requires it.&lt;br /&gt;&lt;br /&gt;Before we start, let me explain the basic layout of the UI.  There are three views, and one presenter per view.  The view on the left is the NavigationView.  The purpose of it is to load fictitious data into the top right view which is the RealtorView.  When the user selects a realtor from the RealtorView it will show all the customers associated with that particular realtor.  For those who noticed the title of the article, Lazy User Interface is refering to making the view as lazy as possible by delegating everything to its presenter.  I will start coding the lazy UI in the next post.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114584781242886126?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114584781242886126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114584781242886126' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114584781242886126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114584781242886126'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/lazy-user-interface-part-ii.html' title='Lazy User Interface Part II'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114581104335658775</id><published>2006-04-23T10:54:00.000-04:00</published><updated>2006-04-23T23:31:27.043-04:00</updated><title type='text'>Lazy User Interface Part I</title><content type='html'>&lt;span style="font-size:85%;"&gt;I was recently working on code that deals mostly with the front-end portion of our software.&lt;br /&gt;Before I began the task, I glanced over the wire frames, opened up the designer, dragged and dropped a few controls here and there, changed  a few properties, and added some methods to handle the business logic. Before lunch, the task was complete.&lt;br /&gt;&lt;br /&gt;Something just did not feel right about this task.  I noticed that the time I spent writing and running unit tests was significantly less than usual.  At first I dismissed the thought because I convinced myself most of the code was UI related, so no need to test. After work, I decided to take another look.  I started at the presenter level (we use &lt;a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;MVP pattern&lt;/a&gt;), and noticed very little code was in the presenter, and the view seemed to be much larger.  Since we practice &lt;a href="http://www.testdriven.com/modules/news/"&gt;TDD&lt;/a&gt; at work, how could this happen?&lt;br /&gt;&lt;br /&gt;Part of the problem was that I started the code at the UI level instead of the presenter level. The problem with starting the code at the view level is because everything seems to belong inside the view.  For example, when the user right clicks on the grid, it will show a context menu and the items enabled in the context menu are dependent on what the user has selected on the grid.  Pretty simple scenario, right?  When I worked on this part, I enabled the context menu items in the view because it seems like the view should be responsible for it.  After all, context menu it is a visual thing.  In order to figure out which context menu items to enable, I need to figure out what the user has selected.  How can the view retrieve the data?  Oh wait, the grid is DataBound.  Perfect!  All I have to do is peak at the BindingSource to figure out which context menu to enable.  The problem now is that I do not have unit tests to prove the context menu is correctly enabling the items.    Since all the code lives in the view, I have no way to tell what is enabled in the context menu without spinning up the view.&lt;br /&gt;&lt;br /&gt;If  I start at the view level a lot of the code seems to belong in the view instead of the presenter.  There is nothing wrong with adding code in the view, as long as it does not  stop you from writing unit tests and has proper separation.  The view should be responsible for all UI renderings such as popping up a message box or drawing something on the form.  Everything else, in my opinion, should belong in the presenter which makes the code testable.  In the next few posts I will use a simple application to address how to write testable UI using the &lt;a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;MVP pattern&lt;/a&gt; with &lt;a href="http://www.testdriven.com/modules/news/"&gt;TDD&lt;/a&gt;.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114581104335658775?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114581104335658775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114581104335658775' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114581104335658775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114581104335658775'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/lazy-user-interface-part-i.html' title='Lazy User Interface Part I'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114532373116039011</id><published>2006-04-17T20:44:00.000-04:00</published><updated>2006-04-17T21:35:30.203-04:00</updated><title type='text'>Internet To Go</title><content type='html'>&lt;span style="font-size:85%;"&gt;We are so used to having fast Internet connection whenever and wherever we want, it can get very irritating when that is not available to us.  I found this cool free utility today that allows you to save any Internet content on to your laptop or mobile device.  Yeah sure, you can manually save any web page on to your laptop, but if you want to save the whole site it might not be possible when there are thousands of external links to other websites.  &lt;a href="http://www.webaroo.com/"&gt;Webaroo&lt;/a&gt; comes to your rescue.  You can add a URL to &lt;a href="http://www.webaroo.com/"&gt;Webaroo&lt;/a&gt;, and it will traverse all the links for you, so any link off the website will still work offline.  I saved &lt;a href="http://www.joelonsoftware.com/"&gt;Joel Spolsky's&lt;/a&gt; whole website on my hard drive and it took four megabytes.  Webaroo also provides an interface that allows you to synchronize with all your local versions of the website.&lt;br /&gt;&lt;br /&gt;This tool is ideal for anyone who travels a lot because now you can surf your favorite website or corporate Intranet even on the airplane.  Since all the pages are saved to your local machine, you can even use it to back up any content you have on the Internet too. &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114532373116039011?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114532373116039011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114532373116039011' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114532373116039011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114532373116039011'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/internet-to-go.html' title='Internet To Go'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114481014614864451</id><published>2006-04-11T22:03:00.000-04:00</published><updated>2006-04-12T15:18:32.036-04:00</updated><title type='text'>Quality With a Name</title><content type='html'>&lt;span style="font-size:85%;"&gt;I felt honored to be one of the first few to read the latest insightful essay written by &lt;a href="http://www.jamesshore.com/"&gt;Jim Shore&lt;/a&gt;: &lt;a href="http://www.jamesshore.com/Blog/New-Article-Quality-With-a-Name.html"&gt;Quality With a Name&lt;/a&gt;.   Since I proof read the essay prior to Jim publishing the post, I do expect my royalty check to be arriving any day now, and yes I do charge interest Jim :)   With all the joking aside,  this article should be read by any serious software developer.  The quality of a good design is a topic that has been explored since the begining of software development.  Jim arrives at the conclusion of what a good design is in a concrete and rigorous manner.  It just got nominated for inclusion in &lt;a href="http://www.joelonsoftware.com/"&gt;Joel Spolksy's&lt;/a&gt; "&lt;a href="http://www.joelonsoftware.com/items/2006/03/31.html"&gt;Best Software Writing II&lt;/a&gt;", need I say more?  Enough talk, go read it, and maybe my check will come sooner.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114481014614864451?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114481014614864451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114481014614864451' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114481014614864451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114481014614864451'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/quality-with-name.html' title='Quality With a Name'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114471854190649768</id><published>2006-04-10T21:18:00.000-04:00</published><updated>2006-04-12T00:03:02.530-04:00</updated><title type='text'>Ruby in .NET?</title><content type='html'>&lt;span style="font-size:85%;"&gt;With Generics in .NET 2.0 more possibilities are availble, such as &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; like closures.  &lt;a href="http://stal.blogspot.com/"&gt;Michael Stal&lt;/a&gt; has a great posting on &lt;a href="http://stal.blogspot.com/2005/01/simulate-closures-in-c-20.html"&gt;Simulate Closures in C# 2.0&lt;/a&gt;, so I decided to try it myself. &lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; Program &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;static&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;void&lt;/span&gt; Main&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt; args&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt; ints &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;span style="color: rgb(0, 140, 0);"&gt;2&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt;&lt;span style="color: rgb(0, 140, 0);"&gt;4&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt;&lt;span style="color: rgb(0, 140, 0);"&gt;6&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt; strings &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;[&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;]&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;a&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;b&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;c&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt; &lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;A&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;A&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;R&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;O&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;N&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(105, 105, 105);"&gt;// output is 12&lt;/span&gt;&lt;br /&gt;   Console&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;WriteLine&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;Collector&lt;span style="color: rgb(128, 128, 48);"&gt;&lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;&gt;&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Collect&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;ints&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; Add&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(0, 140, 0);"&gt;0&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(105, 105, 105);"&gt;// output is 14&lt;/span&gt;&lt;br /&gt;   Console&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;WriteLine&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;Collector&lt;span style="color: rgb(128, 128, 48);"&gt;&lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;&gt;&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Collect&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;ints&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; Add&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(0, 140, 0);"&gt;2&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(105, 105, 105);"&gt;// output is Dabc AARON  &lt;/span&gt;&lt;br /&gt;   Console&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;WriteLine&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;Collector&lt;span style="color: rgb(128, 128, 48);"&gt;&lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;&gt;&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;Collect&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;strings&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; Add&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 230);"&gt;D&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;   Console&lt;span style="color: rgb(128, 128, 48);"&gt;.&lt;/span&gt;ReadLine&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;static&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt; Add&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt; res&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;int&lt;/span&gt; parm&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; res &lt;span style="color: rgb(128, 128, 48);"&gt;+&lt;/span&gt; parm&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;static&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt; Add&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt; string1&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;string&lt;/span&gt; string2&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; string1 &lt;span style="color: rgb(128, 128, 48);"&gt;+&lt;/span&gt; string2&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;class&lt;/span&gt; Collector&lt;span style="color: rgb(128, 128, 48);"&gt;&lt;&lt;/span&gt;T&lt;span style="color: rgb(128, 128, 48);"&gt;&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;delegate&lt;/span&gt; T CollectDelegate&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;T temp&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; T parm&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;public&lt;/span&gt; &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;static&lt;/span&gt; T Collect &lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;ICollection collection&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt;&lt;br /&gt;   CollectDelegate collectDelegate&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; T initVal&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;{&lt;/span&gt;&lt;br /&gt;     T res &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; initVal&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;foreach&lt;/span&gt; &lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;T elem &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;in&lt;/span&gt; collection&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt; res &lt;span style="color: rgb(128, 128, 48);"&gt;=&lt;/span&gt; collectDelegate&lt;span style="color: rgb(128, 128, 48);"&gt;(&lt;/span&gt;res&lt;span style="color: rgb(128, 128, 48);"&gt;,&lt;/span&gt; elem&lt;span style="color: rgb(128, 128, 48);"&gt;)&lt;/span&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt;       &lt;span style="color: rgb(128, 0, 0); font-weight: bold;"&gt;return&lt;/span&gt; res&lt;span style="color: rgb(128, 0, 128);"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 0, 128);"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114471854190649768?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114471854190649768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114471854190649768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114471854190649768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114471854190649768'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/ruby-in-net.html' title='Ruby in .NET?'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114420290869914413</id><published>2006-04-04T21:52:00.000-04:00</published><updated>2006-04-10T21:24:36.176-04:00</updated><title type='text'>Subersion Offline Revert</title><content type='html'>&lt;span style="font-size:85%;"&gt;Sometimes when I am &lt;a href="http://www.refactoring.com/"&gt;refactoring&lt;/a&gt;, I get led down the wrong path.  It is easier to start over with fresh source code then try to dig a bigger hole for yourself.  In the past, I would just simply hunt down those files and delete them and then do an update.  It works fine, but it takes too much time trying to figure out what I have changed.  Just simply doing a revert in your sandbox is much more efficient.  Recently I have noticed files can be reverted without having a connection to &lt;a href="http://subversion.tigris.org/"&gt;SVN&lt;/a&gt;.  This is a really useful feature when you do not have Internet connectivity or do not want to deal with slow VPN connection.  It is very obvious that connectionless revert is possible since &lt;a href="http://subversion.tigris.org/"&gt;SVN&lt;/a&gt; stores all your changes locally in the .svn folder, but for some reason it never occured to me to try it.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114420290869914413?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114420290869914413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114420290869914413' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114420290869914413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114420290869914413'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/subersion-offline-revert.html' title='Subersion Offline Revert'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114386556273285494</id><published>2006-04-01T21:50:00.000-05:00</published><updated>2006-04-10T21:24:56.863-04:00</updated><title type='text'>One Week Iterations</title><content type='html'>&lt;span style="font-size:85%;"&gt;Recently we decided to do an experiment by reducing our iteration duration from three weeks to one week.  We have been having trouble providing accurate estimates on stories during a three week iteration.  Sometimes I feel it is hard to accurately estimate a story that is dependent on other stories that we have not done. Some stories may look like a story you have done before, but you are never sure until you try it.&lt;br /&gt;&lt;br /&gt;It is crucial that we have accurate estimates for all stories because incorrect estimates can lead to false expections.  The idea behind a one week iteration is that we get to practice our estimation skills more often.  We also made the stories much smaller, so we can still fit a few stories within the week.  I have to admit, I was a little skeptical in the begining.&lt;br /&gt;&lt;br /&gt;To my surprise, one week iterations actually worked out really well!  Since all the stories are much smaller, it is much easier to estimate accurately.  Smaller stories also mean that everyone can work in various parts of the system more often.  When we used to do larger stories, sometimes a pair would get stuck in one part of the system for days.  It can be frustrating at times when we encounter a road block.  On top of that, it is very easy to lose contact with other parts of the system if one does not see it often.  One week iterations definitely make the work more pleasant and exciting.&lt;br /&gt;&lt;br /&gt;In the begining, I thought one week iterations would slow us down since we have to estimate once a week. It usually takes us two solid days to estimate all the stories during a three week iteration.  If it still takes two days to esimate during a one week iteration, we would never get anything done!  It turns out we can estimate much faster during a one week iteration since all the stories are smaller, and therefore, more visible.&lt;br /&gt;&lt;br /&gt;Overall I really enjoy working on one week iterations.  One week iterations might not work for all Agile teams, but it has worked well for us so far.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114386556273285494?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114386556273285494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114386556273285494' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114386556273285494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114386556273285494'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/04/one-week-iterations.html' title='One Week Iterations'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114308685732443465</id><published>2006-03-23T19:20:00.000-05:00</published><updated>2006-03-23T21:46:38.040-05:00</updated><title type='text'>CAB Workspace Flickering</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.delarou.name/PermaLink,guid,3b2a69dd-79bf-4a88-be0c-36d3e192b760.aspx"&gt;Delarou has a great post&lt;/a&gt; about how to prevent the flickering when you switch between Controls in a &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; workspace.  This happens because the Controls are drawn while it is initalizing.  With his trick, it will only redraw after Controls have been initalized.  He basically extends a workspace and overrides the default behavior.  Pretty cool trick.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114308685732443465?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114308685732443465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114308685732443465' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114308685732443465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114308685732443465'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/cab-workspace-flickering.html' title='CAB Workspace Flickering'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114308750082036097</id><published>2006-03-22T23:17:00.000-05:00</published><updated>2006-03-23T00:14:55.350-05:00</updated><title type='text'>Smart Client Baseline Architecture Toolkit</title><content type='html'>&lt;span style="font-size:85%;"&gt;At work I am working on a team that develops a Smart Client application with &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;Composite UI Application Block&lt;/a&gt; (&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt;).  We have been struggling to figure out the best way to leverage &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; within our software.  We started the application out with the basic MVP pattern and slowly we fused &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; into our software. In the beginning, we started out with a presenter communicating with multiple views in a &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; module. That turned out to be problematic when we tried to coordinate actions across views. From a TDD point of view, it was also a pain to inject multiple mock views into the presenter. At times we feel the mock views have to be almost as smart as the real views.&lt;br /&gt;&lt;br /&gt;Recently a couple of my colleagues went to Redmond and worked with the &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; team.  They brought back many useful insights on the best practices for &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt;.  One thing I think will be very useful is the&lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"&gt; &lt;/a&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"&gt;Smart Client Baseline Architecture Toolkit&lt;/a&gt; (&lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"&gt;SCBAT&lt;/a&gt;).  &lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"&gt;SCBAT&lt;/a&gt; automates a lot of daily &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; mundane tasks to increase productivity. For example, you can create a new Smart Client project in VS 2005 with all the recommended organizations with one click of a button. New context menus are also added for creating a view with a presenter, and create a new &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; module. But you say: "Wait, I like to organize my Smart Client application differently....". Not to worry, you can tweak the automation to your needs using &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://lab.msdn.microsoft.com/teamsystem/workshop/gat/intro.aspx"&gt;Guidance Automation Toolkit&lt;/a&gt; (&lt;a href="http://lab.msdn.microsoft.com/teamsystem/workshop/gat/intro.aspx"&gt;GAT&lt;/a&gt;).&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Before you install SCBAT,  there are a couple of prequisite packages:&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.microsoft.com/Downloads/details.aspx?familyid=C0A394C0-5EEB-47C4-9F7B-71E51866A7ED&amp;amp;displaylang=en"&gt;Guidance Automation Extensions&lt;/a&gt; - Run time component that is required to run Guidance Automation Toolkit.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://lab.msdn.microsoft.com/teamsystem/workshop/gat/intro.aspx"&gt;Guidance Automation Toolkit&lt;/a&gt; - Create customized "Guidance Packages" for developers. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt; Of course, you must have &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp"&gt;CAB&lt;/a&gt; and &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://msdn.microsoft.com/library/?url=/library/en-us/dnpag2/html/EntLib2.asp"&gt;Enterprise Library&lt;/a&gt; installed already.  Open the Guidance Automation solution from the location where &lt;a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"&gt;SCBAT&lt;/a&gt; is installed.  Compile the solution and installer project.  Run the installer and you should be done.&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114308750082036097?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114308750082036097/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114308750082036097' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114308750082036097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114308750082036097'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/smart-client-baseline-architecture.html' title='Smart Client Baseline Architecture Toolkit'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114298877503177468</id><published>2006-03-21T19:38:00.000-05:00</published><updated>2006-03-21T21:45:07.900-05:00</updated><title type='text'>Smart Client</title><content type='html'>&lt;span style="font-size:85%;"&gt;I remain in touch with people I went to college with, and people I used to work with.  Many of them are not working in the Microsoft world, so whenever I mention &lt;a href="http://msdn.microsoft.com/smartclient/"&gt;Smart Client&lt;/a&gt;, they usually have no idea what I am talking about.  "&lt;a href="http://msdn.microsoft.com/smartclient/"&gt;Smart Client&lt;/a&gt;?  Do you mean Thin Client?"  No.  Here is the generic definiation of Smart Client from Microsoft:&lt;br /&gt;&lt;br /&gt;&lt;b style="font-style: italic;"&gt;Smart client&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt; (n) &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;i style="font-style: italic;"&gt;Definition:&lt;/i&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt; Smart clients are easily deployed and managed client applications that provide an adaptive, responsive and rich interactive experience by leveraging local resources and intelligently connecting to distributed data sources.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;In simple terms, &lt;a href="http://msdn.microsoft.com/smartclient/"&gt;Smart Client&lt;/a&gt; has a rich look and feel of native applications, and simple deployment like a Web application.  A real world example of a &lt;a href="http://msdn.microsoft.com/smartclient/"&gt;Smart Client&lt;/a&gt; is Outlook.  &lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114298877503177468?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114298877503177468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114298877503177468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114298877503177468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114298877503177468'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/smart-client.html' title='Smart Client'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114291608589175094</id><published>2006-03-20T23:20:00.000-05:00</published><updated>2006-03-21T21:51:41.850-05:00</updated><title type='text'>Aspect Oriented Programming</title><content type='html'>&lt;span style="font-size:85%;"&gt;As a software matures, it is normal to see duplication in concepts across a few objects.  It is a very normal phenomenon in any software.  Any good Agile developer will tell you this is an opportunity to refactor out the duplication. Sometimes, however, things are not as easy to refactor out as one might think.&lt;br /&gt;&lt;br /&gt;In our software, we use ORM engine to map our domain objects back into the database.  The domain objects do not have the knowledge of the database.  So when an object needs to be retrived/saved/deleted from/to/from the database, we delegate it to a "manager" object.  For example, Car object can be retrieved from the database by calling the CarManager object with a specified criteria.&lt;br /&gt;&lt;br /&gt;At first glance, this looks like a good solution because we are separating out the responsibilities.  Ok, fine.  As time goes on, a few more domain objects are added, so you also add a few more "managers".  Every time a "manager" is added, one will notice that very similar work has been done elsewhere.&lt;br /&gt;&lt;br /&gt;One simple solution is to have a "generic manager" that can take in any domain objects.  That actually will not work either because some methods in the "manager" object cannot be generic.&lt;br /&gt;&lt;br /&gt;I am not sure what the best solution is to this problem.  Tonight I just so happened to come across &lt;a href="http://geekswithblogs.net/gyoung/archive/2006/03/20/72822.aspx#FeedBack"&gt;Greg Young's post&lt;/a&gt; .  He is doing a presentation on AOP with very similar problems as I described above.  Too bad I can not attend because it takes place in Atlanta, which is too far away from Philadelphia :(&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114291608589175094?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114291608589175094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114291608589175094' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114291608589175094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114291608589175094'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/aspect-oriented-programming.html' title='Aspect Oriented Programming'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114271279599289245</id><published>2006-03-18T15:12:00.000-05:00</published><updated>2006-03-19T21:52:43.033-05:00</updated><title type='text'>Singularity</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a href="http://research.microsoft.com/os/singularity"&gt;Singularity&lt;/a&gt; is a research project at Microsoft.  The goal of &lt;a href="http://research.microsoft.com/os/singularity"&gt;Singularity&lt;/a&gt; is to build a dependable Operating System using Managed code.  The whole OS took about 18 months to develop, and it was developed using a stripped down version of C#.&lt;br /&gt;&lt;br /&gt;I came across a couple of interesting analogies when I was reading the &lt;a href="http://research.microsoft.com/os/singularity/2004_12_07_OSDI_Singularity_WIP_External.ppt"&gt;presentation slides&lt;/a&gt; for &lt;a href="http://research.microsoft.com/os/singularity"&gt;Singularity&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt;"If cars were more like software..."&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt;"Customer service said the seat belt light might turn off if we re-install the engine oil."&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt;"If phone systems were more like software..."&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;font-size:85%;" &gt;"To reach that number, you need Long Distance Version 2.6.19.  Which version do you have?"&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;The philosophy of &lt;a href="http://research.microsoft.com/os/singularity"&gt;Singularity&lt;/a&gt; is to make an OS more dependable by making it more predictable.  I am glad not everything in the world right now is "more like software" ;-)&lt;br /&gt;&lt;br /&gt;If you intested in &lt;a href="http://research.microsoft.com/os/singularity/"&gt;Singularity&lt;/a&gt;, here are a couple of videos from channel 9.&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=141858"&gt;Singularity Revisited&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=68302"&gt;Singularity: A research OS written in C#&lt;/a&gt;&lt;/b&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/20359354-114271279599289245?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114271279599289245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114271279599289245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114271279599289245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114271279599289245'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/singularity.html' title='Singularity'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114266103133754975</id><published>2006-03-18T00:50:00.000-05:00</published><updated>2006-03-18T03:07:25.323-05:00</updated><title type='text'>Override Default .NET Configuration File</title><content type='html'>&lt;span style="font-size:85%;"&gt;In the .NET world App.config is the standard configuration file for an executable. During the compilation process, the compiler will copy the contents App.config into a file with the same name as the executable with .config concatenated in the end.&lt;br /&gt;&lt;br /&gt;The common side effect of this configuration structure is the duplication of App.config when multiple executables are being deployed to a machine that shares common DLL. One way to solve this problem is to override the configuration file by using the following:&lt;br /&gt;&lt;br /&gt;AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"c:\some_path\someConfig.config");&lt;br /&gt;&lt;br /&gt;Just make sure to execute the line above before you read the configuration file. The contents of standard configuration file in the bin directory (programName.exe.config) will remain the same because the compiler is unaware of the code during compilation time.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114266103133754975?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114266103133754975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114266103133754975' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114266103133754975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114266103133754975'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/override-default-net-configuration.html' title='Override Default .NET Configuration File'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114264200001957642</id><published>2006-03-17T19:33:00.000-05:00</published><updated>2006-03-18T02:35:08.896-05:00</updated><title type='text'>Bookpool</title><content type='html'>&lt;span style="font-size:85%;"&gt;In my opinion, &lt;a href="http://www.bookpool.com/"&gt;Bookpool&lt;/a&gt; is the best place to purchase technical books.  I prefer it over &lt;a href="http://amazon.com/"&gt;Amazon&lt;/a&gt; because the price is always better.  I always load all the books I want into both shopping carts and &lt;a href="http://www.bookpool.com/"&gt;Bookpool&lt;/a&gt; always beats &lt;a href="http://amazon.com/"&gt;Amazon&lt;/a&gt; by $5 - $30.  The reason I am plugging &lt;a href="http://www.bookpool.com/"&gt;Bookpool&lt;/a&gt; is because I ordered another batch of books tonight. I have been mooching off the library at work too long, so I decided to purchase my own copy. I have read most or parts of the first four titles, they cover a lot of foundational material. I would recommend them to any serious programmer.&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/020161622X"&gt;Pragmatic Programmer: From Journeyman to Master&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/0735619670"&gt;Code Complete, 2nd Edition&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/0596007124"&gt;Head First Design Patterns&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/0321245660"&gt;Effective C#: 50 Specific Ways to Improve Your C#&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/0932633439"&gt;Peopleware: Productive Projects and Teams, 2nd Edition&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/1590594398"&gt;Pro .NET 2.0 Windows Forms and Custom Controls&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;&lt;a href="http://www.bookpool.com/sm/032126892X"&gt;Data Binding with Windows Forms 2.0: Programming Smart Client Data Applications with .NET&lt;/a&gt;&lt;/b&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/20359354-114264200001957642?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114264200001957642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114264200001957642' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114264200001957642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114264200001957642'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/bookpool.html' title='Bookpool'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114230811972583886</id><published>2006-03-13T22:04:00.000-05:00</published><updated>2006-03-18T02:34:32.186-05:00</updated><title type='text'>Comparing Value Types</title><content type='html'>&lt;span style="color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Value types are commonly used in any meaningful application. People will often implement a static function to compare value types instead of overriding Equals().  &lt;a href="http://geekswithblogs.net/notquiteasage/archive/2006/03/13/72173.aspx"&gt;Tim Watson&lt;/a&gt; has a great post about this with very clear examples.  I will not duplicate his work; however, I will provide a condensed version here.   I do encourage everyone to read it though.&lt;br /&gt;&lt;br /&gt;In the OOP world, an Object contains data and behavior.  If you have any questions about the Object such as "Are you equal to another Object?"   it should be directed to the Object itself.  By providing a static method, it is a procedual way of thinking, even if you implemented the static method off the Object itself.&lt;br /&gt;&lt;br /&gt;Additionally, Equals method is the convention in the OOP world for vaule comparrison. If a static function is implemented, people probably will not know it exists (Assuming they are OOP programmers :)&lt;br /&gt;&lt;br /&gt;The most important reason to stay away from a static comparrison function is because the Object can not be used as keys for a hashtable.  It requires Equals() and GetHashCode() to be implemented.&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(255, 102, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;br /&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/20359354-114230811972583886?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114230811972583886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114230811972583886' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114230811972583886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114230811972583886'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/comparing-value-types.html' title='Comparing Value Types'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114221264991342537</id><published>2006-03-12T19:12:00.000-05:00</published><updated>2006-03-18T02:35:55.510-05:00</updated><title type='text'>Winform Catch All</title><content type='html'>&lt;span style="font-size:85%;"&gt;It is very common for an application to show a user &lt;span style="font-weight: bold;"&gt;friendly&lt;/span&gt; error message with a consistent look and feel of the application when the application bombs out.  The simplest way to accomplish this is to pop up a Winform when the application encounters an exception.  How can we be sure to show the Winform when the application throws an exception?  Put try-catch around &lt;a href="http://msdn2.microsoft.com/en-US/library/system.windows.forms.application.run.aspx"&gt;Application.Run()&lt;/a&gt; then pop up the friendly error Winform inside the catch?  That actually will not work for Winform applications because Winform has its own exception handling mechanism which causes the error message to be shown in a &lt;span style="font-weight: bold;"&gt;unfriendly&lt;/span&gt; manner. Worst of all, it will not actually run anything inside of the catch.&lt;br /&gt;&lt;br /&gt;If you try the example used above inside Visual Studio, you will notice the code inside of the catch &lt;span style="font-weight: bold;"&gt;does&lt;/span&gt; run even when an exception is thrown.  The short answer is Winform application behaves differently inside VS.  If you try it agian by clicking the executable you will get a different result.&lt;br /&gt;&lt;br /&gt;The correct way to achieve this is to handle the &lt;a href="http://msdn2.microsoft.com/system.windows.forms.application.threadexception.aspx"&gt;Application.ThreadException&lt;/a&gt; event.  Inside &lt;a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.application.threadexception.aspx"&gt;ThreadException &lt;/a&gt;event handler you can show your ultra &lt;/span&gt;&lt;span style="font-size:85%;"&gt;friendly &lt;/span&gt;&lt;span style="font-size:85%;"&gt;error message to the user.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114221264991342537?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114221264991342537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114221264991342537' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114221264991342537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114221264991342537'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/winform-catch-all.html' title='Winform Catch All'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114214836217062237</id><published>2006-03-12T02:00:00.001-05:00</published><updated>2006-03-18T02:36:55.023-05:00</updated><title type='text'>Null Coalescing Operator</title><content type='html'>&lt;span style="font-size:85%;"&gt;Code readablility is subjective, and it often depends on personal style.  Some people think the use of ternary operator makes the code hard to read.  .NET 2.0 has a new operator that is similar to the ternary operator.  The two lines listed below are symonymous:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;someBusinessObject ?? new someBusinessObject();&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;null == someBusinessObject ? someBusinessObject : new someBusinessObject();&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;You do not have to check for null anymore, it is built into the operator.  So is this operator readable?   I have to admit, I really like it.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114214836217062237?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114214836217062237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114214836217062237' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114214836217062237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114214836217062237'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/null-coalescing-operator.html' title='Null Coalescing Operator'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114213528889735753</id><published>2006-03-11T22:18:00.000-05:00</published><updated>2006-03-18T02:37:42.466-05:00</updated><title type='text'>Code Smell with .NET Region Directives</title><content type='html'>&lt;span style="font-size:85%;"&gt;The term &lt;a href="http://xp.c2.com/CodeSmell.html"&gt;code smell&lt;/a&gt; is often used in the software development world to describe code that is possibly structured improperly.  The symptom of a &lt;a href="http://xp.c2.com/CodeSmell.html"&gt;code smell&lt;/a&gt; is when the code is hard to comprehend and modify which often leads to code duplication.  The &lt;a href="http://xp.c2.com/CodeSmell.html"&gt;code smells&lt;/a&gt; usually result in hard to find common nasty bugs.  As a software developer, it is our best interest to stay away from &lt;a href="http://xp.c2.com/CodeSmell.html"&gt;code smells&lt;/a&gt; to reduce software debt.&lt;br /&gt;&lt;br /&gt;In the .NET world, many developers use the region directive to hide complexity.  It is used as illustrated below:&lt;br /&gt;&lt;br /&gt;#region "Import Logic"&lt;br /&gt;/*&lt;br /&gt;Many lines of code here....&lt;br /&gt;*/&lt;br /&gt;#endregion&lt;br /&gt;&lt;br /&gt;If you are using an IDE like Visual Studio, you can collapse all the code in between a region directive with a single click.  There is a certain code smell associated with regions when it is used blindly.  If a class' logic needs to be hidden for any reason, chances are it has too many responsibilities.&lt;br /&gt;&lt;br /&gt;In the&lt;a href="http://www.webopedia.com/TERM/O/object_oriented_programming_OOP.html"&gt; OOP&lt;/a&gt; world each class &lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;should &lt;/span&gt;&lt;span style="font-size:85%;"&gt;only have a single responsibility.  That is not to say that regions do not have their place, but it is often over used because it is easier than trying to refactor the code.  One thing I also noticed is that many regions' names usually describe a responsibility of another class (Import Logic as used in my example).  That is definitely a sign of &lt;a href="http://xp.c2.com/CodeSmell.html"&gt;code smell&lt;/a&gt; because the class could possibly delegate the responsibility to another class.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114213528889735753?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114213528889735753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114213528889735753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114213528889735753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114213528889735753'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/code-smell-with-net-region-directives.html' title='Code Smell with .NET Region Directives'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114187993928402463</id><published>2006-03-08T23:52:00.000-05:00</published><updated>2006-03-18T02:38:24.693-05:00</updated><title type='text'>Subversion</title><content type='html'>&lt;span style="font-size:85%;"&gt;Lately we have been having tons of problems with Visual Source Safe which at times, slowed down our development. The problem that caused the most down time is the merge feature. It should be called "&lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;replace&lt;/span&gt;&lt;span style="font-size:85%;"&gt;" instead because it does a replace randomly when merging.  Last week VSS finally blew up, so we buried it.&lt;br /&gt;&lt;br /&gt;We decided on &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; because many of us have used it before. Plus it is Open Source, so what do we have to lose? It took us no time to set up the repository, and show people how to use it. We use &lt;a href="http://tortoisesvn.tigris.org/"&gt;TortoiseSVN&lt;/a&gt;, so we can perform daily source control functions effortlessly.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://tortoisesvn.tigris.org/"&gt;TortoiseSVN&lt;/a&gt; integrates nicely into Windows Explorer. It uses icon overlays to signify items under source control and the state of the file. I really like this because I can tell the state of the file just by browsing the file system. Once you retrieve all the files, it does not synchronize with the server until you commit your changes. When you commit, it will &lt;/span&gt;&lt;span style="font-weight: bold;font-size:85%;" &gt;only &lt;/span&gt;&lt;span style="font-size:85%;"&gt;transmit the bytes that have been changed.  It basically does the opposite of what VSS does.&lt;br /&gt;&lt;br /&gt;It used to take about 30 seconds to open our solution because the solution was bound to VSS. It takes less than 10 seconds now. Our &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET"&gt;Cruise Control&lt;/a&gt; build went from 4 solid minutes to 35 seconds.&lt;br /&gt;&lt;br /&gt;Overall we are very happy with the switch.  &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; is really fast compared to VSS, and it offers a wider range of features. I would definitely recommend anyone to stay away from VSS if possible. I think it is very ironic that VSS has the word "Safe" in it.  If you would like to learn more about &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;, &lt;a href="http://www.bookpool.com/sm/0974514063"&gt;Pragramic Version Control Using Subversion&lt;/a&gt; is a great book to read.&lt;/span&gt;  &lt;span class="f11"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114187993928402463?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114187993928402463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114187993928402463' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114187993928402463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114187993928402463'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/03/subversion.html' title='Subversion'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114117943802898529</id><published>2006-02-28T19:49:00.000-05:00</published><updated>2006-03-18T02:38:53.010-05:00</updated><title type='text'>Back to Basics</title><content type='html'>&lt;span style="font-size:85%;"&gt;In the last post, I discussed the importance of communication during a white board design session.  Communication goes beyond verbal.  There are tools out there that can help you convey your ideas in a &lt;span style="font-weight: bold;"&gt;rigorous &lt;/span&gt;manner.  Are you ready for this?  You better sit down and take notes.  Unified Modeling Language.  I am sure UML is not new to anyone that has done any kind of programming, at least I should hope not.&lt;br /&gt;&lt;br /&gt;I know what you are thinking: "I thought people on an Agile team do not produce heavy documentation because that is what UML is used for".  Yes, I agree that full blown UML can get very hairy.  However, &lt;/span&gt;&lt;span style="font-size:85%;"&gt;UML does not imply heavy documentations.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;Continous design can still be achieved using UML.  Well, you may be wondering what is so good about UML that I do not already know?  Probably nothing.  People tend to use non-standard notation during an informal white board design.  This can be problematic because it allows room for derivation.&lt;br /&gt;&lt;br /&gt;I would not waste time on learning&lt;span style="font-weight: bold;"&gt; ALL &lt;/span&gt;UML notations (if you do not already know them) because all you need is a very small subset of UML to communicate clearly.  Pretty much all you need to know can be found on this &lt;a href="http://tnerual.eriogerg.free.fr/umlqrc.pdf"&gt;UML Reference card&lt;/a&gt; (plus more).  We started to use only Class Diagram notations &lt;/span&gt;&lt;span style="font-size:85%;"&gt; during a white board design &lt;/span&gt;&lt;span style="font-size:85%;"&gt;because it effectively describes relationships.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114117943802898529?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114117943802898529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114117943802898529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114117943802898529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114117943802898529'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/back-to-basics.html' title='Back to Basics'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114092882300557760</id><published>2006-02-25T23:14:00.000-05:00</published><updated>2006-03-18T02:39:27.093-05:00</updated><title type='text'>Wire It Up!</title><content type='html'>&lt;span style="font-size:85%;"&gt;I have been saying "Wire it up" a lot at work, so it is only natural for me to use it in my daily non-computer related vocab.&lt;br /&gt;&lt;br /&gt;People sometimes ask, "What does it mean?" Maybe people ask because I usually snicker after I say it. The phrase came to me during a few of our white board design sessions at work when I noticed a trend. During those sessions, sometimes people would use very generic, broad termonology to describe a complicated process, and draw boxes to cover all the implementation details. After a couple of sentences, the conversation is usually wrapped up by saying "You just wire it up". This approach is fine as an overview, but often more concrete details are required for everyone to get on the same page.&lt;br /&gt;&lt;br /&gt;Basically, I use the phrase "Wire it up" when someone tries to cover all the details by using a very high level approach. The purpose of this post is to point out the importance of communication during white board design sessions.   &lt;/span&gt;&lt;span style="font-size:85%;"&gt;I just think it is important to find out what people do not know and try to provide more details in those areas in a non-critial way.   &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114092882300557760?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114092882300557760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114092882300557760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114092882300557760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114092882300557760'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/wire-it-up.html' title='Wire It Up!'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114084260327270491</id><published>2006-02-24T22:33:00.000-05:00</published><updated>2006-03-18T02:40:16.906-05:00</updated><title type='text'>Visual Studio Automation</title><content type='html'>&lt;span style="font-size:85%;"&gt;We use &lt;a href="http://www.codesmithtools.com/"&gt;Code Smith&lt;/a&gt; at work to generate ORM objects.  It works really well, but there are several steps involved for the code generation process.  Although it can get tedious at times, the process is fairly straight forward.  One of my colleagues automated the process uing a console program.  It made the process so much simpler and faster.  The only thing I did not like is  having to open a console and run the program outside my development environment.  Maybe I am just lazy.  I want to generate my objects by just clicking something in Visual Studio.  I have never done any work using Visual Studio Automation before, so I decided to do some research.&lt;br /&gt;&lt;br /&gt;To my surprise, there is very little information on the web about VS Automation, even on MSDN.  The most helpful information I found was the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=79C7E038-8768-4E1E-87AE-5BBBE3886DE8&amp;amp;displaylang=en"&gt;VS Automation samples&lt;/a&gt; released by Microsoft.  By looking at these samples and using intellisense, I figured out the basics.  I was able to create the Addin for ORM object generation in a few hours of playing around.&lt;br /&gt;&lt;br /&gt;When I think about a simple development automation tool, a console program is usually used.  After finding out how simple it was to create a plugin for VS, I will choose it over a console program from now on.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114084260327270491?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114084260327270491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114084260327270491' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114084260327270491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114084260327270491'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/visual-studio-automation.html' title='Visual Studio Automation'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114040627242923945</id><published>2006-02-19T18:35:00.000-05:00</published><updated>2006-03-18T02:40:57.956-05:00</updated><title type='text'>Working on Your Weakness</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a href="http://steve.emxsoftware.com/Business/BeingAmazing"&gt;Steve&lt;/a&gt; pointed out an interesting blog entry by &lt;a href="http://headrush.typepad.com/creating_passionate_users/"&gt;Kathy Sierra&lt;/a&gt;, co-arthur of Head First books, on being f'n amazing.  I will give you the short version of the blog here, but I do encourage everyone to read it.   She basically states that working on your weakness often leads to mediocrity which will cause you to give up the chance to be f'n amazing.    I do agree with Kathy because it is impossible for anyone to be good at everything, especially in the technology world.  Rather than working on your weakness, one should strengthen their strengths, and in turn, become f'n amazing.  Kathy pointed out a couple of books in agreement with her post, but she has not read them yet.  Those books sound interesting, so I will be adding them to my reading list. &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114040627242923945?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114040627242923945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114040627242923945' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114040627242923945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114040627242923945'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/working-on-your-weakness.html' title='Working on Your Weakness'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-114006282007536679</id><published>2006-02-15T22:40:00.000-05:00</published><updated>2006-03-18T02:42:53.680-05:00</updated><title type='text'>DateTime ParseExact</title><content type='html'>&lt;span style="font-size:85%;"&gt;One of my co-workers on the legacy team was working on a bug fix for our Japanese customer today.  Not sure on the exact scenario because I was not the one that tracked down the bug.  Basically the software bombed out when the code tried to parse a string into DateTime object on a machine with Japanese settings (I think it works fine if the machine is setup with US settings).&lt;br /&gt;&lt;br /&gt;All the dates are stored in Day-Month-Year format separated by hyphen and a space before and after the hyphen.  For example, December 31st 2006 will look like the string below:&lt;br /&gt;&lt;br /&gt;31 - 12 - 2006&lt;br /&gt;&lt;br /&gt;He wanted to know the best way to parse the string without doing custom string manipulation before parsing it.  He played around with Parse function on the DateTime class, but he could not figure a way to parse the string without it throwing an exception.  The solution is to use the ParseExact static function on the DateTime class because it allows you to specify the exact formats you want to parse, and nothing else.  The code listed below shows how the ParseExact function can be used:&lt;br /&gt;&lt;br /&gt;// set it to Japanese culture, and allow the user machine to override it.&lt;br /&gt;IFormatProvider format = new System.Globalization.CultureInfo("ja-JP", true);&lt;br /&gt;&lt;br /&gt;// noticed it's not dd because dd will fail if a single digit day is used, d will work for both.&lt;br /&gt;string[] expectedFormats = {"d-MM-yyyy"};&lt;br /&gt;&lt;br /&gt;DateTime dt = DateTime.ParseExact(&lt;br /&gt;"31 - 12 - 1891",&lt;br /&gt;expectedFormats,&lt;br /&gt;format,&lt;br /&gt;System.Globalization.DateTimeStyles.AllowWhiteSpaces&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;Console.WriteLine("Parsed DD/MM/YY: {0}", dt.ToString("d"));&lt;br /&gt;&lt;br /&gt;There is a really good reason why everyone should use ParseExact over Parse on the DateTime class.  The Parse function on the DateTime class tries to be really smart about the string you passed in, so you might get &lt;span style="font-weight: bold;"&gt;unexpected&lt;/span&gt; results when it tries to be too "smart".  For example, 1/2/2006 should it be Janurary 2nd, 2006 or Feburary 1st, 2006?  Should it throw an exception, if so, which one is valid?  ParseExact will only parse the way you told it to, so the performance is a lot better.  Some things are just meant to be stupid.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-114006282007536679?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/114006282007536679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=114006282007536679' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114006282007536679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/114006282007536679'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/datetime-parseexact.html' title='DateTime ParseExact'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113911179963249266</id><published>2006-02-04T21:59:00.000-05:00</published><updated>2006-03-18T02:58:34.620-05:00</updated><title type='text'>40 hour work week?</title><content type='html'>&lt;span style="font-size:85%;"&gt;As you all know, I'm a member of an Agile team using &lt;a href="http://www.extremeprogramming.org/"&gt;XP methodolgy&lt;/a&gt;.  We are building a financial application using many of the latest technologies.  Since all the technolgies are fresh out of the oven (some are still in the oven), we spent a lot of time on figuring out the best ways to leverage each technology.  We have been doing a fair amount of overtime every week, so we can get a reasonable amount of work done in an iteration.&lt;br /&gt;&lt;br /&gt;XP methodology promotes a 40 hour work week because one can not do good work if they are not well rested, as stated in &lt;a href="http://www.bookpool.com/sm/0321278658"&gt;Kent Beck's XP book&lt;/a&gt;.  We spend a lot of time learning new technologies, and by the time we learn it (ususally late in the week) we have to implement it quickly.  This approach could cause bugs, and lower quality software.  Of course, eventually we will be up to the speed with all the technologies we use.  Before we get to that point, we are building up a lot of debt in our application.  It's going to take some time to clean up all the problem&lt;br /&gt;&lt;br /&gt;Where do you fit in learning new technology in a 40 hour week?   I'm a firm believer that in order to do good work your mind must be clear and fresh.  Maybe the solution to the problem is to include "learning" time into the estimate.  Since we are not familiar with the technologies, sometimes it's hard to predict amount of time needed.&lt;br /&gt;&lt;br /&gt;We started a new iteration by making the stories much smaller.  This seems to be helping because each pair has to figure out less.  This is also good for the team because we are spreading the knowledge thinner cross the board.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113911179963249266?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113911179963249266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113911179963249266' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113911179963249266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113911179963249266'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/40-hour-work-week.html' title='40 hour work week?'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113893748469381534</id><published>2006-02-02T21:58:00.000-05:00</published><updated>2006-03-18T02:58:17.720-05:00</updated><title type='text'>Fo' shizzle my nizzle</title><content type='html'>&lt;span style="font-size:85%;"&gt;I know my blog can be really boring at times.  Today I found a way to spice up any dull websites.  Just run it through &lt;a href="http://gizoogle.com/"&gt;Gizoogle&lt;/a&gt;. It works just like google except it converts all your search results into rap songs that Snoop can be proud of.  You can read &lt;a href="http://gizoogle.com"&gt;Gizoogle&lt;/a&gt; version of my blog &lt;a href="http://sites.gizoogle.com/index2.php?url=http%3A%2F%2Faaronfeng.blogspot.com"&gt;here&lt;/a&gt;.  &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113893748469381534?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113893748469381534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113893748469381534' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113893748469381534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113893748469381534'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/02/fo-shizzle-my-nizzle.html' title='Fo&apos; shizzle my nizzle'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113807903963214731</id><published>2006-01-23T23:02:00.000-05:00</published><updated>2006-03-18T02:55:56.966-05:00</updated><title type='text'>Database Migration with Ruby on Rails</title><content type='html'>&lt;span style="color: rgb(0, 0, 0);font-size:85%;" &gt;Our application will eventually have to support multiple databases like many other applications.&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-size:85%;" &gt;  Managing schema for multiple databases can be really tricky.  One simple solution is to write DDL for all the supported databases.  This is a very time consuming solution if you are supporting 2 or more databases.  On top of that, how do you keep track of the version of the DDL for each client (some of our clients require custom schema) once the software is deployed?&lt;br /&gt;&lt;a href="http://www.rubyonrails.org/"&gt;&lt;br /&gt;Ruby on Rails&lt;/a&gt; has a clever way of handling database migration.  But wait!  We are building a Smart Client application, not a Web application.  ROR database migration is useful even if you are not doing a Web application.  If you have no idea what ROR migration is about, you should watch this &lt;a href="http://media.rubyonrails.org/video/migrations.mov"&gt;video&lt;/a&gt;.  Right out of the box, it didn't do exactly want we wanted, so we had to tweek it by adding some code.  Thank God for Open Source projects.&lt;br /&gt;&lt;br /&gt;By default, ROR migration doesn't handle Stored Procedures because ROR projects use the built in O/R mapper.  That's no big deal to us because we are using Wilson O/R maper, so we don't mess with Stored Procedures anyways.&lt;br /&gt;&lt;br /&gt;Steve has a great artcle on &lt;a href="http://steve.emxsoftware.com/RubyOnRails/Ruby+on+Rails+Migrations+Explained"&gt;ROR migration&lt;/a&gt;.  He does a much better job explaining it.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113807903963214731?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113807903963214731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113807903963214731' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113807903963214731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113807903963214731'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/database-migration-with-ruby-on-rails.html' title='Database Migration with Ruby on Rails'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113755805698892448</id><published>2006-01-17T23:19:00.000-05:00</published><updated>2006-03-18T02:55:10.993-05:00</updated><title type='text'>Philadelphia Agile Users Group</title><content type='html'>&lt;span style="font-size:85%;"&gt;Today I finally made it to my first Philadelphia Agile Users Group with my coworker.  We got there a little bit late, so we didn't get a chance to talk to everyone before the meeting.  We did a "Fishbowl", and the concept is very interesting to me because I have never seen it done before.&lt;br /&gt;&lt;br /&gt;For those of you who don't know what a Fishbowl is, I'll try to describe it as best as I can.  Basically, you setup four seats while everyone gathers around the seats.  Whoever sits down first gets to start the topic, and whoever wants to join the conversation must sit down in the empty seats.  When all the seats are occupied one person must get up and stop participating in the conversation.  So basically the conversation carries on even when one person leaves.  This is interesting because it gives anyone who wants to participate a chance to talk.  I think overall it was an good experience, but it could have been better if we could have made it earlier.  Maybe next month we can go earlier, so we can get a chance to talk to everyone before the meeting starts.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113755805698892448?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113755805698892448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113755805698892448' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113755805698892448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113755805698892448'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/philadelphia-agile-users-group.html' title='Philadelphia Agile Users Group'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113743392419605410</id><published>2006-01-16T12:50:00.000-05:00</published><updated>2006-03-18T02:54:41.160-05:00</updated><title type='text'>DataGridView Adventure</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/e0ywh3cz.aspx"&gt;DataGridView&lt;/a&gt; is a new feature in .NET 2.0, it is supposed to replace DataGrid one day.  Recently I have been playing around with &lt;a href="http://msdn2.microsoft.com/en-us/library/e0ywh3cz.aspx"&gt;DataGridView&lt;/a&gt; a lot to extend some specialized features for work. However, I ran into a road block when I tried to retrieve the area of a displaying row.&lt;br /&gt;&lt;br /&gt;I tried to use &lt;a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.datagridview.getrowdisplayrectangle.aspx"&gt;GetRowDisplayRectangle(int rowIndex, bool cutOverFlow)&lt;/a&gt; to get the current Rectangle of a row. For some unknown reason it never returned the correct size no matter how many columns I have in the &lt;a href="http://msdn2.microsoft.com/en-us/library/e0ywh3cz.aspx"&gt;DataGridView&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If you are new to &lt;a href="http://msdn2.microsoft.com/en-us/library/e0ywh3cz.aspx"&gt;DataGridView&lt;/a&gt; but not new to DataGrid, &lt;a href="http://www.windowsforms.net/Samples/Go%20To%20Market/DataGridView/DataGridView%20FAQ.doc"&gt;here&lt;/a&gt; is a document that does the comparision and explains some of the new features.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113743392419605410?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113743392419605410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113743392419605410' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113743392419605410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113743392419605410'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/datagridview-adventure.html' title='DataGridView Adventure'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113695288519516872</id><published>2006-01-10T23:14:00.000-05:00</published><updated>2006-03-18T02:53:49.240-05:00</updated><title type='text'>SharpDevelop</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.icsharpcode.net/OpenSource/SD/Default.aspx"&gt;SharpDevelop&lt;/a&gt; is an&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;open source IDE for .NET.  It is a great tool to use if you don't have Visual Studio on hand.  Maybe it will be as good as VS one day.  I downloaded &lt;a href="http://www.icsharpcode.net/OpenSource/SD/Download/"&gt;SharpDevelop2&lt;/a&gt;, which is compatible to .NET 1.1 and 2.0.  I was very impressed on how far this open source project has come along since I looked at it last year.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.icsharpcode.net/OpenSource/SD/Download/"&gt;SharpDevelop2&lt;/a&gt; has many features similar to VS 2005, but not all.  It is worth taking a look at,  if you haven't already.  I really love the NUnit integration found in &lt;a href="http://www.icsharpcode.net/OpenSource/SD/Download/"&gt;SharpDevelop2&lt;/a&gt;.  It would be great if VS 2005 had the same integration.&lt;br /&gt;&lt;br /&gt;I didn't really play around with it very long because it crashed shortly after I tried to open a VS 2005 solution from work.  I'm sure not all the features of VS 2005 have been implemented.  That is  probably the reason for the crash.&lt;br /&gt;&lt;br /&gt;I'm sure in a few months all the features of VS 2005 will be implemented.  I hope so.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113695288519516872?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113695288519516872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113695288519516872' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113695288519516872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113695288519516872'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/sharpdevelop.html' title='SharpDevelop'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113686625287806928</id><published>2006-01-09T23:10:00.000-05:00</published><updated>2006-03-18T02:53:17.200-05:00</updated><title type='text'>ANTLR</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt;, developed by &lt;a href="http://www.cs.usfca.edu/%7Eparrt/index.html"&gt;Terrence Parr&lt;/a&gt;, is a great tool to generate Lexical and Syntactical analysers.  It is useful if you want to build some kind of translator or compiler.  It will generate all the code for you in various languages, (Java, C#, C++, and Python) if you can provide the EBNF grammar.&lt;br /&gt;&lt;br /&gt;I haven't had a chance to build something useful with it yet, but hopefully I can in the very near future.&lt;br /&gt;&lt;br /&gt;Ashley J.S Mills has a great ANTLR tutorial that can be found &lt;a href="http://supportweb.cs.bham.ac.uk/documentation/tutorials/docsystem/build/tutorials/antlr/antlrhome.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=";font-family:webdings;font-size:85%;"  &gt;&lt;span style="color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/span&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/20359354-113686625287806928?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113686625287806928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113686625287806928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113686625287806928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113686625287806928'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/antlr.html' title='ANTLR'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113678259246758113</id><published>2006-01-08T23:25:00.000-05:00</published><updated>2006-03-18T02:52:12.790-05:00</updated><title type='text'>IL Merge</title><content type='html'>&lt;span style="font-size:85%;"&gt;Today I saw a neat tool called &lt;a href="http://research.microsoft.com/%7Embarnett/ILMerge.aspx"&gt;IL Merge&lt;/a&gt;.  It merges multiple assemblies into one single assembly.  This might be pretty useful for deployment when you have a lot of assemblies.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113678259246758113?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113678259246758113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113678259246758113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113678259246758113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113678259246758113'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/il-merge.html' title='IL Merge'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113667732483215544</id><published>2006-01-07T18:41:00.000-05:00</published><updated>2006-03-18T02:51:38.430-05:00</updated><title type='text'>Don't Have Time for more Information?</title><content type='html'>&lt;span style="font-size:85%;"&gt;I am a pretty lazy reader, so I found &lt;a href="http://www.itconversations.com/index.html"&gt;ITConversations &lt;/a&gt;an easy way to get more information, just drop it into my iPod and listen.  Here are some of my favorite conversations:&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail215.html"&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail188.html"&gt;Paul Graham - Great Hackers&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail175.html"&gt;Alistair Cockburn - Agile Software Development&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail301.html"&gt;Kent Beck - Developer Testing&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail207.html"&gt;Joel Spolsky - Joel on Software&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail214.html"&gt;Steve Wozniak Part 1&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.itconversations.com/shows/detail215.html"&gt;Steve Wozniak Part 2&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113667732483215544?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113667732483215544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113667732483215544' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113667732483215544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113667732483215544'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/dont-have-time-for-more-information.html' title='Don&apos;t Have Time for more Information?'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113652028022661953</id><published>2006-01-05T23:04:00.000-05:00</published><updated>2006-03-18T02:51:00.653-05:00</updated><title type='text'>DateTime Trick</title><content type='html'>&lt;span style="color: rgb(255, 102, 0);"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);font-size:100%;" &gt;Rencently, one of my co-work showed me a pretty cool DateTime trick.  I needed to retrieve data for a given day from the database.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-size:100%;" &gt;    DateTime startDateTime =  DateTime.Now.Date;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-size:100%;" &gt;    DateTime endDateTime = DateTime.Now.Date.AddDays(1).AddMilliseconds(-1);&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-size:100%;" &gt;Pretty cool, huh?  Well, I like it =)&lt;/span&gt;&lt;br /&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/20359354-113652028022661953?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113652028022661953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113652028022661953' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113652028022661953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113652028022661953'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/datetime-trick.html' title='DateTime Trick'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113638362840964902</id><published>2006-01-04T09:06:00.000-05:00</published><updated>2006-03-18T02:50:19.203-05:00</updated><title type='text'>ClickThrough</title><content type='html'>&lt;span style="color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;What attracted me to use &lt;a href="http://wix.sourceforge.net"&gt;WiX&lt;/a&gt; project in the first place?  Well, I need a simple way to create MSI package for work and writing XML file is definately simple.  On top of that, &lt;a href="http://wix.sourceforge.net"&gt;WiX&lt;/a&gt; is free and Opensource, what more can you ask for?&lt;br /&gt;&lt;br /&gt;Last night I checked source forge, and to my surprise, there's a new tool called &lt;a href="http://wix.sourceforge.net/ctvision.html"&gt;ClickThrough&lt;/a&gt; included in the &lt;a href="http://wix.sourceforge.net"&gt;WiX &lt;/a&gt;tool kit.  I know &lt;a href="http://wix.sourceforge.net/ctvision.html"&gt;ClickThrough&lt;/a&gt; is still in the beta stage, but I decided to give it a test drive.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;It used to take me a good 30 minutes to create a very basic MSI package by writing raw &lt;a href="http://wix.sourceforge.net"&gt;WiX&lt;/a&gt; files.  Using &lt;a href="http://wix.sourceforge.net/ctvision.html"&gt;ClickThrough&lt;/a&gt;, it took me 30 seconds and I can update the deployed software via RSS feed.  I can't wait to see what features are coming next when it's offically released.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;You can find out more about &lt;a href="http://wix.sourceforge.net/ctvision.html"&gt;ClickThrough&lt;/a&gt; on &lt;a href="http://blogs.msdn.com/robmen/archive/2005/11/08/490448.aspx"&gt;Rob Mensching&lt;/a&gt;'s blog.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113638362840964902?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113638362840964902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113638362840964902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113638362840964902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113638362840964902'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/clickthrough.html' title='ClickThrough'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113631135842365690</id><published>2006-01-03T13:02:00.000-05:00</published><updated>2006-03-18T02:49:48.756-05:00</updated><title type='text'>Automated Daily Builds</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold; color: rgb(255, 102, 0);"&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);font-size:85%;" &gt;Our build server slowly died during the end of an iteration, and it stayed dead for the next iteration.  The reason it was down so long is because we had to wait for our IT group to re-image the machine.  I hate how we don't have full control over our build server, but that's another story.&lt;br /&gt;&lt;br /&gt;For a WHOLE iteration, we were unable to do daily builds.   I wasn't too worried about it because I know the build server will be restored sooner or later.&lt;br /&gt;&lt;br /&gt;During our next iteration planning meeting, we did a recap with the business people by demonstrating the software.  Since we didn't have automated daily builds, no one outside of development had access to the latest code.&lt;br /&gt;&lt;br /&gt;Too make a long story short, there were a lot of surprised and puzzled faces for people outside of development.  We spent the whole morning explaining why certain things are done.  I'm sure this wouldn't have happened if everyone could see the software on the regular basis.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(255, 102, 0);"&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/20359354-113631135842365690?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113631135842365690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113631135842365690' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113631135842365690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113631135842365690'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/automated-daily-builds.html' title='Automated Daily Builds'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113624840101228826</id><published>2006-01-02T19:07:00.000-05:00</published><updated>2006-03-18T02:46:51.376-05:00</updated><title type='text'>Want to be a Highly Effective Programmer?</title><content type='html'>&lt;span style="font-weight: bold; color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;/span&gt;&lt;span style="color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;The president of Technicat, Phil Chu, gives us some hints &lt;a href="http://www.technicat.com/writing/programming.html"&gt;here&lt;/a&gt;.&lt;br /&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/20359354-113624840101228826?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113624840101228826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113624840101228826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113624840101228826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113624840101228826'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/want-to-be-highly-effective-programmer.html' title='Want to be a Highly Effective Programmer?'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113616859491689670</id><published>2006-01-01T21:22:00.000-05:00</published><updated>2006-03-18T02:46:09.073-05:00</updated><title type='text'>Null Object?</title><content type='html'>&lt;span style="color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Last week I was browsing though Martin Fowler's &lt;a href="http://www.bookpool.com/sm/0201485672"&gt;Refactoring&lt;/a&gt; book at the airport, in hopes of finding a solution to a recent problem at work. I found myself reading on &lt;a href="http://www.refactoring.com/catalog/introduceNullObject.html"&gt;Null Object&lt;/a&gt;......&lt;br /&gt;&lt;br /&gt;To make a long story short, I had to add a conditional branch block to each method in a class to avoid the code from doing improper calculations.  If some condition is true, then return zero; otherwise,  continue doing the normal calculation.  The code started to smell and turned ugly fast.&lt;br /&gt;&lt;br /&gt;By using &lt;a href="http://www.refactoring.com/catalog/introduceNullObject.html"&gt;Null Object&lt;/a&gt; I can hide a lot of the ugly conditional branches. I'm also a big fan of &lt;a href="http://www.martinfowler.com/ieeeSoftware/failFast.pdf"&gt;Fail Fast&lt;/a&gt; by James Shore.  &lt;a href="http://www.refactoring.com/catalog/introduceNullObject.html"&gt;Null Object&lt;/a&gt; will make the code appear to be cleaner, but the code will be harder to debug if there's a logic error.&lt;br /&gt;&lt;br /&gt;I'm not sure what path I should take right now, maybe &lt;a href="http://www.refactoring.com/catalog/introduceNullObject.html"&gt;Null Object&lt;/a&gt; is not what I'm looking for.&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 102, 0);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113616859491689670?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113616859491689670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113616859491689670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113616859491689670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113616859491689670'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2006/01/null-object.html' title='Null Object?'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113607582572197221</id><published>2005-12-31T19:23:00.000-05:00</published><updated>2006-03-18T02:44:40.870-05:00</updated><title type='text'>Recent Problems with FIT</title><content type='html'>&lt;span style="color: rgb(255, 153, 102);"&gt;&lt;span style="color: rgb(0, 0, 0);font-size:85%;" &gt;&lt;a href="http://fit.c2.com/"&gt;FIT&lt;/a&gt; is a great acceptance test framework; however, I recently ran into a road block at work.  Our application does a lot of calculations, so we use &lt;a href="http://fit.c2.com/"&gt;FIT&lt;/a&gt; to ensure all the formulas are coded correctly.&lt;br /&gt;&lt;br /&gt;The calculations are heavily dependent on each other.  For example, A + B + C + D -E - F = G and G + H - I = J.  In this simple example I'll have two &lt;a href="http://fit.c2.com/"&gt;FIT&lt;/a&gt; tables.  The first table will contain all the values to calculate G.  Here is my dilemma: in the second table I want to calculate J just by providing a value for G in the table.  To make things more complicated, the member variable holds G or J, which are private to the class, and no mutators are available.&lt;br /&gt;&lt;br /&gt;I &lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 153, 102);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 0);"&gt;want&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 153, 102);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-size:85%;"&gt; to do lazy loading and keep all the variables private without mutators; however I don't think that is possible.&lt;br /&gt;&lt;br /&gt;I solved the problem by providing a special constructor that is only used for &lt;a href="http://fit.c2.com/"&gt;FIT&lt;/a&gt; fixture, so I can set all the variables.  It works fine, but I'm no longer doing lazy loading.  The calculations are done in the constructor as soon as the object is instantiated.  The solution doesn't seem to be clean, but will work for now. &lt;/span&gt;&lt;br /&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/20359354-113607582572197221?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113607582572197221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113607582572197221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113607582572197221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113607582572197221'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2005/12/recent-problems-with-fit.html' title='Recent Problems with FIT'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20359354.post-113600130613906637</id><published>2005-12-30T22:42:00.000-05:00</published><updated>2006-03-18T02:44:03.386-05:00</updated><title type='text'>First Blog Entry</title><content type='html'>&lt;span style="font-size:85%;"&gt;Welcome to &lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-size:85%;"&gt;my blog. This is going to be my first post, so it's going to be pretty boring for a while, until I can add some meat to it. I recently joined another Agile team in the Philadelphia area using XP, so I think it's a good time for me to start a blog to capture my experiences.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20359354-113600130613906637?l=aaronfeng.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aaronfeng.blogspot.com/feeds/113600130613906637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20359354&amp;postID=113600130613906637' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113600130613906637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20359354/posts/default/113600130613906637'/><link rel='alternate' type='text/html' href='http://aaronfeng.blogspot.com/2005/12/first-blog-entry.html' title='First Blog Entry'/><author><name>Aaron Feng</name><uri>http://www.blogger.com/profile/09313532120106531143</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
