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

<channel>
	<title>Michael Brunton-Spall</title>
	<atom:link href="http://www.brunton-spall.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.brunton-spall.co.uk</link>
	<description>The rants and musings of a developer advocate</description>
	<lastBuildDate>Fri, 18 May 2012 22:55:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>A geek&#8217;s diet plan</title>
		<link>http://www.brunton-spall.co.uk/post/2012/04/09/a-geeks-diet-plan/</link>
		<comments>http://www.brunton-spall.co.uk/post/2012/04/09/a-geeks-diet-plan/#comments</comments>
		<pubDate>Mon, 09 Apr 2012 14:57:47 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[diet]]></category>
		<category><![CDATA[dieting]]></category>
		<category><![CDATA[weight-loss]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=2445</guid>
		<description><![CDATA[So I&#8217;ve been getting a little rotund of belly of late, and my family had started making jokes about my waistline and the jelly like qualities of my stomach. I&#8217;m...]]></description>
			<content:encoded><![CDATA[<p>So I&#8217;ve been getting a little rotund of belly of late, and my family had started making jokes about my waistline and the jelly like qualities of my stomach.</p>

<p>I&#8217;m not terribly keen on this for all the reasons that you might expect, but I&#8217;ve been putting it down to lack of exercise (I do about 15 minutes walking to a from work every day, that&#8217;s it), and a natural aging spread effect.</p>

<p>This leaves me only three choices, join a gym, start a diet or accept being that fat geek!</p>

<p><span id="more-2445"></span>I kept considering joining a gym, but I&#8217;m not a terribly motivated person, except by money, and a gym seems like a lot of effort and costs a lot of money, so it&#8217;s out for both those reasons. I&#8217;ve tried belonging to a gym before, but the time commitment is something I&#8217;d find hard to keep up, if I could find one at or nearby work that I could use at lunchtimes, maybe I&#8217;d go for it.</p>

<p>Anyway that left me with dieting, but a lot of diets require willpower, dedication and effort, none of which I have in vast quantities. I was speaking to my friend <a href="http://revdancatt.com/" target="_blank">Dan Catt</a> about it recently when he was regaling me with details of his diet. He&#8217;d lost of a lot of weight on the diet, but it was one of these extreme diets, where you go into ketosis, and your body starts eating itself to keep your energy levels up. Besides sounding awful it comes with a lot of side effects that I didn&#8217;t really want, and worst, if you slipped up and ate one single thing that was not on the diet, your body would drop out of ketosis, and you&#8217;d take a few days to get back in, which meant hunger, headaches, dizziness and nausea all over again. No thanks to that!</p>

<p>But it got me thinking, maybe I could just reduce my calorie intake, and see how that would go. Luckily Dan (or possibly somebody else, we don&#8217;t know who) had a whole bunch of <a href="http://www.cambridgeweightplan.com/" target="_blank">Cambridge Weight Plan</a> milkshakes left, and swapping out a great cooked lunch for a milkshake sounded unappatising, but at least doable. Note that the shakes are essentially unpurchasable unless you are seing their nutritionists. Their recommended diet is the uber extreme diet, which I wouldn&#8217;t recommend even trying if you are anything like me. I&#8217;m running out, so I&#8217;m going to try some weight watchers shakes, or might have to hunt around for some good meal replacement shakes.</p>

<p>But before I started my diet, I needed to find out what I was actually eating. This is the essence of being a good developer, measure everything and most iportantly measure before you act. Ideally I wanted 24/7 ganglia monitoring of all the respective statistics of my body, but I figured I&#8217;d start with just two simple emasurements.
<ol>
    <li>What was it that I was actually eating, what was my calorie intake, and therefore which meals/snacks/foods contributed the most</li>
    <li>How much did I actually weigh, and how much should I weigh?</li>
</ol>
I asked a few female freinds of mine who have dieted in the past for modern geeky approaches to dieting, and I got recommended <a href="http://www.sparkpeople.com" target="_blank">Spark People</a>. The website itself is pretty awful, the system for rewards and blogging and so forth don&#8217;t attract me at all, but they had a number of good points on their side.
<ul>
    <li>They have android and iphone apps. This means when out and about, with either my ipad, phone or laptop I can record the food I&#8217;ve eaten.</li>
    <li>They have a great database of calorie information for foods. I tried a number of other apps and a lot of them were very US-centric. I searched for tesco and sainsbury&#8217;s own brand foods and SparkPeople actually had most items.</li>
    <li>They have a user submitted calorie information search. Even if their official recipe isn&#8217;t there, I can search what other users have submitted, and they tend to have pretty much everything.</li>
</ul>
Naturally like everything the dataset is a little dodgy at times, I still struggle to approximate the size of the jacket potato I just ate in grams, I want small/medium/large. Occasionally you search for something and find a completely bonkers calorie estimate, but there&#8217;s often multiple versions of each item and it&#8217;s easy to select a new one.</p>

<p>So using the app I started tracking for a week what I was eating. After a few days it became clear to me that I had absoutely no idea about calories, there were things I thought had little that were high calorie, and things I thought had lots that had hardly any! The main thing I noticed was that I was eating on average at least 2500 calories a day. That&#8217;s about 500 too many (or the upper end of a mans diet, but I&#8217;m essentially sedentary, I shouldn&#8217;t eat 2500), and on many days when I treated myself I was reaching 3000 to 4000 calories.</p>

<p>So I decided to start the diet, and my rules were simple.
<ol>
    <li>Track everything I eat</li>
    <li>Weigh myself once a week on mondays</li>
    <li>Reduce the high calorie snacks and foodstuffs that I&#8217;m already eating</li>
    <li>Replace my lunch with a low calorie milkshake.</li>
    <li>Don&#8217;t affect the foods my family eats at dinner time too much</li>
</ol>
I was aiming to hit about 1500 calories per day on average, but I wasn&#8217;t worrying too much about it, I mostly wanted to record what I was eating and seeing what happened.</p>

<p><strong>So what did I do?</strong></p>

<p>Firstly it seemed that an awful lot of my calories were coming from milk, I was having latte&#8217;s, cappucino&#8217;s and just plain white coffee a lot during the day. Coffee with milk is around 25 calories per cup, black coffee is between 2-5 (the experts seem to vary their opinions). I was having an easy 6 coffee&#8217;s a day (free at the guardian), so that&#8217;s an easy 100 calories to save. A large latte (as I was having every morning thanks to my new Nespresso pod coffee machibne), was about 200 calories.</p>

<p>Breakfast milk also was an issue, theoretically corn flakes with 1/2 cup of milk is only 140 calories, but I tried an experiment and weighed my portion. I was eating more or less a double portion, and my milk was whole fat or semi-skimmed not skimmed. Again I was looking at 300-400 calories for breakfast.</p>

<p>So I removed the latte&#8217;s, capucinos etc and only had them as treats, still once a week or so, but my morning coffee is americano style, and I can cope with that just fine.</p>

<p>I switched breakfast to 2 slices of toast with philadelphia light on it, total of 229 calories. I bought the mini tubs of philidelphia light at first, since 1 entire tub is exactly 35g and 55 calories, and for me spreads over 2 slices of toast just fine. That meant I was sure of how much I was eating.</p>

<p>Lunch is a cambridge diet shake, 140 calories in one of those, and they fill me up just fine it seems. I don&#8217;t have one every day, for a start there is a long standing ritual at my workplace to go for all-day breakfast on a thursday lunchtime, that I&#8217;ve been doing for over 3 years now, and I can&#8217;t break the habit.</p>

<p>Dinner is whatever my wife has cooked for us, and this is the area where I did slightly change my diet. In advance of deciding to actually do the diet, I was thinking of losing weight, and I was also reminded by Aral about how awesome vegetarian diets can be. I used to be vegetarian for 5 years or so, and I really enjoyed the interesting diet. So on January 1st I switched back to being vegetarian. Now this wasn&#8217;t entirely for a slimming reason, but one of the reasons that I did it was because generally speaking, vegetarian food is lighter in calories and better for you, if you make sure to keep a good nutritious diet going.</p>

<p>So dinner for me might be spaghetti bolognese, made with vegetarian soya mince, whcih I estimate at about 300 &#8211; 350 calories. That&#8217;s actually a much lighter dinner than I would normally have calorie wise, but the idea is that I&#8217;m free to enjoy up to a normal 1000 calorie big dinner, including a couple of glasses of wine and still be in or around the 1500 calorie range.</p>

<p><strong>So how did it all go?</strong></p>

<p><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2012/04/SparkPeople_-View-your-Results-2.jpg"><img class="alignnone size-full wp-image-2450" title="My Diet Results" src="http://www.brunton-spall.co.uk/wp-content/uploads/2012/04/SparkPeople_-View-your-Results-2.jpg" alt="" width="709" height="309" /></a></p>

<p>Well I did 3 weeks of the diet before I had to stop (more details below), and then I essentially cut out the shakes and dieting proper for about 6 weeks, and I was simply counting the calories and eating salads and light lunches a lot. I&#8217;ve since decided to start the diet proper again, and this is the 1 weeks mark.</p>

<p>During the diet, I went from 181.1 to 174.2 at the lowest, coming back up to 176 at worst but hovering around 175. That&#8217;s a loss of 13 pounds in 3 weeks, and keeping stable at the end. Last week I weighed in at 175 pounds, today I&#8217;m 171.6, despite the easter splurge this week.</p>

<p><strong>Issues</strong></p>

<p>On the diet I didn&#8217;t feel particularly hungry, but I did encounter a few problems.</p>

<p><strong>Firstly: The diet shakes.</strong></p>

<p>They do not look terribly appetising. I also made a massive mistake on the first day of going to lunch with all my work mates and sitting with them and trying to drink the shake. This was my first taste of the shake, and while they are actually quite nice, they take a bit of getting used to. My workmates, rather naturally, were not terribly encouraging, pointing out how disgusting it looked, and talking about hte delicious meals that they had purchased. I think I&#8217;ve already mentioned that I don&#8217;t have a lot of willpower, and I ended up binning the shake and buying a jacket potato with beans and cheese instead (approx 500 calories). The next day I stayed at my desk and forced myself to drink the shake alone.</p>

<p>After the week was up, and I&#8217;d gotten used to the shakes, I was able to rejoin my work mates, partly because I&#8217;d gotten used to it, and partly because I&#8217;d seen my weight drop, so knew it was worth doing!</p>

<p>The other thing, as referenced above is that I was lucky that there was about 15-20 diet shakes left over from Dan&#8217;s diet that he kindly gave me.  Getting hold of those shake powders isn&#8217;t just a case of popping into tescos.</p>

<p><strong>Secondly: Dizziness, Nausea.</strong></p>

<p>If you don&#8217;t eat enough your body does not appreciate it. I&#8217;ve had a few days where I&#8217;ve been presenting at morning conference, or talking over lunch and I&#8217;ve been stressed or much more active than normal. In those cases I have gotten brief waves of feeling sick or dizzy. Every time I&#8217;ve had a big glass of water and normally a go-ahead or weightwatchers snackbar, and felt just fine.</p>

<p>Make sure you keep a stash of snacks around that you can eat if it comes to it. I often want to snack at about 4pm, and I let myself have 1 snack a day at 4pm. Because I tend to be so busy at work I&#8217;ve often forgotten so I don&#8217;t eat it every day, but it&#8217;s nice to have, and at around 100-150 calories they are pretty good snacks to have.</p>

<p><strong>Thirdly: Drinking</strong></p>

<p>It&#8217;s a common british work culture to go for drinks after work on a fairly regular basis, and the Guardian has a pub/wine bar in the building itself, so it&#8217;s even easier to nip out for just one drink. Unfortunately I&#8217;m not very good at just one drink! Alcohol is high in calories, a normal sized glass of red wine is around 90 calories, and a pint of bitter has nearly 200 calories. A recent evening out involved me drinking 4 pints, which is the same number of calories as I&#8217;d had all day, and meant I was around 2200 calories by the time I got on the train (eating a small burrito &#8211; 600 calories, as my dinner)</p>

<p><strong>Finally: Travel and conferences</strong></p>

<p>I had a hectic fortnight recently where I attended multiple events in San Francisco, then flew back to attend InfoQ&#8217;s QCon in London. I know that I couldn&#8217;t possibly do the shakes with a schedule like that, and I tend to be far more active, on my feet and lot, and having to do a lot fo talking and walking. I gave up the diet, ate whatever was put in front of me (vegetarian of course), and just didn&#8217;t worry about it. It took me a week or so to recover from the conferences and get back into recording eating and therefore watching my weight as well, and I expected that I&#8217;d have ut on a lot of weight, but it turned out to only put on about 2 pounds of weight, which is not bad for completely abandoning the diet. I went back down by a pound once I started measuring again.</p>

<p><strong>Summary</strong></p>

<p>So whats so geeky about dieting then? Well it seems that everybody has a fad they want to use, red days/green days, points systems, the chocolate cake for breakfast diet. But like many geeks I realised that the first step is measurement. Once you can measure your system (calories and weight) you can start to change the things you do and see what difference it makes. Sitting and counting calories on an iPad or phone at the dinner table, estimating portion sizes and even entire meals and starting to understand food better, that&#8217;s all part of the geekiness.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2012/04/09/a-geeks-diet-plan/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>What is DevOps not?</title>
		<link>http://www.brunton-spall.co.uk/post/2012/03/13/what-is-devops-not/</link>
		<comments>http://www.brunton-spall.co.uk/post/2012/03/13/what-is-devops-not/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 12:13:14 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[devops]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=2153</guid>
		<description><![CDATA[I&#8217;ve spent the last two weeks at conferences, and for some reason people keep assuming that I work in operations. I can kind of understand why, but it&#8217;s also started...]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve spent the last two weeks at conferences, and for some reason people keep assuming that I work in operations.  I can kind of understand why, but it&#8217;s also started a number of conversations about DevOps, and the complete misunderstanding of the term.  It seems that DevOps is a confusing movement for people, and lots of people are assuming that some of the practices that might come with organisations embracing DevOps are themselves what make you DevOps.</p>

<p>Defining what devops is can be hard, so instead I thought I&#8217;d feature a few of the things that devops isn&#8217;t.<span id="more-2153"></span></p>

<h2>&#8220;I&#8217;ve renamed our Ops team the DevOps team&#8221;</h2>

<p>This is not DevOps, you&#8217;ve renamed your operations team, but that is all!  You may as well print a million pound note or command the sea to stop for all the good it will do.</p>

<h2>&#8220;But our devops team run puppet/chef/CFEngine to manage their systems&#8221;</h2>

<p>This is not devops, this is just ops using new tools.  You Just configure your tool in a ruby based DSL (or use CFengine), so now you have two problems instead of just the one.</p>

<h2>&#8220;We split our ops team into Infrastructure and DevOps.  Our infrastructure team rack and stack, our devops team manage puppet/chef&#8230;&#8221;</h2>

<p>Congratulations! You&#8217;ve recognised that some operations people don&#8217;t want to do development tasks, how happy for you. But all you&#8217;ve done is split them out of the Ops team, but your ops team still sounds like an ops team to me.</p>

<h2>&#8220;Ok, so we got rid of our ops team, and our devs have root now&#8221;</h2>

<p>This is not just not devops, but it&#8217;s pretty damn stupid.  It turns out that people have specialisations.  I wouldn&#8217;t expect a java developer to be as productive with backbone.js as one of our javascript engineers, and I wouldn&#8217;t expect every developer to be able to setup and configure apache or nginx.  Full stack engineers are great, and if you&#8217;ve got a full team of them then you have a great resource there, but even then everybody will have things that they prefer doing and things they are more efficient at doing.</p>

<h2>&#8220;Ok, so we got rid of our ops team, our devs have root now, and we hired a DevOp (or DevOps) to manage configuration management. Better?&#8221;</h2>

<p>So now you got rid of a team, replaced them with a new team with a different name, less authority and expect your team to be functional?  Get out of here!</p>

<h2>&#8220;I see DevOps for what I think it is, a power grab. Revenge for not giving &#8216;devs&#8217; root when they wanted it&#8221;</h2>

<p>I think you are assuming that DevOps is a developer movement, and that it&#8217;s all about power.  You are so far wrong that I&#8217;m pretty confused right now.  However this is also an accurate view of how some people view the devops movement, sometimes those people are grumpy sysadmins who don&#8217;t want to do that configuration management thing, but that might be exactly how senior business decision makers are viewing devops.</p>

<p>My experience of DevOps is that the general trend is not of developers wanting to do sysadmin work or have root, but of existing sysadmins wanting to make their lives easier by working more closely with developers.  All of the people who I would consider to be doing &#8220;Devops&#8221; are brilliant sysadmins who understand something bigger than the inner workings of IPv4, BGP, Apache and nginx.</p>

<p>So lets make a simple list, DevOps is not about:</p>

<ul>
<li>Less racking and stacking hardware</li>
<li>Developers having root</li>
<li>Using configuration management tools (like Puppet or Chef)</li>
<li>Continuous Deployment (10 times a day)</li>
<li>Getting rid of the Ops team</li>
</ul>

<p>But surely I hear you ask, that&#8217;s what all the blogosphere has been talking about, how DevOps will revolutionise Ops, and that all of these things are possible?
Well that is kind of true, it looks like organisations that embrace DevOps might do some of those things, they also might not, it depends on the requirements of the organisation.</p>

<p>Ok, so I&#8217;ve talked a lot about misconceptions of DevOps, so what do I think DevOps actually is?</p>

<blockquote>
  <p>&#8220;You are DevOps when your operations team and your developer team are measured and rewarded by the same metric, did you help the business deliver value today&#8221;.</p>
</blockquote>

<p>The traditional view that pits devs versus ops is that ops teams are measured on reliability and availability (essentially uptime), whereas devs are measured on number of stories delivered.  These two goals are in direct opposition and it leads to developers wanting root access to get around the pesky ops team, and very grumpy sysadmins at 4am fixing bugs that devs didn&#8217;t see.</p>

<p>Both are bad measurements, they are proxy metrics for a real metric which is business value.  Downtime is probably bad for your business, except that there are cases where it isn&#8217;t.  The Apple store is taken down during apple keynotes.  Do you think that the Apple ops team looses their bonus over this?  Downtime is a proxy for business value, so greater downtime probably means lower business value.</p>

<p>Delivering new stories is a great metric if every story delivers value, but deploying 20 times a day is completely wasted if what you are deploying are minor ideas that one internal stakeholder wants that have no impact.  Again, deploying stories is a proxy for business value, and generally the higher the rate, the greater the business value.</p>

<p>See that&#8217;s the problem with DevOps, it&#8217;s so hard to get right because you need a team that is willing to focus around what the business actually needs, be willing to measure themselves and each other and work out what the business value is.</p>

<p>To do DevOps successfully you need to be able to measure and estimate the business value of a new story, and the business risk to each deployment.  Teams that do that are likely to start deploying more often, use configuration management and may even move towards removing the ops team, but in each case it will only happen if doing that action creates more business value than risk.</p>

<p>Of course with DevOps there is the eternal truth that if you get 5 DevOps in a room to debate &#8220;What is DevOps&#8221; you&#8217;d get 7 answers out at the end, and this is one of mine, so you can take it with a pinch of salt but my main point is that DevOps is not a set of practices, it&#8217;s not <em>what</em> you do, it&#8217;s <em>why</em> you do it.</p>

<p>[Updated for spelling and clarity in a few sentences, thanks to @mart_brooks and @tomnomnom]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2012/03/13/what-is-devops-not/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tech Weekly podcast: when books go social</title>
		<link>http://www.brunton-spall.co.uk/post/2012/01/09/tech-weekly-podcast-when-books-go-social/</link>
		<comments>http://www.brunton-spall.co.uk/post/2012/01/09/tech-weekly-podcast-when-books-go-social/#comments</comments>
		<pubDate>Mon, 09 Jan 2012 11:20:16 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[From the guardian]]></category>
		<category><![CDATA[Apps]]></category>
		<category><![CDATA[Audio]]></category>
		<category><![CDATA[Books]]></category>
		<category><![CDATA[Charles Arthur]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[iPlayer]]></category>
		<category><![CDATA[Josh Halliday]]></category>
		<category><![CDATA[Michael Brunton-Spall]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Mobile phones]]></category>
		<category><![CDATA[Rupert Murdoch]]></category>
		<category><![CDATA[Social media]]></category>
		<category><![CDATA[Social networking]]></category>
		<category><![CDATA[Tablet computers]]></category>
		<category><![CDATA[Tech Weekly]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=1507</guid>
		<description><![CDATA[Charles Arthur meets the man behind Anobii.com, a social network for your bookshelf. Plus the curious case of Rupert Murdoch and Wendi Deng's Twitter accounts. Are they real?]]></description>
			<content:encoded><![CDATA[<p><p>I blathered on the podcast for a bit again.</p><hr /><!-- GUARDIAN WATERMARK --><p><a href="http://www.guardian.co.uk/technology/blog/audio/2012/jan/03/social-media-socialnetworking"><img class="alignright" src="http://image.guardian.co.uk/sys-images/Guardian/Pix/pictures/2010/03/01/poweredbyguardianBLACK.png" alt="Powered by Guardian.co.uk" width="140" height="45" />This article titled &#8220;Tech Weekly podcast: when books go social&#8221; was written by Presented by Charles Arthur and produced by Matt Hill, for guardian.co.uk on Tuesday 3rd January 2012 17.36 UTC</a></p><p>How do you discover new books? Matteo Berlucchi is tired of buying books from a certain online retailer only to be recommended very similar reads. He tells us why his <a href="http://www.anobii.com/">aNobii.com</a> is different.</p><p><strong><a href="http://twitter.com/charlesarthur">Charles Arthur</a></strong> sits in the presenter hotseat for this week&#8217;s programme. He&#8217;s joined by <strong>Josh Halliday</strong> and <strong>Michael Brunton-Spall</strong> to discuss the week&#8217;s developments, including what Rupert Murdoch&#8217;s supposed Twitter feed tells us about the verification process and why those network crashes on New Year&#8217;s Eve look to be a thing of the past.</p><p>Plus, <strong><a href="http://twitter.com/aleksk">Aleks Krotoski</a></strong> talks to Chad Dickerson from vintage retailer <a href="http://www.etsy.com/">Etsy</a> about its rise and rise, and how to scale up a business without losing your customer focus.</p><p><strong>Don&#8217;t forget to&#8230;</strong></p><p>• Comment below<br />• Mail the producer <a href="mailto:tech@guardian.co.uk">tech@guardian.co.uk</a><br />• Get our <a href="http://www.twitter.com/guardiantw">Twitter feed</a> for programme updates or follow our <a href="http://twitter.com/#!/guardiantw/guardian-tech-podders">Twitter list</a><br />• Like our <a href="http://www.facebook.com/techweekly">Facebook page</a><br />• See our <a href="http://www.flickr.com/photos/guardiantechweekly/">pics on Flickr</a>/Post <a href="http://www.flickr.com/groups/guardiantechweekly/">your tech pics</a></p><div class="gu_advert"></p>

<pre><code>      &lt;a rel="nofollow" href="http://oas.guardian.co.uk/RealMedia/ads/click_nx.ads/guardianapis.com/technology/oas.html/@Bottom"&gt;
          &lt;img alt="Ads by The Guardian" src="http://oas.guardian.co.uk/RealMedia/ads/adstream_nx.ads/guardianapis.com/technology/oas.html/@Bottom"&gt;&lt;/img&gt;
      &lt;/a&gt;

  &lt;/div&gt;&lt;img src='http://hits.guardian.co.uk/b/ss/guardiangu-api/1/H.20.3/98867?ns=guardian&amp;amp;pageName=Tech+Weekly+podcast%3A+when+books+go+social+Audio+1683419&amp;amp;ch=Technology&amp;amp;c2=67197&amp;amp;c4=Technology%2CSocial+media%2CSocial+networking%2CBooks%2CInternet%2CGoogle+%28Technology%29%2CTablet+computers%2CMicrosoft+%28Technology%29%2CRupert+Murdoch+%28Media%29%2CTwitter+%28Technology%29%2CMobile+phones+%28Technology%29%2CiPlayer%2CApps&amp;amp;c3=guardian.co.uk&amp;amp;c6=Presented+by+Charles+Arthur+and+produced+by+Matt+Hill&amp;amp;c7=12-Jan-03&amp;amp;c8=1683419&amp;amp;c9=Audio' width='1' height='1' /&gt;&lt;!-- Guardian Watermark: technology/blog/audio/2012/jan/03/social-media-socialnetworking|2012-05-18T22:55:34Z|f84029f6f8c74b451e53fdd3ea23508a7efe1d40 --&gt;&lt;p&gt;guardian.co.uk &amp;#169; Guardian News &amp;amp; Media Limited 2010&lt;/p&gt; &lt;p&gt;Published via the &lt;a href="http://www.guardian.co.uk/open-platform/news-feed-wordpress-plugin" target="_blank" title="Guardian plugin page"&gt;Guardian News Feed&lt;/a&gt; &lt;a href="http://wordpress.org/extend/plugins/the-guardian-news-feed/" target="_blank" title="Wordress plugin page"&gt;plugin&lt;/a&gt; for WordPress.&lt;/p&gt;&lt;!-- END GUARDIAN WATERMARK --&gt;
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2012/01/09/tech-weekly-podcast-when-books-go-social/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Map, map and flatMap in Scala</title>
		<link>http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 10:56:39 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[learning]]></category>
		<category><![CDATA[scala]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=1348</guid>
		<description><![CDATA[One of the things I like about Scala is it&#8217;s collections framework. As a non CS graduate I only very lightly covered functional programming at university and I&#8217;d never come...]]></description>
			<content:encoded><![CDATA[<div id="attachment_1351" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/12/1464056042_169a1b6a14_z.jpeg"><img class="size-medium wp-image-1351" title="Scala (stairs) by Paolo Campioni" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/12/1464056042_169a1b6a14_z-300x199.jpg" alt="" width="300" height="199" /></a><p class="wp-caption-text">Scala (stairs) by Paolo Campioni</p></div>

<p>One of the things I like about Scala is it&#8217;s collections framework.  As a non CS graduate I only very lightly covered functional programming at university and I&#8217;d never come across it until Scala.  One the benefits of Scala is that the functional programming concepts can be introduced slowly to the programmer.  One of the first places you&#8217;ll start to use functional constructs is with the collections framework.</p>

<p>Chances are your first collection will be a list of items and we might want to apply a function to each item in the list in some way.</p>

<p>Map works by applying a function to each element in the list.</p>

<pre><code>scala&gt; val l = List(1,2,3,4,5)

scala&gt; l.map( x =&gt; x*2 )
res60: List[Int] = List(2, 4, 6, 8, 10)
</code></pre>

<p>So there are some occasions where you want to return a sequence or list from the function, for example an Option</p>

<pre><code>scala&gt; def f(x: Int) = if (v &gt; 2) Some(v) else None

scala&gt; l.map(x =&gt; f(x))
res63: List[Option[Int]] = List(None, None, Some(3), Some(4), Some(5))
</code></pre>

<p>flatMap works applying a function that returns a sequence for each element in the list, and flattening the results into the original list.  This is easier to show than to explain:</p>

<pre><code>scala&gt; def g(v:Int) = List(v-1, v, v+1)
g: (v: Int)List[Int]

scala&gt; l.map(x =&gt; g(x))
res64: List[List[Int]] = List(List(0, 1, 2), List(1, 2, 3), List(2, 3, 4), List(3, 4, 5), List(4, 5, 6))

scala&gt; l.flatMap(x =&gt; g(x))
res65: List[Int] = List(0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6)
</code></pre>

<p>This comes in really useful with the built in Option class because an option can be considered a sequence that is either empty or has 1 item.</p>

<pre><code>scala&gt; l.map(x =&gt; f(x))
res66: List[Option[Int]] = List(None, None, Some(3), Some(4), Some(5))

scala&gt; l.flatMap(x =&gt; f(x))
res67: List[Int] = List(3, 4, 5)
</code></pre>

<p>So with that all covered, lets look at how you can apply those concepts to a Map. Now a map can be implemented a number of different ways, but regardless of how it is implemented it can be thought of as a sequence of Tuples, where a tuple is a pair of items, the key and the value.</p>

<pre><code>scala&gt; val m = Map(1 -&gt; 2, 2 -&gt; 4, 3 -&gt; 6)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -&gt; 2, 2 -&gt; 4, 3 -&gt; 6)

scala&gt; m.toList
res69: List[(Int, Int)] = List((1,2), (2,4), (3,6))
</code></pre>

<p>We can access a tuple by accessing the inner variables _1 and _2</p>

<pre><code>scala&gt; val t = (1,2)
t: (Int, Int) = (1,2)

scala&gt; t._1
res70: Int = 1

scala&gt; t._2
res71: Int = 2
</code></pre>

<p>So we want to think about using map and flatMap on our Map, but because of the way a map works it often doesn&#8217;t make quite the same sense, we probably don&#8217;t want to apply a function to the tuple, but to the value side of the tuple, leaving the key as is, so for example we might want to double all the values.  Map provides us with a function to do exactly that.</p>

<pre><code>scala&gt; m.mapValues(v =&gt; v*2)
res73: scala.collection.immutable.Map[Int,Int] = Map(1 -&gt; 4, 2 -&gt; 8, 3 -&gt; 12)

scala&gt; m.mapValues(v =&gt; f(v))
res74: scala.collection.immutable.Map[Int,Option[Int]] = Map(1 -&gt; None, 2 -&gt; Some(4), 3 -&gt; Some(6))
</code></pre>

<p>But in my case I wanted to do something more like flat map in this case, I want a map to come out that misses out the key 1 because it&#8217;s value is None.  flatMap doesn&#8217;t work on maps like mapValues, it get&#8217;s passed the tuple and if it returns a List single items you&#8217;ll get a list back, but if you return a tuple you&#8217;ll get a Map back.</p>

<pre><code>scala&gt; m.flatMap(e =&gt; List(e._2))
res85: scala.collection.immutable.Iterable[Int] = List(2, 4, 6)

scala&gt; m.flatMap(e =&gt; List(e))
res86: scala.collection.immutable.Map[Int,Int] = Map(1 -&gt; 2, 2 -&gt; 4, 3 -&gt; 6)
</code></pre>

<p>Ok so we are pretty close to using options with flatMap, we need to filter out our None&#8217;s, we can do returning a list with just e => f(e._2) and we&#8217;ll get the list of values without the None&#8217;s, but that isn&#8217;t really what I want.  What I need to do is return an Option containing a tuple.  So here&#8217;s our updated function:</p>

<pre><code>scala&gt; def h(k:Int, v:Int) = if (v &gt; 2) Some(k-&gt;v) else None
h: (k: Int, v: Int)Option[(Int, Int)]
</code></pre>

<p>and here&#8217;s how we might call it:</p>

<pre><code>scala&gt; m.flatMap ( e =&gt; h(e._1,e._2) )
res109: scala.collection.immutable.Map[Int,Int] = Map(2 -&gt; 4, 3 -&gt; 6)
</code></pre>

<p>but this is pretty ugly, all those _1 and _2&#8242;s make me sad.  If only there was a nice way of unapplying the tuple into variables.  Given that this works in python and in a number of places in scala I thought this code should work:</p>

<pre><code>scala&gt; m.flatMap ( (k,v) =&gt; h(k,v) )
&lt;console&gt;:10: error: wrong number of parameters; expected = 1
</code></pre>

<p>I spent way too long today looking at this (in 5 minute chunks broken by meetings to be fair), before I gave in and asked a coworker what the hell I was missing.  The answer is seems is that an unapply is normally only executed in a PartialFunction, which in scala is most easily defined as a case statement.  So this is the code that works as expected:</p>

<pre><code>scala&gt; m.flatMap { case (k,v) =&gt; h(k,v) }
res108: scala.collection.immutable.Map[Int,Int] = Map(2 -&gt; 4, 3 -&gt; 6)
</code></pre>

<p>Note that we switch to using curly braces, indicating a function block rather than parameters, and the function is a case statement.  This means that the function block we pass to flatMap is a partialFunction that is only invoked for items that match the case statement, and in the case statement the unapply method on tuple is called to extract the contents of the tuple into the variables.  This form of variable extraction is very common, and you&#8217;ll see it used a lot.</p>

<p>There is of course another way of writing that code that doesn&#8217;t use flatMap.  Since what we are doing is removing all members of the map that don&#8217;t match a predicate, this is a use for the filter method:</p>

<pre><code>scala&gt; m.filter( e =&gt; f(e._2) != None )
res114: scala.collection.immutable.Map[Int,Int] = Map(2 -&gt; 4, 3 -&gt; 6)

scala&gt; m.filter { case (k,v) =&gt; f(v) != None }
res115: scala.collection.immutable.Map[Int,Int] = Map(2 -&gt; 4, 3 -&gt; 6)

scala&gt; m.filter { case (k,v) =&gt; f(v).isDefined }
res116: scala.collection.immutable.Map[Int,Int] = Map(2 -&gt; 4, 3 -&gt; 6)
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/12/02/map-map-and-flatmap-in-scala/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Annoyed by Guardian Facebook app?</title>
		<link>http://www.brunton-spall.co.uk/post/2011/11/12/annoyed-by-guardian-facebook-app/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/11/12/annoyed-by-guardian-facebook-app/#comments</comments>
		<pubDate>Sat, 12 Nov 2011 15:26:26 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[bookmarklet]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[guardian]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=1238</guid>
		<description><![CDATA[Are your friends sharing links to the Guardian Facebook app in their twitter feeds but you don&#8217;t use Facebook and want to see the original guardian page? Unfortunately due to...]]></description>
			<content:encoded><![CDATA[<p>Are your friends sharing links to the Guardian Facebook app in their twitter feeds but you don&#8217;t use Facebook and want to see the original guardian page?</p>

<p>Unfortunately due to the way the web (and Facebook) works, if somebody copies the URL in their browser and posts it to twitter you&#8217;ll be looking at the same thing as them, and if that was a guardian Facebook app, but you haven&#8217;t logged into Facebook, Facebook wont tell us anything so we can&#8217;t redirect you back to the guardian.</p>

<p>However, most modern browsers support special bookmarks with javascript in them, called Bookmarklets, and since the original Facebook url has the important path data needed for the guardian site, it&#8217;s possible to manipulate the current url to take you back to the guardian site without logging into Facebook.</p>

<p>Basically, drag this link: <iframe style="width: 100%; height: 100px;" src="http://jsfiddle.net/bruntonspall/La9yG/embedded/result/" frameborder="0" width="320" height="240"></iframe>
to your bookmarks toolbar up above this page, then click this link: <a href="http://apps.facebook.com/theguardian/music/musicblog/2011/nov/10/10-heaviest-albums-all-time?fb_ref=U-204nodQNlQBg4kqpI36BV6-CFCONX01FRS-339eqXXX,U-1aSIB2sgy2SC4xtjLBhpeM-CFCONX01FRS-339eqXXX,U-aN5g4adecUQD4urFI4BbEC-CFCONX01FRS-339eqXXX,U-2kdBzVKet5QY4dqoIr7TOu-CFCONX01FRS-33992XXX,U-EozmILdgd7yv4xUCJhdt3F-CFCONX01FRS-339nqXXX&amp;fb_source=home_multiline&amp;fb_action_types=news.reads" target="_blank">Are these the 10 heaviest albums ever made?</a> and then click the new fb-&gt;g link on your toolbar and you should go to the guardian site.</p>

<p>This will only work if you are not logged into facebook.
<h2>How does it work?</h2>
The Bookmarklet is a link with a javascript protocol (before the colon).  Your browser will execute the code when you click the button, and it will do so within the context of your current page.</p>

<p>It gets the current url, and looks for a parameter called cancel_url.  That&#8217;s where the url for the original apps.facebook.com is.  Next we replace apps.facebook.com/theguardian with www.guardian.co.uk, then we update window.location with the result.  This causes your browser to load the new url, and you should be on the guardian site.</p>

<p>Note that it does no error checking, it does not handle unusual guardian urls (that might not start www.guardian.co.uk) nor does it check whether there is a cancel_url before acting.</p>

<p>You can view the source and repurpose for your own uses at <a title="jsfiddle" href="http://jsfiddle.net/bruntonspall/La9yG" target="_blank">jsfiddle</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/11/12/annoyed-by-guardian-facebook-app/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Adding Google Plus redirect to your Nginx powered site</title>
		<link>http://www.brunton-spall.co.uk/post/2011/11/12/adding-google-plus-redirect-to-your-nginx-powered-site/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/11/12/adding-google-plus-redirect-to-your-nginx-powered-site/#comments</comments>
		<pubDate>Sat, 12 Nov 2011 12:55:02 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Technical]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[plus]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=1230</guid>
		<description><![CDATA[A quick one, this morning I&#8217;ve added the plus url to my website, so http://www.brunton-spall.co.uk/+ now redirects to my Google+ profile. This, it turns out, is really easy to implement...]]></description>
			<content:encoded><![CDATA[<p>A quick one, this morning I&#8217;ve added the plus url to my website, so <a href="http://www.brunton-spall.co.uk/+" target="_blank">http://www.brunton-spall.co.uk/+</a> now redirects to my Google+ profile.</p>

<p>This, it turns out, is really easy to implement if you run Nginx as the front to your website.</p>

<p>You simply need to update your server configuration to include the following snippet:
<pre>
location ~ ^/?&#43;$ {
  rewrite ^ https://plus.google.com/YOUR_NUMBER permanent;
}
</pre></p>

<p>This will ensure that your domain.tld/+ issues a redirect to your Google+ profile.</p>

<p>Hope this helps</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/11/12/adding-google-plus-redirect-to-your-nginx-powered-site/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Identifiers are not numbers</title>
		<link>http://www.brunton-spall.co.uk/post/2011/09/24/identifiers-are-not-numbers/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/09/24/identifiers-are-not-numbers/#comments</comments>
		<pubDate>Sat, 24 Sep 2011 12:13:14 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[rants]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=1026</guid>
		<description><![CDATA[&#8220;I am not a number, I am a free man&#8221; So something bugs me (I know, big shock), and it&#8217;s API documentation like this: The document will be returned as:...]]></description>
			<content:encoded><![CDATA[<p><em>&#8220;I am not a number, I am a free man&#8221;</em></p>

<p>So something bugs me (I know, big shock), and it&#8217;s API documentation like this:</p>

<pre><code>The document will be returned as:
ID: Integer
Name: String
Published: Date/Time
</code></pre>

<p>My position on this is simple, in an API (we&#8217;ll come back to internal design later), an ID should <em>always</em> be of String type.</p>

<p>So why is this a big deal?  I mean you implement this with a database table with autoincrement right, so it is a number underneath?</p>

<p>There&#8217;s a few issues with this and I&#8217;ll deal with them in reverse stupidity order.</p>

<h2>Numbers are more than identifiers</h2>

<p>A number represents a mathematical concept.  It implies strict ordering (2 is always > than 1), it implies a set of operations (1+2=3) and it implies an infinite set.
If you provide external developers with numbers they are going to assume that these implications are available and might make some form of sense.</p>

<p>You would hope that most people wouldn&#8217;t assume that something like twitter ids can be added or multiplied and expect anything sensible from them, but that comparison function, that&#8217;s a bit more tricky. It&#8217;s true that tweet 1 was sent before tweet 2, and even that tweet 1,000,000,000 was sent before tweet 2,000,000,000.  But as twitter scales guaranteeing that ordering becomes harder and harder in a massively parallel system, and there is no value in a client ordering tweets this way.  Each tweet has a date/time field on it indicating when it was sent, and ordering based on that field is far more semantically correct (and what the user expects).</p>

<h2>Numbers aren&#8217;t equal in all languages</h2>

<p>If you argue that representing something as a number is saving you memory, because an integer only occupies say 2 bytes, you are probably prematurely optimising.
Number representation is a very complex subject, one which I know only a little, but I know enough to know that I should never make assumptions about how a number is represented internally.</p>

<p>I come from a C background, and despite it being fairly common knowledge how big various numbers are stored, we have a sizeof operator for a reason.  Compiling your program on a slightly different architecture could change your integers from 2 bytes to 4 bytes to 8 bytes to anything inbetween. It&#8217;s a pretty common source of bugs for new developers to assume that unsigned int a is 4 bytes in size.</p>

<p>When you provide a number in an API, You have no idea who is consuming the API or what system they are running on.  It might be an x86 EC2 instance, or it might be a mobile device, it might be a super computer, or a graphic compute unit.</p>

<p>It&#8217;s fine in your system when you create your 4 billionth item and exceed the 32bit MAXINT (4,294,967,295 for unsigned ints), but will it be fine for all your users?  If your samples and current users get numbers in the low 100&#8242;s, but 2 years down the line you have a wildly successful product and your id&#8217;s are now into the billions upon billions?  Do you want people writing API libraries to have to worry and think about this?</p>

<p>One fantastic issue that <a href="https://dev.twitter.com/docs/twitter-ids-json-and-snowflake">twitter discovered</a> fairly recently is that javascript and therefore many json libraries are required to <a href="http://ecma262-5.com/ELS5_HTML.htm#Section_8.5">represent integers as a 53 bit number</a>, that&#8217;s a pretty large number, but it&#8217;s several orders of magnitude less than most people would expect.</p>

<h2>You make database scaling hard</h2>

<p>Autoincrementing primary keys are fine if your datastore is a single logical machine (a highly connected cluster), but as you add parallelism, there are a number of situations where you might want to be able to allocate id&#8217;s from more than one cluster at the same time without synchronisation between them.</p>

<p>If your ID&#8217;s in your table are not autoincrementing integers, but are an identifier that maybe looks like &#8220;DC1-DB1-0001&#8243; (or some other similar system), an identifier that takes into account the datacenter and database identifiers, reconciliation for tweet creation is perfectly possible.</p>

<h2>You lock yourself into technologies</h2>

<p>Autoincrementing primary keys are a feature of most relational databases.  Some support it natively, some support it with triggers and stored procedures.
However for scalability reasons, most non-relational databases don&#8217;t support them.  Mongo for example provides primary keys that are OID&#8217;s or Object ID&#8217;s.  These are a UUID4 type identifier that takes into account the host, the time and a few other things at creation time.  BigTable provides horrible &#8220;keys&#8221; that are totally opaque, I have no idea how a key is generated (nor should I need to know).</p>

<p>Adding an autoincrementing key on top of these technologies is often possible, but it is often not ideal.</p>

<h2>Conclusion</h2>

<p>So there is a number of good reasons not to use numbers as an identifier in your API.  Just use a string, trust me on this, you&#8217;ll use sightly more bytes, but you wont have to convert the integer into a string at API render time, and your client wont convert it back.  Your string will be opaque to the user, meaning you can change primary identifier format willy nilly and providing the old and new format don&#8217;t conflict it won&#8217;t matter.  Nobody will try to use false ordering on your ID&#8217;s when they should use a field instead, and it wont make me angry and ranty when I read your API documentation.</p>

<h2>Addendum</h2>

<p>I&#8217;m not saying don&#8217;t use a number in your database schema.  It&#8217;s entirely possible for your ID&#8217;s that you know you&#8217;ll only ever generate a few hundred ID&#8217;s and that you wont have a date/time field, but order of creation is important and ordering the ID&#8217;s is the simplest way to do so.  There are many valid reasons to use a numerical id internally for various things, but when you convert it into an API or external system, just turn that number into a string.</p>

<p>I strongly suspect that there will be people who will see your &#8220;{ &#8216;id&#8217;:&#8217;123&#8242; }&#8221; and will turn it into a number themselves, but then later if you return a document &#8220;{ &#8216;id&#8217;: &#8217;01-007&#8242;}&#8221; they can&#8217;t really complain, because you always told them it was an opaque string.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/09/24/identifiers-are-not-numbers/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Scala, lazy collections, streams and recursion</title>
		<link>http://www.brunton-spall.co.uk/post/2011/09/01/scala-lazy-collections-streams-and-recursion/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/09/01/scala-lazy-collections-streams-and-recursion/#comments</comments>
		<pubDate>Thu, 01 Sep 2011 17:08:22 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Technical]]></category>
		<category><![CDATA[learning]]></category>
		<category><![CDATA[scala]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=912</guid>
		<description><![CDATA[I&#8217;m currently rewriting the deployment system at the guardian in Scala, and although I&#8217;d say I know Scala, I&#8217;m learning lots of things as we go.  I&#8217;m lucky enough to...]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently rewriting the deployment system at the guardian in Scala, and although I&#8217;d say I know Scala, I&#8217;m learning lots of things as we go.  I&#8217;m lucky enough to be pairing with <a href="http://blog.tackley.net/" target="_blank">Graham Tackley</a>, our platform team lead and someone who knows Scala far better than I do, and this means that we often write a bit of code, then go back and improve it and so forth.</p>

<p>The bit of Scala code I&#8217;m particularly proud of is around waiting for a port to be opened.  During our deployment scripts we restart our application servers, then we want the scripts to wait until the server is up and able to serve requests before we move on.</p>

<p>Writing this kind of code is not terribly difficult, but testing that it works can be very tricky.  I decided to take the blackbox kind of approach to this, and my test spins up a second thread that listens on the port in question so that we can execute the real code that attempts to connect to the port.  In java or most other languages this would be something fairly long winded, but in my Scala test it looks like this:</p>

<p><script type="text/javascript" src="https://gist.github.com/1187013.js?file=spawn_test.scala"></script>The spawn function is provided by concurrent.ops and is built into Scala and represents a throwaway thread that we aren&#8217;t terribly interested in.  We don&#8217;t want to join on it, we just want it to start up and execute. The code inside creates a new java.net.ServerSocket, calls the blocking accept method which blocks until it gets a connection, closes the connection and then closes the original listening connection. We can then create and execute our port connection code and it should validly connect to the port 9998 on localhost and work beautifully.</p>

<p>The next test needed to be the failure case, if the waitForPort task cannot connect to a port after a specified timeout it should error, preferably by throwing an exception of some form. Testing this was also fairly easy, I wrote the traditional try { blah(); fail()} catch&#8230; stuff, then checked with Graham if there was a better way, and of course there was:<script type="text/javascript" src="https://gist.github.com/1187013.js?file=test_evaluating.scala"></script></p>

<p>ScalaTest with the ShouldMatchers makes for a simply beautiful test that is clear to read and was easy to write.</p>

<p>However when it came to implementing the method, I struggled a little bit.  I&#8217;ve never learnt functional programming, so closures and maps and so forth are still a bit alien to me, so I ended up writing some very java style code:</p>

<p><script type="text/javascript" src="https://gist.github.com/1187013.js?file=javaish.scala"></script>The isSocketOpen simply tries to open a socket and catches any exceptions to return false, and true if it opened successfully. Having written this, knowing there was a better solution, I asked again, and this prompted Phil Wills to upload his blogpost about the <a href="http://blog.phil-wills.com/streams-of-pleasure" target="_blank">Stream class and lazy evaluation</a>. I won&#8217;t cover the details here, but essentially using the return statement in Scala is frowned upon because of the way it works, and it&#8217;s more idiomatic Scala to use Options and flatMap, here&#8217;s the updated code:<script type="text/javascript" src="https://gist.github.com/1187013.js?file=range.scala"></script></p>

<p>Here we&#8217;ve changed isSocketOpen to checkSocketOpen and made it return an option.  At this point I also made checkSocketOpen do the sleep, which we could have done before, but is necessary now.</p>

<p>To explain, this code takes the range 1 to 10, which is a Seq of ints (1,2,3&#8230;) and we flatMap across it with a function that returns an option.  If you haven&#8217;t seen this before, here&#8217;s a quick overview of what the flatMap actually does:
<p style="padding-left: 30px;">map applies a function on each item in a collection and returns a transformed collection, essentially [a,b].map(f) is the same as calling [f(a), f(b)].</p>
<p style="padding-left: 30px;">If our function f returns an Option, this is either Some(true) or None.  An Option can really be thought of as a sequence that either contains 1 item or is empty, so Some(true) is the same as [true] and None is the same as [].</p>
<p style="padding-left: 30px;">This means our assuming that our function f returns None for everything but c, the map on [a, b, c, d] will return something like [ [], [], [true], [] ].  That&#8217;s often not a lot of use for us, and what we are interested in is stuff that returned something.</p>
<p style="padding-left: 30px;">flatMap is a function that essentially flattens the returned sequences catenated together, so if f(x) = [1,2] and f(y) = [4,5], then [x, y] map f == [ [1,2], [4,5] ] but [x, y] flatMap f == [ 1, 2, 3, 4 ].  This also has the handy shortcut that [] flattens into nothing, so essentially gets skipped, so our flatMap on [a, b, c, d] should return [true].</p>
We then use headOption, since it&#8217;s possible that we returned either [true], [true, true...] or [].  head would return us the first true, but on an empty list would die horribly, headOption returns an option that is Some(h) where the list is [h, t] and None where the list is [].  We then match on the option and throw an error if we got None (and therefore not a single call returned a true).</p>

<p>Our function checkSocketOpen has a side effect of pausing for an amount of time though, and since flatMap executes the function once for each item in the original list, this means that we will always pause for the entire connection timeout no matter whether we successfully connect the first time or not. (kind of, actually if we only pause on a failed connection, and if we successfully connect each time, we wont pause, but we will create 10 connections rather than just the one we need to confirm the port is open).</p>

<p>Phil in his blog has a very simple fix for this, which is to wrap our original sequence in a Stream class.  Stream is another Scala provided class, and in this case it is a sequence that is lazily evaluated.  Essentially this means that the flatMap doesn&#8217;t call the checkSocketOpen on all items immediately but instead only calls it when you try to get to the first item.  This means that headOption executes each function one after another until one of them returns true or it gets to the end of the sequence, it then returns the option based on what happened.</p>

<p>This means that if the first call returned none, it moved on and called f again over and over until it returned true, then the headOption stopped and never called the remaining calls, making this system stop as soon as the first connection was made.</p>

<p>Success! We&#8217;ve removed the return statement and made the code significantly harder to read and understand. <img src='http://www.brunton-spall.co.uk/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />   I&#8217;ve just taken several hundred words explaining why it works and I&#8217;m still not entirely clear on the details.</p>

<p>So we started wondering if there was an alternative way of doing this, something that would still be idiomatic Scala but that would be obvious to junior or learning Scala programmers like myself. Graham and I wondered if what a recursive solution would look like, so we came up with this code:</p>

<p><script src="https://gist.github.com/1187013.js?file=recursive.scala"></script>&nbsp;</p>

<p>We decided very early on to inline the checkSocketOpen function as recursive itself, so although this looks like more lines of code, it now combines both functions.</p>

<p>This function, when called at the bottom with checkOpen(0) initialises currentTry to 0, then tries to open a socket, if it is successful it just returns, if attempting to open a socket throws an exception it sleeps for a bit, then calls checkOpen with currentTry incremented by one.</p>

<p>All recursive functions have to have a guard, which is to say some statement that prevents infinite recursion (unless that&#8217;s what you want anyway), this function checks to find out if currentTry is greater than MAX<em>CONNECTION</em>ATTEMPTS and if it is, sys.error throws an exception which bubbles all the way back up through 10 copies of checkOpen before exiting properly.</p>

<p>If you know that your range is bounded fairly low, (such as 10 retry attempts) this is a perfectly acceptable way of writing this function.  We suspect because of the way we&#8217;ve written the try catch that it&#8217;s not possible to make this function tail recursive, which would effectively allow infinite (or lots) recursive calls, but I&#8217;m sure it&#8217;s possible to adjust the try catch into a subfunction that might make it tail recursive if you really wanted to.</p>

<p>&nbsp;</p>

<p>So there you go, that&#8217;s been a day of Scala learning for me, I now know the issues with the return statement, the Stream classes which might be useful later, and I&#8217;ve written my first truly recursive program in anger.  I&#8217;m feeling a little bit proud.</p>

<p>Of course there are improvements to make, making the function tail recursive would be education as I&#8217;m aware of tail recursion but am not entirely sure how to actually make a function tail recursive.  I&#8217;d also love to make that ServerSocket stuff into one line again, originally I had ServerSocket(port).accept().close() as one line, but I discovered in testing the stream stuff that the ServerSocket hangs around and keeps accepting connections if you don&#8217;t close it, which I can&#8217;t do in a single line without keeping a reference to it.</p>

<p>If you are interested in our new deploy system Magenta and the upcoming RifRaf web application for it, then I suggest you keep an eye out on our <a href="http://github.com/guardian" target="_blank">github repository</a> and feel free to send patches, advice and help our way.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/09/01/scala-lazy-collections-streams-and-recursion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google+ &#8211; A gentle introduction</title>
		<link>http://www.brunton-spall.co.uk/post/2011/07/01/googleplus-a-gentle-introduction/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/07/01/googleplus-a-gentle-introduction/#comments</comments>
		<pubDate>Fri, 01 Jul 2011 21:48:59 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=639</guid>
		<description><![CDATA[So a couple of days ago Google launched Google+, a product that did not slip out quietly it seems despite Google’s intentions. You’ve probably read journalists who love it and...]]></description>
			<content:encoded><![CDATA[<p>So a couple of days ago Google launched <a href="http://plus.google.com" target="_blank">Google+</a>, a product that did not slip out quietly it seems despite Google’s intentions.</p>

<p>You’ve probably read journalists who love it and journalists that hated it, but since the cat appears to be out of the bag and the invitations are flowing fast and furious I thought I’d write a quick few bits about how to get started using it.</p>

<p>First of all your invitation.  If somebody you know has invited you, there’s a good chance that you didn’t realise it was an invitation.  There are 2 forms of invitation.</p>

<p>As a &#8220;member of the press&#8221; (by association not directly) I got a real invitation from the Google PR team, which appeared to come from one of our developers.  It looked a bit like this and it was a real invitation.</p>

<div id="attachment_660" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-An-Invite-4.jpg"><img class="size-medium wp-image-660" title="Google+ - An Invite" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-An-Invite-4-300x266.jpg" alt="" width="300" height="266" /></a><p class="wp-caption-text">A real full invite</p></div>

<p><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-An-Invite-4.jpg"></a>You can see clearly that it is an invitation and you can sign up from the mail easily.</p>

<p>During the first few hours, Google ‘accidentally’ left a send invitation feature into Google+, which was quickly noticed by the press and the number of people coming in massively increased.  Google quickly disabled the send an invite functionality, and we don’t know when it’s coming back.</p>

<p>However there is another way to invite people to Google+ and they get an email that looks like this:</p>

<div id="attachment_641" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-An-Invite-1-1.jpg"><img class="size-medium wp-image-641 " title="Google+ An Invite" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-An-Invite-1-1-300x90.jpg" alt="" width="300" height="90" /></a><p class="wp-caption-text">This is actually an invite</p></div>

<p>Firstly this is not an official way of inviting someone, and may not work.  This email doesn’t say invitation except in tiny print at the bottom of the email, and instead looks like an opportunity to see the marketing bumph about Google+.</p>

<p>But clicking that button will result in your seeing one of two screens, if you are unlucky, it appears that Google are disabling signups globally for a few hours at a time, and you’ll get the “We are overloaded” page.</p>

<div id="attachment_642" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Overloaded.jpg"><img class="size-medium wp-image-642" title="Google+ Overloaded" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Overloaded-300x145.jpg" alt="" width="300" height="145" /></a><p class="wp-caption-text">When Google is not allowing invites, this is what you see</p></div>

<p>If you get this try again in a few hours (or minutes) and you might get lucky and get the “Make an account” page (I don&#8217;t have a screenshot I&#8217;m afraid, you can&#8217;t miss it, it asks for your name and has a big signup button).</p>

<p>&nbsp;
<h2>First steps in Google+</h2>
The first page you’ll see will contain a lot of welcome bumph.  Go ahead and read it, watch the videos and come back after you’ve experimented.  I’ll wait for you.If you are a popular kind of person with geeks, then there is a good chance that you will have a number of notifications that you are in peoples circles already.</p>

<div id="attachment_643" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Sharing-with-me.jpg"><img class="size-medium wp-image-643" title="Google+ - Sharing with me" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Sharing-with-me-300x115.jpg" alt="" width="300" height="115" /></a><p class="wp-caption-text">People are sharing with me</p></div>

<p>If you unlucky and only know one or two geeks then it’s possible that the only person who has added you is the person who invited you.  Never mind, you can find friends all on your own.</p>

<p>First of all, you can simply mine your gmail contact book.  This is particularly easy to do, and Google have put a lot of thought into it.</p>

<div id="attachment_648" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Adding-friends-2.jpg"><img class="size-medium wp-image-648" title="Google+ Adding friends" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Adding-friends-2-300x64.jpg" alt="" width="300" height="64" /></a><p class="wp-caption-text">A list of friends</p></div>

<p>In the section that looks like this under your circles, you can see all of your contacts who are not yet on Google+.  At first you will probably instinctively start dragging contacts down to the relevant circle one at a time.  This is a fairly inefficient way of sorting your contacts.</p>

<div id="attachment_645" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Selecting-multiple-friends.jpg"><img class="size-medium wp-image-645" title="Google+ - Selecting multiple friends" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Selecting-multiple-friends-300x67.jpg" alt="" width="300" height="67" /></a><p class="wp-caption-text">Click to select multiple friends</p></div>

<p>Instead simply click all of the contacts that you want in a single circle (say the 25 members of my family I wanted to select) and then drag one of them, you should see that they all come down and group together to be dropped into a circle.  This makes life a lot easier when sorting out those tricky large groups.</p>

<div id="attachment_649" class="wp-caption alignnone" style="width: 238px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Create-a-new-circle.jpg"><img class="size-full wp-image-649" title="Google+ Create a new circle" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Create-a-new-circle.jpg" alt="" width="228" height="190" /></a><p class="wp-caption-text">Creating a new circle of friends</p></div>

<p>Create lots of circles, you can add people to multiple circles, and it’s very easy to rename, delete and even move people from one circle to another.  I currently have circles for my church, my friends from Milton Keynes, my friends from School, people I’ve worked with, and people I currently work with at the Guardian.</p>

<p>Speaking of people you went to school with, I don’t really use GMail (especially not my gmail account itself) to email people, so I only had 60 − 80 addresses in there.  For a number of my contacts, I instead use Facebook.  At the time I’m writing this, adding your Facebook contacts requires a couple of steps.  I expect this to change eventually, but for now, it turns out that Yahoo works as a very good middleman.</p>

<p><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Yahoo-Mail.jpg"><img class="alignnone size-medium wp-image-652" title="Yahoo! Mail" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Yahoo-Mail-300x162.jpg" alt="" width="300" height="162" /></a></p>

<p><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Yahoo-Mail.jpg"></a>Login to Yahoo Mail for your Yahoo account (or create one if you don’t have one).  Click the contacts link, and select the Import Contacts link from the Popular Tools that you should see.</p>

<p><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Yahoo-Add-Facebook.jpg"><img class="alignnone size-medium wp-image-651" title="Yahoo Add Facebook" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Yahoo-Add-Facebook-300x169.jpg" alt="" width="300" height="169" /></a></p>

<p><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Yahoo-Add-Facebook.jpg"></a>You can now select Facebook, enter your Facebook details and Yahoo will happily slurp all of your Facebook friends into your Yahoo email list.  Handy huh?</p>

<div id="attachment_653" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Find-and-Invite-1.jpg"><img class="size-medium wp-image-653" title="Google+ - Find and Invite" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Find-and-Invite-1-300x36.jpg" alt="" width="300" height="36" /></a><p class="wp-caption-text">Find and invite from Yahoo</p></div>

<p>Now back in Google+, Under the circles tab, select the Find and Invite link and you should be able to add your Yahoo contacts.  Authorise it from your Yahoo account by following the instructions and suddenly all of your Facebook friends should be available in the Find and Invite tab.</p>

<div id="attachment_647" class="wp-caption alignnone" style="width: 157px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Someones-circles.jpg"><img class="size-medium wp-image-647" title="Google+ - Someones circles" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Someones-circles-147x300.jpg" alt="" width="147" height="300" /></a><p class="wp-caption-text">People who are in paul&#39;s circles</p></div>

<p>Finally, once you’ve got a few friends who are on Google+, you can start looking at their circles to see if there are any friends that you are missing.  In pretty much any section of Google+ you can click somebodies name and get to their profile page.  On the left is a quick view of a few people in their circle, and people who have added them to their circles (and people you’ve got in common).</p>

<div id="attachment_644" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-People-in-circles.jpg"><img class="size-medium wp-image-644" title="Google+ - People in circles" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-People-in-circles-300x173.jpg" alt="" width="300" height="173" /></a><p class="wp-caption-text">People in pauls circles</p></div>

<p>If you hit the view more, you can get a nice view of all their contacts with an easy way to add them to your own circles.  With this you can very easily start adding a large number of people who are already on Google circles.</p>

<p>Doing all of this should give you a fair number of people into your circles, but you might be missing a number of the less geeky people in your life.  You might have them in your circles, but they don’t have a Google+ profile yet.  How disappointing.  So lets discuss invites.I cannot guarantee that this works, the only sure way to send invites is to wait for Google to fully enable invites.   For now the following seems to send out the magic email.</p>

<div id="attachment_654" class="wp-caption alignnone" style="width: 310px"><a href="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Email-friends.jpg"><img class="size-medium wp-image-654" title="Google+ Email friends" src="http://www.brunton-spall.co.uk/wp-content/uploads/2011/07/Google+-Email-friends-300x116.jpg" alt="" width="300" height="116" /></a><p class="wp-caption-text">Email your friends</p></div>

<p>Go to your stream and start sharing something.  Remove the Public/All Circles users that are currently in the list and add a circle that has members you want to invite.  You should see an option to email people not on Google+, tick it and confirm the pop up that comes up when you click share.</p>

<p>This will cause each of those people to get an email indicating that they’ve been mentioned, and they can click the link in the email and hopefully they’ll get in and sign up.</p>

<p>I hope you found this useful, and feel free to <a href="https://plus.google.com/100589676414609537192/posts?tab=XX">find me on Google+</a> and say hello or thanks.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/07/01/googleplus-a-gentle-introduction/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google&#8217;s Chrome browser hits 160m users &#8211; but what does it mean for the web?</title>
		<link>http://www.brunton-spall.co.uk/post/2011/06/14/googles-chrome-browser-hits-160m-users-but-what-does-it-mean-for-the-web/</link>
		<comments>http://www.brunton-spall.co.uk/post/2011/06/14/googles-chrome-browser-hits-160m-users-but-what-does-it-mean-for-the-web/#comments</comments>
		<pubDate>Tue, 14 Jun 2011 12:30:38 +0000</pubDate>
		<dc:creator>bruntonspall</dc:creator>
				<category><![CDATA[From the guardian]]></category>
		<category><![CDATA[Article]]></category>
		<category><![CDATA[Blogposts]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[Michael Brunton-Spall]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Technology blog]]></category>

		<guid isPermaLink="false">http://www.brunton-spall.co.uk/?p=566</guid>
		<description><![CDATA[Search giant's browser gets automatically updated, yet there's a hint that it might be shifting towards the territory that made Internet Explorer so divisive]]></description>
			<content:encoded><![CDATA[<p>&nbsp;</p>

<!-- GUARDIAN WATERMARK --><p><a href="http://www.guardian.co.uk/technology/blog/2011/may/11/html5-google"><img class="alignright" src="http://image.guardian.co.uk/sys-images/Guardian/Pix/pictures/2010/03/01/poweredbyguardianBLACK.png" alt="Powered by Guardian.co.uk" width="140" height="45" />This article titled &#8220;Google&#8217;s Chrome browser hits 160m users &#8211; but what does it mean for the web?&#8221; was written by Michael Brunton-Spall, for guardian.co.uk on Wednesday 11th May 2011 19.38 UTC</a></p><p>We have decisively moved from a world of one browser provided by your operating system to a world where people install the browser of their choice. The increasing growth of Firefox usage has risen to the point where 31% of users on the Guardian website use Firefox and only 37% use Microsoft&#8217;s Internet Explorer (split into 22% IE8, 9% IE7 and approx 3% each for IE6 and IE9). </p><p>Google&#8217;s entry into the market has increased usage over time: one year ago at the previous Google IO, there were 70m Chrome users worldwide; today we were told there are over 160m. Unusually for a browser, Google has committed to a forced upgrade process and releases updates every six weeks. </p><p>Why? To combat the problem that more than 50% of Windows computers around the world are still running Windows XP – an operating system that is approaching 10 years old &#8211; and a browser that&#8217;s often the same age.</p><p>Google has been trumpeting its <a href="http://www.google.com/chrome/">Chrome browser</a> achievements at Google IO, showing off what a wonderful platform it is for the web. Over the last year, the team has improved the performance of the browser when running complex web applications by improving the performance of the underlying Javascript engine that web developers use to add logic to a simple web page. Additional improvements in security have made the &#8220;Google web&#8221; a safer place to be &#8211; which can only be good for the web, and for users.</p><p>The biggest announcements they have made is massive improvements to the graphics functionality in your browser. Implementations of the <a href="http://diveintohtml5.org/canvas.html">HTML5 Canvas</a> technology that powers many of the graphical bits of the web are 10 times faster than they were in previous versions, and those improvements don&#8217;t require the developers to upgrade their application. </p><p>This is good news for game developers such as Rovio, who are able to build Angry Birds for the web, and on new builds of the Chrome browser it will run faster.</p><p>If developers want much, <em>much</em> faster graphics, the Chrome browser team has spent time vastly improving the <a href="http://en.wikipedia.org/wiki/WebGL">WebGL graphics library</a> available in Chrome. This is a subsystem of the browser, often called part of the HTML5 specification, but actually a separate specification in its own right, that allows developers to build 3D applications and utilise the high performance graphics hardware available in your machine. </p><p>Google&#8217;s improvements in Chrome means that WebGL applications can run up to 10 times faster than the equivalent Canvas implementation.</p><p>The dark side of all of these improvements is that we are likely to start seeing &#8220;Optimized for Google Chrome&#8221; badges on the web, as many of these features won&#8217;t work across all browsers. That wasn&#8217;t good with Internet Explorer in the bad old days of the Netscape wars, and wouldn&#8217;t be good today. Some things such as Canvas work in most browsers (but not in the most common versions of Internet Explorer), but WebGL&#8217;s implementation is inconsistent across all the browsers. </p><p>Google&#8217;s advancements are welcome for experimental applications, and developers building applications for the Chrome App Store, but their impact on the wider web will probably be negligible, since cross-browser implementation is considered so important by many organisations.</p><div class="gu_advert">
        
          <a rel="nofollow" href="http://oas.guardian.co.uk/RealMedia/ads/click_nx.ads/guardianapis.com/technology/oas.html/@Bottom">
              <img alt="Ads by The Guardian" src="http://oas.guardian.co.uk/RealMedia/ads/adstream_nx.ads/guardianapis.com/technology/oas.html/@Bottom"></img>
          </a>
        
      </div><img src='http://hits.guardian.co.uk/b/ss/guardiangu-api/1/H.20.3/98867?ns=guardian&amp;pageName=Google%27s+Chrome+browser+hits+160m+users+-+but+what+does+it+mean+for+the+web%3F+Article+1557091&amp;ch=Technology&amp;c2=67197&amp;c4=HTML5%2CGoogle+%28Technology%29%2CChrome+%28technology%29%2CTechnology&amp;c3=guardian.co.uk&amp;c6=Michael+Brunton-Spall&amp;c7=11-May-11&amp;c8=1557091&amp;c9=Article' width='1' height='1' /><!-- Guardian Watermark: technology/blog/2011/may/11/html5-google|2012-05-18T22:55:33Z|1b89c2a4a5f516064bab492ce47ad0fa64e1f41d --><p>guardian.co.uk &#169; Guardian News &amp; Media Limited 2010</p> <p>Published via the <a href="http://www.guardian.co.uk/open-platform/news-feed-wordpress-plugin" target="_blank" title="Guardian plugin page">Guardian News Feed</a> <a href="http://wordpress.org/extend/plugins/the-guardian-news-feed/" target="_blank" title="Wordress plugin page">plugin</a> for WordPress.</p><!-- END GUARDIAN WATERMARK -->
]]></content:encoded>
			<wfw:commentRss>http://www.brunton-spall.co.uk/post/2011/06/14/googles-chrome-browser-hits-160m-users-but-what-does-it-mean-for-the-web/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

