<?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>Ben Longden</title>
	<atom:link href="http://nocarrier.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>http://nocarrier.co.uk</link>
	<description>PHP and some other bits...</description>
	<lastBuildDate>Sat, 28 Jan 2012 12:06:18 +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>So you think TDD isn&#8217;t worth the cost?</title>
		<link>http://nocarrier.co.uk/2012/01/so-you-think-tdd-isnt-worth-the-cost/</link>
		<comments>http://nocarrier.co.uk/2012/01/so-you-think-tdd-isnt-worth-the-cost/#comments</comments>
		<pubDate>Sat, 28 Jan 2012 11:16:57 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[unittests]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=118</guid>
		<description><![CDATA[<p>Think of the full software development life cycle. We gather requirements, create user stories, break them down into tasks, estimate, fight with your client about how long it&#8217;s all going to take, renegotiate the timings (what&#8217;s 35% of the development time on unit tests? Do we need those?), submit a revised timescale with cut down [...]]]></description>
			<content:encoded><![CDATA[<p>Think of the full software development life cycle. We gather requirements, create user stories, break them down into tasks, estimate, fight with your client about how long it&#8217;s all going to take, renegotiate the timings (what&#8217;s 35% of the development time on unit tests? Do we need those?), submit a revised timescale with cut down requirements and no time allocated to testing. Then we start development.</p>
<p>And soon the problems start coming up. At the end of the first sprint the client raises a few bugs with the software delivery&#8230; We didn&#8217;t account for those in the plan! And we can&#8217;t estimate them &#8211; we don&#8217;t know the size of the problem. That&#8217;s why it&#8217;s a bug&#8230; So we allocate some time in the next sprint to work on the top priority bugs and commit to developing fewer features.</p>
<p>The second sprint finishes, and more defects are raised in the software &#8211; some of them can be attributed to requirements not been defined clearly enough, but some of them are just code that we don&#8217;t understand how it even worked in development! Did someone actually test it before it went into the main development branch?! (how many people can honestly say they have never heard that one before&#8230;?)</p>
<p>Pretty soon you&#8217;re way behind the plan. The number of bugs that we cannot estimate and didn&#8217;t plan for are sucking up too much time and we don&#8217;t know how long it&#8217;s going to take to get back to a point where we know how long the project is going to take.</p>
<p>So what&#8217;s to be done? Bugs throughout the development life cycle are inevitable &#8211; but because we cannot know how many there will be and how long they will take to fix, we need to be able to minimise the number that crop up.</p>
<p>Some research done by microsoft (http://research.microsoft.com/en-us/groups/ese/nagappan_tdd.pdf) has shown that spending 15-35% extra development time on adopting test driven development resulted in a pre-release defect density decrease of 40-90%.</p>
<p>The ideal is when we can plan, develop and release software that contains no defects in a timescale that everyone agrees on. This wont happen any time soon &#8211; but an increase of 15-35% development time for up to a 90% decrease in the number of defects has *got* to be worth it by anybody&#8217;s standards.</p>
<p>Have you used TDD (or BDD) and experienced similar results? Comments encouraged! </p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2012/01/so-you-think-tdd-isnt-worth-the-cost/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>REST and the Hypermedia Constraint</title>
		<link>http://nocarrier.co.uk/2012/01/rest-and-the-hypermedia-constraint/</link>
		<comments>http://nocarrier.co.uk/2012/01/rest-and-the-hypermedia-constraint/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 10:39:33 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[php rest fdrop]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=111</guid>
		<description><![CDATA[<p>The video of my talk at PHPNW &#8217;11 has now been posted online at <a href="http://blip.tv/phpnw/phpnw11-ben-longden-rest-and-hateoas-a-case-study-5858742">blip.tv</a></p> <p>Enjoy!</p>]]></description>
			<content:encoded><![CDATA[<p>The video of my talk at PHPNW &#8217;11 has now been posted online at <a href="http://blip.tv/phpnw/phpnw11-ben-longden-rest-and-hateoas-a-case-study-5858742">blip.tv</a></p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2012/01/rest-and-the-hypermedia-constraint/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Magento Enterprise PageCache</title>
		<link>http://nocarrier.co.uk/2012/01/magento-enterprise-pagecache/</link>
		<comments>http://nocarrier.co.uk/2012/01/magento-enterprise-pagecache/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 20:28:13 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[magento]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=103</guid>
		<description><![CDATA[<p>I have split this post into two parts &#8211; starting with how pages are cached in the first place, and then how Magento retrieves a page from the cache before falling back to dispatching a controller.</p> <p>How pages are cached</p> <p>The Magento enterprise page cache module observes several events that are fired during the course [...]]]></description>
			<content:encoded><![CDATA[<p>I have split this post into two parts &#8211; starting with how pages are cached in the first place, and then how Magento retrieves a page from the cache before falling back to dispatching a controller.</p>
<p><strong>How pages are cached</strong></p>
<p>The Magento enterprise page cache module observes several events that are fired during the course of dispatching your controller and sending a full page in the response. I&#8217;m going to dive into only a few of them &#8211; the main observers that actually cause your content to end up in the page cache, and then exactly how Magento gets it back out again.</p>
<p>The first thing we&#8217;re going to look at is how Magento caches pages, and that starts with the observation of the &#8216;controller_action_predispatch&#8217; event &#8211; triggered before a request is dispatched (but after we have determined we will not be fulfilling the request from the cache). It&#8217;s here that the PageCache module will determine if the request that&#8217;s about to be dispatched is to be cached for subsequent requests. There are many things that will prevent a page from being cached and we can start by looking at these.</p>
<p>Examine the processPreDispatch method in Enterprise_PageCache_Model_Observer. This is the event that is fired on the controller_action_predispatch event. All the handlers first check to ensure that the page cache is enabled before doing anything else. Then we examine the no cache cookie and set a flag (memorize_disabled) in the session.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_processor<span style="color: #339933;">-&gt;</span><span style="color: #004000;">canProcessRequest</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_processor<span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRequestProcessor</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>The first of the above two condiditions does some basic validation on the request. $this->_processor will normally be an instance of &#8216;Enterprise_PageCache_Model_Processor&#8217; by this point (it&#8217;s instantiated by the &#8216;enterprise_pagecache/processor&#8217; model here so can be overridden), and here we will find the canProcessRequest method. First, we dip into the isAllowed method where we check that we&#8217;ve generated a requestId during the construction of this object. The requestId will become important later on in the process as it provides the key into your cache storage backend for the page content and needs to be reliably recreated based on the request parameters. We then check that the request is not over https, the no cache cookie (NO_CACHE) is not present, the no_cache GET variable is not present and that full page caching is enabled. If any of these checks fail we do not process this request any further in the full page cache module.</p>
<p>Assuming we pass, we move onto checking the configuration. We inspect the page depth parameter (the number of variations a page can have based on the number of variables in the query string). If we&#8217;re over the limit, the page is not cached. Then we check the cache settings for pages that are not in the default currency (system/page_cache/multicurrency = 0 and the presence of the CURRENCY cookie in the request).</p>
<p>The second of the two checks above is where we examine how the page is going to be cached. This is configured in &#8216;frontend/cache/requests&#8217; and the defaults are found in app/code/core/Enterprise/PageCache/etc/config.xml in the following section of XML. By default all cms, catalog/category and catalog/product pages have a processor configured.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;frontend<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    ...
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cache<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;requests<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cms<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>enterprise_pagecache/processor_default<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cms<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;catalog<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;category<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;view<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>enterprise_pagecache/processor_category<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/view<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/category<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/catalog<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;catalog<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;product<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;view<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>enterprise_pagecache/processor_product<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/view<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/product<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/catalog<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/requests<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cache<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/frontend<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>getRequestProcessor is where this configuration is examined and we we use the request data to attempt to construct a processor for the target page. Assuming one is configured, Magento is now ready to cache the page for the next request.</p>
<p>If at this point it looks as though we&#8217;re going to cache the page, the independent block cache is disabled and the first peice of setting up the cache is complete.</p>
<p>The next time we&#8217;re back in the PageCache code is once the request has been handled and we&#8217;re about to send the response. This is accomplished by hooking into the controller_front_send_response_before event and executing the &#8216;cacheResponse&#8217; method on the observer. We very quickly end up back in the processor and in the processRequestResponse method.</p>
<p>The first two calls will be familiar. The same methods (canProcessRequest and getRequestProcessor) are called again &#8211; however the processor for this request already exists so the second method returns immediately. We delegate to the configured processor (configured above) at this point and call the &#8216;allowCache&#8217; method with the Request object as a parameter. A number of further checks are done which could prevent the request from being cached &#8211; the presence of &#8216;___store&#8217; or &#8216;___from_store&#8217; in the query string (for the default processor) or the presence of the no cache flag in the session data.</p>
<p>Finally we&#8217;re actually ready to cache the response. Some filtering occurs to strip out blocks and replace them with placeholders (blocks can be cached independently from the page &#8211; to allow for independant cache rules &#8211; like the navigation menu which can persist across multiple pages). The placeholder configuration is stored in app/code/core/Enterprise/PageCache/etc/cache.xml and is structured like the following (this is a real example for the catalog/navigation block).</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;placeholders<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;catalog_navigation<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;block<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>catalog/navigation<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/block<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>catalog.topnav<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;placeholder<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CATALOG_NAVIGATION<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/placeholder<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Enterprise_PageCache_Model_Container_Catalognavigation<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/container<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;cache_lifetime<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>86400<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/cache_lifetime<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/catalog_navigation<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/placeholders<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/config<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>The above peice of XML declares the catalog/navigation block to be cached separately to any page that is appears on with CATALOG_NAVIGATION as the placeholder. It specifies the container class (used during storing and extracting the block) and the lifetime in seconds for the cached block.</p>
<p>Blocks are marked up at the time they are rendered and you can view them in the HTML source code between comment blocks that consist of the placeholder value defined in cache.xml, and a hash that is made up by the md5 sum of the results of calling the getCacheKey. They look something like the following (again, using CATALOG_NAVIGATION as an example).</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">&lt;!--{CATALOG_NAVIGATION_a61df2dc9b9e5868f17a56461177d8c4}--&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>some html<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #808080; font-style: italic;">&lt;!--/{CATALOG_NAVIGATION_a61df2dc9b9e5868f17a56461177d8c4}--&gt;</span></pre></div></div>

<p>This functionality gives you the ability to be able to cache blocks separately to the full page &#8211; with their own rules on how long they stay in the cache for (and independently of the page that they are on). This means that blocks can be made to be cached across pages rather than within them &#8211; meaning that blocks such as catalog/navigation need only be generated once &#8211; and served up from the cache for every request after that regardless of if the page itself is being served from the cache.</p>
<p><strong>How pages are served up from the cache</strong></p>
<p>Rather unlike how pages end up in the cache (using observers to watch for specific points in the dispatch process for a request), the method by which Magento retrieves information from the cache is somewhat more hard coded. Before dispatching the front controller in Mage_Core_Model_App::run (one of the very first methods that gets called in fulfilling a request) a check is done to see if the current request can be served up from the pages in the cache. This happens inside Mage_Core_Model_Cache::processRequest where we immediately check to see if there is a request processor configured that we can check the request against. The request processors are configured inside app/etc/enterprise.xml &#8211; the default one is set to Enterprise_PageCache_Model_Processor (predictably the same class used to cache the results of a dispatched request).</p>
<p>This is quite important &#8211; if you have a reason to extend the logic in Enterprise_PageCache_Model_Processor (like adding data that forms part of the cache id for a page), you not only have to extend it and rewrite &#8216;enterprise_pagecache/processor&#8217;, but also make sure that it&#8217;s added to this list of request processors so that Magento has a chance of being able to retrieve your items back out of the cache again.</p>
<p>Magento then loops through all the configured request processors, and calls extractContent on each of them. The first thing that this function does is create the cache id based on the request parameters (this happens when the processor is constructed, when the _createRequestIds method is called &#8211; as we saw earlier when the content was being cached in the first place). We check to see if any design changes have been cached for the current page, and then check the configured cache storage to see if we can retrieve the full page content for this request. If we do not get a match at this point, the request is considered a cache miss &#8211; and we return to the run method and start the process of dispatching the request (and potentially populating the cache with the results).</p>
<p>Assuming that we have a cache hit, we decompress it (content will be gzipped whenever possible in the cache storage to minimise space), and the content is processed by _processContent to replace all of the placeholders with separate cached blocks (ie, the catalog/navigation block that we cached separately when putting the page into the cache in the first place).</p>
<p>When writing about how pages are served up from the cache I referred to the configured cache storage. Prior to Magento EE 1.11, the full page cache simply used what you configured in the <cache></cache> section in app/etc/local.xml. From 1.11 this has changed and you must now also have a <full_page_cache></full_page_cache> section in your local.xml configuration (it uses exactly the same options as the <cache></cache> config).</p>
<p>The aim of this post is to give an overview of how page caching works in magento and I am intending on following it up with some more detailed investigations into how more areas of cacheing work. If you have a specific request for more information, please do leave a comment and it may form part of a future blog post.</p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2012/01/magento-enterprise-pagecache/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>My OS X apps</title>
		<link>http://nocarrier.co.uk/2011/11/my-os-x-apps/</link>
		<comments>http://nocarrier.co.uk/2011/11/my-os-x-apps/#comments</comments>
		<pubDate>Sat, 19 Nov 2011 18:28:58 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[osx mac]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=89</guid>
		<description><![CDATA[<p>I&#8217;ve had to reinstall OS X Lion in the past few days. Here is a list of apps that I really like (in no particular order)</p> <p>Chrome / Firefox &#8211; Pretty much all that I use Safari for (sorry, apple!)</p> <p>Twitter &#8211; obvious reasons</p> <p>Alfred &#8211; really great app launcher (and other stuff)</p> <p>Caffeine &#8211; [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had to reinstall OS X Lion in the past few days. Here is a list of apps that I really like (in no particular order)</p>
<p>Chrome / Firefox &#8211; Pretty much all that I use Safari for (sorry, apple!)</p>
<p>Twitter &#8211; obvious reasons</p>
<p>Alfred &#8211; really great app launcher (and other stuff)</p>
<p>Caffeine &#8211; keep your mac awake for longer</p>
<p>Skype &#8211; Well, more out of necessity.</p>
<p>Dropbox &#8211; would have been lost without this!</p>
<p>Virtualbox / vagrant &#8211; dev tools.</p>
<p>Homebrew + git + vim &#8211; more dev tools&#8230;</p>
<p>GitX &#8211; Nice OS X native git gui.</p>
<p>1Password &#8211; Conundrum &#8211; what do you do when your password file is in dropbox, and your dropbox password is in 1Password? Use the iPhone app! Brilliant.</p>
<p>Moom &#8211; really cool window resizing management for OS X</p>
<p>Growl &#8211; part of OS X but deserves a mention for v1.3 in the app store.</p>
<p>iTerm2 &#8211; much nicer than the default Terminal.</p>
<p>I&#8217;ll leave it at that for now. Will update this if I remember anything else that I have missed!</p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2011/11/my-os-x-apps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>xhtml as a hypermedia format</title>
		<link>http://nocarrier.co.uk/2011/10/xhtml-as-a-hypermedia-format/</link>
		<comments>http://nocarrier.co.uk/2011/10/xhtml-as-a-hypermedia-format/#comments</comments>
		<pubDate>Sun, 02 Oct 2011 08:34:10 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=84</guid>
		<description><![CDATA[<p>XHTML is a tempting hypermedia format to use in a web service. A lot of the time, the sort of data that you serve using an API is very similar (if not the same) to what your website displays on its own. XHTML already has all the functionality built in for describing forms, where to [...]]]></description>
			<content:encoded><![CDATA[<p>XHTML is a tempting hypermedia format to use in a web service. A lot of the time, the sort of data that you serve using an API is very similar (if not the same) to what your website displays on its own. XHTML already has all the functionality built in for describing forms, where to post them back to once filled in, how to link to images, documents or any other form of data across the whole web of information.</p>
<p>Despite all this good stuff that you get for free, xhtml, or rather the xhtml media type (application/xhtml+xml) has its problems. And one of those problems is webkit.</p>
<p>Mobile devices are incredibly important in modern web development, so designing for the capabilities of those devices is just part of a standard workflow. The problem however, is that webkit on these devices prefer application/xml and application/xhtml over our friend, text/html. Take a look at the following Accept header sent by two desktop browsers (Firefox and Chrome):<br />
<code><br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9, */*;q=0.8<br />
</code></p>
<p>Contrast this with what is sent from the iPhone (iOS 4.3.5):<br />
<code><br />
Accept: application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5<br />
</code></p>
<p>And further, and Android phone (2.3.5):</p>
<p><code><br />
Accept: text/xml, text/html, application/xhtml+xml, image/png, text/plain, */*;q=0.8<br />
</code></p>
<p>And suddenly we have a problem. If we use application/xhtml+xml then we have to account for iOS and Android devices preferring it over text/html.</p>
<p>There&#8217;s two things we can do to counter this. The first is to put a filter in front of your application to detect the user agents for browsers that are known to prefer the xml/xhtml representation that we want to reserve for our API clients. This is an application specific solution &#8211; you have to know that the browsers that you are filtering and then rewrite the Accept header so that text/html is served up by your application. You also have to accept that requests from those browsers will never be issuing requests against your web service as those requests will be rewritten to text/html.</p>
<p>The second solution is to use a vendor specific media type, and serve xhtml up on that. This means that you lose a small part of the self describing nature of using application/xhtml+xml &#8211; but means that you can be absolutely certain that no existing browser will prefer your API content over what it should be seeing. Vendor media types take the format of application/vnd.<name>.<subtype> &#8211; for example application/vnd.fdrop.xhtml+xml</p>
<p>Opinions on which of these two options are preferred (or if you have heard of other solutions or have any suggestions on other ways of dealing with this) would be most welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2011/10/xhtml-as-a-hypermedia-format/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Speaking at PHPNW 2011</title>
		<link>http://nocarrier.co.uk/2011/06/speaking-at-phpnw-2011/</link>
		<comments>http://nocarrier.co.uk/2011/06/speaking-at-phpnw-2011/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 19:24:29 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[community]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php conference]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=75</guid>
		<description><![CDATA[<p>I&#8217;m delighted to have been accepted to speak on REST and HATEOAS at the PHPNW conference. This marks the start of my speaking &#8216;career&#8217;, something that I have wanted to kick start for some time. The subject matter is something that I am very interested in, and it gives me a chance (and a focus [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m delighted to have been accepted to speak on REST and HATEOAS at the PHPNW conference. This marks the start of my speaking &#8216;career&#8217;, something that I have wanted to kick start for some time. The subject matter is something that I am very interested in, and it gives me a chance (and a focus point) for one of my pet projects that actually gets a little day to day usage over on <a href="http://fdrop.it">http://fdrop.it</a>. It&#8217;s been needing a well designed (and easy to use) API to give it the edge over other file sharing websites, and being accepted to speak at PHPNW on REST has given me the motivation that I need to polish this area of the site and it gives me the opportunity to explain REST with a real life practical example, that people can actually go away and play with.</p>
<p>The abstract is as follows;</p>
<p>REST and HATEOAS: A Case Study</p>
<p>A RESTful API is only truly RESTful if it uses hypermedia to tell us<br />
about all the actions that can be performed on the curent resource,<br />
allowing us to traverse the API from a single entry point.  This<br />
session looks at REST and HATEOAS (Hypermedia As The Engine Of<br />
Application State) to illustrate good service structure.</p>
<p>We&#8217;ll use the RESTful file sharing service fdrop.it to illustrate the<br />
various examples of how this can be used.  This session is recommended<br />
for architects and senior developers alike and will give a good<br />
grounding in writing excellent, self-explanatory RESTful services.</p>
<p>Looking forward to seeing you there!</p>
<p><a href="http://conference.phpnw.org.uk/phpnw11/"><img src="http://conference.phpnw.org.uk/phpnw11/files/2011/05/phpnw11_details_200x144.png" alt="PHPNW 2001" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2011/06/speaking-at-phpnw-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP on Azure</title>
		<link>http://nocarrier.co.uk/2011/02/php-on-azure/</link>
		<comments>http://nocarrier.co.uk/2011/02/php-on-azure/#comments</comments>
		<pubDate>Sun, 13 Feb 2011 12:00:58 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[azure]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=67</guid>
		<description><![CDATA[<p>When I first started out playing with PHP a number of years ago, I did it on my home PC running windows. I remember manually setting up apache (I never tried with IIS), configuring php to work with it and getting a mysql database up and running. The whole process was time consuming and frustrating [...]]]></description>
			<content:encoded><![CDATA[<p>When I first started out playing with PHP a number of years ago, I did it on my home PC running windows. I remember manually setting up apache (I never tried with IIS), configuring php to work with it and getting a mysql database up and running. The whole process was time consuming and frustrating &#8211; without package management it&#8217;s not a particularly pleasant experience.</p>
<p>With Microsofts Azure cloud platform available on a trial [<a href="http://www.microsoft.com/windowsazure/offers/">link</a>], and with PHP Benelux running the PHP on Azure contest [<a href="http://www.phpazurecontest.com/">link</a>] I decided it would be a good opportunity to have another go at using the windows environment as a hosting platform &#8211; though this time using the Web Platform Installer (WebPI) with IIS and SQL Server instead of my traditional LAMP stack.</p>
<p>WebPI promised that this would be a simple process. It certainly looks the part, and has a good range of PHP apps that can be setup out the box. Unfortunately as I was getting all the pre-requisites installed in my Windows 7 VM, the PHP command line tools didn&#8217;t appear to have the Windows Azure SDK available as a dependency. Nor was it available when I searched for it within WebPI.</p>
<p>SQL Server did install ok though, so I followed the manual instructions [<a href="http://azurephp.interoperabilitybridges.com/articles/getting-the-windows-azure-pre-requisites-via-manual-installation">link</a>] to get IIS set up with PHP, and get the SDK installed.</p>
<p>That was fine &#8211; up until the point that I was building my first test deployment to my local development &#8216;cloud&#8217;. It transpires that the package.php script (used to build an azure package out of your php project ready for deployment) assumes that your username does not contain a space. Mine was &#8216;Ben Longden&#8217;.</p>
<p>So I created a new user account and tried again. None of the Azure SDK tools worked under my new user and just claimed that &#8216;A fatal error occured&#8217;, but reinstalling them helped. The next issue was that my new user doesn&#8217;t have access to connect to the SQL server installation (this is something that I have not yet resolved!).</p>
<p>So not plain sailing so far! I found it quite frustrating in all (compared to &#8216;sudo tasksel install lamp-server&#8217;), however my initial deployment to the Azure Cloud went fine in the end, once the environment was set up.</p>
<p>Initial concerns are with how the development process will work. Up next, will be setting up IIS as a development environment that I can work with, and automating the deployment to my local cloud.</p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2011/02/php-on-azure/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Zend 5.3 certification</title>
		<link>http://nocarrier.co.uk/2010/11/zend-5-3-certification/</link>
		<comments>http://nocarrier.co.uk/2010/11/zend-5-3-certification/#comments</comments>
		<pubDate>Sat, 06 Nov 2010 23:09:55 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=60</guid>
		<description><![CDATA[<p>Hurrah! It&#8217;s probably about time I did this&#8230;</p> <p><a href="http://www.zend.com/en/store/education/certification/authenticate.php/ClientCandidateID/ZEND015542/RegistrationID/238383360">Zend Yellow Pages</a></p> <p> </p>]]></description>
			<content:encoded><![CDATA[<p>Hurrah! It&#8217;s probably about time I did this&#8230;</p>
<p><a href="http://www.zend.com/en/store/education/certification/authenticate.php/ClientCandidateID/ZEND015542/RegistrationID/238383360">Zend Yellow Pages</a></p>
<p> <img src='http://nocarrier.co.uk/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2010/11/zend-5-3-certification/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ryan Tomayako &#8211; How I explained REST to my wife</title>
		<link>http://nocarrier.co.uk/2010/10/ryan-tomayako-how-i-explained-rest-to-my-wife/</link>
		<comments>http://nocarrier.co.uk/2010/10/ryan-tomayako-how-i-explained-rest-to-my-wife/#comments</comments>
		<pubDate>Mon, 11 Oct 2010 08:28:32 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[REST web development CS]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=56</guid>
		<description><![CDATA[<p>Having attended a talk by David Zuelke on Saturday at the PHPNW Conference 2010, he provided a link at the end of his talk to a blog post by Ryan Tomayoko, titled &#8216;How I explained REST to my wife&#8217;.</p> <p>It&#8217;s a brilliantly simple explanation of something that I have struggled to vocalise for a few [...]]]></description>
			<content:encoded><![CDATA[<p>Having attended a talk by David Zuelke on Saturday at the PHPNW Conference 2010, he provided a link at the end of his talk to a blog post by Ryan Tomayoko, titled &#8216;How I explained REST to my wife&#8217;.</p>
<p>It&#8217;s a brilliantly simple explanation of something that I have struggled to vocalise for a few years!</p>
<p>Here it is in all it&#8217;s glory (don&#8217;t be scared by the size of the page &#8211; it&#8217;s mostly comments!).</p>
<p><a href="http://tomayko.com/writings/rest-to-my-wife">Ryan Tomayoko &#8211; How I explained REST to my Wife</a></p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2010/10/ryan-tomayako-how-i-explained-rest-to-my-wife/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Buildings a Continuous Integration Server for PHP with Hudson</title>
		<link>http://nocarrier.co.uk/2010/10/buildings-a-continuous-integration-server-for-php-with-hudson/</link>
		<comments>http://nocarrier.co.uk/2010/10/buildings-a-continuous-integration-server-for-php-with-hudson/#comments</comments>
		<pubDate>Mon, 04 Oct 2010 08:48:11 +0000</pubDate>
		<dc:creator>blongden</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[php hudson]]></category>

		<guid isPermaLink="false">http://nocarrier.co.uk/?p=50</guid>
		<description><![CDATA[<p>An article that I wrote for techPortal has been published.</p> <p><a href="http://techportal.ibuildings.com/2010/09/20/building-a-continuous-integration-server-for-php-with-hudson/">http://techportal.ibuildings.com/2010/09/20/building-a-continuous-integration-server-for-php-with-hudson/</a></p>]]></description>
			<content:encoded><![CDATA[<p>An article that I wrote for techPortal has been published.</p>
<p><a href="http://techportal.ibuildings.com/2010/09/20/building-a-continuous-integration-server-for-php-with-hudson/">http://techportal.ibuildings.com/2010/09/20/building-a-continuous-integration-server-for-php-with-hudson/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://nocarrier.co.uk/2010/10/buildings-a-continuous-integration-server-for-php-with-hudson/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

