tag:blogger.com,1999:blog-203593542007-06-25T15:25:20.076-04:00Aaron FengAgile Software Development (XP), Test Driven Development, .NET, etc.....Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comBlogger56125tag:blogger.com,1999:blog-20359354.post-1150084716952111662006-06-11T23:56:00.000-04:002006-06-12T09:56:37.533-04:00ClosedI have been having a lot of problems with blogger, so I decided to move my blog. My new home can be found <a href="http://geekswithblogs.net/afeng">here</a>.Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1149742349743790762006-06-08T00:52:00.000-04:002006-06-10T01:07:28.346-04:00Agile Transition<span style="font-size:85%;">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. </span><span style="font-size:85%;"><a href="http://blogs.msdn.com/mpuleio/">Michael Puleio</a> described the changes he has made in his <a href="http://blogs.msdn.com/mpuleio/comments/606561.aspx">post</a> since he joind <a href="http://msdn.microsoft.com/practices/default.aspx">Microsoft patterns &amp; practices</a>. 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 :)</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1149007061335747742006-06-03T12:37:00.000-04:002006-06-03T10:46:27.946-04:00Random Thoughts<span style="font-size:85%;">Nowadays people think Agile development is a substitute for success. As <a href="http://alistair.cockburn.us/">Alistair Cockburn</a> 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.<br /><br />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.<br /><br />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. </span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1148871144174827702006-05-28T22:52:00.000-04:002006-05-28T22:53:52.090-04:00Indigo Security with AzManIn the <a href="http://aaronfeng.blogspot.com/2006/05/declarative-security-with-azman-and.html">previous post</a>, 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:<br /><ul><li><a href="http://steve.emxsoftware.com/Indigo-WCF/WCF+Extensibility+Behaviors+and+Inspectors">WCF Extensibility: Behaviors and Inspectors</a></li><li><a href="http://codebetter.com/blogs/sam.gentile/archive/2006/05/26/145540.aspx">How To: STS/Windows Authentication with ADAM/AD, Roles in AzMan with WCF</a></li></ul>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1148670280544556062006-05-27T09:02:00.000-04:002006-05-27T00:54:08.533-04:00Declarative Security with AzMan and CAB<a href="http://aaronfeng.blogspot.com/2006/05/dynamically-disable-controls-on-fly.html"><span style="font-size:85%;">In a </span></a><span style="font-size:85%;"><a href="http://aaronfeng.blogspot.com/2006/05/dynamically-disable-controls-on-fly.html">previous post</a>, I mentioned Controls can be dynamically disabled based on users' permission by using .NET attribute with <a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/">AzMan</a> and <a href="http://practices.gotdotnet.com/projects/cab">CAB</a>. This week is our security iteration, so we are able to test the concept described in this <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html/Attbasauth.asp">MSDN article</a>. The article suggested modifying the </span><span style="font-weight: bold;font-size:85%;" >RootWorkItemInitializationStrategy.cs</span><span style="font-size:85%;">, 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 </span><span style="font-weight: bold;font-size:85%;" >BuilderStrategy</span><span style="font-size:85%;"> then overiding </span><span style="font-weight: bold;font-size:85%;" >AddBuilderStrategies </span><span style="font-size:85%;">method in the shell, so you can add the strategy during run time. It will look something like this:<br /></span><pre><span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">class</span> YourShell <span style="color: rgb(128, 128, 48);">:</span> FormShellApplication <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">protected</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">override</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> AddBuilderStrategies<span style="color: rgb(128, 128, 48);">(</span>Builder builder<span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">base</span><span style="color: rgb(128, 128, 48);">.</span>AddBuilderStrategies<span style="color: rgb(128, 128, 48);">(</span>builder<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> builder<span style="color: rgb(128, 128, 48);">.</span>Strategies<span style="color: rgb(128, 128, 48);">.</span>AddNew<span style="color: rgb(128, 128, 48);">(</span>BuilderStage<span style="color: rgb(128, 128, 48);">.</span>Initialization<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><span style="color: rgb(128, 0, 128);">}</span></pre><span style="font-size:85%;"><workitem, yourform=""><authorizationbuilderstrategy>Here are some pitch falls we ran across when we tried to implement security with attributes.<br /></authorizationbuilderstrategy></workitem,></span><ul><li><span style="font-size:85%;">Dynamically created controls cannot be applied.</span></li><li><span style="font-size:85%;">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.</span></li><li><span style="font-size:85%;">The declaration of Controls cannot be in the designer file because the designer file will get overwritten.</span></li><li><span style="font-size:85%;">Performance penalty during startup of the application.</span></li><li><span style="font-size:85%;">Explicit logic already exists to enable or disable the UI based on the state of the system will override the attribute.<br /></span></li></ul><span style="font-size:85%;">In that article, XML file is used on the client side to map the <a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/">AzMan</a> 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.<br /><br />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.<br /></span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146533056797806982006-05-26T15:35:00.000-04:002006-05-26T15:37:39.303-04:00Invisible Leadership<p class="MsoNormal"><span style="font-size:85%;">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.<br /></span></p><p class="MsoNormal"><span style="font-size:85%;">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?<br /><br />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.<br /><br />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: <o:p></o:p></span></p> <ul type="disc"><li class="MsoNormal" style=""><span style="font-size:85%;">Enjoys and cares about the type of work being produced.<o:p></o:p></span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Strong problem solver.<o:p></o:p></span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Approachable personality.<o:p></o:p></span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Shares ideas with others.<o:p></o:p></span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Assumes good faith of others.<o:p></o:p></span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Shares a common goal with other members on the team.<o:p></o:p></span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Exhibits patience with others.</span></li><li class="MsoNormal" style=""><span style="font-size:85%;">Works well with others.</span></li><li class="MsoNormal" style=""><span style="font-size:85%;"><span style="font-weight: bold;">Strong Communication skills.</span> <o:p></o:p></span></li></ul> <p class="MsoNormal"><span style="font-size:85%;">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 <span style="font-weight: bold;">(I know this is a cliche, but it is true)</span>.<br /></span></p><p class="MsoNormal"><span style="font-size:85%;">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.</span></p><p class="MsoNormal"><span style="font-size:85%;">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.<br /></span></p> <p class="MsoNormal"><span style="font-size:85%;">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</span><span style="font-size:10;"></span><span style="font-size:10;"><span style="font-size:85%;"> <span style="font-weight: bold;">beneficial</span><o:p style="font-weight: bold;"></o:p></span></span><span style="font-size:85%;"> to the entire team.<br /></span></p>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1147829862995437502006-05-16T20:59:00.000-04:002006-05-16T23:47:11.306-04:00CoolCommands<span style="font-size:85%;">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.<br /></span><ul><li><span style="font-size:85%;"> Open Explorer browser by right clicking on a file.</span></li><li><span style="font-size:85%;"> Automatically resolves missing references.<br /></span></li><li><span style="font-size:85%;"> Locate item in Solution Explorer on demand when active tracking is turned off.</span></li><li><span style="font-size:85%;"> Copy and paste references from one project to another.</span></li><li><span style="font-size:85%;"> Add multiple projects at once.</span></li><li><span style="font-size:85%;"> Collapse all projects.</span></li><li><span style="font-size:85%;"> Visual Studio Command prompt here.</span></li></ul><span style="font-size:85%;">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.<br /><br />The latest version can be found <a href="http://weblogs.asp.net/gmilano/archive/2006/05/10/446010.aspx">here</a>.<br /></span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1147654404898107432006-05-14T19:46:00.000-04:002006-05-15T20:54:44.170-04:00Refactoring from Active Record to Repository<span style="font-size:85%;">In the begining of our project, we started with a <a href="http://www.martinfowler.com/eaaCatalog/repository.html">Repository</a> 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.<br /><br /><a href="http://www.martinfowler.com/eaaCatalog/activeRecord.html">Active Record</a> 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.<br /><br />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 <a href="http://www.bookpool.com/sm/0321125215">Domain-Driven Design</a> 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.<br /><br />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.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1147650026944255282006-05-14T19:40:00.000-04:002006-05-14T21:06:36.530-04:00Popup Advertisement<span style="font-size:85%;">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.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146976562948964112006-05-06T23:28:00.000-04:002006-05-07T01:05:00.643-04:00Dynamically Disable Controls on the Fly<span style="font-size:85%;">In an earlier <a href="http://aaronfeng.blogspot.com/2006/05/role-based-command-authentication-with.html">post</a>, 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 <a href="http://www.chrisholmesonline.com/">Chris Holmes</a> (the guy who wrote the first version of the Outlook Explorer bar before <a href="http://staff.southworks.net/blogs/matiaswoloski/default.aspx">Matias Woloski</a>) on sending me so many userful links and ideas regarding this issue.<br /><br />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 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html/Attbasauth.asp">here</a>. 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 <span style="font-weight: bold;">COM interop</span>, 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:<br /><br />[Authorization("DeleteUser", "Enabled", False)]<br /><br />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.</span><br /><pre class="code"></pre><pre class="code"></pre>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146880608350010102006-05-05T20:24:00.000-04:002006-05-05T22:54:14.563-04:00Databinding is EVIL<span style="font-size:85%;">Ok, I am <span style="font-weight: bold;">officially</span> done with databinding. Today I was working with <a href="http://steve.emxsoftware.com/">Steve</a> 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.<br /><br />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 "<span style="font-weight: bold;">look</span>" 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 <a href="http://www.softinsight.com/bnoyes/">Brian Noyes</a>' book "<a href="http://www.bookpool.com/sm/032126892X">Data Binding with Windows Forms 2.0</a>" 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.<br /><br />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.<br /><br />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.<br /></span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146709712988454482006-05-04T08:55:00.000-04:002006-05-03T22:28:37.630-04:00Role Based Command Authentication With CAB<span style="font-size:85%;">At work, we've been having some conversations about the security architecture for our Smart Client. Specifically, we talked about using <a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/">Authorization Manager</a> (<a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/">AzMan</a>) 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 <a href="http://staff.southworks.net/blogs/mariano">Mariano Szklanny</a> blog on CAB role based authentication. One of them is using <a href="http://msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager/">AzMan</a>.<br /><br /><a href="http://staff.southworks.net/blogs/mariano/archive/2006/03/15/260.aspx">CAB - Adding Command-level security to applications</a><br /><a href="http://staff.southworks.net/blogs/mariano/archive/2006/03/16/262.aspx">CAB - CommandAuthorization AzMan Sample Application</a><br /><br /></span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146543557936574372006-05-03T08:38:00.000-04:002006-05-03T08:38:43.946-04:00.NET BigInteger and BigDecimalI 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 <a href="http://geekswithblogs.net/gyoung/">Greg</a> pointed out in his <a href="http://geekswithblogs.net/gyoung/archive/2006/05/01/76869.aspx">post</a>, 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 <span style="font-weight: bold;">any</span> .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? ;)Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146627718179531552006-05-02T23:16:00.000-04:002006-05-02T23:41:58.760-04:00Aardvark'dWe all know <a href="http://www.joelonsoftware.com/">Joel</a> 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? <a href="http://www.projectaardvark.com/movie/">Aardvark'd</a> is a documentary on last summer's interns at his company, <a href="http://www.fogcreek.com/">Fog Creek</a>. I checked out the <a href="http://www.projectaardvark.com/movie/aardvarkdtrailersmall.mov">trailer</a>, it looked interesting, but it is a little short in my opinion. What will Joel do next?Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1146452539466950642006-04-30T22:46:00.000-04:002006-04-30T23:02:20.036-04:00Rethrowing ExceptionsIt is very common to see code that catches an exception then rethrows it without doing anything. <a href="http://kinnie.blogspot.com/2006/03/bad-exceptionhandling.html">Pieter Gheysens</a> has a post on why you should not just rethrow the exception.Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1145933760755825972006-04-25T22:53:00.000-04:002006-04-26T14:40:12.740-04:00Lazy User Interface Part III<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2772/2038/1600/solution.1.gif"><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" /></a>Lets start with our fictitious application from the <a href="http://www.testdriven.com/modules/news/">TDD </a>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:<br /><pre><span style="font-weight: bold; color: rgb(128, 0, 0);"><br /><br /></span><span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> CustomerViewPresenter Presenter <span style="color: rgb(128, 0, 128);">{</span><br /> get <span style="color: rgb(128, 0, 128);">{</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">return</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">this</span><span style="color: rgb(128, 128, 48);">.</span>presenter<span style="color: rgb(128, 0, 128);">;</span> <span style="color: rgb(128, 0, 128);">}</span><br /> set <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">this</span><span style="color: rgb(128, 128, 48);">.</span>presenter <span style="color: rgb(128, 128, 48);">=</span> value<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">this</span><span style="color: rgb(128, 128, 48);">.</span>presenter<span style="color: rgb(128, 128, 48);">.</span>View <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">this</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><span style="color: rgb(128, 0, 128);">}</span><span style="color: rgb(128, 0, 128);"></span><br /></pre><!-- ***** 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 <cail@nm.ru>. - 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 ***** -->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.<br /><br />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.<pre><span style="color: rgb(128, 0, 0); font-weight: bold;">namespace</span> RealtorApplicationTest <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 128, 48);">[</span>TestFixture<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">class</span> NavigationViewPresenterTest <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">private</span> NavigationViewPresenter presenter<span style="color: rgb(128, 0, 128);">;</span><br /><br /> <span style="color: rgb(128, 128, 48);">[</span>SetUp<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> SetUp<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> presenter <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> NavigationViewPresenter<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><br /> <span style="color: rgb(128, 128, 48);">[</span>Test<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> CanNotifyNavigationViewWhenButtonIsClicked<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> EventSubscriber subscriber <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> EventSubscriber<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> presenter<span style="color: rgb(128, 128, 48);">.</span>LoadData <span style="color: rgb(128, 128, 48);">+</span><span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> EventHandler<span style="color: rgb(128, 128, 48);">(</span>subscriber<span style="color: rgb(128, 128, 48);">.</span>Handler<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> presenter<span style="color: rgb(128, 128, 48);">.</span>NotifyNavigationView<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> Assert<span style="color: rgb(128, 128, 48);">.</span>IsTrue<span style="color: rgb(128, 128, 48);">(</span>subscriber<span style="color: rgb(128, 128, 48);">.</span>HasBeenCalled<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><br /> <span style="color: rgb(128, 128, 48);">[</span>Test<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> NotifyNavigationWithNoHandler<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> EventSubscriber subscriber <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> EventSubscriber<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> presenter<span style="color: rgb(128, 128, 48);">.</span>NotifyNavigationView<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><span style="color: rgb(128, 0, 128);">}</span><span style="color: rgb(128, 0, 128);"></span></pre><!-- ***** 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 <cail@nm.ru>. - 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 ***** --><!-- ***** 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 <cail@nm.ru>. - 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 ***** --><!-- ***** 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 <cail@nm.ru>. - 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 ***** -->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.<br /><br />When practicing <a href="http://www.testdriven.com/modules/news/">TDD</a><!-- ***** 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 <cail@nm.ru>. - 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 ***** -->, 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.<br /><pre><span style="color: rgb(128, 0, 0); font-weight: bold;">private</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> loadButton_Click<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 0, 0); font-weight: bold;">object</span> sender<span style="color: rgb(128, 128, 48);">,</span> EventArgs e<span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> presenter<span style="color: rgb(128, 128, 48);">.</span>NotifyNavigationView<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /><span style="color: rgb(128, 0, 128);">}</span><span style="color: rgb(128, 0, 128);"></span></pre><!-- ***** 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 <cail@nm.ru>. - 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 ***** -->Lets move on to the RealtorViewPresenter and write a test before we run the application.<br /><pre><span style="color: rgb(128, 0, 0); font-weight: bold;">namespace</span> RealtorApplicationTest <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 128, 48);">[</span>TestFixture<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">class</span> RealtorViewPresenterTest <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">private</span> RealtorViewPresenter presenter<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">private</span> MockRealtorView view<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">private</span> MockRealtorService service<span style="color: rgb(128, 0, 128);">;</span><br /><br /> <span style="color: rgb(128, 128, 48);">[</span>SetUp<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> SetUp<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> service <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> MockRealtorService<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> view <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> MockRealtorView<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> presenter <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> RealtorViewPresenter<span style="color: rgb(128, 128, 48);">(</span>service<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> presenter<span style="color: rgb(128, 128, 48);">.</span>View <span style="color: rgb(128, 128, 48);">=</span> view<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><br /> <span style="color: rgb(128, 128, 48);">[</span>Test<span style="color: rgb(128, 128, 48);">]</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> HasTheServiceBeenCalled<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> presenter<span style="color: rgb(128, 128, 48);">.</span>OnLoadData<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 0, 0); font-weight: bold;">this</span><span style="color: rgb(128, 128, 48);">,</span> EventArgs<span style="color: rgb(128, 128, 48);">.</span>Empty<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> Assert<span style="color: rgb(128, 128, 48);">.</span>IsTrue<span style="color: rgb(128, 128, 48);">(</span>service<span style="color: rgb(128, 128, 48);">.</span>HasFindAllRealtorsBeenCalled<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> Assert<span style="color: rgb(128, 128, 48);">.</span>IsTrue<span style="color: rgb(128, 128, 48);">(</span>view<span style="color: rgb(128, 128, 48);">.</span>HasBindingSourceBeenCalled<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><span style="color: rgb(128, 0, 128);">}</span><span style="color: rgb(128, 0, 128);"></span></pre><!-- ***** 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 <cail@nm.ru>. - 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 ***** --><!-- ***** 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 <cail@nm.ru>. - 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 ***** --><!-- ***** 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 <cail@nm.ru>. - 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 ***** -->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.<br /><br /><!-- ***** 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 <cail@nm.ru>. - 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 ***** -->Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1145847812428861262006-04-23T22:49:00.000-04:002006-04-25T14:15:32.960-04:00Lazy User Interface Part II<span style="font-size:85%;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2772/2038/1600/LazyApplication.1.gif"><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" /></a><br />In order to make the application testable, proper separation is required. I will be using <a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html">MVP </a>pattern to separate out the tiers. <a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html">MVP</a> is a derivitive of <a href="http://www.martinfowler.com/eaaCatalog/modelViewController.html">MVC</a>, 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 <a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html">MVP</a> better because I think it is a little cleaner when the Model does not know about the View.<br /><br />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.<br /><br />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.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1145811043356587752006-04-23T10:54:00.000-04:002006-04-23T23:31:27.043-04:00Lazy User Interface Part I<span style="font-size:85%;">I was recently working on code that deals mostly with the front-end portion of our software.<br />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.<br /><br />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 <a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html">MVP pattern</a>), and noticed very little code was in the presenter, and the view seemed to be much larger. Since we practice <a href="http://www.testdriven.com/modules/news/">TDD</a> at work, how could this happen?<br /><br />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.<br /><br />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 <a href="http://www.martinfowler.com/eaaDev/ModelViewPresenter.html">MVP pattern</a> with <a href="http://www.testdriven.com/modules/news/">TDD</a>.<br /></span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1145323731160390112006-04-17T20:44:00.000-04:002006-04-17T21:35:30.203-04:00Internet To Go<span style="font-size:85%;">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. <a href="http://www.webaroo.com/">Webaroo</a> comes to your rescue. You can add a URL to <a href="http://www.webaroo.com/">Webaroo</a>, and it will traverse all the links for you, so any link off the website will still work offline. I saved <a href="http://www.joelonsoftware.com/">Joel Spolsky's</a> 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.<br /><br />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. </span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1144810146148644512006-04-11T22:03:00.000-04:002006-04-12T15:18:32.036-04:00Quality With a Name<span style="font-size:85%;">I felt honored to be one of the first few to read the latest insightful essay written by <a href="http://www.jamesshore.com/">Jim Shore</a>: <a href="http://www.jamesshore.com/Blog/New-Article-Quality-With-a-Name.html">Quality With a Name</a>. 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 <a href="http://www.joelonsoftware.com/">Joel Spolksy's</a> "<a href="http://www.joelonsoftware.com/items/2006/03/31.html">Best Software Writing II</a>", need I say more? Enough talk, go read it, and maybe my check will come sooner.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1144718541906497682006-04-10T21:18:00.000-04:002006-04-12T00:03:02.530-04:00Ruby in .NET?<span style="font-size:85%;">With Generics in .NET 2.0 more possibilities are availble, such as <a href="http://www.ruby-lang.org/en/">Ruby</a> like closures. <a href="http://stal.blogspot.com/">Michael Stal</a> has a great posting on <a href="http://stal.blogspot.com/2005/01/simulate-closures-in-c-20.html">Simulate Closures in C# 2.0</a>, so I decided to try it myself. </span><br /><pre><span style="color: rgb(128, 0, 0); font-weight: bold;">class</span> Program <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">static</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">void</span> Main<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 0, 0); font-weight: bold;">string</span><span style="color: rgb(128, 128, 48);">[</span><span style="color: rgb(128, 128, 48);">]</span> args<span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">int</span><span style="color: rgb(128, 128, 48);">[</span><span style="color: rgb(128, 128, 48);">]</span> ints <span style="color: rgb(128, 128, 48);">=</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">int</span><span style="color: rgb(128, 128, 48);">[</span><span style="color: rgb(128, 128, 48);">]</span><span style="color: rgb(128, 0, 128);">{</span><span style="color: rgb(0, 140, 0);">2</span><span style="color: rgb(128, 128, 48);">,</span><span style="color: rgb(0, 140, 0);">4</span><span style="color: rgb(128, 128, 48);">,</span><span style="color: rgb(0, 140, 0);">6</span><span style="color: rgb(128, 0, 128);">}</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">string</span><span style="color: rgb(128, 128, 48);">[</span><span style="color: rgb(128, 128, 48);">]</span> strings <span style="color: rgb(128, 128, 48);">=</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">new</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">string</span><span style="color: rgb(128, 128, 48);">[</span><span style="color: rgb(128, 128, 48);">]</span> <span style="color: rgb(128, 0, 128);">{</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">a</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">b</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">c</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);"> </span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">A</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">A</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">R</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">O</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">N</span><span style="color: rgb(128, 0, 0);">"</span> <span style="color: rgb(128, 0, 128);">}</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(105, 105, 105);">// output is 12</span><br /> Console<span style="color: rgb(128, 128, 48);">.</span>WriteLine<span style="color: rgb(128, 128, 48);">(</span>Collector<span style="color: rgb(128, 128, 48);"><</span><span style="color: rgb(128, 0, 0); font-weight: bold;">int</span><span style="color: rgb(128, 128, 48);">></span><span style="color: rgb(128, 128, 48);">.</span>Collect<span style="color: rgb(128, 128, 48);">(</span>ints<span style="color: rgb(128, 128, 48);">,</span> Add<span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(0, 140, 0);">0</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(105, 105, 105);">// output is 14</span><br /> Console<span style="color: rgb(128, 128, 48);">.</span>WriteLine<span style="color: rgb(128, 128, 48);">(</span>Collector<span style="color: rgb(128, 128, 48);"><</span><span style="color: rgb(128, 0, 0); font-weight: bold;">int</span><span style="color: rgb(128, 128, 48);">></span><span style="color: rgb(128, 128, 48);">.</span>Collect<span style="color: rgb(128, 128, 48);">(</span>ints<span style="color: rgb(128, 128, 48);">,</span> Add<span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(0, 140, 0);">2</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(105, 105, 105);">// output is Dabc AARON </span><br /> Console<span style="color: rgb(128, 128, 48);">.</span>WriteLine<span style="color: rgb(128, 128, 48);">(</span>Collector<span style="color: rgb(128, 128, 48);"><</span><span style="color: rgb(128, 0, 0); font-weight: bold;">string</span><span style="color: rgb(128, 128, 48);">></span><span style="color: rgb(128, 128, 48);">.</span>Collect<span style="color: rgb(128, 128, 48);">(</span>strings<span style="color: rgb(128, 128, 48);">,</span> Add<span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(0, 0, 230);">D</span><span style="color: rgb(128, 0, 0);">"</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> Console<span style="color: rgb(128, 128, 48);">.</span>ReadLine<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">static</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">int</span> Add<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 0, 0); font-weight: bold;">int</span> res<span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">int</span> parm<span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">return</span> res <span style="color: rgb(128, 128, 48);">+</span> parm<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">static</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">string</span> Add<span style="color: rgb(128, 128, 48);">(</span><span style="color: rgb(128, 0, 0); font-weight: bold;">string</span> string1<span style="color: rgb(128, 128, 48);">,</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">string</span> string2<span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">return</span> string1 <span style="color: rgb(128, 128, 48);">+</span> string2<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><span style="color: rgb(128, 0, 128);">}</span><br /><br /><span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">class</span> Collector<span style="color: rgb(128, 128, 48);"><</span>T<span style="color: rgb(128, 128, 48);">></span> <span style="color: rgb(128, 0, 128);">{</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">delegate</span> T CollectDelegate<span style="color: rgb(128, 128, 48);">(</span>T temp<span style="color: rgb(128, 128, 48);">,</span> T parm<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">public</span> <span style="color: rgb(128, 0, 0); font-weight: bold;">static</span> T Collect <span style="color: rgb(128, 128, 48);">(</span>ICollection collection<span style="color: rgb(128, 128, 48);">,</span><br /> CollectDelegate collectDelegate<span style="color: rgb(128, 128, 48);">,</span> T initVal<span style="color: rgb(128, 128, 48);">)</span> <span style="color: rgb(128, 0, 128);">{</span><br /> T res <span style="color: rgb(128, 128, 48);">=</span> initVal<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">foreach</span> <span style="color: rgb(128, 128, 48);">(</span>T elem <span style="color: rgb(128, 0, 0); font-weight: bold;">in</span> collection<span style="color: rgb(128, 128, 48);">)</span> res <span style="color: rgb(128, 128, 48);">=</span> collectDelegate<span style="color: rgb(128, 128, 48);">(</span>res<span style="color: rgb(128, 128, 48);">,</span> elem<span style="color: rgb(128, 128, 48);">)</span><span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 0); font-weight: bold;">return</span> res<span style="color: rgb(128, 0, 128);">;</span><br /> <span style="color: rgb(128, 0, 128);">}</span><br /><span style="color: rgb(128, 0, 128);">}</span></pre>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1144202908699144132006-04-04T21:52:00.000-04:002006-04-10T21:24:36.176-04:00Subersion Offline Revert<span style="font-size:85%;">Sometimes when I am <a href="http://www.refactoring.com/">refactoring</a>, 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 <a href="http://subversion.tigris.org/">SVN</a>. 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 <a href="http://subversion.tigris.org/">SVN</a> stores all your changes locally in the .svn folder, but for some reason it never occured to me to try it.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1143865562732854942006-04-01T21:50:00.000-05:002006-04-10T21:24:56.863-04:00One Week Iterations<span style="font-size:85%;">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.<br /><br />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.<br /><br />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.<br /><br />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.<br /><br />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.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1143086857324434652006-03-23T19:20:00.000-05:002006-03-23T21:46:38.040-05:00CAB Workspace Flickering<span style="font-size:85%;"><a href="http://www.delarou.name/PermaLink,guid,3b2a69dd-79bf-4a88-be0c-36d3e192b760.aspx">Delarou has a great post</a> about how to prevent the flickering when you switch between Controls in a <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> 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.</span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.comtag:blogger.com,1999:blog-20359354.post-1143087500820360972006-03-22T23:17:00.000-05:002006-03-23T00:14:55.350-05:00Smart Client Baseline Architecture Toolkit<span style="font-size:85%;">At work I am working on a team that develops a Smart Client application with <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">Composite UI Application Block</a> (<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a>). We have been struggling to figure out the best way to leverage <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> within our software. We started the application out with the basic MVP pattern and slowly we fused <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> into our software. In the beginning, we started out with a presenter communicating with multiple views in a <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> 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.<br /><br />Recently a couple of my colleagues went to Redmond and worked with the <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> team. They brought back many useful insights on the best practices for <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a>. One thing I think will be very useful is the<a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170"> </a></span><span style="font-size:85%;"><a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170">Smart Client Baseline Architecture Toolkit</a> (<a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170">SCBAT</a>). <a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170">SCBAT</a> automates a lot of daily <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> 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 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> 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 </span><span style="font-size:85%;"><a href="http://lab.msdn.microsoft.com/teamsystem/workshop/gat/intro.aspx">Guidance Automation Toolkit</a> (<a href="http://lab.msdn.microsoft.com/teamsystem/workshop/gat/intro.aspx">GAT</a>).</span><br /><span style="font-size:85%;"><br />Before you install SCBAT, there are a couple of prequisite packages:<br /></span><ul><li><span style="font-size:85%;"><a href="http://www.microsoft.com/Downloads/details.aspx?familyid=C0A394C0-5EEB-47C4-9F7B-71E51866A7ED&amp;displaylang=en">Guidance Automation Extensions</a> - Run time component that is required to run Guidance Automation Toolkit.</span></li><li><span style="font-size:85%;"><a href="http://lab.msdn.microsoft.com/teamsystem/workshop/gat/intro.aspx">Guidance Automation Toolkit</a> - Create customized "Guidance Packages" for developers. </span></li></ul><span style="font-size:85%;"> Of course, you must have <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/cab.asp">CAB</a> and </span><span style="font-size:85%;"><a href="http://msdn.microsoft.com/library/?url=/library/en-us/dnpag2/html/EntLib2.asp">Enterprise Library</a> installed already. Open the Guidance Automation solution from the location where <a href="http://www.gotdotnet.com/codegallery/codegallery.aspx?id=941d2228-3bb5-42fd-8004-c08595821170">SCBAT</a> is installed. Compile the solution and installer project. Run the installer and you should be done.</span><span style="font-size:85%;"><br /></span>Aaron Fenghttp://www.blogger.com/profile/09313532120106531143noreply@blogger.com