<?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>Jonathan George&#039;s Blog &#187; nhibernate</title>
	<atom:link href="http://jonathangeorge.co.uk/tag/nhibernate/feed/" rel="self" type="application/rss+xml" />
	<link>http://jonathangeorge.co.uk</link>
	<description>True confessions of a technical architect</description>
	<lastBuildDate>Fri, 30 Sep 2011 07:28:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='jonathangeorge.co.uk' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/c6670528bd320dfa4e609e09f50e5df4?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Jonathan George&#039;s Blog &#187; nhibernate</title>
		<link>http://jonathangeorge.co.uk</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://jonathangeorge.co.uk/osd.xml" title="Jonathan George&#039;s Blog" />
	<atom:link rel='hub' href='http://jonathangeorge.co.uk/?pushpress=hub'/>
		<item>
		<title>Introducing Who Can Help Me? &#8211; A S#arp Architecture Demo Site</title>
		<link>http://jonathangeorge.co.uk/2009/12/21/introducing-who-can-help-me-a-sarp-architecture-demo-site/</link>
		<comments>http://jonathangeorge.co.uk/2009/12/21/introducing-who-can-help-me-a-sarp-architecture-demo-site/#comments</comments>
		<pubDate>Mon, 21 Dec 2009 23:03:57 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Technical Stuff]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[automapper]]></category>
		<category><![CDATA[castle windsor]]></category>
		<category><![CDATA[mspec]]></category>
		<category><![CDATA[nhibernate]]></category>
		<category><![CDATA[postsharp]]></category>
		<category><![CDATA[s#arp architecture]]></category>
		<category><![CDATA[spark]]></category>
		<category><![CDATA[xval]]></category>

		<guid isPermaLink="false">http://jonathangeorge.wordpress.com/2009/12/21/introducing-who-can-help-me-a-sarp-architecture-demo-site/</guid>
		<description><![CDATA[A couple of months ago, myself and some colleagues had the pleasure of pushing the metaphorical big red button and seeing www.fancydressoutfitters.co.uk go live. We all agreed it was one of the best projects we’d worked on in a long time, for a number of reasons. Those reasons can be split into two categories: the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=45&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A couple of months ago, myself and some colleagues had the pleasure of pushing the metaphorical big red button and seeing <a href="http://www.fancydressoutfitters.co.uk">www.fancydressoutfitters.co.uk</a> go live. We all agreed it was one of the best projects we’d worked on in a long time, for a number of reasons. Those reasons can be split into two categories: the team and the technology.</p>
<p>The core dev team was mostly made up of people who’d worked with one another before. For example I first worked with <a href="http://jamesbroo.me/" target="_blank">James</a> back in 2002, well before either of us joined Conchango (as it then was.) James had spent a lot of time working with <a href="http://howard.vanrooijen.co.uk/blog" target="_blank">Howard</a> on <a href="http://www.tescoentertainment.com/store/browse/mp3/" target="_blank">Tesco Digital</a>, and although I’d never worked with Howard directly I’d had a lot of contact with him on my previous project. We’d all previously worked with Ling (our data architect), Justin (developer, yet to create his own online presence for reasons unknown) and Naz (tester, ditto) on other projects over the previous 3 years. </p>
<p>On most projects, the team spends a fair amount of time up front becoming effective, and a big part of that is getting to know one another – strengths, weaknesses, the way we all communicate and so on. For us, there were only a couple of people that none of us had worked with on previous projects, and that made it simple for the team as a whole to gel really quickly. The process was simplified even further by a great project manager who knew how to make things happen without needing to control the dev team, and a business analyst who managed to take a huge amount of grief from us all about his gratuitous use of clip art in his Powerpoint presentations whilst at the same time winning the respect of the client for the speed with which he understood how they worked internally.</p>
<p>Also, because the team was well resourced up front, Howard and James were able to spend the time laying the appropriate foundations. <a href="http://consultingblogs.emc.com/jamesbroome/archive/2009/10/06/the-importance-of-conventions-from-asp-net-mvc-to-a-successful-project-team.aspx" target="_blank">James has talked about this previously</a>, so I won’t cover it again, but suffice it to say that the time invested up front paid massive dividends later in the project.</p>
<p>The foundations they laid included the core software stack we would use and the tools and techniques we would adopt. They decided that the core of the site would be based on ASP.NET MVC and <a href="http://sharparchitecture.net/" target="_blank">S#arp Architecture</a>, which is a best practice framwork joining MVC with <a href="https://www.hibernate.org/343.html" target="_blank">NHibernate</a>. They also picked some other bits and pieces to reduce friction – things like <a href="http://sparkviewengine.com/" target="_blank">Spark</a>, <a href="http://automapper.codeplex.com/" target="_blank">AutoMapper</a> and <a href="http://xval.codeplex.com/" target="_blank">xVal</a> – and James decided that the project would use <a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development" target="_blank">Behaviour Driven Development</a> as a testing approach.</p>
<p>When all of these things came together, one thing that stood out was how clean the resulting solution became. Core design concepts such as <a href="http://c2.com/cgi/wiki?SeparationOfConcerns" target="_blank">separation of concerns</a>, encapsulation and <a href="http://c2.com/cgi/wiki?DependencyInjection" target="_blank">dependency injection</a> were baked in, making the code clean and easy to test. The layers of the solution were well defined and understood, meaning it was always obvious where a particular piece of code should live and it was easy to discuss the codebase between us because we were <a href="http://c2.com/cgi/wiki?UbiquitousLanguage" target="_blank">all talking the same language</a>. The adoption of <a href="http://c2.com/cgi/wiki?BehaviorDrivenDevelopment" target="_blank">BDD</a> finally made using a test-driven approach make sense for those like me who always found it a challenge.</p>
<p>As the project neared it’s end, myself, James and Howard <a href="http://delicious.com/howardvanrooijen/fdo-casestudy?sort=alpha&amp;order=asc" target="_blank">wrote some blog posts talking about various aspects of the solution</a>, but it became hard for all of us to pull out specific bits of code to talk about because removing them from the wider context of the solution caused them to lose their meaning. Howard suggested that we could address this – as well as giving something back to the community that gave us such great software – by putting together an app based on the same architecture and publishing the source code. We could then use it to talk around specific features or areas of the architecture, and at the same time demonstrate to the community the approach we took for the FDO site.</p>
<p>A couple of years back, Howard spent a few hours one evening creating an app called “Who can help me?” Originally intended to capture information about the skills and experience available within Conchango, it took him about 3 hours to put together using ASP.NET WebForms and Linq to SQL. It was the ideal application for our purpose; it has a practical application (we still use it inside EMCC) and it’s simple so the focus can be on the solution design rather than the business logic.</p>
<p>So, <a href="http://who-can-help.me/" target="_blank">here it is: Who Can Help&#160; Me</a>, built using <a href="http://sharparchitecture.net/" target="_blank">S#arp Architecture</a>, <a href="https://www.hibernate.org/343.html" target="_blank">NHibernate</a>, <a href="http://sparkviewengine.com/" target="_blank">Spark View Engine</a>, <a href="http://xval.codeplex.com/" target="_blank">xVal</a>, <a href="http://automapper.codeplex.com/" target="_blank">AutoMapper</a>, <a href="http://www.castleproject.org/container/index.html" target="_blank">Castle Windsor</a>, <a href="http://codebetter.com/blogs/aaron.jensen/archive/2008/05/08/introducing-machine-specifications-or-mspec-for-short.aspx" target="_blank">MSpec</a>, <a href="http://www.ayende.com/projects/rhino-mocks.aspx" target="_blank">RhinoMocks</a> and <a href="http://www.postsharp.org/" target="_blank">PostSharp</a>. We’ve pulled in some new bits, such as MEF and <a href="http://www.ohloh.net/p/dotnetopenauth" target="_blank">DotNetOpenAuth</a>, hooked it up to Twitter using <a href="http://tweetsharp.com/" target="_blank">TweetSharp</a> to demonstrate the pattern for external service integration, and <a href="http://whocanhelpme.codeplex.com/" target="_blank">published the whole lot on Codeplex</a>.</p>
<p>The result is definitely more complex than the problem requires, but that’s ok – as I mentioned above, we specifically chose a simple application to demonstrate an enterprise level architectural approach with the hope that the focus could be on the latter. So <a href="http://who-can-help.me/" target="_blank">please have a play with the live site</a>, download the code, give it the once over and let us know what you think. We’ll be blogging about the bits we find interesting (links below), as well as tidying up the bits we’re not so keen on and we’d love to hear any feedback you have.</p>
<ul>
<li><a href="http://jonathangeorge.co.uk/">Jonathan George</a> &#8211; <a href="http://twitter.com/jon_george1">@jon_george1</a> </li>
<li><a href="http://howard.vanrooijen.co.uk/blog">Howard van Rooijen</a> &#8211; <a href="http://twitter.com/HowardvRooijen">@HowardvRooijen</a> </li>
<li><a href="http://jamesbroo.me/">James Broome</a> &#8211; <a href="http://twitter.com/broomej">@broomej</a> </li>
</ul>
<p>We’ll also be using the <a href="http://twitter.pbworks.com/Hashtags" target="_blank">hashtag</a> <a href="http://twitter.com/#search?q=%23wchm" target="_blank">#WCHM on Twitter</a> when we talk about this, so keep an eye out.</p>
<p><a href="http://twitter.com/jon_george1" target="_blank">@jon_george1</a></p>
<br /> Tagged: asp.net, asp.net mvc, automapper, castle windsor, mspec, nhibernate, postsharp, s#arp architecture, spark, xval <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jonathangeorge.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jonathangeorge.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jonathangeorge.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jonathangeorge.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jonathangeorge.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jonathangeorge.wordpress.com/45/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jonathangeorge.wordpress.com/45/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jonathangeorge.wordpress.com/45/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=45&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jonathangeorge.co.uk/2009/12/21/introducing-who-can-help-me-a-sarp-architecture-demo-site/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6038fabf4927137a504608f99b48f91f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Jonathan</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimising an ASP.NET MVC web site, part 5: Putting your money where your mouth is</title>
		<link>http://jonathangeorge.co.uk/2009/11/03/optimising-an-asp-net-mvc-web-site-part-5-putting-your-money-where-your-mouth-is/</link>
		<comments>http://jonathangeorge.co.uk/2009/11/03/optimising-an-asp-net-mvc-web-site-part-5-putting-your-money-where-your-mouth-is/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 17:51:00 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Technical Stuff]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[n2cms]]></category>
		<category><![CDATA[nhibernate]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[s#arp architecture]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[spark]]></category>

		<guid isPermaLink="false">http://jonathangeorge.wordpress.com/2009/11/03/optimising-an-asp-net-mvc-web-site-part-5-putting-your-money-where-your-mouth-is/</guid>
		<description><![CDATA[Note: This was originally posted on my old blog at the EMC Consulting Blogs site. This is the final part of a series of posts on optimisation work we carried out on my last project, www.fancydressoutfitters.co.uk – an ASP.NET MVC web site built using S#arp Architecture, NHibernate, the Spark view engine and Solr. There’s not [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=27&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>Note: This was originally posted on </strong><a href="http://consultingblogs.emc.com/jonathangeorge/archive/2009/09/09/how-to-improve-your-yslow-score-under-iis7.aspx"><strong>my old blog</strong></a><strong> at the </strong><a href="http://consultingblogs.emc.com/"><strong>EMC Consulting Blogs site</strong></a><strong>.</strong></p>
<p><i>This is the final part of a series of posts on optimisation work we carried out on my last project, <a href="http://www.fancydressoutfitters.co.uk">www.fancydressoutfitters.co.uk</a> – an ASP.NET MVC web site built using </i><a href="http://code.google.com/p/sharp-architecture/"><i>S#arp Architecture</i></a><i>, </i><a href="https://www.hibernate.org/343.html"><i>NHibernate</i></a><i>, the </i><a href="http://sparkviewengine.com/"><i>Spark view engine</i></a><i> and </i><a href="http://lucene.apache.org/solr/"><i>Solr</i></a><i>. There’s not much point starting here – please have a look at parts <a href="http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-1-introduction/">1</a>, <a href="http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-2-database-and-nhibernate/">2</a>, <a href="http://jonathangeorge.co.uk/2009/10/12/optimising-an-asp-net-mvc-web-site-part-3-application-caching/">3</a> and <a href="http://jonathangeorge.co.uk/2009/11/03/optimising-an-asp-net-mvc-web-site-part-4-output-caching-in-the-brave-new-world-of-mvc/" target="_blank">4</a>, as well as <a href="http://jonathangeorge.co.uk/2009/09/09/how-to-improve-your-yslow-score-under-iis7/">my post on improving YSlow scores for IIS7 sites</a>, for the full picture.</i></p>
<p>In the posts on this series, I’ve reflected the separation of concerns inherent in ASP.NET MVC applications by talking about how we optimised each layer of the application independently. Good separation of concerns is by no means unique to applications built using the MVC pattern, but what stood out for me as I became familiar with the project was that for the first time it seemed like I hardly had to think to achieve it, because it’s so baked into the framework. I know I share this feeling with <a href="http://consultingblogs.emc.com/howardvanrooijen/default.aspx" target="_blank">Howard</a> and <a href="http://consultingblogs.emc.com/jamesbroome/" target="_blank">James</a> (respectively architect and developer on the project), who’ve both talked about it in their own blogs.</p>
<p>The MVC pattern also makes it much easier to apply optimisations in the code. For example, it’s much easier to identify the points where caching will be effective, as the Model-View-ViewModel pattern makes it straightforward to apply a <a href="http://jonathangeorge.co.uk/2009/10/12/optimising-an-asp-net-mvc-web-site-part-3-application-caching/" target="_blank">simple and highly effective caching pattern</a> within the controllers. I know that this kind of thing isn’t limited to performance work – for example, our team security guru certainly felt that it was easier to carry out his threat modelling for this site than it would have been in a WebForms equivalent.</p>
<p>On the flip side, this process also brought home to me some of the dangers of using NHibernate. It’s an absolutely awesome product, and has totally converted me to the use of an ORM (be it NHib or Entity Framework). However, the relatively high learning curve and the fact that most of the setup was done before I joined the project made it easy for me to ignore what it was doing under the covers and code away against my domain objects in a state of blissful ignorance. Obviously this is not a brilliant idea, and properly getting to grips with NH it now jostling for first place on my to-do list (up against <a href="http://www.postsharp.org/" target="_blank">PostSharp 2</a> and <a href="http://haacked.com/archive/2009/10/01/asp.net-mvc-preview-2-released.aspx" target="_blank">ASP.NET MVC 2.0</a>, amongst other things.)</p>
<p>My big challenge for future projects is ensuring that the optimisations I’ve talked about are baked in from the start instead of being bolted on at the end. The problem with this is that it’s not always clear where to stop. The goal of optimising the site is to get it to the point where it performs as we need it to, not to get it to the point where we can’t optimise any more. The process of optimisation is one of diminishing returns, so it’s essential to cover issues you know need to be covered and to then use testing tools to uncover any further areas to work on.</p>
<p>That said, in an ideal world I’d like to be able to build performance tests early and use them to benchmark pages on a regular basis. Assuming you work in short iterations, this can be done on an iteration by iteration basis, with results feeding into the plan for the next iteration. My next series of posts will be on performance and load testing, and as well as covering what we did for this project I will be looking at ways of building these processes into the core engineering practices of a project.</p>
<h2>Was it all worth it?</h2>
<p>I’ll be talking separately about the performance and load testing we carried out on the site prior to go live, but in order to put these posts into some context I thought it might be interesting to include some final numbers. For our soak testing, we built a load profile based on 6 user journeys through the site:</p>
<ul>
<li>Homepage: 20% of total concurrent user load </li>
<li>Browse (Home -&gt; Category Landing -&gt; Category Listing -&gt; Product): 30% </li>
<li>Search (Home -&gt; Search Results): 30% </li>
<li>News (Home -&gt; News list -&gt; News story): 10% </li>
<li>Static Pages (Home -&gt; Static page): 5% </li>
<li>Checkout (As for browse journey, then -&gt; Add to basket -&gt; View Basket -&gt; Checkout): 5% </li>
</ul>
<p>With a random think time of 8 – 12 seconds between each step of each journey, we demonstrated that each of the web servers in the farm could sustainably support 1000 concurrent users and generate 90 pages per second. Given the hardware in question, this far exceeds any project I’ve worked on recently.</p>
<p>In the end, we put <a href="http://www.fancydressoutfitters.co.uk">www.fancydressoutfitters.co.uk</a> live in the run up to Halloween, the busiest time of the year for the fancy dress industry. We did this with no late nights and enough confidence to go to the pub for a celebratory pint within the hour. It was also interesting that the majority of technical colleagues who responded to our go-live announcement commented on how fast it runs (which given the machinations of our corporate network’s internet routing is even more remarkable.) And best of all, we’ve had no major shocks since the site went live.</p>
<h2>A final note</h2>
<p>If you’ve read this series of posts, I hope you’ve got something out of it. I’d certainly be interested in any feedback that you might have – as always, please feel free to leave a comment or contact me on <a href="http://twitter.com/jon_george1" target="_blank">Twitter</a>.&#160; In addition, the EMC Consulting blog site has been nominated in the <a href="http://www.computerweekly.com/Articles/2009/09/14/237679/it-blog-awards-2009-name-your-favourite-blogger.htm" target="_blank">Computer Weekly IT Blog Awards 2009</a>, under the <a href="http://www.computerweekly.com/Articles/2009/09/20/237826/it-blog-awards-2009-company-corporate-large-enterprise.htm" target="_blank">“Corporate/Large Enterprise” category</a> – please consider <a href="http://www.computerweekly.com/Articles/2009/11/03/238190/vote-in-the-computer-weekly-it-blog-awards-2009.htm" target="_blank">voting for us</a>.</p>
<p>I’d also like to extend a final thanks to <a href="http://consultingblogs.emc.com/howardvanrooijen/default.aspx" target="_blank">Howard</a> for proof reading the first draft of these posts and giving me valuable feedback, as well as for actually doing a lot of the work I’ve talked about here.</p>
<p><a href="http://twitter.com/jon_george1" target="_blank">@jon_george1</a></p>
<br /> Tagged: asp.net, asp.net mvc, n2cms, nhibernate, performance, s#arp architecture, solr, spark <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jonathangeorge.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jonathangeorge.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jonathangeorge.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jonathangeorge.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jonathangeorge.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jonathangeorge.wordpress.com/27/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jonathangeorge.wordpress.com/27/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jonathangeorge.wordpress.com/27/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=27&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jonathangeorge.co.uk/2009/11/03/optimising-an-asp-net-mvc-web-site-part-5-putting-your-money-where-your-mouth-is/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6038fabf4927137a504608f99b48f91f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Jonathan</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimising an ASP.NET MVC web site, part 2: Database and NHibernate</title>
		<link>http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-2-database-and-nhibernate/</link>
		<comments>http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-2-database-and-nhibernate/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 23:28:00 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Technical Stuff]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[nhibernate]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[s#arp architecture]]></category>
		<category><![CDATA[solr]]></category>

		<guid isPermaLink="false">http://jonathangeorge.wordpress.com/2009/10/03/optimising-an-asp-net-mvc-web-site-part-2-database-and-nhibernate/</guid>
		<description><![CDATA[Note: This was originally posted on my old blog at the EMC Consulting Blogs site. This is part 2 in a series of posts on optimisation work we carried out on my current project – an ASP.NET MVC web site built using S#arp Architecture, NHibernate, the Spark view engine and Solr. Please see “Optimising an [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=22&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>Note: This was originally posted on </strong><a href="http://consultingblogs.emc.com/jonathangeorge/archive/2009/09/09/how-to-improve-your-yslow-score-under-iis7.aspx"><strong>my old blog</strong></a><strong> at the </strong><a href="http://consultingblogs.emc.com/"><strong>EMC Consulting Blogs site</strong></a><strong>.</strong></p>
<p><i>This is part 2 in a series of posts on optimisation work we carried out on my current project – an ASP.NET MVC web site built using <a href="http://code.google.com/p/sharp-architecture/" target="_blank">S#arp Architecture</a>, <a href="https://www.hibernate.org/343.html" target="_blank">NHibernate</a>, the <a href="http://sparkviewengine.com/" target="_blank">Spark view engine</a> and <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a>. Please see <a href="http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-1-introduction/">“Optimising an ASP.NET MVC web site part 1 – Introduction”</a> for the background.</i></p>
<p>Whilst there are many different things you can do to a web application to kill performance, having a badly implemented database &#8211; or a well implemented database that you access in a bad way – has got to be right up there with the best. We therefore made the database our first port of call, and started off with a pretty simple approach – fire up&#160; SQL Server Profiler, start a new trace and see what the pain points are in each database. </p>
<h2>Using SQL Server Profiler to find data access mistakes</h2>
<p>As I mentioned in the introduction, the goal of our optimisation wasn’t to do everything, just to get the main things we thought were causing problems before we began our load testing. If you use the TSQL_Duration template in SQL Profiler for your trace, you can hit your site and quickly see what the most expensive queries are. </p>
<p><a href="http://jonathangeorge.files.wordpress.com/2009/11/sampletsql_durationtrace.png"><img style="display:inline;border-width:0;" title="Sample TSQL_Duration Trace" border="0" alt="Sample TSQL_Duration Trace" src="http://jonathangeorge.files.wordpress.com/2009/11/sampletsql_durationtrace_thumb.png?w=680&#038;h=345" width="680" height="345" /></a> </p>
<p>The screenshot above shows the results of repeatedly executing three different stored procedures in a random order. As you can see, the results are organised in ascending order of cost, with the interesting column being “Duration” – which shows the execution time in milliseonds.</p>
<p>When <a href="http://blogs.conchango.com/howardvanrooijen/default.aspx" target="_blank">Howard</a> first ran this against some of our landing and search result pages he quickly noticed a large nugget of smelliness at the bottom of the list, in the form of repeated calls to a stored procedure that was taking a whopping 400ms to execute. Whilst 400ms is not a long time – I’m sure it’s taken longer than that for you to read this sentence so far – when you call it 20 times you’ve suddenly spent 8 seconds just on database calls before any other page activity.</p>
<p>Digging into this identified three separate, but related issues.</p>
<p><b>1. One of our NHibernate mappings included a view based on a recursive query</b></p>
<p>Of course, this was something we’d told NHibernate to do. Our entities are organised hierarchically, and an entity can appear in multiple positions in the hierarchy. When we pass entity data to Solr for indexing, we work out the full list of paths for an entity and pass that through (see item 3 for more details.) This was done by creating a CTE to generate the list of hierarchy paths for each entity. </p>
<p>For the uninitiated, a <a href="http://msdn.microsoft.com/en-us/library/ms190766.aspx" target="_blank">Common Table Expression</a> (or CTE) is a T-SQL construct that (amongst other things) <a href="http://msdn.microsoft.com/en-us/library/ms186243.aspx" target="_blank">enables you to execute recursive queries</a>. They are very handy when dealing with hierarchical datasets, but aren’t the most efficient queries you can execute. Some time after the initial creation of the view, we’d realised that it would be useful to have the data it contained as part of our entity so we added a mapping into our NHibernate configuration. This meant that accessing that data would cause NHibernate to go off and execute a SELECT statement which included a join from the main entity table to the view. This query took in the region of 400ms. </p>
<p>We have two main types of page on the site landing pages and search/browse pages. The landing pages were causing this query to be executed 13 times and the browse pages were causing it to be executed 20 times, so it’s no wonder that performance had dropped. Whilst the view was never intended for use in this way, the requirement to have the data as part of our entity was still valid. </p>
<p>The simple solution to the problem was essentially to materialize the view. SQL Server can do this by <a href="http://msdn.microsoft.com/en-us/library/dd171921.aspx" target="_blank">turning the view into an indexed view</a> – adding a unique clustered index to it does this. However, this approach isn’t applicable when the SELECT statement for the view uses a CTE, so we went with a more basic approach – since our product catalogue is actually managed in the back office and populated via ETL, we replaced the view with a table (complete with all the appropriate indexes) and tweaked the ETL to populate this table at the same time as all the rest.</p>
<p>For the pages in question, load time dropped from around 8 seconds to under 2, at which point we all got quite excited. However, this wasn’t solely to do with the materialisation of the view, as the investigation also showed up that…</p>
<p><b>2. Everything was being lazy loaded </b></p>
<p>By default, NHibernate uses lazy loading across the board. Depending on your object model and how it is used, this can lead to massive inefficiences. The classic example is the &quot;SELECT N+1” anti-pattern, in which you retrieve an entity from a repository then iterate over a collection on that entity. If you’ve left NHibernate lazy loading the values, then this results in a SELECT statement being issued for every iteration of the loop. Have a look at <a href="http://nhprof.com/Learn/Alert?name=SelectNPlusOne" target="_blank">this page on the NHibernate Profiler site</a> for more information.</p>
<p><a href="http://blogs.conchango.com/howardvanrooijen/default.aspx" target="_blank">Howard</a> spent some time using the <a href="http://nhprof.com/" target="_blank">NHibernate profiler</a> to better understand what our app was doing, and made a number of tweaks to our mapping configuration to apply eager loading where it made sense. This provided another significant improvement, dramatically reducing the number of database calls made by the application.</p>
<p><b>3. An architectural rule imposed for performance reasons had been broken</b></p>
<p>We’d made an architectural decision to drive the search and browse functions on our website exclusively from Solr. We did this because it gives us more options for scalability. Since all the data in question comes from a single database, pulling the data directly out of that database would mean that as website load increases then so does the load on the database. The problem with that is that it’s difficult to scale a single database out &#8211; you can throw CPUs and RAM at your database server, but you’re always going to hit a limit, at which point you face some architectural challenges. This kind of basic architecture is shown in the following diagram:</p>
<p><a href="http://jonathangeorge.files.wordpress.com/2009/11/simplearchitecture.png"><img style="display:inline;border-width:0;" title="Simple architecture" border="0" alt="Simple architecture" src="http://jonathangeorge.files.wordpress.com/2009/11/simplearchitecture_thumb.png?w=432&#038;h=432" width="432" height="432" /></a> </p>
<p>Even though the main entity database is static, meaning that it would be possible to have a number of replicas of this database (potentially even one per webhead), this would require architectural change and would bring with it a new set of issues around data consistency. By pushing that load onto Solr, which has a far more straightforward scale-out story, we can grow far further without requiring a redesign. Solr basically stores a flat set of data in a form optimised for searching, and provides access via a web service. This means it is straightforward to have multiple instances of Solr running behind a load balancer. Solr makes this kind of setup even easier, as it supports a master-slave configuration as shown in the following diagram (I apologise now for the proliferation of connecting lines – I’m more of a <a href="http://simonmunro.com/2009/09/08/it-architecture-the-usual-suspects/" target="_blank">reluctant architect than a Powerpoint architect</a>):</p>
<p><a href="http://jonathangeorge.files.wordpress.com/2009/11/withsolrtier.png"><img style="display:inline;border-width:0;" title="With solr tier" border="0" alt="With solr tier" src="http://jonathangeorge.files.wordpress.com/2009/11/withsolrtier_thumb.png?w=431&#038;h=486" width="431" height="486" /></a> </p>
<p>In this example, the web tier will still talk direct to the data tier for some tasks – it’s unavoidable. However, we introduce the search tier which consists of a set of load balanced search servers, each of which contains an identical copy of the search index. In order to build that index, we push data from the database into the Solr master server, and the Solr master server indexes it and pushes the result out to each slave. If you can see past the nasty mess of lines, it should be obvious that as load grows, adding more webheads and/or Solr slaves is a relatively trivial operation. </p>
<p>However, you can have the best intentions in the world when you design your solution, but if you then go on to break the rules then it’s not going to happen. In our case, the code had ended up in a state where for each result retrieved from a Solr search, a database query would be made. Not only that, but the query in question was the horribly expensive one I mentioned in point 1.</p>
<p>This will no doubt cause some brow-wrinkling activity if you’re paying attention, as I mentioned that the original intended purpose of the view being used for the expensive query was to push data into Solr – so why, if the data was already in there, would we be accessing it again from the database once we’d pulled it out of Solr?</p>
<p>I can think of a number of good explanations, the best of which might be “My name’s Jon, and <a href="http://subwindow.com/articles/2" target="_blank">I’m a terrible programmer</a>”. The day I get it right 100% of the time is quite probably the day I get to decide which of my Ferrari’s I drive to work, as well as the day that my projects no longer require testers, and I doubt that will ever happen. Maybe I just missed the <a href="http://xkcd.com/323/" target="_blank">Ballmer Peak</a> on that day, but whatever happened, I’m just happy when the mistakes I make are as easy to identify and fix as this one was.</p>
<h2>Using the SQL Server Database Engine Tuning Advisor</h2>
<p>In tandem with this, we also made use of the SQL Server Database Engine Tuning Advisor. This is the next stage of evolution for the Index Tuning Wizard that (I believe) first appeared in SQL Server 2000. The <a href="http://msdn.microsoft.com/en-us/library/ms173494.aspx" target="_blank">MSDN page for it is here</a>; the short (aka .NET developer) version is that you put a trace file into one end, and out of the other comes a variety of changes you can make to your database to make it go faster.</p>
<p>In order to generate the input, you use SQL Server Profiler with the “Tuning” template. Once this is running, and saving the trace to a file, you need to generate a “typical” load against your application. There are various ways to do this, ranging from fully manual to fully automated. We were fortunate on our project that we had a complete set of <a href="http://seleniumhq.org/" target="_blank">Selenium</a> tests for the site and a way of running them as part of the build. I’m hoping that Tom, the consultant responsible for this, will start blogging about it at some point as it’s really interesting stuff. It meant that to generate our trace, all we had to do was start the profiler, kick of the test suite and go for a beer. The next morning, we pushed the resultant file through the tuning advisor and received our recommendations out of the other end. There was little we disagreed with, and most of the recommendations were subsequently applied to the database. </p>
<h2>The rest?</h2>
<p>You may have noticed that the main focus in this post has been around the way the application accessed the data, rather than the way the database was built. Over the duration of the project, and in addition to the fantastic data architect we had in the team, we’ve had guest appearances by <a href="http://consultingblogs.emc.com/jamesrowlandjones/" target="_blank">JRJ</a>, <a href="http://sqlblog.com/blogs/jamie_thomson/" target="_blank">Jamie</a> and <a href="http://consultingblogs.emc.com/simonmunro/" target="_blank">Simon</a>, so it shouldn’t come as a massive surprise that the database works well. EMC Consulting is rightly proud of the database guys we have on the team and whilst I’m sure that there are many further tweaks that could be made to our databases to add further go-faster stripes, they aren’t needed at the moment.&#160; Optimisation is one of many things that doesn’t benefit by having the word “premature” put in front of it – it’s basically another form of&#160; <a href="http://en.wikipedia.org/wiki/You_ain't_gonna_need_it" target="_blank">YAGNI</a>. So, until testing proved otherwise, we were happy to stop at this point and move on to something else.</p>
<p><i>In the next exciting epsiode of “Optimising an ASP.NET MVC web site”, we look at a pattern for applying application layer caching. Don’t touch that dial!</i></p>
<p>Please let me know what you think of my blog posts, either by commenting, dropping me an email, or via Twitter.</p>
<p><a href="http://twitter.com/jon_george1" target="_blank">@jon_george1</a></p>
<br /> Tagged: asp.net, asp.net mvc, nhibernate, performance, s#arp architecture, solr <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jonathangeorge.wordpress.com/22/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jonathangeorge.wordpress.com/22/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jonathangeorge.wordpress.com/22/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jonathangeorge.wordpress.com/22/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jonathangeorge.wordpress.com/22/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jonathangeorge.wordpress.com/22/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jonathangeorge.wordpress.com/22/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jonathangeorge.wordpress.com/22/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=22&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-2-database-and-nhibernate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6038fabf4927137a504608f99b48f91f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Jonathan</media:title>
		</media:content>

		<media:content url="http://jonathangeorge.files.wordpress.com/2009/11/sampletsql_durationtrace_thumb.png" medium="image">
			<media:title type="html">Sample TSQL_Duration Trace</media:title>
		</media:content>

		<media:content url="http://jonathangeorge.files.wordpress.com/2009/11/simplearchitecture_thumb.png" medium="image">
			<media:title type="html">Simple architecture</media:title>
		</media:content>

		<media:content url="http://jonathangeorge.files.wordpress.com/2009/11/withsolrtier_thumb.png" medium="image">
			<media:title type="html">With solr tier</media:title>
		</media:content>
	</item>
		<item>
		<title>Optimising an ASP.NET MVC web site part 1 &#8211; Introduction</title>
		<link>http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-1-introduction/</link>
		<comments>http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-1-introduction/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 23:25:00 +0000</pubDate>
		<dc:creator>Jonathan</dc:creator>
				<category><![CDATA[Technical Stuff]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[n2cms]]></category>
		<category><![CDATA[nhibernate]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[s#arp architecture]]></category>
		<category><![CDATA[solr]]></category>
		<category><![CDATA[spark]]></category>

		<guid isPermaLink="false">http://jonathangeorge.wordpress.com/2009/10/03/optimising-an-asp-net-mvc-web-site-part-1-introduction/</guid>
		<description><![CDATA[Note: This was originally posted on my old blog at the EMC Consulting Blogs site. One of the things I’ve been involved in over the past couple of months is performance tuning work for my current project (now live at www.fancydressoutfitters.co.uk). One of my EMC Consulting colleagues, Marcin Kaluza, has recently started posting on this [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=15&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>Note: This was originally posted on </strong><a href="http://consultingblogs.emc.com/jonathangeorge/archive/2009/09/09/how-to-improve-your-yslow-score-under-iis7.aspx"><strong>my old blog</strong></a><strong> at the </strong><a href="http://consultingblogs.emc.com/"><strong>EMC Consulting Blogs site</strong></a><strong>.</strong></p>
<p>One of the things I’ve been involved in over the past couple of months is performance tuning work for my current project (now live at <a href="http://www.fancydressoutfitters.co.uk">www.fancydressoutfitters.co.uk</a>). One of my EMC Consulting colleagues, <a href="http://blogs.conchango.com/marcinkaluza/default.aspx" target="_blank">Marcin Kaluza</a>, has recently started posting on this subject and I’ve been encouraged by <a href="http://blogs.conchango.com/howardvanrooijen/" target="_blank">Howard</a> to post some “war stories” of the kind of things I’ve encountered whilst doing this on projects, starting with the most recent.</p>
<p>So first, some background. It’s an public facing website project, and is based on <a href="http://devlicio.us/blogs/billy_mccafferty/" target="_blank">Billy McCafferty’s</a> excellent <a href="http://code.google.com/p/sharp-architecture/" target="_blank">S#arp Architecture</a> &#8211; which means it’s ASP.NET MVC with <a href="https://www.hibernate.org/343.html" target="_blank">NHibernate</a> talking to SQL Server 2008 databases. We’re using the <a href="http://sparkviewengine.com/" target="_blank">Spark View Engine</a> instead of the out of the box one, and the site uses <a href="http://n2cms.com/" target="_blank">N2 CMS</a> to provide content management capabilities (<a href="http://blogs.conchango.com/jamesbroome/default.aspx" target="_blank">James</a> posted a while back on <a href="http://blogs.conchango.com/jamesbroome/archive/2009/04/24/why-i-like-n2-cms.aspx" target="_blank">the reasons for choosing N2</a>.) Finally, we use <a href="http://lucene.apache.org/solr/" target="_blank">Solr</a> to provide our search functionality, integrated using <a href="http://code.google.com/p/solrnet/" target="_blank">Solrnet</a>. I joined the team a few months into the project, by which point they had laid a firm foundation and were about to be abandoned for 6 weeks by their technical lead who had inconsiderately booked his wedding and an extended honeymoon right in the middle of the project.</p>
<p>When the project was set up it was done so in strictly in accordance with agile principles. A small team was given a fixed date for go-live and the directive to spend the client’s money as if it were their own. One of the first things that happened was the adoption of a number of principles from the excellent <a href="http://37signals.com/" target="_blank">37signals</a> e-book <a href="http://gettingreal.37signals.com/toc.php" target="_blank">“Getting&#160; Real”.</a> A product backlog was assembled, and then – in accordance with the “build less” maxim – divided into “core” and “non-core” user stories. The core stories were what was essential for go live – things the client couldn’t live without, such as basic search and content management. The non-core stories are things that might enhance the site but aren’t essential – for example, advanced search features such as <a href="http://en.wikipedia.org/wiki/Faceted_search" target="_blank">faceted navigation</a>.</p>
<p>The absolute focus the team maintained on the core functionality and target delivery date has made this one of the best and most successful agile projects I’ve worked on – we reached our go live date on budget and were able to substantially over deliver on functionality. Whilst the site is relatively basic compared to some I’ve worked on, it stands out amongst its peers and provides a great platform for new functionality to be built on.</p>
<p>However, now I’ve extolled the virtues of the approach that was taken, I should talk about the performance optimisation and testing work we did. Since I have some experience from previous projects, I took on the task of testing the site to make sure it could handle an acceptable level of load without falling over in an embarrassing heap. However, before I started on that, we did some optimisation work on the site. </p>
<p>The aim was to hit the major pain points, since we knew performance had degraded over the previous few sprints. Once this was done, we could run some load testing and perform further tuning and optimisation work as required. I was originally intending to write a single post covering the optimisation process, then follow that up with one about the load testing process. However, that resulted in a rather lengthy post, so I’m splitting it up into several parts that I will post over the next week or two:</p>
<ul>
<li>Part 1: Introduction (this post) </li>
<li><a href="http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-2-database-and-nhibernate/">Part 2: Database and NHibernate-based repositories</a> </li>
<li><a href="http://jonathangeorge.co.uk/2009/10/12/optimising-an-asp-net-mvc-web-site-part-3-application-caching/">Part 3: Application caching</a> </li>
<li><a href="http://jonathangeorge.co.uk/2009/11/03/optimising-an-asp-net-mvc-web-site-part-4-output-caching-in-the-brave-new-world-of-mvc/">Part 4: View optimisation and output caching</a> </li>
<li><a href="http://jonathangeorge.co.uk/2009/11/03/optimising-an-asp-net-mvc-web-site-part-5-putting-your-money-where-your-mouth-is/">Part 5: Putting your money where your mouth is</a>&#160; </li>
</ul>
<p>In addition, I’ve already covered the work we did to correctly configure IIS in my post <a href="http://jonathangeorge.co.uk/2009/09/09/how-to-improve-your-yslow-score-under-iis7/">How to improve your YSlow score under IIS7</a>.</p>
<p>I hope you find these posts interesting – please let me know what you think by leaving a comment.</p>
<p><a href="http://twitter.com/jon_george1" target="_blank">@jon_george1</a></p>
<br /> Tagged: asp.net, asp.net mvc, n2cms, nhibernate, performance, s#arp architecture, solr, spark <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jonathangeorge.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jonathangeorge.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jonathangeorge.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jonathangeorge.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jonathangeorge.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jonathangeorge.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jonathangeorge.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jonathangeorge.wordpress.com/15/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jonathangeorge.co.uk&amp;blog=10577589&amp;post=15&amp;subd=jonathangeorge&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jonathangeorge.co.uk/2009/10/03/optimising-an-asp-net-mvc-web-site-part-1-introduction/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6038fabf4927137a504608f99b48f91f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Jonathan</media:title>
		</media:content>
	</item>
	</channel>
</rss>
