<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Scott Lilly - Agile .Net Developer</title>
	<atom:link href="http://www.scottlilly.com/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.scottlilly.com</link>
	<description>My adventures in writing .Net software</description>
	<lastBuildDate>Mon, 31 May 2010 18:01:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>My PGP public key</title>
		<link>http://www.scottlilly.com/?p=54</link>
		<comments>http://www.scottlilly.com/?p=54#comments</comments>
		<pubDate>Mon, 31 May 2010 18:01:45 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=54</guid>
		<description><![CDATA[&#8212;&#8211;BEGIN PGP PUBLIC KEY BLOCK&#8212;&#8211;
Version: PGP Desktop 10.0.2 (Build 13)
mQENBEvohxQBCADnBH+Dc3OMgTfH7zbZt4ycDujXrtFwyQvMaOoceRs4Zdv31cl7
ikxOjABH9uPqMlh+UWDEy85+cXVfeDQGLLIeLFW+V2dbegWBAoAIzZL7yuzlaEcD
kyKsSNVMlQtZbhHiX1RfnGWB65xiENJUhB7l/BB0UXHKXgFZRyA7Hxp41hpFFkHC
48BPenjnBVt4TZXF9oVJObaHj2oZm8KKDS9Ms1maw0s5oAnLGdKgtL3xe3Gq8wr1
GlDf8v2RsCwIkPh8lMC2X3Ogt77IivjeVdwQzGWDZ0qeuAYsbXNPx8tZpiNnLLOA
T1iFkaECX0HJEAxnoRe4btOhM5yO9Ry6VBS5ABEBAAG0J1Njb3R0IExpbGx5IDxz
Y290dGxpbGx5QHNjb3R0bGlsbHkuY29tPokBjAQQAQIAdgUCS+iHIDAUgAAAAAAg
AAdwcmVmZXJyZWQtZW1haWwtZW5jb2RpbmdAcGdwLmNvbXBncG1pbWUICwkIBwMC
CgECGQEZGGxkYXA6Ly9rZXlzZXJ2ZXIucGdwLmNvbQUbAwAAAAUWAAMCAQUeAQAA
AAYVCAkKAgMACgkQxLPmtSm8A4io/gf/eNQXblQzPzdbccPSZyE4OAjXb6OMIW8V
JM0FUGptPnLT3ugzixpg97Cj1UYriGDlonh4btA5KFaae/gUONBVvafMkpAPW94H
x6ZAhxRReiOzRCNf7wzlx+RtOPPZcaAzmOI4pqzXFGna+F9YZGml/+uhWL4jWE/a
Xmx6FKWp2PWmWaP7f/fgXfa/vnKqHRdkRdR44LGb6wZzQTA1KV2ZVDZlEIFQmCrt
nG9LxCjOM71zPGend3l/qisoRhHq2T/r1CEFTO1UG0GDkUJLB0ylld8o+QQ3uxMb
TVPfKyuxEhSg8zKlZWQBAKGktIua9sUTs4JlNqiyh+mjCo7se///p7kBDQRL6IcV
AQgAwUfQ7anaxItW4gB6cVasgbAohdOMNdubgnWtQxjD8tqNXyQMwUn30NqraJY7
5/hGybyKhTIuq1zwNnrDsZGZKmrpKhii927RCmfSiI/nnbY61OkWueKTclAwyZjJ
no8HqaU9F9btJBjyfiLL6hthFa89eWdktyVLPTcSlghQanOOBghFT5Px41yI/BWY
BrJ8UHo45MFeyjgX8QKQ2HcFadRx4y5/MLY7rZFKzqRDBrB0u/hD/ieRuWNn/YmC
OvueZDykYKNitmiP4vmEsDsAwhOG/RUVzPBmioX6AoxbirrjnoqtxLkQOTURw8RM
8IoVuqRAwczr/K7xxC1LJQkAMQARAQABiQJBBBgBAgErBQJL6IcWBRsMAAAAwF0g
BBkBCAAGBQJL6IcVAAoJEDU9m/W0tx+k7DgH/A9Qt9Cb98ZpFfhBMplaHOyTUNxN
2DG9Znxpx9l9IpNyaRRGnxbL8KG+MT79DYP4iQFEMSCA4KMs4QA12CRDqFrtu5Hs
D71A7GES/sSkLurPdYy+KulWSudFcZb5PNaZmw3fpEZWrsDAf7qbkhinGkYsNsj1
rkyCAojuIVsiqe7HywnH4X9BE7zWLZAxWTLdJ4jLhwSkFmBkJ+TOpuNyVMPB3hag
53vYP+dhJe9YMWGDdTSTUjVtA5CHqgsPCByQQRDjwgN8rfySrpHQwWmNbEmYtEYX
60hbuR4FPLBZdHw8LNZpiphfhiC6p15/NZmUNim2UEg31jjoV06E8L6zOcwACgkQ
xLPmtSm8A4iUmggAmnjy0gv2CnmcpnUISsPB9NK94C9FMAMspK+2Ad5Q3jT+YZ0Q
pjjkBNIYzYUsz7wvUx80i25g2NkWQ+Fh9QD/hSX/gF8drJS9ixU+kHiXEUMpnQZ7
yyFGWIfWOQUQ410G01IKcmIeprPFUdFTLITTEOBkQ9anMvaIWx+yUY5t+BSO0yNB
CMki/vl0zxgmRhp5f7KIKEV+wYY6LVfiHD4DiDQW3Qjcb+H43v6q/uLBth/re+xk
iLXKuCULV2965nr8CWWKZz38ZEjXE5T0dUrYkSLUW1thpb2FytdTLv5+fZ0IkWVq
8NODBoMqrQFao6b+0bsPYrTG5LHPuMpE6B8Kqg==
=tt0w
&#8212;&#8211;END PGP PUBLIC KEY BLOCK&#8212;&#8211;
]]></description>
			<content:encoded><![CDATA[<p>&#8212;&#8211;BEGIN PGP PUBLIC KEY BLOCK&#8212;&#8211;<br />
Version: PGP Desktop 10.0.2 (Build 13)</p>
<p>mQENBEvohxQBCADnBH+Dc3OMgTfH7zbZt4ycDujXrtFwyQvMaOoceRs4Zdv31cl7<br />
ikxOjABH9uPqMlh+UWDEy85+cXVfeDQGLLIeLFW+V2dbegWBAoAIzZL7yuzlaEcD<br />
kyKsSNVMlQtZbhHiX1RfnGWB65xiENJUhB7l/BB0UXHKXgFZRyA7Hxp41hpFFkHC<br />
48BPenjnBVt4TZXF9oVJObaHj2oZm8KKDS9Ms1maw0s5oAnLGdKgtL3xe3Gq8wr1<br />
GlDf8v2RsCwIkPh8lMC2X3Ogt77IivjeVdwQzGWDZ0qeuAYsbXNPx8tZpiNnLLOA<br />
T1iFkaECX0HJEAxnoRe4btOhM5yO9Ry6VBS5ABEBAAG0J1Njb3R0IExpbGx5IDxz<br />
Y290dGxpbGx5QHNjb3R0bGlsbHkuY29tPokBjAQQAQIAdgUCS+iHIDAUgAAAAAAg<br />
AAdwcmVmZXJyZWQtZW1haWwtZW5jb2RpbmdAcGdwLmNvbXBncG1pbWUICwkIBwMC<br />
CgECGQEZGGxkYXA6Ly9rZXlzZXJ2ZXIucGdwLmNvbQUbAwAAAAUWAAMCAQUeAQAA<br />
AAYVCAkKAgMACgkQxLPmtSm8A4io/gf/eNQXblQzPzdbccPSZyE4OAjXb6OMIW8V<br />
JM0FUGptPnLT3ugzixpg97Cj1UYriGDlonh4btA5KFaae/gUONBVvafMkpAPW94H<br />
x6ZAhxRReiOzRCNf7wzlx+RtOPPZcaAzmOI4pqzXFGna+F9YZGml/+uhWL4jWE/a<br />
Xmx6FKWp2PWmWaP7f/fgXfa/vnKqHRdkRdR44LGb6wZzQTA1KV2ZVDZlEIFQmCrt<br />
nG9LxCjOM71zPGend3l/qisoRhHq2T/r1CEFTO1UG0GDkUJLB0ylld8o+QQ3uxMb<br />
TVPfKyuxEhSg8zKlZWQBAKGktIua9sUTs4JlNqiyh+mjCo7se///p7kBDQRL6IcV<br />
AQgAwUfQ7anaxItW4gB6cVasgbAohdOMNdubgnWtQxjD8tqNXyQMwUn30NqraJY7<br />
5/hGybyKhTIuq1zwNnrDsZGZKmrpKhii927RCmfSiI/nnbY61OkWueKTclAwyZjJ<br />
no8HqaU9F9btJBjyfiLL6hthFa89eWdktyVLPTcSlghQanOOBghFT5Px41yI/BWY<br />
BrJ8UHo45MFeyjgX8QKQ2HcFadRx4y5/MLY7rZFKzqRDBrB0u/hD/ieRuWNn/YmC<br />
OvueZDykYKNitmiP4vmEsDsAwhOG/RUVzPBmioX6AoxbirrjnoqtxLkQOTURw8RM<br />
8IoVuqRAwczr/K7xxC1LJQkAMQARAQABiQJBBBgBAgErBQJL6IcWBRsMAAAAwF0g<br />
BBkBCAAGBQJL6IcVAAoJEDU9m/W0tx+k7DgH/A9Qt9Cb98ZpFfhBMplaHOyTUNxN<br />
2DG9Znxpx9l9IpNyaRRGnxbL8KG+MT79DYP4iQFEMSCA4KMs4QA12CRDqFrtu5Hs<br />
D71A7GES/sSkLurPdYy+KulWSudFcZb5PNaZmw3fpEZWrsDAf7qbkhinGkYsNsj1<br />
rkyCAojuIVsiqe7HywnH4X9BE7zWLZAxWTLdJ4jLhwSkFmBkJ+TOpuNyVMPB3hag<br />
53vYP+dhJe9YMWGDdTSTUjVtA5CHqgsPCByQQRDjwgN8rfySrpHQwWmNbEmYtEYX<br />
60hbuR4FPLBZdHw8LNZpiphfhiC6p15/NZmUNim2UEg31jjoV06E8L6zOcwACgkQ<br />
xLPmtSm8A4iUmggAmnjy0gv2CnmcpnUISsPB9NK94C9FMAMspK+2Ad5Q3jT+YZ0Q<br />
pjjkBNIYzYUsz7wvUx80i25g2NkWQ+Fh9QD/hSX/gF8drJS9ixU+kHiXEUMpnQZ7<br />
yyFGWIfWOQUQ410G01IKcmIeprPFUdFTLITTEOBkQ9anMvaIWx+yUY5t+BSO0yNB<br />
CMki/vl0zxgmRhp5f7KIKEV+wYY6LVfiHD4DiDQW3Qjcb+H43v6q/uLBth/re+xk<br />
iLXKuCULV2965nr8CWWKZz38ZEjXE5T0dUrYkSLUW1thpb2FytdTLv5+fZ0IkWVq<br />
8NODBoMqrQFao6b+0bsPYrTG5LHPuMpE6B8Kqg==<br />
=tt0w<br />
&#8212;&#8211;END PGP PUBLIC KEY BLOCK&#8212;&#8211;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=54</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I&#8217;m writing a caveman web game at ShinyRockHunter.com</title>
		<link>http://www.scottlilly.com/?p=50</link>
		<comments>http://www.scottlilly.com/?p=50#comments</comments>
		<pubDate>Sat, 26 Sep 2009 23:21:45 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=50</guid>
		<description><![CDATA[I haven&#8217;t been posting here because I&#8217;ve been working on a side project for a while.  It&#8217;s a free web game where you get to be a caveman.  The game is at www.shinyrockhunter.com.  You can also read about the development progress at http://blog.shinyrockhunter.com.
One cool thing that I recently installed  there is a feedback system [...]]]></description>
			<content:encoded><![CDATA[<p>I haven&#8217;t been posting here because I&#8217;ve been working on a side project for a while.  It&#8217;s a free web game where you get to be a caveman.  The game is at <a href="http://www.shinyrockhunter.com" target="_blank">www.shinyrockhunter.com</a>.  You can also read about the development progress at <a href="http://blog.shinyrockhunter.com" target="_blank">http://blog.shinyrockhunter.com</a>.</p>
<p>One cool thing that I recently installed  there is a feedback system from <a href="http://www.uservoice.com" target="_blank">www.uservoice.com</a>.  It&#8217;s a simple piece of JavaScript to add to your pages, which lets users submit suggestions, vote on them (so you can prioritize them, and even have a forum to discuss them.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=50</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Framework Foundations (what&#8217;s going into each assembly)</title>
		<link>http://www.scottlilly.com/?p=41</link>
		<comments>http://www.scottlilly.com/?p=41#comments</comments>
		<pubDate>Sun, 17 May 2009 20:10:59 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Enterprise Architecture]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=41</guid>
		<description><![CDATA[One of the important aspects of the framework is that it should be highly re-usable.  In order to make it re-usable, I&#8217;m building it with many small, independent (for the most part) projects.  Those small projects will eventually be used to make the more complex projects.
Think of this like cooking.  Let&#8217;s say that our framework [...]]]></description>
			<content:encoded><![CDATA[<p>One of the important aspects of the framework is that it should be highly re-usable.  In order to make it re-usable, I&#8217;m building it with many small, independent (for the most part) projects.  Those small projects will eventually be used to make the more complex projects.</p>
<p>Think of this like cooking.  Let&#8217;s say that our framework provides potatoes to chefs.  Without the framework, each chef  needs to get their potatotoes, peel them, slice them up into the shape needed for the recipe, and cook them.  If we build something that provides us with peeled potatoes, that saves time for 95% of our recipes.  However, if we build something only provides peeled and diced potatoes, that&#8217;s not going to help the chef who needs sliced potatoes.  If our &#8220;cooking framework&#8221; only provided us with peeled, diced, roasted potatoes, it would be a great time-saver for 5% of the recipes, but useless for the remaining 95% of them.  So, I&#8217;m starting out the framework to do the simplest, most common tasks.</p>
<p>In the applications at work, one of the most common tasks is to get a list of jobs from the database.  I expect that most programs have their own code to access the database and get this list of jobs.  With all those different versions, we end up with several problems.</p>
<ul>
<li>- The code for each versions may not be optimized (the query being used, handling of disposable objects, caching, etc.)</li>
<li>- If we ever need to change the database (or it&#8217;s structure), we need modify each program.</li>
<li>- If we want to improve performance with caching, we end up with one cache per program (not as efficient as a common cache).</li>
<li>- Each programmer had to spend time writing, testing, and debugging their version of the function.</li>
</ul>
<p>So, this will be the first thing I&#8217;ll add to the framework.</p>
<p>I created two projects: ABCD.BusinessObjects and ABCD.Persistence (&#8221;ABCD&#8221; will be the fake acronym I use for our real division).</p>
<p>The ABCD.BusinessObjects project will be used in almost every project.  This contains classes like the Job object.  I&#8217;m building these classes using the Data Mapper design pattern.  I don&#8217;t want to use the Active Record design pattern, where the record contains methods to create, read, update, and delete that object from the database.  All the database access code is going into the ABCD.Persistence project.  My feeling is that the Active Record pattern produces objects that don&#8217;t pass the &#8220;Single Responsibility&#8221; aspect of the SOLID principles.  These classes are currently fairly simple, containing mostly get/sets for the properies.</p>
<p>All the business objects inherit from a BaseBusinessObject class.  The only thing in that class is a getter for a virtual boolean property named &#8220;IsValid&#8221;.  It currently returns &#8220;true&#8221; in the base class.  By overriding this method in the derived classes, we can have all the validation rules stored along with the class.  Even though the base class doesn&#8217;t do anything yet, I put it in place to provide me with a point of flexibility in the code.  If we need to add in something that applies to all classes later on, we already have a place to put it.  If we don&#8217;t, even though this class violates the YAGNI principle, it isn&#8217;t a burden on us for performance or developer understanding.</p>
<p>The only thing in this project (other than more business objects) is a class to hold enums used by the business objects.  It&#8217;s a public static class named ABCDEnums.  I&#8217;m a fan of using enums for the datatypes of properties.  I&#8217;ve run into too many situations where a boolean property suddenly needs to store a third value.  I believe that FxCop (Microsoft&#8217;s code quality tool) even mentions that you should have an &#8220;Unknown&#8221; or other default value available with each enum.  The reason I&#8217;ve added this enums class is because it makes the enums very visible through Intellisense.  If I can&#8217;t remember the exact enum name, all I have to do is type &#8220;ABCDEnums.&#8221; and they will all appear.  That&#8217;s also the reason why I&#8217;m naming all the namespaces with ABCD.whatever.  When I&#8217;m adding in my &#8220;using&#8221; statements at the top of the class, I quickly get to the point where Intellisense starts showing the available namespaces.  That&#8217;s much easier than trying to remember the exact spelling and upper-casing of some long namespace like &#8220;BusinessObjectsForEAISystem&#8221;.  Although, a tool like ReSharper would be even better (IIRC how it worked during the 30-day trial of it).</p>
<p>My next post will be on the ABCD.Persistence project.  I&#8217;ve been going back and forth on a couple of ways of building it, and I expect I&#8217;ll have that finalized soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=41</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>You got your procedure in my object!</title>
		<link>http://www.scottlilly.com/?p=39</link>
		<comments>http://www.scottlilly.com/?p=39#comments</comments>
		<pubDate>Fri, 08 May 2009 17:22:27 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=39</guid>
		<description><![CDATA[There used to be a television commercial for some candy that had chocolate and peanut butter.  In it, there would be one person walking around with an open jar of peanut butter and another walking around with a chocolate bar.  They would bump into each other and the chocolate would end up in the peanut [...]]]></description>
			<content:encoded><![CDATA[<p>There used to be a television commercial for some candy that had chocolate and peanut butter.  In it, there would be one person walking around with an open jar of peanut butter and another walking around with a chocolate bar.  They would bump into each other and the chocolate would end up in the peanut butter.  The peanut butter owner would exclaim, &#8220;You got your chocolate in my peanut butter!&#8221;  While the chocolate bar owner would shout, &#8220;You got your peanut butter on my chocolate!&#8221;  They&#8217;d both try this new concoction, declare it an amazing snack, and all of us viewing would go out to buy the candy.</p>
<p>What does all this have to do with programming?  While thinking about how to develop a good framework for the suite of apps I work with, I&#8217;ve been looking at what I&#8217;ve seen that works and what doesn&#8217;t work.  One thing that I see a lot of is procedural code written in object-oriented languages.  We&#8217;ve all seen (and probably created) classes with a method that is hundreds, if not thousands, of lines long.  You got you procedure in my object!  But I think the opposite problem can also occur.  When working towards an &#8220;ideal&#8221; application, you can try forcing procedural processes into objects, handling them with massive event raising or forcing them into place with an implementation of the Chain of Responsibility pattern.  You got your object in my procedure!</p>
<p>One of my thoughts when creating this framework is to have objects (Customers, Jobs, etc.) represented by objects, and have processes handled in procedural methods.  I&#8217;ll still be following the <a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod" target="_blank">SOLID principles</a>, especially Single Responsibility and Dependency Inversion.  However, I won&#8217;t be forcing things to use styles that don&#8217;t seem to be appropriate.  My next post will go into some detail of how (and why) I&#8217;ve set up the projects for the framework.</p>
<p>BTW, as I started writing this, a friend of mine sent me an e-mail with a link to a funny history of computer languages, complete with a reference to the chocolate/peanut butter commercial.  Check out this <a href="http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html" target="_blank">Brief, Incomplete, and Mostly Wrong History of Programming Languages</a> for a laugh.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=39</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Back to Posting</title>
		<link>http://www.scottlilly.com/?p=36</link>
		<comments>http://www.scottlilly.com/?p=36#comments</comments>
		<pubDate>Thu, 07 May 2009 02:52:29 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=36</guid>
		<description><![CDATA[It&#8217;s been quite a while since I last posted, but I&#8217;ve been keeping extremely busy.  Since my last post, I started a new job, in a new industry, writing a [mostly] new to me type of application. Add in moving and all the other things that life entails, and it&#8217;s been hectic.  But sanity is [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been quite a while since I last posted, but I&#8217;ve been keeping extremely busy.  Since my last post, I started a new job, in a new industry, writing a [mostly] new to me type of application. Add in moving and all the other things that life entails, and it&#8217;s been hectic.  But sanity is slowly starting to return.</p>
<p>The job I&#8217;m at now is full-time, heads-down development.  However, it&#8217;s Windows Forms applications instead of the web services, Windows services, and back-end business processing that I&#8217;ve been doing for most of the last several years.  I finally get to spend my days writing programs that users can actually see!  After years of staring at XML all day, it&#8217;s cool to work on something that shows graphs of data &#8230; in different colors, even.  Without going into more detail than my boss probably wants me to, the programming team I&#8217;m working on produces a suite of dozens of individual applications that all go against the same database.  &#8220;My&#8221; application parses files in numerous formats, displaying the data in graphs and reports.  It also needs to send the parsed data to the database and be able to output it in a couple of other formats.</p>
<p>My current focus (and what I&#8217;ll be posting about) is building a high-performance framework that can be used by all the applications in our suite.  I&#8217;m not building the framework from an ivory tower.  Instead, I&#8217;m writing a stripped-down version of the application I work on, and building it in a way that will make it highly re-usable and improve the performance.  At work, there&#8217;s a definite C++ bias for anything that needs to be high-performance, but I think I can do just as well in plain-old C# (plus avoid the overhead of COM interop or P/Invoke).  So, whenever I build part of the framework, I write a mini-load test app to see how well it works.  I&#8217;ll eventually start doing some more serious profiling of the throughput, CPU load, and memory usage.</p>
<p>Another thing on my research list is F#.  In order to get a further performance boost, I&#8217;ll also be looking at using F# to create code to take advantage of multi-core processors.  I haven&#8217;t even written a Hello World program in F# yet, but what I&#8217;ve been reading about it has impacted how I&#8217;m writing code.  I&#8217;m focusing more on separating my &#8220;state&#8221; from my &#8220;process&#8221;.  I&#8217;ve noticed that I&#8217;m starting to write more static methods, which isn&#8217;t helping with testability.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=36</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GridViewCommandEventArgs.CommandName problem in Visual Studio.Net Cassini</title>
		<link>http://www.scottlilly.com/?p=35</link>
		<comments>http://www.scottlilly.com/?p=35#comments</comments>
		<pubDate>Mon, 04 Aug 2008 15:04:30 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=35</guid>
		<description><![CDATA[I ran into an extremely frustrating problem with GridViewCommandEventArgs.CommandName this weekend.
While working with the OnRowCommand event on a GridView object in ASP.Net, the code in my code-behind page was not doing what it should have for the asp:ButtonField that I had in the grid.  So, I set a breakpoint and watched what was happening.  When the [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into an extremely frustrating problem with GridViewCommandEventArgs.CommandName this weekend.</p>
<p>While working with the OnRowCommand event on a GridView object in ASP.Net, the code in my code-behind page was not doing what it should have for the asp:ButtonField that I had in the grid.  So, I set a breakpoint and watched what was happening.  When the code got to the line &#8220;if ( e.CommandName == &#8220;RaiseStoryInPriority&#8221; )&#8221;, it never executed the code within the &#8220;if&#8221; statement, even though hovering over &#8220;e.CommandName&#8221; showed that the value was equal.  After trying several different things (and beating my head against the wall for far too long) I tried running the code through IIS, instead of the Cassini web server that runs your code when you press F5 in Visual Studio.Net.  The code worked perfectly in IIS.</p>
<p>I also ran into a different problem with Cassini a while back.  I was using a cache object and tried to clear out a value by assigning &#8220;null&#8221; to it.  That worked in Cassini, but not in IIS.  In IIS, I had to use the Remove() method.</p>
<p>So, if you see something that looks like it should be working, but isn&#8217;t, it might be worthwhile to run it your application through IIS and see if you still have the problem.  That might save you from an hour of frustration.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=35</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Rhino Mocks with Void (or &#8216;Sub&#8217;) Methods</title>
		<link>http://www.scottlilly.com/?p=34</link>
		<comments>http://www.scottlilly.com/?p=34#comments</comments>
		<pubDate>Tue, 22 Jul 2008 18:39:41 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Mock Objects]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=34</guid>
		<description><![CDATA[I ran into a bit of trouble the other day when I was writing a test with Rhino Mocks.  It took a while to find the solution, so I figured I&#8217;d post it here for anyone else looking to do the same thing.
The problem I had was trying use a mock object for my data [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into a bit of trouble the other day when I was writing a test with Rhino Mocks.  It took a while to find the solution, so I figured I&#8217;d post it here for anyone else looking to do the same thing.</p>
<p>The problem I had was trying use a mock object for my data access layer, and calling a void method on the class.  There are thousands of examples of how to mock a method call that returns a value, but it took a while to find out how to handle a method call that doesn&#8217;t return anything.  In my test below, if the method returned something, I&#8217;d use code like this:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw1">using</span> <span class="br0">&#40;</span> mockery.<span class="me1">Record</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;Expect.<span class="me1">Call</span><span class="br0">&#40;</span> dal.<span class="me1">ExecuteQuery</span><span class="br0">&#40;</span> <span class="kw1">null</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span>.<span class="me1">IgnoreArguments</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="kw1">Return</span><span class="br0">&#40;</span> results <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
<p>For a void method (or &#8216;Sub&#8217;, instead of &#8216;Function&#8217;, for the VB.Net developers), you need to set up a delegate instead.  See the line that calls &#8220;ExecuteNonQuery&#8221; for an example.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="br0">&#91;</span>Test<span class="br0">&#93;</span><br />
<span class="kw1">public</span> <span class="kw1">void</span> CreateNewUserStory<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;MockRepository mockery = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> MockRepository<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;IDataAccessor dal = mockery.<span class="me1">CreateMock</span>&lt;idataaccessor&gt;<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp;IUserStoryControl screen = mockery.<span class="me1">Stub</span>&lt;iuserstorycontrol&gt;<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;UserStoryController controller = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> UserStoryController<span class="br0">&#40;</span> dal <span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp;screen.<span class="me1">StoryTitle</span> = <span class="st0">&#8220;Test title&#8221;</span>;<br />
&nbsp; &nbsp;screen.<span class="me1">Description</span> = <span class="st0">&#8220;Test description&#8221;</span>;</p>
<p>&nbsp; &nbsp;<span class="kw1">using</span> <span class="br0">&#40;</span> mockery.<span class="me1">Record</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Expect.<span class="me1">Call</span><span class="br0">&#40;</span> <span class="kw4">delegate</span> <span class="br0">&#123;</span> dal.<span class="me1">ExecuteNonQuery</span><span class="br0">&#40;</span> <span class="kw1">null</span> <span class="br0">&#41;</span>; <span class="br0">&#125;</span> <span class="br0">&#41;</span>.<span class="me1">IgnoreArguments</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;<span class="kw1">using</span> <span class="br0">&#40;</span> mockery.<span class="me1">Playback</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; controller.<span class="me1">CreateNewUserStory</span><span class="br0">&#40;</span> screen <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp;Assert.<span class="me1">AreEqual</span><span class="br0">&#40;</span> <span class="st0">&#8220;&#8221;</span>, screen.<span class="me1">StoryTitle</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;Assert.<span class="me1">AreEqual</span><span class="br0">&#40;</span> <span class="st0">&#8220;&#8221;</span>, screen.<span class="me1">Description</span> <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=34</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Putting interfaces in their own project(s)</title>
		<link>http://www.scottlilly.com/?p=33</link>
		<comments>http://www.scottlilly.com/?p=33#comments</comments>
		<pubDate>Mon, 14 Jul 2008 05:49:05 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=33</guid>
		<description><![CDATA[When I started using test-driven development and the model-view-controller pattern, I noticed a change in the way I broke up the projects in a typical solution.  Well, I noticed several changes, but the one I&#8217;m going to talk about now is how the user stories started to become the API of my business logic.  Because [...]]]></description>
			<content:encoded><![CDATA[<p>When I started using test-driven development and the model-view-controller pattern, I noticed a change in the way I broke up the projects in a typical solution.  Well, I noticed several changes, but the one I&#8217;m going to talk about now is how the user stories started to become the API of my business logic.  Because of the separation of the UI and the business logic that&#8217;s created by using the MVC pattern, my user interface has become a consumer of my business logic through this API.  Writing code this way gives me the flexibility to use the same logic with a completely different UI.</p>
<p>That may not sound like the kind of things that comes in handy very often; however, it&#8217;s making my life much easier for the latest project I&#8217;m working on.  I&#8217;m working on an ASP.Net website, but I also plan on creating a Visual Studio plug-in, so developers can access the website features without needing to leave their editor and open a new browser.  I may also end up writing a system tray tool that works the same way.  I haven&#8217;t decided if the plug-in will communicate with my application by a web service, remoting, or WCF.  But whatever method it uses, I&#8217;ll just end up writing a small bit of wrapper code in it to communicate with my business logic through the user story API.</p>
<p>Normally, my solution file will start out with four projects in it.  They are:</p>
<p>- MyLibrary (containing things like my data access layer)<br />
- Domain (the application&#8217;s business logic)<br />
- Application (the UI project)<br />
- TestDomain (unit tests for the Domain project)</p>
<p>The MyLibrary and Domain projects each contain an Interfaces folder, and the files within them are in the MyLibrary.Interfaces and Domain.Interfaces namespaces.  The Application project has references to both the MyLibrary and Domain projects.  However, since I&#8217;m going to have additional projects that will be passing objects of the interface types into a web service (for this example), They will either need to include the complete MyLibrary and Domain assemblies, or I&#8217;ll need to move the interfaces into their own assemblies.  In order to keep the installations for the new projects small, I&#8217;ll move the interfaces into their own projects.  So, the solution will now look something like this:</p>
<p>- MyLibrary (containing things like my data access layer)<br />
- MyLibrary.Interfaces (the public interfaces used within MyLibrary)<br />
- Domain (the application&#8217;s business logic)<br />
- Domain.Interfaces (the public interfaces used within Domain)<br />
- Application (the UI project)<br />
- Notifier (system tray notifier project)<br />
- Plugin (Visual studio plugin project)<br />
- WebService (used by the Notifier and Plugin projects to communicate with the Domain layer)<br />
- TestDomain (unit tests for the Domain project)</p>
<p>The Application and TestDomain projects (along with the new Notifier and WebService projects) will now need references to the new *.Interfaces projects.  However, the Notifier and Plugin will only need to have the small *.Interfaces assemblies included for the installation.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=33</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building my ultimate development computer (Part 3, Software)</title>
		<link>http://www.scottlilly.com/?p=32</link>
		<comments>http://www.scottlilly.com/?p=32#comments</comments>
		<pubDate>Wed, 09 Jul 2008 16:38:45 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=32</guid>
		<description><![CDATA[Now that I have a clean development environment running as a virtual machine, it&#8217;s time to set up the software I need to do my work.
The first thing I did to my development virtual machine was to set the desktop background to a different color.  Since I&#8217;ll be switching between multiple VMs, I figured I&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>Now that I have a clean development environment running as a virtual machine, it&#8217;s time to set up the software I need to do my work.</p>
<p>The first thing I did to my development virtual machine was to set the desktop background to a different color.  Since I&#8217;ll be switching between multiple VMs, I figured I&#8217;d add a visual indicator as to what machine I&#8217;m currently on.  Obviously, the background won&#8217;t be visible when I have my programs open.  If I still need something to remind me what machine I&#8217;m on, I&#8217;ll use one of those utilities that keeps the machine name and details floating above all applications.</p>
<p>For web browsing, I downloaded an installed the following:<br />
<a href="http://www.mozilla.com/en-US/firefox/" target="_blank">Firefox</a><br />
<a href="http://www.opera.com/" target="_blank">Opera</a><br />
<a href="https://addons.mozilla.org/en-US/firefox/addon/10" target="_blank">AdBlock</a><br />
<a href="http://www.avast.com/eng/download-avast-home.html" target="_blank">Avast! anti-virus</a> (I had been using AVG, but it&#8217;s been having some problems lately.  See <a href="http://www.theregister.co.uk/2008/06/26/avg_disguises_fake_traffic_as_ie6/" target="_blank">here</a> and <a href="http://it.slashdot.org/article.pl?sid=08/07/03/1411254" target="_blank">here</a> for more<br />
details)<br />
<a href="http://lavasoft.com/products/ad_aware_free.php" target="_blank">AdAware</a></p>
<p>For .Net development, I installed the following:<br />
IIS (Map a virtual CD drive to the operating system ISO, to get the required files)<br />
SQL Server 2005<br />
Visual Studio 2008<br />
<a href="http://www.microsoft.com/silverlight/resources/install.aspx" target="_blank">Silverlight</a></p>
<p>Then, the development libraries and tools that I use on a regular basis:<br />
<a href="http://www.ayende.com/projects/rhino-mocks/downloads.aspx" target="_blank">RhinoMocks</a><br />
<a href="http://www.nunit.org/index.php?p=download" target="_blank">NUnit</a><br />
<a href="http://www.testdriven.net/" target="_blank">TestDriven.Net</a><br />
<a href="http://www.jetbrains.com/resharper/" target="_blank">ReSharper 4.0</a> is next on my list</p>
<p>For source control, I went with Visual SourceSafe.  I prefer to use Subversion when developing with others; however, VSS suited all the extremely basic requirements I need for solo development.  Plus, it integrates better with Visual Studio than Subversion does.  When I tried VisualSVN and AnkhSVN, there were still a few things they had trouble with (moving and renaming files, IIRC).</p>
<p>For my continuous integration build server, I went with TeamCity, since it makes builds so much easier to create and manage than CruiseControl.  Ideally, I&#8217;d set this up on another VM, but I&#8217;m keeping things simple, until I find a need to make them more complex.  Something I&#8217;ve seen with their system tray notification tool is that the web server service hasn&#8217;t started before the system tray notification tool tries to connect to it.  I get a pop-up that the build website is not available yet.  I just give it a minute for the website to start up, then tell it to retry connecting.  I sent off an enhancement suggestion to the TeamCity developers that it would be nice to have a configurable wait setting before the notifier tries to connect to the web page.<br />
<a href="http://www.jetbrains.com/teamcity/index.html" target="_blank">TeamCity</a></p>
<p>Although it&#8217;s not on my development VM, I want to mention that I also installed SpamBayes on my &#8216;office&#8217; VM.  This is a nice filtering tool that helps keep spam out of my inbox.<br />
<a href="http://spambayes.sourceforge.net/" target="_blank">SpamBayes</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=32</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building my ultimate development computer (Part 2, Virtual Machines)</title>
		<link>http://www.scottlilly.com/?p=31</link>
		<comments>http://www.scottlilly.com/?p=31#comments</comments>
		<pubDate>Sun, 06 Jul 2008 18:29:42 +0000</pubDate>
		<dc:creator>Scott Lilly</dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://www.scottlilly.com/?p=31</guid>
		<description><![CDATA[After using virtual machines for test and build servers, I knew that I&#8217;d want to use them for my personal development environment.  However, when I was planning things out, I changed my mind as to how I was going to use the VMs.
My first thought was to have one image for Visual Studio 2005, another [...]]]></description>
			<content:encoded><![CDATA[<p>After using virtual machines for test and build servers, I knew that I&#8217;d want to use them for my personal development environment.  However, when I was planning things out, I changed my mind as to how I was going to use the VMs.</p>
<p>My first thought was to have one image for Visual Studio 2005, another for Visual studio 2008, another for my development SQL server, another for my build server, etc.  But I started to realize that I was going to need to be running several VMs simultaneously, just to work on one typical application.  Even with the CPU and RAM that I have, that might start straining my computer.  I also might end up needing to manage multiple versions of each image (e.g., a development SQL Server with no service pack installed, another with SP1 installed, another with SP2 installed).  That was going to get messier than I wanted.</p>
<p>So, I decided to create an image to hold my full development environment for each project.  That gives me the ability to move a complete development environment to offline storage, once I&#8217;m done with the project.  If the client comes back a year later and wants me to make some enhancements, I can bring the complete environment back to where it was when I last worked on it.</p>
<p>To do this, I created an image with my base operating system installed.  After running Windows Update until everything was updated, I saved that image as my base OS image.  Then, I cloned that to a base development image.  I installed all the software that I would need for a full development environment (editor, database, source control, etc.) on that image.  After running Windows Update on that image, I cloned that to another image that I would actually use for development.  That way, if I ever need to build up another VM, I can clone from the base and have a clean environment.  When building base images, keep in mind that things will be easier if you configure all your applications the way you want, then build your clones off of that image.  Download your favorite browser and set your home page to your normal home page.  Go into your editor and set your tab stops where you want.  You won&#8217;t want to do that each time you make a new VM.</p>
<p>Figure out the size RAM and hard disk you want for your virtual machines.  If they are all fairly close, use the maximum size as your standard VM configuration.  If they are significantly different, you may want to create a few different base images.  If you are using Windows as your operating system, significant changes in machine configuration may cause Windows to think it is installed on another computer, and expect another license key.  I went with 2 gigs of RAM and a 100 gig hard disk.  Even though I set up the hard disk as 100 gigs, they image sizes are currently only taking up from five to seventeen gigs of actual space.</p>
<p>When installing software from an ISO, set up the ISO image as a CD-ROM drive.  If you have trouble running the install from the virtual CD (as I did for a few programs), copy the files over to the VM&#8217;s &#8216;local drive&#8217; and run the setup application from there.</p>
<p>A couple of things I&#8217;m not fully happy about, but haven&#8217;t figured out how I want to handle them yet, are having my source control and continuous integration on each development VM.  Ideally, I&#8217;d like to have all the source control in one place, so I can share code between applications easier.  I can also see that there may potentially be problems with running my CI build on my development VM.  If it starts to cause problems, I&#8217;ll post what is happening and how I get around it.</p>
<p>I also created a couple of other VMs, one for all my office functions (e-mail, word processor, spreadsheet, etc.), and one for web browsing.  Doing my browsing on one VM limits the amount of damaged that could be caused by spyware or the latest browser exploit.  If something starts to get strange, just make sure my bookmarks are stored somewhere and rebuild my image.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.scottlilly.com/?feed=rss2&amp;p=31</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.454 seconds -->
