<?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>Chris Holmes Online &#187; ALT.NET</title>
	<atom:link href="http://www.chrisholmesonline.com/categories/altdotnet/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.chrisholmesonline.com</link>
	<description>Adventures in .NET &#38; Agile Development...</description>
	<lastBuildDate>Mon, 28 Nov 2011 00:52:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Silverlight RIA Services with POCO &amp; Oracle: Part 2</title>
		<link>http://www.chrisholmesonline.com/2011/01/19/silverlight-ria-services-with-poco-oracle-part-2/</link>
		<comments>http://www.chrisholmesonline.com/2011/01/19/silverlight-ria-services-with-poco-oracle-part-2/#comments</comments>
		<pubDate>Wed, 19 Jan 2011 19:29:34 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Work Related]]></category>

		<guid isPermaLink="false">http://www.chrisholmesonline.com/?p=567</guid>
		<description><![CDATA[You can read Part Ihere. In the last post I gave an overview of the sample Silverlight + RIA application (code can be found here). For Part 2, I wanted to talk more about the specifics of the service layer and the order of the calls. You&#8217;ll notice the declaration of several data sources in [...]]]></description>
			<content:encoded><![CDATA[<p>You can read Part I<a href="http://www.chrisholmesonline.com/2011/01/13/silverlight-ria-services-with-poco-oracle-part-i/">here</a>.</p>
<p>In the last post I gave an overview of the <a href="http://www.chrisholmesonline.com/SilverlightAggregate.zip">sample Silverlight + RIA application </a> (code can be found <a href="http://www.chrisholmesonline.com/SilverlightAggregate.zip">here</a>). For Part 2, I wanted to talk more about the specifics of the service layer and the order of the calls. </p>
<p>You&#8217;ll notice the declaration of several data sources in the constructor of the service: </p>
<pre name="code" class="c-sharp">
[EnableClientAccess()]
  public class TicketService : DomainService
  {
    private TicketDataSource _ticketDataSource;
    private CustomerDataSource _customerDataSource;
    private ProductDataSource _productDataSource;
    private ActionTypeDataSource _actionTypeDataSource;
    private ResultTypeDataSource _resultTypeDataSource;
    private TicketActionDataSource _ticketActionDataSource;

    public TicketService()
    {
      _ticketDataSource = new TicketDataSource();
      _customerDataSource = new CustomerDataSource();
      _productDataSource = new ProductDataSource();
      _actionTypeDataSource = new ActionTypeDataSource();
      _resultTypeDataSource = new ResultTypeDataSource();
      _ticketActionDataSource = new TicketActionDataSource();
    }
</pre>
<p>In our production environment we&#8217;re delegating the actual database operations to separate classes that make calls to Oracle Stored Procedures through ADO.NET using an Oracle provider. It doesn&#8217;t have to be an Oracle DB of course &#8211; you could use any database you like when you just want to hide the details away behind an abstraction such as this. For the sample application, we store the data in memory using the HTTP Session. </p>
<p><strong>Insert: Order Of Operations</strong></p>
<p>What I really wanted to talk about in this post is the order of operations when it comes to doing inserts and saving new entities. For this application we have three pieces of data that can be inserted into the database:</p>
<ul>
<li>Ticket</li>
<li>Customer</li>
<li>TicketAction</li>
</ul>
<p>Product, ActionType and ResultType are also data on the Ticket or TicketAction objects, but they are pulled from the database tables as static lookups and only referenced in their parent objects as foreign keys. No new values are inserted into these three tables via the application and that is why they do not have INSERT methods on the TicketService. </p>
<p>Ticket is our root aggregate object. Customer is a child object on the root, and TicketActions are a collection on the root. The order of operations is determined by RIA. InsertCustomer() will be called first, then InsertTicket() and finally, InsertTicketAction(). Let&#8217;s see how and why this happens. </p>
<p><strong>Inserting a Customer</strong></p>
<p>All single-entity child objects on the root will have their respective INSERT methods called first. If you think about it, this makes sense. The primary key of each child object is used as a foreign key on the parent object, so the child object primary key has to be known BEFORE the parent object can be saved. Thus, for a new Customer object, we have to first insert it into the DB and return the newly generated CustomerId to the Ticket BEFORE the Ticket gets saved.  </p>
<pre name="code" class="c-sharp">
public void Insert(Customer customer)
{
    customer.CustomerId = _customerDataSource.Insert(customer);
}
</pre>
<p>So here we&#8217;re passing the Customer to a class that will perform the actual INSERT into Oracle, and in turn that method will get the generated PK from Oracle and return it. It is then our responsibility in this call to associate that PK with the Customer object, because the Customer is going to get sent back across the wire to the client when RIA is done making all these calls. </p>
<p><strong>Inserting a Ticket</strong></p>
<p>Once the Customer has been saved to the DB (and the new CustomerId returned and set on the Customer object) then RIA will call the INSERT method for the Ticket itself. At this point in time we need to set the CustomerId (and any other child foreign keys) on the Ticket object:</p>
<pre name="code" class="c-sharp">
public void Insert(Ticket ticket)
{
      ticket.CustomerId = ticket.Customer.CustomerId;

      ticket.TicketId = _ticketDataSource.Insert(ticket);

      foreach (var ticketAction in ticket.TicketActions)
      {
        ticketAction.TicketId = ticket.TicketId;
      }
}
</pre>
<p>And just like the Customer INSERT method, once we save the Ticket to the database we need to get the generated PK back from Oracle and set it on our Ticket. </p>
<p><strong>Inserting TicketActions</strong></p>
<p>The last thing that happens here is the insertion of multiple TicketActions, as this is a child collection on the Ticket object. And again, if you think about it from a DB point of view, this makes sense. Each TicketAction has a foreign key TicketId. Thus, a TicketAction can&#8217;t be saved to the DB until the TicketId is known. For a new Ticket, that won&#8217;t be until the Ticket is saved and the id returned. Once the Ticket&#8217;s primary key (TicketId) is known, we can attach it to each TicketAction and save them as well. RIA will make that call automatically, after the INSERT method for the Ticket is done: </p>
<pre name="code" class="c-sharp">
public void InsertTicketAction(TicketAction ticketAction)
{
      ticketAction.TicketActionId = _ticketActionDataSource.Insert(ticketAction);
}
</pre>
<p><strong>Done Inserting</strong></p>
<p>Once all of those calls are made and the various pieces of data have been saved to their respective tables, the root aggregate object is ready to be reloaded by RIA. This will happen AUTOMATICALLY. You do not need to call Load() on the service context again in your ViewModel after you have called SubmitChanges(). RIA will automatically reload your entity client-side depending on what kind of LoadBehavior you specified (for this project we&#8217;ve specified a LoadBehavior.RefreshCurrent). This is another reason why it is so important to return the primary keys and set those values on the objects when you saved that data to the database. </p>
<p>Next time I&#8217;ll cover UPDATE operations and explain one of the quirks of RIA sending entities down the wire&#8230;. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.chrisholmesonline.com/2011/01/19/silverlight-ria-services-with-poco-oracle-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Folly Of Stored Procedures</title>
		<link>http://www.chrisholmesonline.com/2008/10/30/the-folly-of-stored-procedures/</link>
		<comments>http://www.chrisholmesonline.com/2008/10/30/the-folly-of-stored-procedures/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 13:32:10 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Work Related]]></category>

		<guid isPermaLink="false">http://www.chrisholmesonline.com/?p=279</guid>
		<description><![CDATA[Allow me to lay out a story that should sound familiar: A couple of coworkers are discussing a bug in the software. In this particular bug&#8217;s case, it concerns an icon that appears in a column of a datagrid. Each row in the grid is either supposed to have this little icon in a specified [...]]]></description>
			<content:encoded><![CDATA[<p>Allow me to lay out a story that should sound familiar: </p>
<p>A couple of coworkers are discussing a bug in the software. In this particular bug&#8217;s case, it concerns an icon that appears in a column of a datagrid. Each row in the grid is either supposed to have this little icon in a specified column, or not. It depends on the data. But that&#8217;s not really important, just background info. </p>
<p>What&#8217;s really important is that the icon was previously coded and tested and <em>worked</em>. It appeared under the correct conditions and was hidden when it should be. Now, all of a sudden, it wasn&#8217;t working. We get an e-mail from customers saying, &#8220;The icon should show up in this circumstance, but it doesn&#8217;t.&#8221; Time to investigate. </p>
<p>While my two coworkers are hashing out exactly what could have happened, why, and how to fix it, I start thinking to myself, &#8220;<em>There should be unit tests to catch this. This shouldn&#8217;t have happened. I&#8217;ll just go find the test suite and write a couple new tests to ensure the icon properly displays based on the criteria of the data.</em>&#8221; </p>
<p>Sounds easy, right? </p>
<p>As I started digging through the specific class code and examining the unit tests, I notice that there are no unit tests for this functionality. That seems suspicious. Then I notice something else: there&#8217;s no code. All that exists is a method call to a service that returns a datatable. </p>
<p>As Alice did, I decided to drop through the rabbit hole and see what&#8217;s up. </p>
<p>When I get to the bottom I see a gigantic SQL statement &#8211; several hundred lines long. It is embedded in the application, deep down in the data access layer, complete with multiple sub-selects and even an SQL case statement! It&#8217;s got multiple parameters in the where clause. It&#8217;s the kind of thing that makes SQL admins all warm and fuzzy inside, I&#8217;m sure. The whole thing is then handed off to our OR/M, which returns a simple datatable. While it is not a stored procedure, it might as well have been &#8211; it only has one step remaining on the cliff before it jumps right off into the database. </p>
<p>And the killer is, it&#8217;s untestable. </p>
<p>The caveat here is that this particular stored procedure was written as a performance gain, because the nature of the data requested is complex in its selection. But still, I&#8217;m of the belief that there might be a better way to query the data than one giant stored procedure. </p>
<p>Because the minute you put business logic in a stored procedure you compromise the quality of your application. You introduce the capability for your team to make mistakes that are no longer easily caught by a regression suite of unit tests. More importantly, I think, is that you increase the probability of <strong>repeated bugs</strong>. And to me, repeated bugs are a cardinal sin of programming. Nothing makes a development team look dumber than fixing a bug only to have it crop up again, and again, and again. It makes the software look bad, and by proxy it makes the developers look incompetent. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.chrisholmesonline.com/2008/10/30/the-folly-of-stored-procedures/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Too Obvious A Solution To Actually Happen</title>
		<link>http://www.chrisholmesonline.com/2008/10/30/too-obvious-a-solution-to-actually-happen/</link>
		<comments>http://www.chrisholmesonline.com/2008/10/30/too-obvious-a-solution-to-actually-happen/#comments</comments>
		<pubDate>Thu, 30 Oct 2008 13:22:39 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Work Related]]></category>

		<guid isPermaLink="false">http://www.chrisholmesonline.com/?p=280</guid>
		<description><![CDATA[Bob, lamenting the continued bloated nature of Windows OS, writes: Personally I think they should clean house on the OS side, put the development tools in maintenance mode for a couple of years, and put Scott Guthrie and the rest of those geniuses behind Visual Studio to work on building a new OS from scratch. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://bobondevelopment.com/2008/10/29/time-to-jump-ship/">Bob</a>, lamenting the continued bloated nature of Windows OS, writes:</p>
<blockquote><p>    Personally I think they should clean house on the OS side, put the development tools in maintenance mode for a couple of years, and put Scott Guthrie and the rest of those geniuses behind Visual Studio to work on building a new OS from scratch. </p></blockquote>
<p>This is something I’ve been saying for years. Windows needs to be rewritten from scratch. Start over, and let the guiding principal be: Simple Is Better.</p>
<p>Windows has become so big and bloated that it can’t do the basics anymore. I mean, really &#8211; what do you need your OS to do? I know what I want my OS to do: run my apps. That’s it; it’s that simple. Manage my files, memory and processes so I can run my apps. And even Windows can’t get that right.</p>
<p>Have you tried working with Explorer lately? Copying large files? Over a network? When was the last time you tried to kill a process in Windows? Guess what? It’s still easier and more reliable to kill a process in Unix/Linux than it is in Windows. Why is that?</p>
<p>As Riply said, “I say we take off, and nuke the site from orbit. It’s the only way to be sure.”</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chrisholmesonline.com/2008/10/30/too-obvious-a-solution-to-actually-happen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Backlog-In Development-Done</title>
		<link>http://www.chrisholmesonline.com/2008/05/19/backlog-in-development-done/</link>
		<comments>http://www.chrisholmesonline.com/2008/05/19/backlog-in-development-done/#comments</comments>
		<pubDate>Tue, 20 May 2008 05:22:49 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Work Related]]></category>

		<guid isPermaLink="false">http://www.chrisholmesonline.com/2008/05/19/backlog-in-development-done/</guid>
		<description><![CDATA[Simon has a new post describing how they&#8217;ve revamped their planning board. I found it to be an interesting read because for once someone else&#8217;s board looks similar to ours. Our board has undergone a few makeovers as well over the past couple of years. In the beginning we tried to do what everyone else [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.agileinaction.com/">Simon</a> has a new post describing how they&#8217;ve <a href="http://www.think-box.co.uk/blog/2008/05/simplified-planning-board.html">revamped their planning board</a>. I found it to be an interesting read because for once someone else&#8217;s board looks similar to ours. </p>
<p>Our board has undergone a few makeovers as well over the past couple of years. In the beginning we tried to do what everyone else was doing. We had a big board with several columns. But our shop was small (at it&#8217;s peak, three developers and a PM) and the extra columns seemed wasteful. We didn&#8217;t really have a QA team, for instance, because we <em>were </em>the QA team. A &#8220;Testing&#8221; column seemed like a waste because we practice TDD as much as possible, so testing is part of the process of development. Same goes for acceptance tests, hands-on testing and customer approval. It&#8217;s all part of the process of developing software. Personally, I don&#8217;t look at the different elements &#8211; like architecture, design, testing or customer feedback &#8211; as separate phases. I see them as the one thing: developing software. They are all necessary elements to reach the final goal of a completed, working, and <em>trusted </em>software feature. </p>
<p>In the end, we finally settled on was <a href="http://en.wikiquote.org/wiki/Ward_Cunningham#The_Simplest_Thing_that_Could_Possibly_Work">the simplest thing that could possibly work</a>: Backlog, In Development &#038; Done. </p>
<p>Our <strong>Backlog </strong>is every story card in our possession. We don&#8217;t categorize; we just let the customer prioritize. <strong>In Development</strong> is everything we&#8217;re working on during this iteration. Since we &#8211; the developers &#8211; do it all, then <strong>In Development</strong> carries a comprehensive meaning. And when all the bases are covered, regardless of what order they were performed (although I hope unit tests were written <em>before </em>the code was) then, and only then, does it move to <strong>Done</strong>. </p>
<p>What I enjoy most about our board is that it is so simple to read. It&#8217;s easy to determine what&#8217;s left to do (Backlog), what&#8217;s being worked on (In Development) and what&#8217;s ready for the next publish at the end of the iteration (Done). And I don&#8217;t need to worry about testing or customer approval because those elements of the development process are implied. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.chrisholmesonline.com/2008/05/19/backlog-in-development-done/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>We&#8217;re Hiring</title>
		<link>http://www.chrisholmesonline.com/2008/04/16/were-hiring/</link>
		<comments>http://www.chrisholmesonline.com/2008/04/16/were-hiring/#comments</comments>
		<pubDate>Thu, 17 Apr 2008 06:23:58 +0000</pubDate>
		<dc:creator>Chris</dc:creator>
				<category><![CDATA[ALT.NET]]></category>
		<category><![CDATA[CAB]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Work Related]]></category>

		<guid isPermaLink="false">http://www.chrisholmesonline.com/2008/04/16/were-hiring/</guid>
		<description><![CDATA[For a while now, my employer has maintained an opening for a talented software developer. They have not advertised the position very heavily because (a) we live in an area that is not rich with developers and (b) our small, Agile team has chugged along fairly well without this extra person. That all changed today [...]]]></description>
			<content:encoded><![CDATA[<p>For a while now, my employer has maintained an opening for a talented software developer. They have not advertised the position very heavily because (a) we live in an area that is not rich with developers and (b) our small, Agile team has chugged along fairly well without this extra person. </p>
<p>That all changed today when a colleague &#8211; and friend &#8211; opted for greener pastures. He&#8217;s returning to the company where he started his career as an intern, a place he is particularly fond of, and I cannot blame him for taking a job that more closely fulfills his professional and personal desires. I wish him all the best. </p>
<p>Still, our small team of developers just shrunk by one, and we need to fill the gap. </p>
<p>In a larger city this would not be a problem. We&#8217;d just advertise the position and the resumes would pour in. But our location is our biggest hurdle when it comes to attracting talented developers. We simply can&#8217;t pull from as large a pool as a city like Austin, Texas can. </p>
<p>So where do I work? <a href="http://www.co.nezperce.id.us/">Nez Perce County</a>, a small county government in north-central Idaho. As one might imagine, it is not exactly a mecca for software development talent. But that hasn&#8217;t stopped us from trying. People we talk to are always surprised to learn that our tiny little IT shop in Idaho is practicing Agile techniques. Yet that is exactly what we&#8217;re doing. </p>
<p>We subscribe to <a href="http://en.wikipedia.org/wiki/Agile_software_development">Agile </a>practices, <a href="http://en.wikipedia.org/wiki/Extreme_Programming">Extreme Programming</a> in particular, and we drink from the <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD </a>fountain. We use <a href="http://en.wikipedia.org/wiki/Continuous_Integration">Continuous Integration</a>, unit tests, acceptance tests, and frequent customer feedback along with short iterations to write quality, maintainable code and deliver business value to our customers (which, incidentally, includes us, since we are also taxpayers; we&#8217;re our own bosses in manner of speaking). </p>
<p>We work in an open environment and every developer has two monitors at their workstation. We work closely together as a team and have an on-site customer to help provide rapid feedback. </p>
<p><strong>What We&#8217;re Looking For</strong></p>
<p>We realize that we&#8217;re a bit handicapped by our geography. We&#8217;re not going to see a lot of great resumes. So it&#8217;s important for us to identify candidates that have the capacity to <em>learn </em> and possess a passion for software development. Ideally, candidates for our shop would have the following qualifications: </p>
<ul>
<li>Knowledge of Object Oriented design and principles</li>
<li>Knowledge/Experience with C# .Net, or a similar object-oriented language (Java, C++)</li>
<li>Database experience</li>
<li>Willingness to learn</li>
</ul>
<p>Bonus points for knowledge/experience with any of the following: Gang of Four design patterns, Unit Testing, IoC, CAB and/or SQL Server.</p>
<p>More information about the position, including benefits and pay, can be gathered by contacting my boss, <strong>Randy Buttenhoff</strong>, via the <a href="http://www.co.nezperce.id.us/infosy/Commissioners/InformationSystems/tabid/270/Default.aspx">Nez Perce County IT web page.</a> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.chrisholmesonline.com/2008/04/16/were-hiring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

