<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>codeface</title>
	<atom:link href="http://blog.markrendle.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.markrendle.net</link>
	<description>on making software</description>
	<lastBuildDate>Fri, 01 Jun 2012 21:56:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.markrendle.net' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>codeface</title>
		<link>http://blog.markrendle.net</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.markrendle.net/osd.xml" title="codeface" />
	<atom:link rel='hub' href='http://blog.markrendle.net/?pushpress=hub'/>
		<item>
		<title>Simple.Web</title>
		<link>http://blog.markrendle.net/2012/06/01/simple-web/</link>
		<comments>http://blog.markrendle.net/2012/06/01/simple-web/#comments</comments>
		<pubDate>Fri, 01 Jun 2012 01:07:09 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Web]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[simple.web]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=308</guid>
		<description><![CDATA[So on Wednesday at the Skills Matter Progressive .NET Tutorials, I gave a session offering an introduction to this new thing I’ve been working on, Simple.Web. The session was recorded, and you can watch it here if you like (it’s just over 3 hours), but I’m going to try and give a rough idea of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=308&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So on Wednesday at the <a href="http://skillsmatter.com/event/open-source-dot-net/prognet-2012" target="_blank">Skills Matter Progressive .NET Tutorials</a>, I gave a session offering an introduction to this new thing I’ve been working on, <a href="https://github.com/markrendle/simple.web" target="_blank">Simple.Web</a>. The session was recorded, and you can watch it <a href="http://skillsmatter.com/podcast/home/simpleweb-intro/js-4398" target="_blank">here</a> if you like (it’s just over 3 hours), but I’m going to try and give a rough idea of what it’s all about in this post. I’ll be following this up with some more detail on specific areas in the coming days.</p>
<h2>Why?</h2>
<p>Obvious question, really. There are lots of web frameworks out there for .NET already, which all offer different things, so why build a new one? The primary answer is: none of them worked quite the way I wanted. There were things I liked about some of them, but not all in the same package. I loved WCF Web API while it was still called that, when Glenn Block was working on it, but by the time it became ASP.NET Web API it wasn’t the same thing any more. It’s had a Controller base class foisted upon it, for a start, and the routing was all completely different, and it broke my (current, start-up, commercial) project, which soured the relationship. I needed something else for my project, and nothing I knew of did the things I really needed right away.</p>
<p>The other thing was that I read a couple of blog posts around the theme that the MVC pattern breaks the rules of SOLID, most notably the Single Responsibility Principle. In a traditional MVC application, a Controller represents a resource type, and has Actions for all the possible operations against that type of resource: Create, Read, Update, Delete and so on. That’s multiple responsibilities right there. And this impacts on performance as well as maintainability, because you have to inject the dependencies for all the possible actions in the constructor, even though none of them may be needed. Search for “single action controller” and you’ll find dozens of posts warming to this theme and offering that workaround, but it got me thinking, what if all the controllers were single action? What if, instead of using a method to represent an action (or a URI), you used a class? How would a framework like that look?</p>
<h2>Design goals</h2>
<p>I decided to try building a framework like this in tandem with the commercial project, primarily focusing on getting it to do the things I needed it to do for that. My primary goals for the initial version were:</p>
<ul>
<li>Keep it simple;</li>
<li>It should be ridiculously easy to do TDD and/or BDD;</li>
<li>Support asynchronous, non-blocking handling of requests;</li>
<li>Make it easy to build a <em>proper</em> RESTful, hypermedia-driven application and services, including supporting content-type negotiation for all requests, including HTML;</li>
<li>Be really open and extensible, because if people can write plug-ins and add-ons easily, I don’t have to build all that stuff in.</li>
</ul>
<p>To that end, the framework has been built to be extensible, but currently provides a limited set of options. The only hosting option at the moment is on top of ASP.NET. The only view engine supported is Razor. It uses JsonFx for handling JSON, and a very rough system built on the WCF DataContractSerializer for XML. And the only IoC container I’ve built support for is Ninject. These are all personal preferences, and while I’ve tried to make sure they’re all abstracted in a way that will make it very easy for additional plug-ins to be built, I fully expect to have to make at least a few core changes if and when people want to build them. In particular, the work I did on refactoring out the hosting code into a separate project for ASP.NET probably took too much code with it.</p>
<h3>Keeping it simple</h3>
<p>I’ve tried to make everything obvious, and cut out boilerplate as much as possible. In particular, there are no base classes for handlers, although you are free to create your own if you want to. Everything is done through interfaces. Lots and lots of interfaces, each one very small, in accordance with the Interface Segregation Principle. Also, everything gets put together automatically, with no complex routing tables and brittle dependencies.</p>
<h3>Facilitating TDD</h3>
<p>The biggest barrier to automated testing of web apps is the need to fake, mock or stub the accoutrements of HTTP in order to fool the object under test into thinking that it’s running in a web server. In Simple.Web, handler objects know nothing about HTTP. They implement interfaces to tell the framework what information they need from the request, and what information they provide for the response. The framework takes care of mapping the various properties and methods to HTTP. This means a handler can be created and have those properties set in very simple “arrange” code, and you never need to mock another Request object in order to set a header or a cookie or a request body. Handlers can stick to implementing application and business logic, and you can stick to testing that logic, which is how it should be.</p>
<p>Building the handlers in this way has had other positive effects on the system and the code. It’s made for some very small, modular types; it’s made the HTTP&lt;-&gt;handler mapping into an extension point which developers can hook into really easily; and it’s meant that the runtime system can be highly optimised, since all the information about what a handler needs and does is right there in its type declaration.</p>
<h3>Supporting asynchrony</h3>
<p>This is as important on a web server as it is on a client machine. In general, web servers spend most of their time waiting on I/O operations, pointlessly blocking on threads while a database or another web service does its thing. If this time spent waiting can instead be spent processing other requests, we can service more clients with fewer servers. This is, of course, the principle behind Node.js, but it turns out it works just as well in .NET, thanks to the Task Parallel Library and Windows’ kernel-level evented I/O. ASP.NET MVC 4 allows you to return a Task&lt;ActionResult&gt;, and when combined with the awesome new async/await features in C# 5, it’s really easy to write non-blocking web code.</p>
<p>In Simple.Web, the primary method on each handler is taken from the HTTP method represented by the handler interface. For example, a GET operation is handled by a type which implements the IGet interface, and that declares a Get method which returns a Status. It’s all very getty. Like this:</p>
<pre class="code">[<span style="color:#2b91af;">UriTemplate</span>(<span style="color:#a31515;">"/"</span>)]
<span style="color:blue;">public class </span><span style="color:#2b91af;">GetIndex </span>: <span style="color:#2b91af;">IGet</span>
{
    <span style="color:blue;">public </span><span style="color:#2b91af;">Status </span>Get()
    {
        <span style="color:blue;">return </span><span style="color:#2b91af;">Status</span>.OK;
    }
}
</pre>
<p>Don’t worry about where the output comes from, we’ll come to that. The important thing at this stage is that for every HTTP method interface, there is an asynchronous variant, where the relevant method returns a Task&lt;Status&gt; instead, and that would look like this:</p>
<pre class="code">[<span style="color:#2b91af;">UriTemplate</span>(<span style="color:#a31515;">"/"</span>)]
<span style="color:blue;">public class </span><span style="color:#2b91af;">GetIndex </span>: <span style="color:#2b91af;">IGetAsync</span>
{
    <span style="color:blue;">public </span><span style="color:#2b91af;">Task</span>&lt;<span style="color:#2b91af;">Status</span>&gt; Get()
    {
        <span style="color:blue;">return </span>DoLongRunningThing()
            .ContinueWith(t =&gt; <span style="color:#2b91af;">Status</span>.OK);
    }
}
</pre>
<p>Except of course you’d have some error checking and stuff in there. That’s where you want to be using C# 5 and async/await, otherwise it’ll bake your brain.</p>
<p>The point is, the decision to make something asynchronous is not a big one, and you’re free to mix and match synchronous and asynchronous handlers in a project; it’s up to you.</p>
<h3>REST and hypermedia</h3>
<p>The most important feature for implementing good, flexible, robust web apps and APIs is proper content-type handling. This is one of the biggest problems with ASP.NET MVC: actions do not return resources; they return specific representations of resources. The action decides whether to render a view or some XML or some JSON, when in fact it should be the client telling the action what representation it’s after. To do this, you need a content-type negotiation system, so Simple.Web has one, although it’s in a fairly embryonic state at this point.</p>
<p>A Simple.Web handler outputs an object, or a collection of objects, and lets the content-type negotiation system work out what to do with it. If the client is a browser asking for HTML, then the view-engine system kicks in, and tries to find a view. It can do this using the @model directive if only one view in the application declares that model type:</p>
<pre class="code"><span style="background:yellow;">@</span><span style="color:red;">model </span>Sandbox.Form
<span style="color:blue;">&lt;!</span><span style="color:maroon;">DOCTYPE </span><span style="color:red;">html</span><span style="color:blue;">&gt;
&lt;</span><span style="color:maroon;">html</span><span style="color:blue;">&gt;
</span><span style="color:blue;">    &lt;</span><span style="color:maroon;">body</span><span style="color:blue;">&gt;
        &lt;</span><span style="color:maroon;">div</span><span style="color:blue;">&gt;
</span><span style="color:blue;">            &lt;</span><span style="color:maroon;">h1</span><span style="color:blue;">&gt;</span><span style="background:yellow;">@</span><span style="color:red;">Model</span>.Text<span style="color:blue;">&lt;/</span><span style="color:maroon;">h1</span><span style="color:blue;">&gt;
        &lt;/</span><span style="color:maroon;">div</span><span style="color:blue;">&gt;
    &lt;/</span><span style="color:maroon;">body</span><span style="color:blue;">&gt;
&lt;/</span><span style="color:maroon;">html</span><span style="color:blue;">&gt;
</span></pre>
<p>or, if that is not specific enough, or if there is no model type for a given handler, there is a new @handler directive to support directly linking between view and handler:</p>
<pre class="code"><span style="background:yellow;">@</span><span style="color:red;">handler </span>Sandbox.GetForm
<span style="color:blue;">&lt;!</span><span style="color:maroon;">DOCTYPE </span><span style="color:red;">html</span><span style="color:blue;">&gt;
&lt;</span><span style="color:maroon;">html</span><span style="color:blue;">&gt;
</span><span style="color:blue;">&lt;</span><span style="color:maroon;">body</span><span style="color:blue;">&gt;
&lt;</span><span style="color:maroon;">h1</span><span style="color:blue;">&gt;</span><span style="background:yellow;">@</span><span style="color:red;">Handler</span>.Title<span style="color:blue;">&lt;/</span><span style="color:maroon;">h1</span><span style="color:blue;">&gt;
&lt;</span><span style="color:maroon;">form </span><span style="color:red;">action</span><span style="color:blue;">="/submit" </span><span style="color:red;">method</span><span style="color:blue;">="POST"&gt;&lt;</span><span style="color:maroon;">input </span><span style="color:red;">type</span><span style="color:blue;">="text" </span><span style="color:red;">name</span><span style="color:blue;">="Text" /&gt;&lt;</span><span style="color:maroon;">input </span><span style="color:red;">type</span><span style="color:blue;">="submit" /&gt;&lt;/</span><span style="color:maroon;">form</span><span style="color:blue;">&gt;
&lt;/</span><span style="color:maroon;">body</span><span style="color:blue;">&gt;
&lt;/</span><span style="color:maroon;">html</span><span style="color:blue;">&gt;
</span></pre>
<p>This also results in the handler being a property in the view, with all its public variables available; no more need for ViewBags.</p>
<p>The other aspect to HTTP and hypermedia-based apps and APIs is that all resources should come with a complete, human- and machine-readable set of the available state transitions for the resource, represented as links. There is a system for building these links within Simple.Web, and I’ll be covering that in an upcoming post.</p>
<h3>Be open and extensible</h3>
<p>Over the last year and a half of maintaining Simple.Data, I’ve been really impressed by the can-do attitude of people who have built and maintained their own adapters and providers, and submitted code back to the core project when they needed something. There’s an astonishing number of databases, both SQL and NoSQL supported, and mostly that support is nothing to do with me.</p>
<p>I want to let the same kind of people do that with Simple.Web too, whether it’s for view engines, or hosting systems, or content-type handlers. And with a web framework, there’s an additional driver for being open and extensible, because there are plenty of points within a specific project where you might want to change the way something works.</p>
<p>So the framework comes out of the box with some plug-ins, which are included in the Simple.Web package for the time being for convenience, but I’m hoping that fans of other hosts/view-engines/serializers will pop up with their own alternatives, at which point I’ll separate out the JsonFx and the Razor, for instance.</p>
<p>But Simple.Web is extensible in smaller ways, too. For example, there are interfaces for GET, PUT, POST, PATCH, etc., but I haven’t created an interface for MERGE, which some systems use. What I have done is make it easy for you to add your own HTTP method interfaces, which will get picked up by the framework and integrated just like the built in ones. So you can add MERGE, or TRACE, or make up your own methods, like SMITE and BESTOW.</p>
<p>And then there’s all those interfaces which map information between the HTTP infrastructure and your handlers. Those are all built on a very simple pattern, using public types and attributes, and you can create your own interfaces which will get integrated into the pipeline in exactly the same way that the built-in ones do. If you have a custom header called X-User-Mood, you can create a “behavior” interface and some “implementation” code, and it will get hooked in for you, so you never need to pollute your handler code with HTTP contexts and requests and responses.</p>
<h2>Getting started</h2>
<p>OK, that’s enough waffle for now. If it sounds interesting, then the Skills Matter video has a lot more of me blathering on about it and doing some demos, many of which fail spectacularly. You can install the package from <a href="http://nuget.org/packages/Simple.Web" target="_blank">NuGet</a>, or download the source from <a href="https://github.com/markrendle/simple.web" target="_blank">Github</a>, where there is also a <a href="https://github.com/markrendle/SimpleWebSignupDemo" target="_blank">demo application</a> which demonstrates some of the main features. There’s <a href="https://groups.google.com/forum/?fromgroups#!forum/simpleweb-users" target="_blank">a Google Group</a> for people who want to use the framework to build applications, and <a href="https://groups.google.com/forum/?fromgroups#!forum/simpleweb-dev" target="_blank">another one</a> for people who want to build plug-ins or add-ons or contribute to the core in some way (hint: Razor needs some love).</p>
<p>Also, because this one is all statically-typed, with no dynamic oddness, IntellSense is your friend, and there are documentation comments all over the place so it should be reasonably easy to pick up. I’m looking into something that generates actual help from the comments and isn’t Sandcastle, so hopefully there’ll be a manual soon.</p>
<p>Finally, I’ll be putting up some more detailed posts about various features over the next few days and weeks, so watch this space.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/308/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/308/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/308/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/308/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/308/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/308/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/308/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/308/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=308&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/06/01/simple-web/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>The Three Little Pigs (Redux)</title>
		<link>http://blog.markrendle.net/2012/05/11/the-three-little-pigs-redux/</link>
		<comments>http://blog.markrendle.net/2012/05/11/the-three-little-pigs-redux/#comments</comments>
		<pubDate>Fri, 11 May 2012 13:50:30 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=302</guid>
		<description><![CDATA[Once upon a time there were three little pigs who were all grown up and ready to strike out on their own. As they left their childhood home, their dear old mother warned them to look out for the Big Bad Wolf, who was at large in the area and hungry for little pig meat. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=302&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Once upon a time there were three little pigs who were all grown up and ready to strike out on their own. As they left their childhood home, their dear old mother warned them to look out for the Big Bad Wolf, who was at large in the area and hungry for little pig meat.</p>
<p>The first little pig was lazy and frivolous, so he built his house out of straw. When the Big Bad Wolf arrived, he huffed and he puffed and he blew the house down, and ate the little pig, because this is the Grimm version.</p>
<p>The second little pig was very serious, so he decided to engage a large consultancy firm to handle the building of his house for him. The consultancy firm assigned four of their best Big Fat Pigs to the project, and they scheduled a very expensive meeting with the little pig to discuss requirements. The little pig told them he wanted a nice, comfortable house with modern conveniences which would keep the Big Bad Wolf at bay. The Big Fat Pigs told the little pig that he should plan ahead more, and recommended that he build a large skyscraper in case he ever decided to run a multi-national corporation from the house. The little pig worried that this would be expensive, but the big fat pigs assured him that costs would be kept down by using cost-effective materials and off-shoring the actual building of the skyscraper. The little pig didn&#8217;t really understand much about building houses, and the big fat pigs seemed to be very clever and had lots of experience, so he signed a very long contract and waited for his skyscraper. Two months later the Big Fat Pigs came back to tell the little pig that they had had a pre-pre-meeting meeting meeting, and had clearly defined an early draft of the project plan. In only eight months they would have the final draft of The Plan, and would be ready to select an architect, who would then submit three different designs for the skyscraper along with thousands of pages of documentation detailing the wolf-proofing measures, so the little pig could be absolutely sure he was going to get the very bestest skyscraper that had ever been built. The Big Fat Pigs had a Gantt chart that covered three years and 142 participants and stakeholders, all with clearly defined activities and responsibilities so they knew exactly where they would be and what they would be doing at any time over the three year project. The Gantt chart was printed in colour on A0 paper and everything.</p>
<p>Sadly, the little pig never got to see the beautiful Gantt chart, because he had been eaten by the Big Bad Wolf. Luckily for the Big Fat Pigs, a clause in the contract he had signed meant that the project could continue in spite of his death, so they carried on. Nine years later, as the final prefabricated part of the skyscraper was fitted for the seventh time (because the previous six parts had not fitted correctly when they arrived from the land far away), the entire skyscraper collapsed because, it turned out, it had been built from substandard parts made from cheap materials in several different countries by unqualified workers who were working from different versions of the design document, which was two thousand pages long. Oh, and somebody had forgotten to dig the foundations, but by the time this was noticed, it was too late to do anything about it, so a complicated system of tensile steel cables and tent pegs was added to the base of the skyscraper to stop it falling over. </p>
<p>(The Big Fat Pigs were very surprised when the tent pegs didn&#8217;t work, despite the fact that they had used the same idea on every project they&#8217;d ever done and it had never worked. They thought maybe it would work next time, if they incorporated the learnings from this project.)</p>
<p>The local council insisted that the little pig&#8217;s family clean up the mess that the collapsing skyscraper had created, and make good the damage to neighbouring properties. The Big Fat Pigs put in a tender for the clean-up project, and got it. That was four years ago. The rusting remains of the skyscraper are still where they landed; the Big Fat Pigs have succeeded in designing a new system for reporting on the progress of the clean-up operation, and are currently waiting for executive approval so that they can move on to the pseudo code stage.</p>
<p>The third little pig hired a really smart architect, who knew a very good builder. The little pig told them he needed a house to protect him from the wolf, so the architect drew up a simple, strong design and the builder built it. After he had moved in, the little pig wanted some improvements, so he went back to the architect and the builder to ask for them. Because the house was very simple, and the builder had built it properly, they were able to make the new improvements quickly and easily, and the third little pig lived happily ever after.</p>
<p>THE END</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/302/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/302/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/302/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/302/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/302/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/302/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/302/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/302/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=302&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/05/11/the-three-little-pigs-redux/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>&#8220;Pity&#8221;, ninjas, and how not to suck</title>
		<link>http://blog.markrendle.net/2012/04/23/pity-ninjas-and-how-not-to-suck/</link>
		<comments>http://blog.markrendle.net/2012/04/23/pity-ninjas-and-how-not-to-suck/#comments</comments>
		<pubDate>Mon, 23 Apr 2012 15:30:13 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[meta]]></category>
		<category><![CDATA[professional]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[501 developers]]></category>
		<category><![CDATA[craftsmanship]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=296</guid>
		<description><![CDATA[TL;DR Another post giving the 501 Developer Manifesto more attention than it deserves. I honestly wouldn’t waste my time reading it if I were you. … Why are you still here? If you’ve seriously got nothing better to do than read this, I pity you. I really, really pity you. Because you’re pitiable. “Pity” is [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=296&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h3>TL;DR</h3>
<p><em>Another post giving the </em><a href="http://501manifesto.org/" target="_blank"><em>501 Developer Manifesto</em></a><em> more attention than it deserves. I honestly wouldn’t waste my time reading it if I were you.</em></p>
<p><em>…</em></p>
<p><em>Why are you still here? If you’ve seriously got nothing better to do than read this, I pity you. I really, really pity you. Because you’re </em><a href="http://thesaurus.com/browse/pitiable" target="_blank"><em>pitiable</em></a><em>.</em></p>
<h3>“Pity” is a derogatory word</h3>
<p>Let’s get this one out of the way for a start. There’s a reason why “I don’t want your pity” is one of the hallmark clichés of badly written dialogue. If there is <a href="http://501manifesto.org/" target="_blank">probably some pity in</a> your attitude toward someone, it implies that you feel lucky not to be that person; that their situation is deficient in some way that yours is not. If you are making specific reference to an aspect of that someone’s life that they consider important and special and even defining, then you shouldn’t be surprised when they are insulted, and <a href="http://news.ycombinator.com/item?id=3854565" target="_blank">paraphrase Fight Club in Hacker News comments</a>.</p>
<h3>A clarification of terms</h3>
<p>I shouldn’t really need to write this, as <a href="http://www.hanselman.com/blog/501DevelopersFamilyAndExcitementAboutTheCraft.aspx" target="_blank">this post on Scott Hanselman’s blog</a> (the first link on the 501 Manifesto page) explains very clearly what is intended by the epithet “501 developer”. It has nothing to do with what time you leave work, or how hard you work while you are there. Being a 501 developer means that you have no great enthusiasm for your work; no desire to learn new and interesting things; no ambition within your chosen career. It means you’re probably just grinding the levels until you get to a better-paid management role, which you will then carry out very badly because you don’t really understand thing one about software development.</p>
<p><em>If you:</em></p>
<ul>
<li><em>Never read technical blogs</em></li>
<li><em>Are not aware of open source projects (unless they’re forced on you at work)</em></li>
<li><em>Have never attended any kind of developer-focused event</em></li>
<li><em>Don’t own any books about coding or productivity</em></li>
<li><em>Aren’t quite sure why Github is called Github</em></li>
<li><em>Couldn’t* care less about trying to be better at your job</em></li>
</ul>
<p><em>…then you are a 501 developer, and no, we don’t respect you for it. If you do <strong>any</strong> of those things, you’re not a 501 developer, regardless of what time you leave work, and I respect you as a professional and as a human being.</em></p>
<p><em><font size="1">*Yes, Americans, the term is “couldn’t care less”. “I could care less” means “I care”.</font></em></p>
<p>It is perfectly possible to arrive at work at 9am, leave work at 5 or 5:30pm, and yet still read blogs and discuss software development on the internet and follow internet-famous software people Twitter and go to your local user group when there’s a speaker talking about something that interests you and read <a href="http://www.amazon.co.uk/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" target="_blank"><em>Clean Code</em></a><em> </em>and maybe do a little bit of extra-curricular coding with something new, and still spend plenty of time with your family and <a href="http://501manifesto.org/blog/?p=18" target="_blank">your Moog synthesiser and collection of blank cassette tapes</a>. </p>
<p>That’s the real issue here, is that by taking the time to register a domain and create a web page and attach a blog to it, and by linking to <a href="http://www.hanselman.com/blog/" target="_blank">Computer Zen</a> and <a href="http://www.codinghorror.com/blog/" target="_blank">Coding Horror</a> and making apparent his knowledge of the Agile manifesto, the author of the 501 manifesto has identified himself as anything but a 501 developer. Maybe the problem is that he’s lucky enough to have never worked with an actual 501 developer, in a massive room full of 501 developers for a 501 company in a 501 vertical market, so he doesn’t understand just how bad it can be.</p>
<p>Because you don’t have to be obsessive about it. You don’t have to self-identify as a ninja or a rock-star or a temporally-displaced Olympian demi-god (no? Just me then*). You don’t have to <em>write</em> the blogs, or <em>speak</em> at the user groups, or <em>write</em> the books, or <em>make</em> the next big thing to avoid being classified 501 (but the people who do those things would prefer it if you didn’t make fun of them for it). You just need to care, just a little bit, that’s all.</p>
<p><em><font size="1">*Irony, dipshit.</font></em></p>
<h3>One last thing</h3>
<p>If you do have an obsession, and it’s not your job, what are you doing to rectify that situation? Because if you have one all-consuming passion and it’s not what you do all day, every day, and the thing that you <em>do</em> do all day every day keeps you from that passion, that sucks.</p>
<p>It sucks to be in that situation. And you can write a manifesto and you can think you’re “taking back the word” and you can convince yourself the people you work with who love what they’re doing and can’t believe somebody’s paying them to do it are pitiable, but at the end of the day you’re the one being kept from doing the thing you really love by having to do something you merely tolerate because you have two kids and an oppressive mortgage.</p>
<blockquote class="twitter-tweet tw-align-center"><p><a href="https://twitter.com/search/%2523501manifesto">#501manifesto</a>? Here&#8217;s a better idea: Find a job you love and you&#8217;ll never work a day in your life.</p>
<p>— Mark Rendle (@markrendle) <a href="https://twitter.com/markrendle/status/192337415048925184">April 17, 2012</a></p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/296/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=296&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/04/23/pity-ninjas-and-how-not-to-suck/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>My ideal laptop</title>
		<link>http://blog.markrendle.net/2012/03/18/my-ideal-laptop/</link>
		<comments>http://blog.markrendle.net/2012/03/18/my-ideal-laptop/#comments</comments>
		<pubDate>Sun, 18 Mar 2012 20:29:00 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[meta]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=284</guid>
		<description><![CDATA[In which I want the moon on a stick, I do. As I browse around fantasy-laptop-shopping, I see lots of laptops which have features that I really, really want, but I’ve never found one laptop that has everything. So I’m going to outline the spec I want, comprised entirely of things that are either available [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=284&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em>In which I want the moon on a stick, I do.</em></p>
<p>As I browse around fantasy-laptop-shopping, I see lots of laptops which have features that I really, really want, but I’ve never found one laptop that has everything. So I’m going to outline the spec I want, comprised entirely of things that are either available in current laptops or, at least, announced and imminent parts.</p>
<p>Currently I have a late-2009 15” MacBook Pro, which has a 2.53Ghz Core 2 Duo CPU, and has been upgraded with 8GB of RAM and a 512GB Crucial m4 SSD. I also have access to a 17” HP Envy, on loan from my last employer while I am doing some freelance work for them.</p>
<p>I do most of my own development, including open source stuff and some speculative projects, on the MacBook, using Parallels 7 to virtualise Windows 7, because when I had it running under Snow Leopard’s Boot Camp it kept blue-screening at inopportune moments. Like five minutes from the end of my presentation at DDD SouthWest 2011.</p>
<p>The MacBook also gets used for most of my speaking engagements, although I have been known to use the Envy when I’m talking about Azure because I’m not sure about running the Azure Emulator inside an emulator.</p>
<h2>The Spec</h2>
<h2></h2>
<h1></h1>
<h3>Form factor</h3>
<p>I’m happy with the size and weight of the MacBook Pro, although obviously thinner and lighter is always welcome. <a href="http://techland.time.com/2012/03/16/rumor-that-air-style-macbook-pro-youve-been-hearing-about-its-in-production/" target="_blank">Remains to be seen whether those Air-style MacBook Pro rumours are true or not</a>. The other good thing about Macs is their small, light power supplies. The brick that comes with the Envy seems to weigh almost as much as the laptop itself, and it insists on you dragging the three-pronged not-quite-a-kettle lead around too. It all adds to the mass and bulk, especially on long trips to overseas conferences. Just make it as thin and light as you can; whatever it adds to the cost I’ll easily make up in savings on chiropractic bills.</p>
<h3>CPU</h3>
<p>I’m running Visual Studio 2010 and 2011, plus SQL Server 2008 R2 and 2012 and IIS 7.5 or IIS 8 running as services, and emulators for Azure and Windows Phone and VMs for Linux and suchlike, and a whole bunch of other cool beta stuff because I’m an incurable neophile, so I want a beefy CPU. I’m thinking <a href="http://www.cpu-world.com/CPUs/Core_i7/Intel-Core%20i7-3820QM%20(PGA)%20Mobile%20processor.html" target="_blank">Intel Core i7-3820QM</a>, which is supposed to be available next month and is based on the new 22nm Ivy Bridge architecture. Shouldn’t be too much of a problem to get that.</p>
<h3>Hard disk</h3>
<p>Needs to be solid-state, obviously. In pure fantasy-land, I’d have a pair of 512GB SSDs set up in RAID/0, but I’d settle for one 512GB SSD (which I already own) and a 750GB Seagate Momentus XT secondary drive. So two drive bays, obviously.</p>
<p>Before we move on, let me just suggest one extra thing: can I get an easily-accessible HDD/SDD caddy system for the primary drive (maybe a bit like a PCMCIA), so I can switch between operating systems by swapping drives? That would be <em>awesome</em>.</p>
<h3>Memory</h3>
<p>The <a href="http://www.lenovo.com/products/us/laptop/thinkpad/w-series/index.html" target="_blank">Lenovo ThinkPad W520</a> is the existing example here: you can spec that up with 32GB of RAM. That should do it. But can I please have that in a laptop that weighs less than <a href="http://hypertextbook.com/facts/2006/DmitriyGekhman.shtml" target="_blank">my head</a>? And a tip: if adding 24GB of RAM to your default 8GB spec in your “Configure your laptop” page costs more than buying 32GB of compatible RAM from Crucial, guess which I’m going to do? Yeah.</p>
<h3>GPU</h3>
<p>I don’t play games on PC, because I have an Xbox 360 and a PS3 and a Wii and a DS and a PS Vita so I’m really OK for that stuff. But there are other uses for GPUs these days: I want to play with <a href="http://channel9.msdn.com/Blogs/Charles/C-AMP-Daniel-Moth-Overview" target="_blank">C++ AMP</a>, and make backups of my Blu-ray and DVD discs, which takes much less time when you’ve got a few CUDA cores kicking around. So I’d like an nVidia GPU, preferably one of the <a href="http://uk.geforce.com/hardware/notebook-gpus/geforce-gt-555m/specifications" target="_blank">500M</a> series, although I’d accept an <a href="http://www.nvidia.co.uk/object/notebook-nvs-uk.html" target="_blank">NVS 4200M</a> (which appears to be the new Quadro). Obviously the GPU should be switchable, so it can fall back to the integrated graphics in the CPU when running unplugged.</p>
<p>Update: <a href="http://arstechnica.com/author/peter-bright/" target="_blank">Peter Bright</a> has pointed out that <a href="http://www.tomshardware.com/reviews/sandy-bridge-core-i7-2600k-core-i5-2500k,2833-5.html" target="_blank">Quick Sync is better than GPU for video encoding/transcoding</a>, which is true. I still want a GPU for playing with C++ AMP, though.</p>
<h3></h3>
<h3>Screen</h3>
<p><a title="MacRumors: Apple to Launch 2880x1800 Resolution 'Retina Display' MacBook Pro in Q2 2012?" href="http://www.macrumors.com/2011/12/14/apple-to-launch-2880x1800-resolution-retina-display-macbook-pro-in-q2-2012/" target="_blank">One of these, please.</a> 15”, and 16:10 (or 8:5) format. 16:9 is all very well for watching movies, but when you’re working on text, that extra height is really nice to have. Oh, and make it multi-touch with <a href="http://www.engadget.com/2012/01/10/corning-gorilla-glass-2-hands-on-video/" target="_blank">Gorilla Glass 2</a> while you’re at it. Ta.</p>
<h3></h3>
<h3>Keyboard</h3>
<p>A nice, backlit, chiclet keyboard, obviously. With a physical Insert key, because I use ReSharper and there’s a ton of neat things hiding under the Alt-Ins keyboard shortcut. Oh, and if you’re Apple, put bloody # on a key already. Seriously.</p>
<p>If you want to do the <a title="Warning: this page makes noise." href="http://www.razerzone.com/blade#/switchblade-ui" target="_blank">Razer</a> thing and bung some programmable OLED keys on there, that would be awesome, but stick them on the top row, not to one side where I’ll keep hitting them instead of Esc or Ctrl or Backspace.</p>
<h3>Track-pad</h3>
<p>A decent track-pad, which goes *click* when you click it, is essential, and it should support gestures like two-finger scrolling and… actually, just two-finger scrolling would be fine. Yes, I know the screen is touch, but it’s <em>all the way over there</em>; I can’t be reaching for that all the time. Again, Apple is the exemplar here.</p>
<h3>Connectivity</h3>
<p>A built-in VGA output would be useful for attaching to all those 1024&#215;768 projectors, but stick a Mini DisplayPort on there too, like HP have done on my Envy.</p>
<p>A decent set of USB 3.0 ports (at least two), maybe with a couple of 2.0 for keyboard and mouse.</p>
<p>Really good WiFi is more important than a physical Ethernet port, and frankly, I’m not that fussed about being able to fit a 3G SIM until I can find a carrier who will give me multiple SIMs for the same account/allowance. Until that frabjous day, I will make do with my MiFi thing. Bluetooth, though, I need Bluetooth for communicating with the Lego Mindstorms robots.</p>
<p>Personally, I don’t care whether it’s got an SD/XD/CF/BS slot or not, but people seem to like them, so I have no objection to there being one. Put one on, or don’t, it’s all good. Its presence, or lack thereof, is not going to stop me buying this thing, is what I’m saying.</p>
<h3>Docking station</h3>
<p>Now, what you could do here, Mr/Ms Laptop Manufacturer, is take a leaf out of Sony’s Vaio Z book and offer an optical-cable-connected docking station which has got a full desktop GPU in it and can drive 3 monitors. But for preference, make it an nVidia GPU. If you can do that, then the on-board graphics can be the NVS chip.</p>
<h3></h3>
<h3>Optical drive</h3>
<p>Yeah, <a href="http://blog.markrendle.net/2011/11/21/im-going-100percen-digital-in-2012/" target="_blank">no</a>.</p>
<h3>In summary, then:</h3>
<p>I want the moon on a stick. But if you build the moon on a stick, I will buy it, and so will others like me. And there are enough like me to justify building this. So go on. What are you waiting for?</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/284/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=284&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/03/18/my-ideal-laptop/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Learn Simple.Data &amp; Nancy at SkillsMatter</title>
		<link>http://blog.markrendle.net/2012/02/17/learn-simple-data-nancy-at-skillsmatter/</link>
		<comments>http://blog.markrendle.net/2012/02/17/learn-simple-data-nancy-at-skillsmatter/#comments</comments>
		<pubDate>Fri, 17 Feb 2012 11:36:46 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Nancy]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[Training]]></category>
		<category><![CDATA[nancyfx]]></category>
		<category><![CDATA[simpledata]]></category>
		<category><![CDATA[skillsmatter]]></category>
		<category><![CDATA[training]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=275</guid>
		<description><![CDATA[I should have blogged about this ages ago, but I’ve been unbelievably busy. Still, better late-but-not-too-late than never-or-not-soon-enough. Following the well-received half-day Introduction to Nancy and Simple.Data that I presented with Steven Robbins (@Grumpydev) at the Progressive .NET Tutorials 2011, Wendy at SkillsMatter approached me and asked if I’d be interested in doing a full [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=275&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I should have blogged about this ages ago, but I’ve been unbelievably busy. Still, better late-but-not-too-late than never-or-not-soon-enough.</p>
<p>Following the well-received half-day <a href="http://skillsmatter.com/podcast/open-source-dot-net/introduction-to-nancy-and-simple-data">Introduction to Nancy and Simple.Data</a> that I presented with Steven Robbins (<a href="https://twitter.com/#!/Grumpydev">@Grumpydev</a>) at the Progressive .NET Tutorials 2011, Wendy at <a href="http://skillsmatter.com/">SkillsMatter</a> approached me and asked if I’d be interested in doing a full two-day course. I’ve always been very impressed with the courses they offer, so I jumped at the chance to get involved. So you can now sign up for <a href="http://skillsmatter.com/course/open-source-dot-net/mark-rendles-web-app-development-with-nancy-and-simple-data">a full-on, two day deep dive into building web applications with minimal code</a>.</p>
<p>The course will quickly cover the basics, such as View Engines, Dependency Injection, Nancy’s TDD/BDD test helpers and Simple.Data’s built-in data mocking functionality, then move on to more interesting things like: security, authentication (including OAuth) and authorisation; building RESTful web APIs (<a href="http://kellabyte.com/2011/09/04/clarifying-rest/">proper ones, not just HTTP web services</a>); using different data stores with Simple.Data; and different methods for validating data.</p>
<p>It’ll be a heavily interactive couple of days. You can either turn up with an idea for a web application that you want to get started on, or you can work on an app I’ve designed to exercise the skills you’ll be learning. Either way, at the end of the course, that code is yours to take away and use as a starting-off point or a useful reference.</p>
<p>The first instance of the course is on the 12th and 13th of March, and there are still places available. Lots of places. All of them, in fact. So <a href="https://skillsmatter.com/register-online/course/2429">go sign up for it</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/275/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=275&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/02/17/learn-simple-data-nancy-at-skillsmatter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Simple.Data 1.0.0-beta1</title>
		<link>http://blog.markrendle.net/2012/02/16/simple-data-1-0-0-beta1/</link>
		<comments>http://blog.markrendle.net/2012/02/16/simple-data-1-0-0-beta1/#comments</comments>
		<pubDate>Thu, 16 Feb 2012 22:23:02 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[simpledata]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=266</guid>
		<description><![CDATA[At last It’s taken me so much longer to get here than I originally expected, but I’ve released the first 1.0 beta version of Simple.Data. If this post is the first you’ve heard of Simple.Data, then head over to the GitHub page and browse back through previous posts to find out more. New features I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=266&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h2>At last</h2>
<p>It’s taken me so much longer to get here than I originally expected, but I’ve released the first 1.0 beta version of Simple.Data.</p>
<p>If this post is the first you’ve heard of Simple.Data, then head over to <a href="http://github.com/markrendle/simple.data">the GitHub page</a> and browse back through previous posts to find out more.</p>
<h2>New features</h2>
<p>I didn’t do a post for the 0.14 release, so I’ll cover the changes from that as well as what’s new in the 1.0 beta.</p>
<h3>Eager-loading with With</h3>
<p>Since very early on, Simple.Data has supported lazy-loading when you reference a joined property from the dynamic record type. There were two issues with that: firstly, if you assigned the record to a static type, the joined properties were not hydrated; secondly, multiple selects do not make DBAs happy, and should be avoided if possible.</p>
<p>Now you can use the <strong>With</strong> method to load the joined data at the same time as the main record.</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:#2b91af;">Customer </span>actual = db.Customers.FindAllByCustomerId(1).WithOrders().FirstOrDefault();
</pre>
<p>This uses a single SQL select statement to pull all the Customer rows, plus the Order detail rows, and groups the data in-memory; generally, that’s more efficient than running two select operations. When the record is converted to the Customer type, it sets the ICollection&lt;Order&gt; property at the same time, either creating a new instance of List&lt;Order&gt;, or populating an existing instance if the property is readonly.</p>
<p>The inverse works too:</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:#2b91af;">Order </span>actual = db.Orders.FindAllByOrderId(1).WithCustomer().FirstOrDefault();
</pre>
<p>If the property name is not the same as the database table name, you can use an alias to tweak it:</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:blue;">var </span>actual = db.Orders.FindAllByOrderId(1).With(db.Orders.OrderItems.As("Items"));
</pre>
<p>And if there’s no referential integrity in the database, you can specify an explicit join separately:</p>
<pre class="code"><span style="color:blue;">dynamic </span>manager;
<span style="color:blue;">var </span>q = _db.Employees.All()
    .OuterJoin(_db.Employees.As(<span style="color:#a31515;">"Manager"</span>), <span style="color:blue;">out </span>manager)
    .On(Id: _db.Employees.ManagerId)
    .With(manager);
</pre>
<p>&nbsp;</p>
<p>(Oh, yeah, and check out the <strong>OuterJoin</strong> method. Finally.)</p>
<p>Of course, if there’s no referential integrity, it’s hard for Simple.Data to work out whether the joined property is a collection or a complex object, so you can specify <strong>WithOne</strong> or <strong>WithMany</strong> to help it out:</p>
<pre class="code"><span style="color:blue;">dynamic </span>manager;
<span style="color:blue;">var </span>q = _db.Employees.All()
    .OuterJoin(_db.Employees.As(<span style="color:#a31515;">"Manager"</span>), <span style="color:blue;">out </span>manager)
    .On(Id: _db.Employees.ManagerId)
    .WithOne(manager);
</pre>
<p>&nbsp;</p>
<p>And of course, you can mix and match all these. This test gives you a good idea of some of the heavy lifting that’s going on for you with this feature, just with the SQL:</p>
<pre class="code"><span style="color:blue;">public void </span>MultipleWithClauseJustDoesEverythingYouWouldHope()
{
    <span style="color:blue;">const string </span>expectedSql = 
        <span style="color:#a31515;">"select [dbo].[employee].[id],[dbo].[employee].[name]," </span>+
        <span style="color:#a31515;">"[dbo].[employee].[managerid],[dbo].[employee].[departmentid]," </span>+
        <span style="color:#a31515;">"[manager].[id] as [__withn__manager__id]," </span>+
        <span style="color:#a31515;">"[manager].[name] as [__withn__manager__name]," </span>+
        <span style="color:#a31515;">"[manager].[managerid] as [__withn__manager__managerid]," </span>+
        <span style="color:#a31515;">"[manager].[departmentid] as [__withn__manager__departmentid]," </span>+
        <span style="color:#a31515;">"[dbo].[department].[id] as [__with1__department__id]," </span>+
        <span style="color:#a31515;">"[dbo].[department].[name] as [__with1__department__name]" </span>+
        <span style="color:#a31515;">" from [dbo].[employee] left join [dbo].[employee] [manager] " </span>+
        <span style="color:#a31515;">"on ([manager].[id] = [dbo].[employee].[managerid])" </span>+
        <span style="color:#a31515;">" left join [dbo].[department] " </span>+
        <span style="color:#a31515;">"on ([dbo].[department].[id] = [dbo].[employee].[departmentid])"</span>;

    <span style="color:blue;">dynamic </span>manager;
    <span style="color:blue;">var </span>q = _db.Employees.All()
        .OuterJoin(_db.Employees.As(<span style="color:#a31515;">"Manager"</span>), <span style="color:blue;">out </span>manager)
        .On(Id: _db.Employees.ManagerId)
        .With(manager)
        .WithDepartment();

    GeneratedSqlIs(expectedSql);
}
</pre>
<p>(Never mind the logic involved in turning that result set into the correct in-memory object graphs.)</p>
<p>Now, this works on multi-record queries, but not on single-record ones such as FindById or the key-driven Get method, and that’s more problematic since those methods don’t return a query you can modify, just a record. In the past I did actually toy with having the SimpleRecord type do lazy self-evaluation, but the fact that the NUnit Assert.IsNull test wouldn’t accept that the object was null even when it swore black-was-blue that it was put me off. (It works for Nullable&lt;T&gt;; no fair.)</p>
<p>Instead of that, and this is only in the 1.0 beta release, you can specify your With clause before the Get or FindBy:</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:#2b91af;">Customer </span>actual = db.Customers.WithOrders().Get(1);
</pre>
<p>So now you get all that goodness for single records, where it’s arguably more useful anyway.</p>
<h3>Upsert</h3>
<p>Inserting and updating is all very well, but sometimes you’ve got some data and you just don’t know whether it’s in the database already or not. If it is, you want to update the row with some new values; if it’s not, you want to insert it. Boring.</p>
<p>To save you the time and trouble, Simple.Data now provides the <strong>Upsert</strong> method. Give it a record, and it will do all the checking to see if it exists or not. And in beta2, there’ll be back-end database-specific optimizations; for example, if you’re using the SQL Server provider with SQL 2008 or later, it will use the MERGE operation.</p>
<p>Upsert returns the record as it is in the database following the operation, with any database-specified values intact.</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:blue;">var </span>user = <span style="color:blue;">new </span><span style="color:#2b91af;">User </span>{Id = 2, Name = <span style="color:#a31515;">"Charlie"</span>, Password = <span style="color:#a31515;">"foobar"</span>, Age = 42};
<span style="color:blue;">var </span>actual = db.Users.Upsert(user);
</pre>
<p>&nbsp;</p>
<p>That’s one example, but there are plenty of other ways to use Upsert. Take a look at <a href="https://github.com/markrendle/Simple.Data/blob/master/Simple.Data.SqlTest/UpsertTests.cs">the tests</a> to see the others.</p>
<h2></h2>
<h2>NuGet and SemVer</h2>
<p>I’ve pushed this release to <a href="http://nuget.org/packages/simple.data.core">NuGet</a> using the <a href="http://semver.org">Semantic Version</a> number for pre-release (1.0.0-beta1), which NuGet added support for in 1.6. Using this form means that NuGet knows that it’s pre-release software, and you’ll have to explicitly tell it that that’s what you want. So to get the 1.0 beta releases, remember to use the –Pre flag for the Install-Package command. The great thing about this is that when we get to 1.0 RTW, I’ll start on 1.1.0-alpha1 and both package types will be available from the repository.</p>
<p>If you’re waiting for the Mono build, I hope to have it out as a tgz by the end of this weekend.</p>
<h2>What’s still to do?</h2>
<p>So with those two features, I’m drawing a temporary line in the sand and focusing on getting everything to release quality. That means implementing some optimizations around object creation and database tricks, but more importantly, working on test coverage, refactoring some messy code, and making <a href="http://simplefx.org/simpledata/docs">the documentation</a> comprehensive. Help on that last one would be much appreciated!</p>
<p>Come to that, if anybody wants to make a really nice website… <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/266/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=266&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/02/16/simple-data-1-0-0-beta1/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Mark Rendle, Freelance Consultant</title>
		<link>http://blog.markrendle.net/2012/01/13/mark-rendle-freelance-consultant/</link>
		<comments>http://blog.markrendle.net/2012/01/13/mark-rendle-freelance-consultant/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 14:12:10 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[consulting]]></category>
		<category><![CDATA[professional]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=237</guid>
		<description><![CDATA[As some of you may know, for some time I have been considering starting my own venture, and I’m pleased to announce that I’m taking the first step on this journey. Starting in March 2012 I will be reducing my commitment to my current employer, Dot Net Solutions, and spending the remainder of my time [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=237&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>As some of you may know, for some time I have been considering starting my own venture, and I’m pleased to announce that I’m taking the first step on this journey. Starting in March 2012 I will be reducing my commitment to my current employer, <a href="http://www.dotnetsolutions.co.uk/" target="_blank">Dot Net Solutions</a>, and spending the remainder of my time working as an independent software development consultant, focusing on both Cloud Computing and Software Quality. Work on a web site is underway, which will outline the full set of services I will be offering.</p>
<p>This does not, however, mark in any way an end to my relationship with Dot Net Solutions. I will remain in my current position as Principal Consultant and will continue to work closely on major projects and supporting Microsoft as an active member of the VTSP (Virtual Technology Specialist Program) performing consulting and conducting ADSs (Architecture Design Sessions).</p>
<p>From my perspective, there are things one cannot achieve as a singleton, and this continuing relationship will enable me to pursue potential work that would otherwise be out of reach.</p>
<p>Dot Net Solutions has been a great company to work for, and over the last two years they have been very supportive of my community and OSS work. I have learned a great deal, and I like to think that I have made a valuable contribution too. As a company, DNS are in an excellent position to grow this year and beyond, and I am very excited to remain part of that process.</p>
<p>If you would like to discuss what I can do for your project, team, or company, please use <a href="http://blog.markrendle.net/contact-me/">the Contact Me page</a> to get in touch.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/237/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=237&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/01/13/mark-rendle-freelance-consultant/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Eager-loading RFC</title>
		<link>http://blog.markrendle.net/2011/12/01/eager-loading-rfc/</link>
		<comments>http://blog.markrendle.net/2011/12/01/eager-loading-rfc/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 14:53:06 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=227</guid>
		<description><![CDATA[There are two more features I want to get into Simple.Data before releasing 1.0beta1: upserts, and eager loading. Upserts are pretty straight-forward, but there are a few different approaches to eager loading and I want to get some input from the community before I pick one. In case you don’t know, eager loading is a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=227&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There are two more features I want to get into Simple.Data before releasing 1.0beta1: <a href="http://en.wikipedia.org/wiki/Upsert">upserts</a>, and eager loading. Upserts are pretty straight-forward, but there are a few different approaches to eager loading and I want to get some input from the community before I pick one.</p>
<p>In case you don’t know, eager loading is a pattern for getting data from the database in an optimal fashion, with the minimum number of requests or least-possible server load. It’s the opposite of <a href="http://en.wikipedia.org/wiki/Lazy_loading">lazy loading</a>, which Simple.Data already does.</p>
<p>The implementation syntax will look like this:</p>
<pre class="code"><span style="color:blue;">    IEnumerable&lt;Customer&gt; </span>customers = _db.Customers.FindAllByRegion(<span style="color:#a31515;">"South"</span>)
                .With(_db.Customers.Orders)<br />                .Cast&lt;Customer&gt;();<br /></pre>
<p>This will create the customer objects and populate an <strong>ICollection&lt;Order&gt; Orders</strong> property in each one, assuming there is one.</p>
<p>There are two directions in which a class may have relationships with other classes: it may have “parent” (or “lookup”) classes, where there is at most a single instance of that parent class within the instance of the class in question; and it may have “child” classes, where there is a collection of instances of the child class. Eager loading of parent classes is trivial; you just add the necessary join(s) to the master table(s) and marshal the data into the right places in code.</p>
<p>Eager loading of child classes is similarly easy when there is only a single child collection to be loaded; you join to the detail table and then process the results so that a single instance of the main table row is created, and instances of the detail table rows are grouped into collections.</p>
<p>For example, loading user objects with a list of phone numbers:</p>
<p>SELECT User.Id, User.Name, Phone.Number<br />FROM User<br />LEFT JOIN Phone ON User.Id = Phone.UserId</p>
<p>Returned rows:</p>
<table border="1" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="133">User.Id</td>
<td valign="top" width="133">User.Name</td>
<td valign="top" width="133">Phone.Number</td>
</tr>
<tr>
<td valign="top" width="133">1</td>
<td valign="top" width="133">Alice</td>
<td valign="top" width="133">0123456789</td>
</tr>
<tr>
<td valign="top" width="133">1</td>
<td valign="top" width="133">Alice</td>
<td valign="top" width="133">0738473284</td>
</tr>
<tr>
<td valign="top" width="133">2</td>
<td valign="top" width="133">Bob</td>
<td valign="top" width="133">0129934845</td>
</tr>
<tr>
<td valign="top" width="133">2</td>
<td valign="top" width="133">Bob</td>
<td valign="top" width="133">0729478594</td>
</tr>
</tbody>
</table>
<p>From this we create a User object for Alice with her two phone numbers, and an object for Bob with his. Even if there are a lot of rows in the detail table, this is still the preferred way of handling eager loading for this scenario as it involves the fewest round-trips to the database. Often, you can handle a parent-child-child relationship using this algorithm, too, although beyond that point you’re getting a bit scary.</p>
<p>The complexity arises when you want to load two unrelated child collections, say, load Customers with their Invoices and Orders:</p>
<p>SELECT Customer.*, Invoice.*, Order.*<br />FROM Customer<br />LEFT JOIN Invoice ON Customer.Id = Invoice.CustomerId<br />LEFT JOIN Order ON Customer.Id = Order.CustomerId</p>
<p>This creates what is technically called an “outer <a href="http://db.grussell.org/section010.html#_Toc67114480">Cartesian product</a>”, where a row is returned for every possible combination of the rows from the two outer-joined tables. So if you’re grabbing the details for a single valuable customer who has placed a thousand orders and generated a thousand invoices, you get a million rows back from the database. I have a hunch this might not be optimal.</p>
<p>So this is my <a href="http://en.wikipedia.org/wiki/Request_for_Comments">Request for Comments</a>: what would you like to see done here?</p>
<p>The options are:</p>
<ol>
<li>Only allow one detail-table With clause to be specified per query. Throw an exception if there is more than one.</li>
<li>Allow multiple detail-table With clauses, and use additional SELECT operations for all except the first.</li>
<li>Add a parameter to the With method <em>allowing</em> the developer to specify the technique on a per-detail-table basis:</li>
<pre class="code"><span style="color:blue;">    var </span>customers = _db.Customers.FindAllByRegion(<span style="color:#a31515;">"South"</span>)
                .With(_db.Customers.Orders, <span style="color:#2b91af;">WithUsing</span>.Join)
                .With(_db.Customers.Orders.Items, <span style="color:#2b91af;">WithUsing</span>.Join)
                .With(_db.Customers.Invoices, <span style="color:#2b91af;">WithUsing</span>.ExtraQuery);
</pre>
<p>If only one detail table is specified, or one detail with a detail below it (e.g. _db.Customers.Orders.Items), the default behaviour when no <strong>WithUsing</strong> parameter is supplied will be to use JOIN. Multiple detail tables without a <strong>WithUsing</strong> will cause the ADO adapter to throw an exception (other adapters, such as <a href="https://github.com/craiggwilson/Simple.Data.MongoDB">the one for MongoDB</a>, can use the With clause as they see fit).</ol>
<p>I think I’ve <a href="http://c2.com/cgi/wiki?RubberDucking">rubber ducked</a> here a bit, as Option 3 is looking like a no-brainer, but I’ve typed it all now, so if you do have any comments or suggestions, please do leave them below. I’m planning on starting code for this on Sunday morning, so there’s plenty of time to change my mind.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/227/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=227&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/12/01/eager-loading-rfc/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Yes, Simple.Data protects against SQL Injection</title>
		<link>http://blog.markrendle.net/2011/12/01/yes-simple-data-protects-against-sql-injection/</link>
		<comments>http://blog.markrendle.net/2011/12/01/yes-simple-data-protects-against-sql-injection/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 12:24:35 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=225</guid>
		<description><![CDATA[Several people who weren’t following the show at the inception of Simple.Data have asked whether it does anything to prevent SQL Injection attacks. Those of you who remember the start of the project will understand why I’m kind of amused by the question. I originally built Simple.Data as a proof-of-concept when there was a big [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=225&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Several people who weren’t following the show at the inception of Simple.Data have asked whether it does anything to prevent <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL Injection</a> attacks. Those of you who remember the start of the project will understand why I’m kind of amused by the question.</p>
<p>I originally built Simple.Data as a proof-of-concept when there was a big web-scuffle over what was then called Microsoft.Data (now <a href="http://msdn.microsoft.com/en-us/library/webmatrix.data%28v=vs.99%29.aspx">WebMatrix.Data</a>). <a href="http://weblogs.asp.net/davidfowler/default.aspx">David Fowler</a>, a developer I have since come to <a href="http://www.codeplex.com/site/users/view/dfowler">respect</a> <a href="https://github.com/SignalR/SignalR">greatly</a>, posted an example on his blog which used concatenated SQL, and everybody lined up to tear him a new one. I’m a big fan of code over cockfights, so I had a go at implementing a simple data access library which made SQL Injection impossible by eliminating SQL strings. Thus Simple.Data. You told it what you wanted, and provided the necessary values, and then it wrapped them safely up in parameters and executed them. I stuck it on <a href="http://github.com/markrendle/Simple.Data">GitHub</a>, and <a href="http://blog.markrendle.net/2010/08/05/introducing-simple-data/">posted about it on my blog</a>.</p>
<p>(In fact, the first version did allow you to execute SQL strings, much like Dapper and Massive, because the functionality was extremely limited otherwise. As I’ve iterated on it, I’ve been able to expose nearly all the required functionality using the dynamic approach, so the only way you can execute SQL directly now is by getting an IDbConnection object from the AdoAdapter and using ADO.NET against it.)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/225/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=225&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/12/01/yes-simple-data-protects-against-sql-injection/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Macro-optimisations</title>
		<link>http://blog.markrendle.net/2011/12/01/macro-optimisations/</link>
		<comments>http://blog.markrendle.net/2011/12/01/macro-optimisations/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 00:36:23 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=210</guid>
		<description><![CDATA[I&#8217;ve used Simple.Data in a few production projects now (and it&#8217;s doing a great job so far). It&#8217;s not often you actually get to use the software that you write, but when you do, it&#8217;s a great opportunity to see it through users&#8217; eyes, and I&#8217;ve made a few changes and improvements over the past [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=210&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve used Simple.Data in a few production projects now (and it&#8217;s doing a great job so far). It&#8217;s not often you actually get to use the software that you write, but when you do, it&#8217;s a great opportunity to see it through users&#8217; eyes, and I&#8217;ve made a few changes and improvements over the past year as a result.</p>
<p>The most recent project that we&#8217;ve used it on at Dot Net Solutions is the Met Office open data thing that was announced on Tuesday. And that forced me to bring forward an optimisation that&#8217;s been way down my to-do list, partly because I didn&#8217;t really just how much of an optimisation it would be.</p>
<p>The Met Office project involves inserting something like 8 million records a day into a SQL Azure database, which isn&#8217;t a huge amount, but enough to need you to be smart about how you do it. The version of Simple.Data that was on NuGet when we started supported bulk inserts, but it wasn&#8217;t friendly to the error handling we needed and it assumed it needed to return the inserted records, doing that whole &#8216;select just-inserted-record&#8217; thing, which is often completely unnecessary.</p>
<p><em>(So it turns out that when you&#8217;re handling TryInvokeMember in a DynamicObject, you can actually find out whether the return value is used by the caller, and not bother if it isn&#8217;t. But that&#8217;s another blog post.)</em></p>
<p>Anyway, I tweaked a couple of things and shaved off a fraction of the time it was taking, but it was a small fraction, and things were still far too slow. So we did what we should have done in the first place, and used <a href="http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx" target="_blank">SqlBulkCopy</a>.</p>
<p>If you haven&#8217;t used this (SqlClient-specific) method, you should read up on it and keep it in your mental list of &#8220;things that are good that I might need some day&#8221;. It lets you prepare a big batch of rows in a DataTable (turns out they&#8217;re still good for something) and then insert them in a single operation, and man, it&#8217;s quick.</p>
<p>But it&#8217;s SQL Server specific, so I couldn&#8217;t support it in the generic ADO adapter code.</p>
<p>I&#8217;ve exposed a few interfaces in the Simple.Data.Ado assembly which providers can optionally implement if they need to do something a little differently or can do something better. The first instance was ICustomInserter, which is implemented in the Oracle provider to handle fetch-backs in a world without IDENTITY columns. Since then I&#8217;ve added more as I went along, and IBulkInserter was one of them because, as I said earlier, I had half a mind to implement this. And now I have.</p>
<p>Anyway, I&#8217;ll stop blathering now and just post the comparison code I wrote (measures time to insert 10,000 records, five times) and the before and after results.</p>
<p><strong>Code:</strong></p>
<p><pre class="brush: csharp;">
namespace BulkInsertComparison
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using Simple.Data;

    class Program
    {
        static void Main(string[] args)
        {
            var db = Database.OpenConnection(&quot;data source=.;initial catalog=BulkInsertTest;integrated security=true&quot;);

            for (int i = 0; i &lt; 5; i++)
            {
                Console.WriteLine(TimeInsert(db));
            }
        }

        private static TimeSpan TimeInsert(dynamic db)
        {
            var stopwatch = Stopwatch.StartNew();
            db.Target.Insert(GenerateItems(10000));
            stopwatch.Stop();
            return stopwatch.Elapsed;
        }

        static IEnumerable&lt;Item&gt; GenerateItems(int number)
        {
            for (int i = 0; i &lt; number; i++)
            {
                var guid = Guid.NewGuid();
                yield return new Item(0, guid, guid.ToString(&quot;N&quot;));
            }
        }
    }

    class Item
    {
        private readonly int _id;
        private readonly Guid _guid;
        private readonly string _text;

        public Item(int id, Guid guid, string text)
        {
            _id = id;
            _guid = guid;
            _text = text;
        }

        public string Text { get { return _text; } }
        public Guid Guid { get { return _guid; } }
        public int Id { get { return _id; } }
    }
}
</pre></p>
<p><strong>Before:</strong></p>
<pre>00:00:16.9799819
00:00:17.1971797
00:00:18.0744958
00:00:19.1514537
00:00:17.3798541</pre>
<p><strong>After:</strong></p>
<pre>00:00:00.4616911 (First run includes MEFing IBulkInserter)
00:00:00.2757802
00:00:00.2852119
00:00:00.2504587
00:00:00.2453277</pre>
<p>Totally worth it.</p>
<p>0.12.2 on NuGet now. <em>Mini-roadmap: eager-loading (0.14) and upserts (0.15).</em></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/210/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&#038;blog=16759552&#038;post=210&#038;subd=markrendle&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/12/01/macro-optimisations/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
	</channel>
</rss>
