<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Yet Another Coding Blog : architecture</title><link>http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx</link><description>Tags: architecture</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>MVVM – This might hurt a little…</title><link>http://blogs.msdn.com/avip/archive/2009/11/14/mvvm-this-might-hurt-a-little.aspx</link><pubDate>Fri, 13 Nov 2009 21:23:57 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9922221</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/avip/comments/9922221.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=9922221</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=9922221</wfw:comment><description>&lt;p&gt;This is an attempt at a collaborative post; I’ll fill in more data if/when people make suggestions; please add comments on more problems and other/better solutions – I’ll add the links.&lt;/p&gt;  &lt;p&gt;Overall, MVVM is very attractive – but all the screen casts I’ve seen avoid some confusing pitfalls that you’ll come up against in the real world. The landscape at the time of writing is a plethora of frameworks that attempt to solve similar problems; I expect the community will settle on a small number eventually, and certain patterns will emerge.&lt;/p&gt;  &lt;p&gt;Until then, I hope this will help.&lt;/p&gt;  &lt;h2&gt;Overall&lt;/h2&gt;  &lt;p&gt;Some things that you take for granted will seem impossible to do in MVVM (without breaking the rules). Sometimes this is due to Silverlight missing WPF features, other times it has nothing to do with that. Most of these holes are pluggable in some sense, which is why…:&lt;/p&gt;  &lt;h2&gt;Using a Framework&lt;/h2&gt;  &lt;p&gt;I recommend you use a framework. You can write your own, but please consider that it needs to handle quite a few things in order to solve the various problems in this article.&lt;/p&gt;  &lt;p&gt;I can’t recommend which framework to use because I have no experience with them, but I do recommend considering the problems below and finding out how each framework solves them. If the framework doesn’t have a “reference application”, stay away – you’re going to need one.&lt;/p&gt;  &lt;p&gt;Here are a few that I know of:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://compositewpf.codeplex.com/"&gt;PRISM2.0&lt;/a&gt;, which is from the MS Patters&amp;amp;Practices group.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://projects.nikhilk.net/SilverlightFX"&gt;SilverlightFX&lt;/a&gt;, by NikhilK. Does alot more than just MVVM; great samples/posts.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://mvvmlight.codeplex.com/"&gt;MVVM Light&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.codeplex.com/site/search?projectSearchText=mvvm&amp;amp;sortBy=Relevance"&gt;Lots of others&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Reacting to a click&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: User clicks button; you want something to happen.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: You’re “not allowed” to use the codebehind and an event-handler, so it needs to be done in the ViewModel. However, the ViewModel is ignorant of the view, so it doesn’t know about the button’s existence – it can’t hook into the click event.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: You need support for “commanding”. Put very simply, this is usually a broadcast/listen mechanism where a “command” gets raised by someone, and someone else chooses to listen to it. In this case, the button would raise a command, and the ViewModel would be listening for it, and act.&lt;/p&gt;  &lt;p&gt;WPF has it built-in, Silverlight does not – but the various frameworks have tacked it on, and it’s a basic pillar of MVVM.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Opening a dialog&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: You have a listbox, the user double-clicks on an element, and you want an edit dialog to pop up with that element’s data to be edited.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: You’re not allowed to have logic in your code-behind, so you can’t simply react to the event there. So you raise a command, and the ViewModel listens to it… But it’s not allowed to reference a UI component such as a dialog!&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Much as above, you use the broadcast/listen pattern… However, instead of having the ViewModel listen, you have some central app “router” listening, and it knows how to open a dialog. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Passing a value to a dialog&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Same as above.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: You’ve raised the command, and it knows to open a dialog – but how does it know to pass in the currently selected item from the listbox?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution 1:&lt;/strong&gt; Perhaps your framework allows that item to be set as the command argument as part of the XAML. If so, perfect. If not (or if you need something more complex):&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution 2&lt;/strong&gt;: Raise the command, but have the ViewModel listen to it instead of a central “router”. The ViewModel figures out what needs to be passed in (for example, a “CurrentlySelected” bound property on itself), and raises an appropriate command.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Closing a dialog&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: You opened the dialog, the user made their edits and clicked “Save”, then the dialog’s ViewModel called the web service to save the changes. Now the dialog should be closed.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: The last bit of code that ran was on the dialog’s ViewModel; it can’t tell the dialog to close because it has no notion on the dialog’s existence…&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution 1&lt;/strong&gt;: Some frameworks have built-in support for dialogs and will handle this.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution 2&lt;/strong&gt;: Cheat; if you’re not a purist, try this: The ViewModel raises an event (“TimeToClose”) with an argument of success/failure. The View’s codebehind subscribes, and closes the view itself.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Animations&lt;/h2&gt;  &lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;: Your app shows a list of servers, and their status is all “good”. The ViewModel loads some new data, and one of the server’s changes to “bad”. The UI needs to react by playing an animation for that server.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Fundamentally, you don’t want your ViewModel to know anything about animations, storyboards, VisualStates, etc. It changed the data, but all we have on the view side of things is how to display the data; what we really want is the ability to trigger a storyboard, or to bind an element from the ViewModel to a VisualState on a framework element.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution 1&lt;/strong&gt;: You can try to cheat here by using the codebehind, but depending on your exact scenario it might not help at all.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Solution 2&lt;/strong&gt;: This article seems to do a good job of replicating DataTrigger for Silverlight (although I’ve yet to experiment with this):&lt;/p&gt;  &lt;p&gt;&lt;a title="http://blois.us/blog/2009/04/datatrigger-bindings-on-non.html" href="http://blois.us/blog/2009/04/datatrigger-bindings-on-non.html"&gt;http://blois.us/blog/2009/04/datatrigger-bindings-on-non.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Avi&lt;/p&gt;  &lt;p&gt;&lt;script type="text/javascript"&gt;addthis_pub  = 'avip';&lt;/script&gt;
&lt;a href="http://www.addthis.com/bookmark.php" onmouseover="return addthis_open(this, '', '[URL]', '[TITLE]')" onmouseout="addthis_close()" onclick="return addthis_sendto()"&gt;&lt;img src="http://s7.addthis.com/button0-share.gif" width="83" height="16" border="0" alt="" /&gt;&lt;/a&gt;&lt;script type="text/javascript" src="http://s7.addthis.com/js/152/addthis_widget.js"&gt;&lt;/script&gt;
&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9922221" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/silverlight/default.aspx">silverlight</category><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category><category domain="http://blogs.msdn.com/avip/archive/tags/mvvm/default.aspx">mvvm</category></item><item><title>Be Paranoid. Be Very Paranoid.</title><link>http://blogs.msdn.com/avip/archive/2008/12/03/be-paranoid-be-very-paranoid.aspx</link><pubDate>Wed, 03 Dec 2008 06:29:33 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9168003</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/avip/comments/9168003.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=9168003</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=9168003</wfw:comment><description>&lt;p&gt;Do you maintain an application with a backend database? Does that application ever write to the database? Be afraid.&lt;/p&gt;  &lt;p&gt;The worst situation to be in with respect to the above is when a customer mails you and says: “Why is my data gone?”&lt;/p&gt;  &lt;p&gt;99% of the time, it’s because they clicked on the “Delete” button; but sometimes you need proof – this is what I want to discuss.&lt;/p&gt;  &lt;p&gt;Log every interesting write to the database. There are various levels at which you can do this:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Application logic level: This gives you the most context, the most usable logs, and in fact gives you data which can generally be exposed directly to the customer, preventing lots of questions. The problem is that it’s not reliable: The app could succeed in writing then fail in logging. Alternatively, a dev on the app might forget to add logging to a new feature. &lt;/li&gt;    &lt;li&gt;Application object model level: A little less context/readability than above, a little more reliability. &lt;/li&gt;    &lt;li&gt;Data-Access-Layer level: Less context than above, more reliability. &lt;/li&gt;    &lt;li&gt;Sproc level: Same tradeoff. &lt;/li&gt;    &lt;li&gt;Table level (triggers): And same again. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;As you can see, the lower you go, the less chance for error and the less value a log entry gives you. You can increase the value of a “deep” log entry by forcing a set of arguments up the stack. For example, you can force every sproc which writes data to require username/machine/reason arguments – but this can become costly to maintain.&lt;/p&gt;  &lt;p&gt;So which is right? Depends on your app, your level of paranoia, your customer’s needs, etc. Generally I stay away from triggers and try to add logging at the sproc level for critical sprocs, and at the app/OM level for extra context; better to have too much logging than too little.&lt;/p&gt;  &lt;p&gt;Here’s a nice trick for creating a footprint log table that your sprocs (or triggers) can use quite easily - Create a simple table with the following columns (at least):&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="92"&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="97"&gt;&lt;strong&gt;Default value&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="210"&gt;&lt;strong&gt;Comment&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="92"&gt;LogEntry&lt;/td&gt;        &lt;td valign="top" width="97"&gt;&amp;#160;&lt;/td&gt;        &lt;td valign="top" width="210"&gt;The text you want to log.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="92"&gt;TimeStamp&lt;/td&gt;        &lt;td valign="top" width="97"&gt;getdate()&lt;/td&gt;        &lt;td valign="top" width="210"&gt;Automatically fills in the current datetime.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="92"&gt;User&lt;/td&gt;        &lt;td valign="top" width="97"&gt;system_user&lt;/td&gt;        &lt;td valign="top" width="210"&gt;Automatically inserts the logged in user’s ID.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="92"&gt;Machine&lt;/td&gt;        &lt;td valign="top" width="97"&gt;host_name()&lt;/td&gt;        &lt;td valign="top" width="210"&gt;Automatically inserts the user’s client machine name.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="92"&gt;Application&lt;/td&gt;        &lt;td valign="top" width="97"&gt;app_name()&lt;/td&gt;        &lt;td valign="top" width="210"&gt;Automatically inserts the name of the application running this code (provided you set it in the connection string, which you should!)&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Inserting into this table requires only the one column, but you capture lots of extra data for free. If this is done from a trigger, then you’ll even catch slackers with access to the DB who are updating it manually.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Oh, don’t forget to age off old entries before the table ends up at 50GB ;)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Avi&lt;/p&gt;  &lt;p&gt;&lt;script type="text/javascript"&gt;addthis_pub  = 'avip';&lt;/script&gt;
&lt;a href="http://www.addthis.com/bookmark.php" onmouseover="return addthis_open(this, '', '[URL]', '[TITLE]')" onmouseout="addthis_close()" onclick="return addthis_sendto()"&gt;&lt;img src="http://s7.addthis.com/button0-share.gif" width="83" height="16" border="0" alt="" /&gt;&lt;/a&gt;&lt;script type="text/javascript" src="http://s7.addthis.com/js/152/addthis_widget.js"&gt;&lt;/script&gt;
&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9168003" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category><category domain="http://blogs.msdn.com/avip/archive/tags/programming/default.aspx">programming</category></item><item><title>On using Arrays</title><link>http://blogs.msdn.com/avip/archive/2008/09/23/on-using-arrays.aspx</link><pubDate>Tue, 23 Sep 2008 03:52:32 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8961772</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/avip/comments/8961772.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=8961772</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=8961772</wfw:comment><description>&lt;p&gt;Eric Lippert has a great article on arrays:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx" href="http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx"&gt;http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;I think this is especially useful to consider if you’re writing an API. Consider not just arrays, but any time you’re returning any collection: Are you returning &lt;em&gt;values&lt;/em&gt; or a &lt;em&gt;variables&lt;/em&gt;? Did you mean to?&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Avi&lt;/p&gt;  &lt;p&gt;&lt;!-- AddThis Button BEGIN --&gt;
&lt;a href="http://www.addthis.com/bookmark.php" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;pub=avip&amp;url='+encodeURIComponent(location.href)+'&amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" title="Bookmark and Share" target="_blank"&gt;&lt;img src="http://s9.addthis.com/button1-share.gif" wid&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8961772" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/api/default.aspx">api</category><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category><category domain="http://blogs.msdn.com/avip/archive/tags/programming/default.aspx">programming</category></item><item><title>Creating Testable Applications Using the MVP Pattern</title><link>http://blogs.msdn.com/avip/archive/2008/08/03/creating-testable-applications-using-the-mvp-pattern.aspx</link><pubDate>Sat, 02 Aug 2008 21:23:51 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8806555</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/avip/comments/8806555.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=8806555</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=8806555</wfw:comment><description>&lt;p&gt;(The following post talks about ASP.NET, but it actually applies to all UI-based applications, web and non-web. PHP, WPF, Winforms, etc. It does not require a framework, nor anything to install - it's just an interesting way to write your code such that it has a clear separation of concerns).&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Your typical ASP.NET application is difficult to test, because much of the logic is contained within the codebehind files, which derive from &lt;em&gt;Web.UI.Page&lt;/em&gt;, which needs an &lt;em&gt;HttpContext&lt;/em&gt;, which is difficult to mock. Furthermore, the output of the methods in the codebehind is often not easily-testable, because it's a side-effect (such as calling &lt;em&gt;DataBind()&lt;/em&gt; on a &lt;em&gt;GridView&lt;/em&gt;).&lt;/p&gt; &lt;p&gt;This same problem exists in most UI frameworks: How do you test the logic used to generate a UI without having to take heavy dependencies on that UI's implementation (thereby complicating the tests immensely)?&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Goal&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Ideally, you'd be able to take all the logic you want to test and put it outside of the UI framework (ie; the ASPX codebehind), such that you can test that logic separately without depending on that UI framework. You want your logic to be able to update the UI, but at the same time need to know as little as possible about the internals of that UI.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Achieving the Separation Using the Model-View-Presenter Pattern&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;The Model-View-Presenter (MVP) pattern separates your app into three parts:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The &lt;strong&gt;Model&lt;/strong&gt;: This is the same object model that you currently use for your business objects, data objects, whatever. This remains unchanged.  &lt;li&gt;The &lt;strong&gt;View&lt;/strong&gt;: This is your ASPX file; but it's as thin and dumb as possible. By that I mean that it only renders data that has been given to it; it doesn't do any thinking about what data it should have and where to get it.  &lt;li&gt;The &lt;strong&gt;Presenter&lt;/strong&gt;: This is the brains of the operation. The View asks it to act on the user's desires; it consults the model, then tells the view what to render (although not &lt;em&gt;how&lt;/em&gt; to render it - that's the key part!).&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The key to all this is that the Presenter avoids having a dependency on the View by having all the View's data requirements defined in an interface, and creating the dependency on that interface instead of on the view. That can then easily be mocked up for testing.&lt;/p&gt; &lt;p&gt;All this is best presented as a before/after example. Here's the scenario: We have a page that needs to display a list of people, filtered by a user-defined string. In order to do this, it eventually needs to bind a list of people to a &lt;em&gt;GridView&lt;/em&gt;, which will take care of the rendering.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The "Before" Code for handling the user's button press to filter the list:&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;In &lt;em&gt;PeopleView.aspx.cs&lt;/em&gt;:&lt;/p&gt; &lt;div&gt; &lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; btnFilter_Click(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     ShowSomePeople(txtFilter.Text);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ShowSomePeople(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; filter)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     List&amp;lt;Person&amp;gt; lst = LoadAllFromDB().Where(p =&amp;gt; p.Name.Contains(filter)).ToList();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     gvwPeople.DataSource = lst;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt;     gvwPeople.DataBind();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  11:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;(Here, the &lt;em&gt;LoadallFromDB()&lt;/em&gt; call is a call to the Model to get a list of all &lt;em&gt;Person&lt;/em&gt; objects from the DB).&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;The "After" Code:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First we create the interface definition which defines what data our View needs in order to render the page. We know it needs the actual list of people to show, and maybe an error message in case of problems. So, in &lt;em&gt;PeopleInterface.cs&lt;/em&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;interface&lt;/span&gt; IPeopleInterface&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// The list of people to show&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     List&amp;lt;Person&amp;gt; Members { get; set; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// Show this if something went wrong&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Error { get; set; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In &lt;em&gt;PeopleView.aspx.cs&lt;/em&gt; (the codebehind), we implement this interface:&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt; 
   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;partial&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; PeopleView : System.Web.UI.Page, IPeopleInterface&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;  &lt;span style="color: #008000"&gt;// ...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then we update &lt;em&gt;ShowSomePeople&lt;/em&gt; to call into the Presenter, instead of doing its own thinking:&lt;br&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ShowSomePeople(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; filter)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     PeoplePresenter Presenter = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; PeoplePresenter(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt;     Presenter.LoadWithFilter(filter);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;     gvwPeople.DataSource = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Members;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt;     gvwPeople.DataBind();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Finally the Presenter itself, in &lt;em&gt;PeoplePresenter.cs &lt;/em&gt;(a standalone class):&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; PeoplePresenter(IPeopleInterface v)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt;     View = v;    &lt;span style="color: #008000"&gt;// "View" is a private member&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   6:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; LoadWithFilter(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; filter)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   7:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   8:&lt;/span&gt;     &lt;span style="color: #008000"&gt;// Tell the view what data it should be showing&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   9:&lt;/span&gt;     View.Members = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.LoadAllFromDB().Where(p =&amp;gt; p.Name.Contains(filter)).ToList();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;  10:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The interface defines the "contract" between the View and the Presenter, allowing the Presenter to be agnostic of the guts of the View. In theory if you wanted to add a WPF client for this application, you would not need to touch the Model or the Presenter or your unit tests - you would just implement a WPF view that adhered to the same interface.&lt;/p&gt;
&lt;p&gt;It may look like much more code, but note that it's just a couple of tiny classes per page; this overhead is fixed and doesn't grow with the complexity of your ASPX page.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unit Testing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because you've made your view "dumb" (it mostly just databinds), all your business logic exists in the Presenter and Model, meaning that you probably don't need to test the View. In order to test the Presenter, all you need to do is pass it a mocked up implementation of the interface that it asks for. So:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a mock that implements the interface (&lt;a title="Rhino-mocks - a very nice, simple mocking framework" href="http://ayende.com/projects/rhino-mocks.aspx"&gt;example&lt;/a&gt;). 
&lt;li&gt;Pass that into a new Presenter. 
&lt;li&gt;Run the Presenter methods. 
&lt;li&gt;Check the properties of the mocked object to see that the Presenter set them correctly.&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about MVC?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As &lt;a href="http://weblogs.asp.net/scottgu/"&gt;Scott Guthrie&lt;/a&gt; has mentioned, MVC is not &lt;em&gt;the&lt;/em&gt; new recommended method of building ASP.NET apps; it's just &lt;em&gt;another&lt;/em&gt; method. I love the simplicity of the MVC framework, but my team has invested in server controls that are incompatible with it, making it too costly to move to at this point.&lt;/p&gt;
&lt;p&gt;MVP gives us similar benefits (testability), without the cost of re-wiring our controls, and with pretty much no learning curve.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft's &lt;a href="http://code.msdn.microsoft.com/websf"&gt;Web Client Software Factory&lt;/a&gt; gives you templates for project creation which implement this pattern for ASP.NET. 
&lt;li&gt;If you want a comprehensive comparison and history of MVC, MVP and related patterns, see &lt;a href="http://ctrl-shift-b.blogspot.com/2007/08/interactive-application-architecture.html"&gt;this article&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Avi&lt;/p&gt;
&lt;p&gt;&lt;!-- AddThis Button BEGIN --&gt;
&lt;a href="http://www.addthis.com/bookmark.php" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;pub=avip&amp;url='+encodeURIComponent(location.href)+'&amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" title="Bookmark and Share" target="_blank"&gt;&lt;img src="http://s9.addthis.com/button1-share.gif" wid&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8806555" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category><category domain="http://blogs.msdn.com/avip/archive/tags/mvp/default.aspx">mvp</category><category domain="http://blogs.msdn.com/avip/archive/tags/asp.net/default.aspx">asp.net</category></item><item><title>It's all just a clock measuring contest...</title><link>http://blogs.msdn.com/avip/archive/2008/07/04/it-s-all-just-a-clock-measuring-contest.aspx</link><pubDate>Fri, 04 Jul 2008 01:13:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8685835</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/avip/comments/8685835.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=8685835</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=8685835</wfw:comment><description>&lt;p&gt;Did you know that &lt;a href="http://groups.google.com/group/comp.lang.lisp/browse_frm/thread/25fb220a1da975fb#"&gt;SBCL is now faster than Java, as fast as Ocaml, and getting better&lt;/a&gt;?! What does this mean for you? Most likely, nothing.&lt;/p&gt; &lt;p&gt;They have &lt;a href="http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&amp;amp;lang=all"&gt;various benchmarks&lt;/a&gt; that are used to measure the speed of a language implementation; and I think it's a good thing - it keeps the &lt;em&gt;implementers &lt;/em&gt;honest, and I'm not crazy about wasting CPU cycles just because they're there.&lt;/p&gt; &lt;p&gt;However, these numbers remind me very strongly of the local CompuMart selling the 2.4GHz machine for 1.5x the price of the 2.0GHz machine and relying on the fact that customers have no idea that this will make exactly zero difference for most uses.&lt;/p&gt; &lt;p&gt;Why? Because pretty much all programs nowadays depend on more than just the CPU. They're competing for RAM, disk access and maybe even network. None of those are nearly as fast as the CPU, hence most often create a bottleneck.&lt;/p&gt; &lt;p&gt;Aside from this, it's very likely that the code you're writing will be more dramatically improved by tweaking &lt;em&gt;your&lt;/em&gt; algorithms than it would by changing the language.&lt;/p&gt; &lt;p&gt;Couple that with the unfortunate fact that most jobs won't allow you to just grab SBCL or OCaml because it happens to be at the top of the list today, and you're left with a measurement that has little real-world value.&lt;/p&gt; &lt;p&gt;What these measurements &lt;em&gt;are &lt;/em&gt;good for is preventing those who write the language implementations from getting too lazy. While I think that application programmers &lt;em&gt;should &lt;/em&gt;generally be spending CPU cycles to save lines of code, I don't necessarily believe the same for platform/language programmers.&lt;/p&gt; &lt;p&gt;Just don't look at this list and get too disheartened about your choice of language. Even if it &lt;em&gt;is &lt;/em&gt;Ruby ;)&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Avi&lt;/p&gt; &lt;p&gt;&lt;!-- AddThis Button BEGIN --&gt;
&lt;a href="http://www.addthis.com/bookmark.php" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;pub=avip&amp;url='+encodeURIComponent(location.href)+'&amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" title="Bookmark and Share" target="_blank"&gt;&lt;img src="http://s9.addthis.com/button1-share.gif" wid&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8685835" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category><category domain="http://blogs.msdn.com/avip/archive/tags/programming/default.aspx">programming</category></item><item><title>Can Software be Reliable?</title><link>http://blogs.msdn.com/avip/archive/2008/06/27/can-software-be-reliable.aspx</link><pubDate>Fri, 27 Jun 2008 09:21:29 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8660252</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/avip/comments/8660252.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=8660252</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=8660252</wfw:comment><description>&lt;p&gt;Just read &lt;a href="http://metaphorcrash.blogspot.com/"&gt;a post&lt;/a&gt; (permalink is broken) regarding how software engineering is nowhere near the level of quality as traditional engineering, partially because we don't have standards, regulations, etc.&lt;/p&gt; &lt;p&gt;While I agree with some of the argument, people often give too much credit to &lt;a href="http://en.wikipedia.org/wiki/Meatspace"&gt;meatspace&lt;/a&gt; engineering when compared to software.&lt;/p&gt; &lt;p&gt;You often get what you pay for, and this applies to both types of engineering. Look at &lt;a href="http://www.fastcompany.com/node/28121/print"&gt;NASA's software engineering team&lt;/a&gt; (&lt;em&gt;awesome&lt;/em&gt; article). Two quotes from there:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;"The last three versions of the program - each 420,000 lines long - had just one error each. The last 11 versions of this software had a total of 17 errors. Commercial programs of equivalent complexity would have 5,000 errors."&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;"...the group's $35 million per year budget is a trivial slice of the NASA pie, but on a dollars-per-line basis, it makes the group among the nation's most expensive software organizations."&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Similarly, there's other very reliable software running very reliable systems (nuclear reactors, chemical factories, fighter jets, stock markets, whatever). Basically, when you're prepared to pay for software quality, you &lt;em&gt;can get it&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;Viewing things from the opposite direction; while it's true that none of my cars have ever spontaneously combusted on the highway, neither have any of them been bug free. There are always rattles, electrical problems, mechanical problems, and they all need constant maintenance - I can't treat my car recklessly and expect it to behave well forever. Just like with software, environmental changes can bring out defects in the original design. Bridges need constant maintenance, cracks form in buildings, roofs leak, gutters rust, foundations sink, water rises, dishwashers break (taking down my whole circuit) and light bulbs fry themselves.&lt;/p&gt; &lt;p&gt;Most of these things can be avoided with the judicious application of more resources (read: money [=time]). It just happens that most software companies get a better return on investment spending that money on new features/products than they do on aiming for &lt;a href="http://en.wikipedia.org/wiki/Five_nines"&gt;five nines&lt;/a&gt;. Why? Because that's generally what customers respond to. What would you prefer - an iPhone with Safari occasionally crashing, or that small Ericsson from 1997 that never &lt;em&gt;ever&lt;/em&gt; crashed?.&lt;/p&gt; &lt;p&gt;Sometimes it makes sense to spend a fortune to get that extra 1% (10%?) of quality, but each percent costs more than the last. I certainly want that last percent on bridges, airplanes and skyscrapers. But if I had to pay 3x the price for my video card (or phone, or DVD player) and wait 3x as long for new versions, I don't think it would be worth it.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Avi&lt;/p&gt; &lt;p&gt;&lt;!-- AddThis Button BEGIN --&gt;
&lt;a href="http://www.addthis.com/bookmark.php" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;pub=avip&amp;url='+encodeURIComponent(location.href)+'&amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" title="Bookmark and Share" target="_blank"&gt;&lt;img src="http://s9.addthis.com/button1-share.gif" wid&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8660252" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category><category domain="http://blogs.msdn.com/avip/archive/tags/programming/default.aspx">programming</category></item><item><title>On Writing Safer APIs</title><link>http://blogs.msdn.com/avip/archive/2008/06/19/on-writing-safer-apis.aspx</link><pubDate>Thu, 19 Jun 2008 05:08:57 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8619813</guid><dc:creator>Avi Pilosof</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/avip/comments/8619813.aspx</comments><wfw:commentRss>http://blogs.msdn.com/avip/commentrss.aspx?PostID=8619813</wfw:commentRss><wfw:comment>http://blogs.msdn.com/avip/rsscomments.aspx?PostID=8619813</wfw:comment><description>&lt;p&gt;Our team owns lots of smallish applications; all of them have a DB layer, an OM/API layer, logic and UI layers. What happens over time is that we have different people working on the same apps, switching between them over the course of time.&lt;/p&gt; &lt;p&gt;This is great for cross-training, for support, for finding missed bugs, for preventing boredom-induced suicides, etc. However, the price you pay is losing that intense expert focus that someone gets from living+breathing a single app for years. That can lead to a few more bugs.&lt;/p&gt; &lt;p&gt;I've noticed that at the core of many of these bugs is the OM/API layer, and I wanted to summarize some issues I've seen and some suggested fixes. I'd also love to hear any other pointers you guys have.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;&lt;u&gt;Problem 1: Database call abuse.&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;We take great pride in squeezing the most out of our database servers. One of the primary ways to do this is to hand-code your DB access via sprocs and ensure that they return multiple result sets where possible. So for example, if I know that the main build status page needs to show builds &lt;em&gt;and &lt;/em&gt;their comments &lt;em&gt;and &lt;/em&gt;their last 15 status events, then I'll make sure that one sproc call returns &lt;em&gt;all &lt;/em&gt;of those for &lt;em&gt;all &lt;/em&gt;the builds - optimize for reducing the number of DB round trips. BTW, you can do this with LINQ-to-SQL.&lt;/p&gt; &lt;p&gt;However, this generally conflicts with writing a "neat" OM which performs simple concise tasks; and is often people's &lt;a title="(I disagree with this guy, FWIW. There are ways to cater for this in good ORMs)" href="http://database-programmer.blogspot.com/2008/06/why-i-do-not-use-orm.html"&gt;resistance to using ORMs&lt;/a&gt;. You need to learn how to balance the two.&lt;/p&gt; &lt;p&gt;Invariably, you'll eventually realize that some page is relying on some call which relies on a deep OM call which makes a sproc call. But that parent page makes the call 300 times; one for each item... Ouch.&lt;/p&gt; &lt;p&gt;Some solutions:&lt;/p&gt; &lt;p&gt;&lt;strong&gt;ABP: Always Be Profiling&lt;/strong&gt;. This simple and brilliant idea comes courtesy of my teammates &lt;a href="http://blogs.msdn.com/jasonward/"&gt;Jason&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/karthik/"&gt;Karthik&lt;/a&gt;. Basically, as you're fixing bugs on an app, have the SQL Profiler running on your 2nd monitor and watch out for crazy spikes in traffic coming from your app.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;: When possible/applicable, cache the results of your DB calls at the lowest level that makes sense. You can cache for the whole lifetime of the app, for the session, for the context, or using a custom caching policy with the caching object. The point is; ask yourself whether you really need to read that stuff from the DB.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Commenting&lt;/strong&gt;: One of my favourite VS features is that the "/// &amp;lt;summary&amp;gt;" comments show up as intellisense hints. This means that as your API consumer (your team-mate!) is using the method call, they get free documentation. So, if the method being called doesn't cache, call it out. It'll cost you 20 seconds:&lt;/p&gt; &lt;div&gt; &lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// Get the comments for a build.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// NO CACHING - this always makes a DB call.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   4:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;u&gt;Problem 2: Units of measurement&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This might seem obvious/stupid, but I bet it happens to &lt;a title="NASA's metric confusion caused Mars orbiter loss" href="http://www.cnn.com/TECH/space/9909/30/mars.metric/"&gt;the best of us&lt;/a&gt;. Take a look at this call:&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; BuildSize = build.Size;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;"Size", eh? Bytes? Megabytes? Gigabytes?&lt;/p&gt;
&lt;p&gt;Some solutions:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Naming&lt;/strong&gt;: If you suffix your properties/methods with the units they return, this is unlikely to happen. &lt;em&gt;SizeInBytes&lt;/em&gt;, &lt;em&gt;SizeInGB&lt;/em&gt;, etc. Really cheap.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Typing&lt;/strong&gt;: Rather than &lt;em&gt;Size&lt;/em&gt; being of type &lt;em&gt;int&lt;/em&gt;, have it be of type "Gigabyte", which you can create yourself. The type system will then ensure you don't make silly mistakes. This can be a little more costly if you do it pervasively, but it's quite powerful and allows for centralizing your unit conversions (are there 1000 MB in a GB, or 1024?).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Commenting&lt;/strong&gt;: Again with the summary comments. Check it out:&lt;/p&gt;
&lt;div&gt;
&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   2:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// Get the size of the build, in BYTES.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #606060"&gt;   3:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;So cheap.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;u&gt;Problem 3: Discoverability&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I'm new to this application and I want to find the size of the build. My instinct is to look for &lt;em&gt;build.Size&lt;/em&gt; (sorry, &lt;em&gt;SizeInGB&lt;/em&gt;! :)), but I don't see it. So I go off and write it, to later find out that there already was a &lt;em&gt;build.GetSize()&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Some suggestions:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Properties vs. Methods&lt;/strong&gt;: Some people would deliberately use the &lt;em&gt;GetSize()&lt;/em&gt; method rather than the &lt;em&gt;Size&lt;/em&gt; property if determining the size required some "work" (DB call, expensive calc), to indicate to the caller not to take this call too lightly. Personally, I think it's confusing. I think that if something is a logical property, then it should be declared as a property; methods are for "doing stuff"; although sometimes that's a gray area. Whatever you choose, ensure that you're consistent across your app(s) when doing this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Smaller classes&lt;/strong&gt;: Often easier said than done, but a class with 30-40 methods and 20 properties is going to have discoverability problems, not to mention other issues. Break it up into smaller classes or helper classes where possible. &lt;a title="Refactoring: Improving the Design of Existing Code, by Martin Fowler" href="http://www.amazon.com/Refactoring-Improving-Existing-Addison-Wesley-Technology/dp/0201485672/ref=sr_11_1?ie=UTF8&amp;amp;qid=1213840370&amp;amp;sr=11-1"&gt;Read this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Design the API&lt;/strong&gt;: Often, the API just "happens" as a result of writing the application; don't pretend you haven't done it! I think that designing the API up front with a view to having it used by other people makes for a much better, more well rounded API that has more discoverable avenues for success and needs less documentation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pretty files&lt;/strong&gt;: This goes in the "Commenting" bucket. Use regions to separate your class file into logical parts. Put all the properties together in one place; put all related methods close to each other. Ensure that methods are named similarly when they do similar things.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If there are suggestions for other solutions (or other problems), please contribute; I've got lots to learn.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Avi&lt;/p&gt;
&lt;p&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;script type="text/javascript" src="http://www.reddit.com/button.js?t=1"&gt;&lt;/script&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;script type="text/javascript"&gt;
digg_skin = 'compact';
&lt;/script&gt;
&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8619813" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/avip/archive/tags/api/default.aspx">api</category><category domain="http://blogs.msdn.com/avip/archive/tags/architecture/default.aspx">architecture</category></item></channel></rss>