<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[banksco.de blog]]></title><description><![CDATA[Notes from a web developer on computer science and website technology.]]></description><link>https://banksco.de</link><generator>NodeJS RSS Module</generator><lastBuildDate>Sun, 21 Jan 2018 08:30:43 GMT</lastBuildDate><atom:link href="https://banksco.de/blog.rss.xml" rel="self" type="application/rss+xml"/><item><title><![CDATA[The State of Real-Time Web in 2016]]></title><description><![CDATA[<p>I&#39;ve been working on infrastructure for real-time notifications for a high-traffic site on and off for a few years, and recently been contributing to <a href="https://github.com/centrifugal">Centrifuge</a>.</p>
<p>This post is an attempt to sum up how I see the state of the relevant technologies at the start of 2016.</p>
<p>I&#39;ll walk through the various techniques for delivering real-time message to browsers. There are good resources for details of each, so I&#39;ll instead focus on the gotchas and incompatibilities I&#39;ve come across that need to be accounted for in the wild.</p>
<p>This information is a mixture of first-hand experience and second-hand reading mostly of well-tested libraries such as <a href="https://github.com/sockjs">SockJS</a>, <a href="https://github.com/socket.io">socket.io</a> and <a href="https://github.com/SamSaffron/message_bus">MessageBus</a>.</p>
<h2 id="websockets">WebSockets</h2>
<p>It&#39;s 2016. We are officially in <a href="http://www.october212015.com/">the future</a>. <a href="https://en.wikipedia.org/wiki/WebSocket">WebSockets</a> are a real standard and are <a href="http://caniuse.com/#search=websockets">supported in all recent major browsers</a>.</p>
<p>That should really be the end of the article but, as always, it isn&#39;t.</p>
<p>Sam Saffron (the author of <a href="https://github.com/SamSaffron/">MessageBus</a> and Co-Founder of <a href="https://www.discourse.org/">Discourse</a>) recently blogged about <a href="https://samsaffron.com/archive/2015/12/29/websockets-caution-required">why WebSockets are not necessarily the future</a>. I found his post truly refreshing as I&#39;ve run into almost all of the pain points he describes.</p>
<p>That said, Sam&#39;s post is focusing on the case where your WebSocket/streaming/polling traffic is served by the same application and same servers as regular HTTP traffic.</p>
<p>There are many reasons I&#39;ve experienced which suggest this <em>might</em> not be the best approach at scale. Sam even mentions this in his article. I can&#39;t say it&#39;s always a bad one - Discourse itself is proof that his model can work at scale - but I&#39;ve found that:</p>
<ol>
<li><p>Long-lived requests are very different to regular HTTP traffic whether they are WebSockets, HTTP/1.1 chunked streams or just boring long-polls. For one real-life test we increased the number of sockets open on our load balancer by a factor of 5 or more in steady state with orders-of-magnitude higher peaks during errors causing mass-reconnects. For <em>most</em> websites, real-time notifications are a secondary feature; failure in a socket server or overload due to a client bug really shouldn&#39;t be able to take out your main website and the best way to ensure that is to have the traffic routed to a totally different load balancer at DNS level (i.e. on a separate subdomain).</p>
</li>
<li><p>If your web application isn&#39;t already an efficient event-driven daemon (or have equivalent functionality like Rack Hijack) long-lived connections in main app are clearly a bad choice. In our case our app is PHP on apache. So handling long-lived connections <em>must</em> occur on separate processes (and in practice servers) with suitable technology for that job.</p>
</li>
<li><p>Scaling real-time servers and load balancing independently of your main application servers is probably a good thing. While load balancing tens or hundreds of thousands of open connections might be a huge burden to your main load balancer as in point 1, you can probably handle that load with an order of magnitude or two fewer socket servers than are in your web server cluster if you are at that scale.</p>
</li>
</ol>
<p>But with those points aside, the main thrust of Sam&#39;s argument that resonates strongly with my experience is that <strong>most apps don&#39;t need bidirectional sockets</strong> so the cons of using WebSockets listed below can be a high price for a technology you don&#39;t really need. <a href="https://samsaffron.com/archive/2015/12/29/websockets-caution-required">Sam&#39;s article</a> goes into more details on some of the issues and includes others that are not as relevant to my overview here so worth a read.</p>
<h3 id="websocket-pros">WebSocket Pros</h3>
<ul>
<li>Now supported in all modern browsers.</li>
<li>Efficient low-latency and high-throughput transport.</li>
<li><em>If</em> you need low-latency, high-throughput messaging back to the server they can do it.</li>
<li>Super easy API - can make a toy app in an hour.</li>
</ul>
<h3 id="websocket-cons">WebSocket Cons</h3>
<ul>
<li>Despite wide browser support, they are still not perfect: IE 8 and 9 and some other older mobile browsers need fallbacks anyway if you care about wide compatibility</li>
<li>There were many revisions and false starts in the history of the WebSocket protocol, in practice you still have to support old quirky protocol versions on the server for wide browser coverage. Mostly this is handled for you by libraries but it&#39;s unpleasant baggage nonetheless.</li>
<li>Even when supported in browser, there are many restrictive proxies and similar in the wild that don&#39;t support WebSockets or which close connections after some short time regardless of ping activity. If you use SSL things improve a lot as proxies don&#39;t get to mangle the actual protocol, but still not perfect.</li>
<li>Due to the two issues above, you almost certainly need to implement fallbacks to other methods anyway, probably using a well-tested library as discussed below.</li>
<li>They work against HTTP/2. Most notably multiple tabs will cause multiple sockets always with WebSocket, whereas the older fallbacks can all benefit from sharing a single HTTP/2 connection even between tabs. In the next few years this will become more and more significant.</li>
<li>You have to choose a protocol over the WebSocket transport. If you do write data back with them, this can end up duplicating your existing REST API.</li>
</ul>
<h2 id="websocket-polyfills">WebSocket Polyfills</h2>
<p>One of the big problems with WebSockets then is the need to support fallbacks. The sensible choice is to reach for a tried and tested library to handle those intricate browser quirks for you.</p>
<p>The most popular options are <a href="https://github.com/sockjs">SockJS</a> and <a href="https://github.com/socket.io">socket.io</a>.</p>
<p>These are both fantastic pieces of engineering, but once you start digging into the details, there are plenty of (mostly well-documented) gotchas and quirks you might still have to think about.</p>
<p>My biggest issue with these options though is that they aim to transparently provide full WebSocket functionality which we&#39;ve already decided isn&#39;t actually what we need most of the time. In doing so, they often make design choices that are far from optimal when all you really want is server to client notifications. Of course if you actually do <em>need</em> bi-directional messaging then there is not a lot to complain about.</p>
<p>For example, it is possible to implement subscription to channel-based notifications with a single long-poll request:</p>
<ul>
<li>Client sends request for <code>/subscribe?channels=foo,bar</code></li>
<li>You wait until there is data then request returns (or times out)</li>
<li>Authentication and resuming on reconnect can be handled by passing headers or query params in a stateless way</li>
</ul>
<p>Yet if you are using a WebSocket polyfill, it&#39;s likely that you use some sort of PubSub protocol on top of the abstracted WebSocket-like transport. Usually that means you connect, then send some sort of handshake to establish authentication, then one or more <code>subscribe</code> requests and then wait for messages. This is how most open source projects I&#39;ve seen work (e.g. <a href="https://docs.cometd.org/current/reference/#_concepts_bayeux_protocol">Bayeux protocol</a>).</p>
<p>All is fine on a real WebSocket but when the transport transparently reverts to plain old long-polls, this starts to get significantly more complicated than the optimal, simple long-poll described above. Each of the handshake and subscribe messages might need to be sent in separate requests. SockJS handles sending on a separate connection to listening.</p>
<p>Worse is that many require that you have sticky-sessions enabled for the polling fallback to work at all since they are trying to model a stateful socket connection over stateless HTTP/1.1 requests.</p>
<p>The worst part is the combination: poor support for load balancing WebSockets in most popular load balancers and sticky session support. That means you may be forced to use Layer 4 (TCP/TLS) balancing for WebSockets <em>but</em> you can&#39;t ensure session stickyness if you do. So SockJS and the like just can&#39;t work behind this kind of load balancer. <a href="http://www.haproxy.org/">HAProxy</a> is the only one of the most popular load balancing solutions I know of that can handle Layer 7 WebSocket balancing right now which is a pain in AWS where ELBs give you auto-scaling and bypass the need to mess with keepalived or other HA mechanism for your load balancer.</p>
<p>To be clear, the benefits of not reinventing the wheel and getting on with dev work probably outweigh these issues for many applications, even if you <em>don&#39;t</em> strictly need bi-directional communication. But when you are working at scale the inefficiencies and lack of control can be a big deal.</p>
<h3 id="websocket-polyfill-pros">WebSocket Polyfill Pros</h3>
<ul>
<li>For the most part they just work, almost everywhere.</li>
<li>The most widely used ones are now battle hardened.</li>
<li>Leave you to write your app and not think about the annoying transport quirks described here.</li>
</ul>
<h3 id="websocket-polyfill-cons">WebSocket Polyfill Cons</h3>
<ul>
<li>Usually require sticky sessions for fallbacks to work.</li>
<li>Usually less efficient and/or far more complex than needed for simple notification-only applications when falling back due to emulating bi-directional API.</li>
<li>Can run into issue like exhausting connections to one domain in older browsers and deadlocking if you make other <code>XMLHttpRequest</code>s to same domain.</li>
<li>Usually don&#39;t give you good control of reconnect timeouts and jitter which can limit your ability to prevent thundering herds or reconnections during incidents.</li>
</ul>
<h2 id="server-sent-events-eventsource">Server Sent Events/EventSource</h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource">EventSource API</a> has been around a while now and enjoys decent browser support - on par with WebSockets. It interacts with a server-protocol named <a href="https://html.spec.whatwg.org/multipage/comms.html#server-sent-events">Server Sent Events</a>. I&#39;ll just refer to both as &quot;EventSource&quot; from now on.</p>
<p>At first glance it looks ideal for the website notification use-case I see being so prevalent. It&#39;s not a bidrectional stream; it uses only HTTP/1.1 under hood so works with most proxies and load balancers; long-lived connection can send multiple events with low latency; has a mechanism for assigning message ids and sending cursor on reconnect; browser implementations transparently perform reconnects for you.</p>
<p>What more can you want? Well...</p>
<h3 id="eventsource-pros">EventSource Pros</h3>
<ul>
<li>Plain HTTP/1.1 is easy to loadbalance at Layer 7.</li>
<li>Not stateful, no need for sticky sessions (if you design your protocol right).</li>
<li>Efficient for low-latency <em>and</em> high-throughput messages.</li>
<li>Built in message delimiting, ids, and replay on reconnect.</li>
<li>No need for the workarounds for quirks with plain chunked encoding.</li>
<li>Can automatically take advantage of HTTP/2 and share a connection with any other requests streaming or otherwise to the same domain (even from different tabs).</li>
</ul>
<h3 id="eventsource-cons">EventSource Cons</h3>
<ul>
<li>No IE support, not even IE 11 or Edge.</li>
<li>Never made it past a <a href="https://w3c.github.io/eventsource/">draft proposal</a>, is no longer being worked on and remains only in the <a href="https://html.spec.whatwg.org/multipage/comms.html#server-sent-events">WhatWG living standard</a>. While it should still work for some time in supported browsers, this doesn&#39;t feel like a tech that people are betting on for the future.</li>
<li>Browser reconnect jitter/back-off policy is not under your control which could limit your ability to mitigate outages at scale just as with WebSocket Polyfills above.</li>
<li>Some older browser versions have incorrect implementations that look the same but don&#39;t support reconnecting or CORS.</li>
<li>Long-lived connections can still be closed early by restrictive proxies.</li>
<li>Streaming fallbacks below are essentially the same (with additional work to implement reconnect, data framing and message ids) with better browser support - you probably need them anyway for IE.</li>
</ul>
<h2 id="xmlhttprequest-xdomainrequest-streaming">XMLHttpRequest/XDomainRequest Streaming</h2>
<p>Uses the same underlying mechanism as EventSource above: HTTP/1.1 chunked encoding on a long-lived connection, but without browser handling the connection directly.</p>
<p>Instead <code>XMLHttpRequest</code> is used to make the connection. For cross-domain connections <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS">CORS</a> must be used, or in IE 8 and 9 that don&#39;t have CORS support, the non-standard <code>XDomainRequest</code> is used instead.</p>
<p>These techniques are often refered to as &quot;XHR/XDR Streaming&quot;.</p>
<h3 id="xhr-xdr-streaming-pros">XHR/XDR Streaming Pros</h3>
<ul>
<li>Plain HTTP/1.1 is easy to loadbalance at Layer 7.</li>
<li>Not stateful, no need for sticky sessions (if you design your protocol right).</li>
<li>Efficient for low-latency <em>and</em> high-throughput messages.</li>
<li>Can automatically take advantage of HTTP/2 and share a connection with any other requests streaming or otherwise to the same domain (even from different tabs).</li>
<li>Works in vast majority of browsers right back to IE 8 and relatively early versions of other major browsers.</li>
</ul>
<h3 id="xhr-xdr-streaming-cons-gotchas">XHR/XDR Streaming Cons/Gotchas</h3>
<ul>
<li>Still doesn&#39;t work (cross domain) in really old browsers like IE 7.</li>
<li><code>XDomainRequest</code> used as fallback for IE 8 and 9 doesn&#39;t support cookies so you can&#39;t use this if you require both cross domain connection <em>and</em> cookies for auth or sticky sessions.</li>
<li><code>XDomainRequest</code> also doesn&#39;t support custom headers. Possibly not a big deal but notable if you are trying to <a href="https://github.com/Yaffle/EventSource/#server-side-requirements">emulate EventSource</a> which uses custom headers for retry cursor.</li>
<li>Long-lived connections can still be closed early by restrictive proxies.</li>
<li>Even well-behaved proxies will close idle connections, so your server needs to send a &quot;ping&quot; or heartbeat packet. Usually this is sent every 25-29 seconds to defeat 30 second timeouts reliably.</li>
<li>There is a subtle memory leak: the body text of the HTTP response grows and grows as new messages come in consuming more memory over time. To mitigate this, you need to set some limit on this body size and when it&#39;s passed close and re-open connection.</li>
<li>In order to defeat load balancer and proxy connection idle timeouts, server needs to periodically send something. Generally 25 seconds is recommended interval to work around proxies with a 30 second timeout.</li>
<li>IE 8 and 9 don&#39;t fire XDR progress handler until they reach some threshold response size. This means you <a href="http://blogs.msdn.com/b/ieinternals/archive/2010/04/06/comet-streaming-in-internet-explorer-with-xmlhttprequest-and-xdomainrequest.aspx">might need to send 2KB of junk</a> when request starts to avoid blocking your real events. Some other older browsers had similar issues with XMLHttpRequest but these are so rare they probably aren&#39;t worth supporting. In practice you can tell if browser supports <code>XMLHttpRequest.onprogress</code> as an indicator that it will work without padding.</li>
<li><a href="http://stackoverflow.com/questions/26164705/chrome-not-handling-chunked-responses-like-firefox-safari">Some browsers</a> require <code>X-Content-Type-Options: nosniff</code> header otherwise they delay delivering messages until they have enough data to sniff (I&#39;ve seen reports this is 256 bytes for Chrome).</li>
<li>You may have to <a href="https://github.com/SamSaffron/message_bus/blob/master/lib/message_bus/client.rb#L183">encapsulate messages in some custom delimiters</a> since proxies might re-chunk the stream and you need to be able to recover original message boundaries to parse them. Google seems to use HTTP/1.1 chunked encoding scheme inside the response text to delimit &quot;messages&quot; (i.e. chunked encoding inside chunked encoding).</li>
<li>The big one: some proxies buffer chunked responses, delaying your events uncontrollably. You may want to send a ping message immediately on a new connection and then <a href="https://github.com/SamSaffron/message_bus/blob/master/assets/message-bus.js#L180">revert to non-streaming</a> in the client if you don&#39;t get that initial message through soon enough.</li>
</ul>
<h2 id="xmlhttprequest-xdomainrequest-long-polling">XMLHttpRequest/XDomainRequest Long-polling</h2>
<p>Same as XHR/XDR streaming except without chunked encoding on response. Each connection is held open by server as long as there is no message to send, or until the long-poll timeout (usually 25-60 seconds).</p>
<p>When an event arrives at the server that the user is interested in, a complete HTTP response is sent and the connection closed (assuming no HTTP keepalive).</p>
<h3 id="xhr-xdr-long-polling-pros">XHR/XDR Long-polling Pros</h3>
<ul>
<li>Plain HTTP/1.0 (no chunked encoding) is easy to load balance at Layer 7.</li>
<li>Can automatically take advantage of HTTP/2.</li>
<li>Works even when proxies don&#39;t like long-lived connection, or buffer chunked responses for too long.</li>
<li>No need for server pings - natural long poll timeout is set short enough.</li>
</ul>
<h3 id="xhr-xdr-long-polling-cons">XHR/XDR Long-polling Cons</h3>
<ul>
<li>Same cross-domain/browser support issues as XHR/XDR streaming.</li>
<li>Overhead of whole new HTTP request and possibly TCP connection every 25 seconds or so.</li>
<li>To achieve high-throughput you have to start batching heavily either on server or by not reconnecting right away in the client to allow bigger batch of events to queue. If you have lots of clients all listening to high-throughput channel this adds up to a huge amount of HTTP requests unless you ramp up batching to be on order of 20-30 seconds. But then you are trading off latency - is 30 seconds latency acceptable for your &quot;real-time&quot; app?</li>
</ul>
<h2 id="jsonp-long-polling">JSONP Long-polling</h2>
<p>The most widely supported cross-domain long-polling technique is JSONP or &quot;script tag&quot; long-polling. This is just like XHR/XDR long-polling except that we are using <a href="https://en.wikipedia.org/wiki/JSONP">JSONP</a> to achieve cross-domain requests instead of relying on CORS or XDR support. This works in virtually every browser you could reasonably want to support.</p>
<h3 id="jsonp-long-polling-pros">JSONP Long-polling Pros</h3>
<ul>
<li>All the pros of XHR/XDR long-polling.</li>
<li>Works in ancient browsers too.</li>
<li>Supports cookies everywhere (although if your long poll server is a totally separate root domain browsers third-party cookie restrictions might prevent that).</li>
</ul>
<h3 id="jsonp-long-polling-cons">JSONP Long-polling Cons</h3>
<ul>
<li>Largely the same as XHR/XDR Long-polling Cons minus the cross-domain issues</li>
</ul>
<h2 id="polling">Polling</h2>
<p>Periodically issuing a plain old XHR (or XDR/JSONP) request to a backend which returns immediately.</p>
<h2 id="polling-pros">Polling Pros</h2>
<ul>
<li>Very simple, always works, no proxy or load balancing issues</li>
<li>Can benefit from HTTP/2</li>
</ul>
<h2 id="polling-cons">Polling Cons</h2>
<ul>
<li>Not really &quot;real-time&quot; with an average of half the poll interval latency per message. That might be 5 or 10 seconds.</li>
<li>Perception is that this is expensive if you service the requests via your regular web app - can easily create orders of magnitude more HTTP request on your web servers. In practice you can use highly optimised path on a separate service to mitigate this.</li>
</ul>
<h2 id="others">Others</h2>
<p>There are many other variants I&#39;m missing out as this is already fairly long. Most of them involve using a hidden iframe. Inside the iframe HTML files with individual script blocks served with chunked encoding or one of the above transports receive events and call <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage">postMessage</a> or a fallback method to notify the parent frame.</p>
<p>These variants are generally only needed if you have requirement to support both streaming <em>and</em> cookie enabled transport for older browsers for example. I won&#39;t consider them further.</p>
<h2 id="the-future-">The Future(?)</h2>
<p>You may have noticed if you use Chrome that Facebook can now send you notifications even when you have no tab open. This is a <a href="http://techcrunch.com/2015/09/14/facechrome">Chrome feature</a> that uses a new <a href="https://martinthomson.github.io/drafts/draft-thomson-webpush-http2.html">Web Push standard</a> currently in draft status.</p>
<p>This standard allows browsers to subscribe to any compliant push service and monitor for updates even when your site isn&#39;t loaded. When they come in <a href="https://developers.google.com/web/updates/2015/03/push-notifications-on-the-open-web">service workers</a> can be called to handle the notification.</p>
<p>Great! Soon we won&#39;t have to worry about this transport stuff at all. All browsers will support this and all we&#39;ll have lovely open-source libraries to easily implement that backend. (But see update below.)</p>
<p>But that&#39;s some way off. Currently Chrome only supports a modified version that doesn&#39;t follow standard because it uses their existing proprietary <a href="https://developers.google.com/cloud-messaging/">Google Cloud Messaging</a> platform (although they claim to be working with Mozilla on standards compliant version).</p>
<p>Firefox is working on an implementation (in Nightlies) but it&#39;s going to be some years yet before there is enough browser support for this to replace any of the other options for majority of users.</p>
<p>I came across this standard after writing most of the rest of this post and I would like to pick out a few points that reinforce my main points here:</p>
<ul>
<li>It&#39;s push only technology</li>
<li><a href="https://martinthomson.github.io/drafts/draft-thomson-webpush-http2.html#monitor">The transport is HTTP/2</a> server push which can fallback to regular HTTP poll. No WebSockets. No custom TCP protocol. Presumably if you have push enabled over HTTP/2 in your browser, then your actual site requests could be made over it too meaning that in some cases it might even cut down on connection overhead for your main page loads... That&#39;s pure speculation though.</li>
<li>The spec <a href="https://martinthomson.github.io/drafts/draft-thomson-webpush-http2.html#rfc.section.7.4">explicitly recommends against application-level fallbacks</a> although clearly they will be needed until this spec is supported virtually everywhere which will be at least a few years away.</li>
</ul>
<p><strong>Update 13th Jan 2016</strong></p>
<p>After reading the spec closely and trying to think about how to use this technology it became clear that it might not be a good fit for general purpose in-page updates.</p>
<p>I <a href="https://lists.w3.org/Archives/Public/public-webapps/2016JanMar/0044.html">clarified with the authors on the mailinglist</a> (resulting in <a href="https://github.com/w3c/push-api/issues/179">this issue</a>). The <strong>tl;dr</strong>: this is designed similar to native mobile push - it&#39;s device centric rather than general pub/sub and is intended for <em>infrequent</em> message that are relevant to a user outside of a page context. Right now <a href="https://developer.mozilla.org/en/docs/Web/API/Push_API">implementations limit or forbid</a> it&#39;s use for anything that doesn&#39;t display <a href="https://developer.mozilla.org/en/docs/Web/API/notification">browser notifications</a>. If that&#39;s all you need, you may be able to use it in-page too, but for live-updating comment threads in your app where you only care about updates for the thread visible on page, it wont be the solution.</p>
<h2 id="do-you-need-bi-directional-sockets-">Do you need bi-directional sockets?</h2>
<p>My thoughts here have a bias towards real-time notifications on websites which really don&#39;t require bi-directional low-latency sockets.</p>
<p>Even applications like &quot;real-time&quot; comment threads probably don&#39;t - submitting content as normal via POST and then getting updates via streaming push works well for <a href="https://www.discourse.org/">Discourse</a>.</p>
<p>It&#39;s also worth noting that GMail uses XHR Streaming and Facebook uses boring XHR long-polls even on modern browsers. Twitter uses even more unsexy short polls every 10 seconds (over HTTP/2 if available). These sites for me are perfect examples of the most common uses for &quot;real-time&quot; updates in web apps and support my conclusion that most of us don&#39;t need WebSockets or full-fidelity fallbacks - yet we have to pay the cost of their downsides just to get something working easily.</p>
<p>Sam Saffron&#39;s <a href="https://github.com/SamSaffron/message_bus">MessageBus</a> is a notable exception which follows this line of thinking however it&#39;s only aimed at Ruby/Rack server apps.</p>
<p>I find myself wishing for a generalisation of MessageBus&#39; transport that can be made portable across other applications, something like SockJS or Socket.io but without the goal of bi-directional WebSocket emulation. Eventually it could support Web Push where available and pave the way for adopting that in the interim before browsers support it. Perhaps an open-source project in the making.</p>
<p><em>Thanks to <a href="https://samsaffron.com/">Sam Saffron</a>, <a href="https://github.com/FZambia">Alexandr Emelin</a> and <a href="https://twitter.com/micahgoulart">Micah Goulart</a> who read through a draft of this very long post and offered comments. Any mistakes are wholly my own - please set me straight in the comments!</em></p>
]]></description><link>https://banksco.de/p/state-of-realtime-web-2016.html</link><guid isPermaLink="true">https://banksco.de/p/state-of-realtime-web-2016.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 11 Jan 2016 00:00:00 GMT</pubDate></item><item><title><![CDATA[Understanding Distributed System Guarantees]]></title><description><![CDATA[<p>Tyler Treat just published <a href="http://bravenewgeek.com/tag/distributed-systems/">another</a> great article about Distributed Systems and the <a href="http://bravenewgeek.com/what-you-want-is-what-you-dont-understanding-trade-offs-in-distributed-messaging/">limited value of strong guarantees</a> they might claim to provide.</p>
<p>I&#39;ll start with a word of thanks to Tyler - his blog is a great read and well recommended for his articulation and clarity on many computer science subjects that are often muddled by others.</p>
<p>Tyler&#39;s article focuses specifically on distributed messaging guarantees but at least some of the discussion is relevant to or even intimately tied to other distributed problems like data consistency and consensus.</p>
<p>I agree with all of his points and I hope this article is a complement to the discussion on trade-offs in the distributed design space.</p>
<p>The article got me thinking about the inverse question - when is it sensible to incur the overhead of working around reduced guarantees, assuming doing so is non-trivial?</p>
<h3 id="when-is-strong-consistency-worth-it-">When is Strong Consistency worth it?</h3>
<p>Let&#39;s consider Google&#39;s database evolution (of which I know nothing more than you can read for yourself in these papers).</p>
<p>In 2006 Google&#39;s published a paper on <a href="http://research.google.com/archive/bigtable.html">BigTable</a>. Unlike <a href="http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf">Dynamo</a> and others, BigTable made some attempt to guarantee strong consistency <em>per row</em>. But it stopped there; no multi-row atomic updates, certainly no cross-node transaction. Five years later a paper on their <a href="http://research.google.com/pubs/pub36971.html">MegaStore</a> database was published. The motivation includes the fact that &quot;[NoSQL stores like BigTable&#39;s] limited API and loose consistency models complicate application development&quot;.</p>
<p>A year later details of <a href="http://research.google.com/archive/spanner.html">Spanner</a> emerged, and in the introduction we discover that despite the high performance cost, engineers inside Google were tending to prefer to use MegaStore over BigTable since it allowed them to get on with writing their apps rather than re-inventing solutions for consistent geographical replication, multi-row transactions, and secondary indexing (my gloss on the wording there).</p>
<p>Google&#39;s cream-of-the-crop engineers with all the resources available to them chose to trade performance for abstractions with stronger guarantees.</p>
<p>That doesn&#39;t mean that MegaStore and Spanner can never fail. Nor (I guess) that Google&#39;s internal users of those systems are blindly assuming those guarantees hold in all cases in application code. But, at least for Google, providing stronger guarantees at the shared datastore level was a win for their engineering teams.</p>
<p>Just because it&#39;s Google doesn&#39;t make it right, but it is worth noting nonetheless.</p>
<h3 id="commutativity-and-idempotence">Commutativity and Idempotence</h3>
<p>A sound conclusion of Tyler&#39;s post is that you are better served if you can shape your problems into commutative and idempotent actions which can naturally tolerate relaxed guarantees correctly.</p>
<p>This is undoubtedly true.</p>
<p>But in cases where idempotence or commutativity are not naturally available, at least some of the possible solutions vary little between applications.</p>
<p>For example de-duplicating events based on a unique ID is a common requirement. It is equivalent to attempting to provide exactly-once delivery. Tyler <a href="http://bravenewgeek.com/you-cannot-have-exactly-once-delivery/">points out this is impossible to do perfectly</a>, nonetheless some applications require at least some attempt at de-duplicating event streams.</p>
<p>Isn&#39;t it better, given a case that requires it, to have an infrastructure that has been specifically designed and tested by distributed systems experts that provides clear and limited guarantees about de-duplicated delivery? Certainly if the alternative is to re-solve that hard problem (and possibly incur the significant storage cost) in every system we build that is not trivially idempotent. The centralised version won&#39;t be perfect, but in terms of development cost it might well be a cheaper path to &quot;good enough&quot;.</p>
<h3 id="trade-offs">Trade-offs</h3>
<p>The title of Tyler&#39;s article is about &quot;Understanding Trade-Offs&quot;. This really is key.</p>
<p>To me the conclusion of the article is spot on: it&#39;s better to consider up-front the real guarantees required and what cost they come at. I just want to add the (probably obvious) idea that application code complexity, re-solving similar problems and the extent to which every application developer needs to be a distributed systems expert are real costs to throw into the trade-off</p>
<p>The Google school of thought argues that it&#39;s better to favour simplicity for application developers and pay the performance cost of that simpler model until the application really needs the increased performance - at this point the additional application complexity can be justified.</p>
<p>This is orthogonal to Tyler&#39;s point that the application developer needs to have clarity on where and how the claimed guarantees of a system break down and how that affects the correctness or availability requirements of their own application. To me that&#39;s a given, but I don&#39;t think it devalues systems that do attempt to provide higher-level guarantees, provided they are properly understood.</p>
]]></description><link>https://banksco.de/p/distributed-system-guarantees.html</link><guid isPermaLink="true">https://banksco.de/p/distributed-system-guarantees.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 24 Aug 2015 00:00:00 GMT</pubDate></item><item><title><![CDATA[Google's AdSense/DFP PII Privacy Gotcha]]></title><description><![CDATA[<p><strong>Google AdSense (and other advertising products) appear to have turned on a new detection system for violations of their <abbr title="Personally Identifiable Information">PII</abbr> policy. Here are a couple of easy steps to fall foul of it without meaning to.</strong></p>
<h3 id="what-is-a-pii-personally-identifiable-information-violation-">What is a PII (Personally Identifiable Information) Violation?</h3>
<p><a href="https://support.google.com/platformspolicy/answer/6026583?hl=en">Google&#39;s support document for their privacy policy</a> describes the issue well.</p>
<p>Specifically the line:</p>
<blockquote>
<p>In particular, please make sure that pages that show ads by Google do not contain your visitors&#39; usernames, passwords, email addresses or other personally-identifiable information (PII) in their URLs.</p>
</blockquote>
<p>Easy right? Just don&#39;t be dumb and pass the visitors info in URL.</p>
<p>Here are a couple of ways to fail at that automatically - you may well be doing them yourself right now.</p>
<h3 id="fail-1-your-search-results-page">Fail #1: Your Search Results Page</h3>
<p>If like every other site on the Internet, you have a search feature, and like every other search engine (copying Google themselves) you present the search results at a URL with the user&#39;s query in a GET parameter e.g. <code>search/?q=ponies</code>, then you will probably violate AdSense policy eventually.</p>
<p>All but one of the handful of breach notifications I&#39;ve come across from Google are due to people searching for an email address. That obviously results in a URL that looks like <code>search/?q=user@exmaple.com</code> and Google&#39;s apparently new automated detection of PII violations flags that.</p>
<p>As an aside, it&#39;s quite likely that they are not searching for their <em>own</em> email address and so it&#39;s not really PII, but who can know? Google will see an email address in URL and call it a breach.</p>
<p>But that&#39;s pretty standard behavior for a search box right? We&#39;ll see what we can do in a bit.</p>
<h3 id="fail-2-users-saving-your-content-for-offline-use-">Fail #2: Users Saving Your Content For &quot;Offline Use&quot;</h3>
<p>Less obviously, you may have users who like to &quot;save&quot; pages on your site for &quot;offline&quot; use. Of course if they really are offline when they view it they will not make any ad requests to Google and you&#39;ll be fine.</p>
<p>But in at least one case I&#39;ve come across, a user saved a page on a site which uses Google AdSense to a folder on their machine like <code>/Users/name@example.com/stuff/your-page.htm</code>. They must have loaded this in their browser while still online and the resulting ad calls from the JS embedded in the page when they saved it fire off to Google with <code>?url=file:///Users/name@example.com/...</code> in the URL, violating their policy.</p>
<h3 id="anti-solution">Anti-Solution</h3>
<p>Actually in both of these cases it&#39;s a little hard to find a good solution. For the first you could perhaps have a special encoding of email addresses in search JS but that goes against the spirit of the policy - the email info is still there if it is in fact PII (probably not if visitor is searching for it but there you go). Not to mention relying on JS instead of regular GET form submission.</p>
<p>It&#39;s a nasty hack and misses many other cases. The second example is one of the many possible reasons you would probably never consider which would not be covered by sticking plasters like that.</p>
<h3 id="solution">Solution</h3>
<p>It would seem the most pragmatic solution is to adjust your ad serving logic to scan URL and referrer for email addresses and just opt to not show ads on that page if you find any. Hopefully it&#39;s rare enough not to lose you too much revenue and the alternatives are likely more expensive.</p>
<p>One thing to note though: checking for email addresses on server side is probably not enough. It wouldn&#39;t have caught that second case above and there are many other cases where it might not work.</p>
<p>So if you rely totally on Google&#39;s provided libraries to display your ads, you may need to write a small wrapper to handle this case on the client side. It seems like this should be something Google&#39;s JS does automatically or at least something you can opt-in to.</p>
]]></description><link>https://banksco.de/p/googles-dfp-pii-privacy-gotcha.html</link><guid isPermaLink="true">https://banksco.de/p/googles-dfp-pii-privacy-gotcha.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 07 Oct 2014 00:00:00 GMT</pubDate></item><item><title><![CDATA[LMDB: The Leveldb Killer?]]></title><description><![CDATA[<p><strong>I&#39;ve been quiet for a while on this blog, busy with many projects, but I just had to comment on my recent discovery of <a href="http://symas.com/mdb/">Lightning Memory-Mapped Database (LMDB)</a>. It&#39;s very impressive, but left me with some questions.</strong></p>
<h3 id="disclaimer">Disclaimer</h3>
<p>Let me start out with this full acknowledgement that I have not yet had a chance to compile and test LMDB (although I certainly will). This post is based on my initial response to the literature and discussion I&#39;ve read, and a quick read through the source code.</p>
<p>I&#39;m also very keen to acknowledge the author <a href="https://twitter.com/hyc_symas">Howard Chu</a> as a software giant compared to my own humble experience. I&#39;ve seen other, clearly inexperienced developers online criticising his code style and I do not mean to do the same here. I certainly hope my intent is clear and my respect for him and this project is understood throughout this discussion. I humbly submit these issues for discussion for the benefit of all.</p>
<h3 id="understanding-the-trade-offs">Understanding the Trade-offs</h3>
<p>First up, with my previous statement about humility in mind, the biggest issue I ran up against when reviewing LMDB is partly to do with presentation. The slides and documentation I&#39;ve read do a good job of explaining the design, but <em>not once</em> in what I&#39;ve read was there any more than a passing mention of anything resembling a trade-off in the design of LMDB.</p>
<p>My engineering experience tells me that no software, especially when attempting to claim &quot;high performance&quot; comes without some set of assumptions and some trade-offs. So far everything I have read about LMDB has been so positive I&#39;m left with a <em>slight</em> (emphasis important) feel of the &quot;silver bullet&quot; marketing hype I&#39;d expect from commercial database vendors and which I&#39;ve come to ignore.</p>
<p>Please don&#39;t get me wrong, I don&#39;t think the material I&#39;ve reviewed is bad, just seems to lack any real discussion of the downsides - the areas where LMDB might <em>not</em> be the best solution out there.</p>
<p>On a personal note, I&#39;ve found the apparent attitude towards leveldb and Google engineers a little off-putting too. I respect the authors opinion that LSM tree is a bad design for this purpose but the lack of respect toward it and it&#39;s authors that comes across in some presentations seems detrimental to the discussion of the engineering.</p>
<p>So to sum up the slight gripe here: engineers don&#39;t buy silver-bullet presentations. A little more clarity on the trade-offs is important to convince us to take the extraordinary benchmark results seriously. </p>
<p>[edit] On reflection the previous statement goes too far - I do take the results seriously - my point was more that they may seem &quot;to good to be true&quot; without a little more clarity on the limitations. [/edit]</p>
<h3 id="my-questions">My Questions</h3>
<p>I have a number of questions that I feel the literature about LMDB doesn&#39;t cover adequately. Many of these are things I can and will find out for myself through experimentation but I&#39;d like to make them public so anyone with experience might weigh in on them and further the community understanding.</p>
<p>Most of these are not really phrased as questions, more thoughts I had that literature does not address. Assume I&#39;m asking the author or anyone with insight their thoughts on the issues discussed.</p>
<p>To reiterate, I don&#39;t claim to be an expert. Some of my assumptions or understanding that lead the the issues below may be wrong - please correct me. Some of these issues may not be at all important in many use cases too. But I&#39;m interested to understand these areas more so please let me know if you have thoughts or preferably experience with any of this.</p>
<h4 id="write-amplification">Write Amplification</h4>
<p>It seems somewhat skimmed over in LMDB literature that the COW B-tree design writes multiple whole pages to disk for every single row update. That means that if you store a counter in each entry then an increment operation (i.e, changing 1 or 2 bits) will result in some number of <em>pages</em> (each 4kb by default) of DB written to disk. I&#39;ve not worked out the branching factor given page size for a certain average record size but I guess in realistic large DBs that could be in the order of 3-10 4k pages written for a single bit change in the data.</p>
<p>All that is said is that &quot;it&#39;s sequential IO so it&#39;s fast&quot;. I understand that but I&#39;d like to understand more of the qualifiers. For leveldb in synchronous mode you only need to wait for the WAL to have the single update record appended. Writing 10s of bytes vs 10s or 100s of kbytes for <em>every update</em> surely deserves a little more acknowledgement.</p>
<p>In fact if you just skimmed <a href="http://symas.com/mdb/microbench/">the benchmarks</a> you might have missed it but in <em>all</em> write configurations (sync, async, random, sequential, batched) except for batched-sequential writes, leveldb performs better, occasionally significantly better.</p>
<p>Given that high update throughput is a strong selling point for leveldb and the fact that LMDB was designed initially for a high-read ratio use case I feel that despite the presence in stats all of the rest of the literature seems to ignore this trade-off as if it wasn&#39;t there at all.</p>
<h4 id="file-fragmentation">File Fragmentation</h4>
<p>The free-list design for reclaiming disk space without costly garbage collection or compaction is probably the most important advance here over other COW B-tree designs. But it seems to me that the resulting fragmentation of data is also overlooked in discussion.</p>
<p>It&#39;s primarily a problem for sequential reads (i.e. large range scans). In a large DB that has been heavily updated, presumably a sequential read will on average end up having to seek backwards and forwards for each 4k page as they will be fragmented on disk.</p>
<p>One of the big benefits of LSM Tree and other compacting designs is that over time the majority of the data ends up in higher level files which are large and sorted. Admittedly, with leveldb, range scans require a reasonable amount of non-sequential IO as you need to switch between the files in different levels as you scan. </p>
<p>I&#39;ve not done any thorough reasoning about it but seems from my intuition that with leveldb the relative amount of non-sequential IO needed will at least remain somewhat linear as more and more data ends up in higher levels where it is actually sequential on disk. With LMDB it <em>seems</em> to me that large range scans are bound to perform increasingly poorly over the life of the DB <em>even</em> if the data doesn&#39;t grow at all, just updates regularly.</p>
<p>But also, beyond the somewhat specialist case of large range scans, it seems to be an issue for writes. The argument given above is that large writes are OK because they are sequential IO but surely once you start re-using pages from the free list this stops being the case. What if blocks 5, 21 and 45 are next free ones and you need to write 3 tree pages for your update? I&#39;m aware there is some attention paid to trying to find contiguous free pages but this seems like it can only be a partial solution.</p>
<p>The micro benchmarks show writes are already slower than leveldb but I&#39;d be very interested to see a long-running more realistic benchmark that shows the performance over a much longer time where fragmentation effects might become more significant.</p>
<h4 id="compression">Compression</h4>
<p>The LMDB benchmarks simply state that &quot;Compression support was disabled in the libraries that support it&quot;. I understand why but in my opinion it&#39;s a misleading step.</p>
<p>The author states &quot;any compression library could easily be used to handle compression for any database using simple wrappers around their put and get APIs&quot;. But that is totally missing the point. Compressing each individual value is a totally different thing to compressing whole blocks on disk. </p>
<p>Consider a trivial example: each value might look like <code>{&quot;id&quot;: 1234567, &quot;referers&quot;: [&quot;http://example.com/foo&quot;, &quot;https://othersite.org/bar&quot;] }</code>. On it&#39;s own gzipping that value is unlikely to give any real saving (the repetition of &#39;http&#39; possibly but the gzip headers is more than the saving there). Whereas compressing a 4k block of such results is likely to give a significant reduction even if it is only in the JSON field names repeated each time.</p>
<p>This is a trivial example I won&#39;t pursue and better serialisation could fix that but in my real-world experience most data even with highly optimised binary serialisation often ends up with a lot of redundancy between records - even if it&#39;s just in the keys. Block compression is MUCH more effective for the vast majority of data types than the LMDB author implies with that comment.</p>
<p>Leveldb&#39;s file format is specially designed in such a way that compression is possible and effective and it seems Google&#39;s intent is to use it as a key part of the performance of the data structure. Their own benchmarks show performance gains of over 40% with compression enabled. And that is ignoring totally the size on-disk which for many will be a fairly crucial part of the equation especially if relatively expensive SSD space is required.</p>
<p>One argument might be that you could apply compression at block level to LMDB too but I don&#39;t think it would be easy at all. It seems like it relies on fixed block size for it&#39;s addressing and compressing contents and leaving blanks gives no disk space saving and probably no IO saving either since all 4k is likely still read from disk.</p>
<p>I&#39;m pretty wary of the benchmarks where leveldb has compression off since I see it as a fairly fundamental feature of leveldb that it is very compression friendly. Any real implementation would surely have compression on since there are essentially no downsides due to the design. It&#39;s also baked in (provided you have the snappy lib) and on by default for leveldb so it&#39;s not like it&#39;s an advanced bit of tuning/modification from basic implementation to use compression for leveldb.</p>
<p>Maybe I&#39;m wrong and it&#39;s trivial to add effective compression to LMDB but if so, and doing it would give ~40% performance increase why is it not already done and compared?</p>
<p>I&#39;d like to see the benchmarks re-run with compression on for leveldb. Given writes are already quicker for leveldb this more realistic real-world comparison might well give a better insight into the tradeoffs of the two designs. If I get a chance I will try this myself.</p>
<h4 id="large-transactions-amplify-writes-even-further">Large Transactions Amplify Writes Even Further</h4>
<p>LMDB makes a big play of being fully transactional. It&#39;s a great feature and implemented really well. My (theoretical) problem is to do with write performance - we&#39;ve already seen how writes can be slower due to COW design but how about the case when you update many rows in one transaction. </p>
<p>Consider worst case that you modify 1 row in every leaf node, that means that the transaction commit will re-write every block in the database file. I realise currently that there is a limit on how many dirty pages can be accumulated by a single transaction but I&#39;ve also read there are plans to remove this. </p>
<p>Leveldb by contrast can do an equivalent atomic batch write without anywhere near the same disk IO in the commit path. It would seem this is a key reason leveldb is so much better in random batch write mode. Again I&#39;d love to see the test repeated with leveldb compression on too. [edit] On reflection, probably not such a big deal - writes to the WAL in leveldb won&#39;t be affected by compression. [/edit]</p>
<p>It may not be a problem for your workload but actually it might. Having certain writes use so much IO could cause you some real latency issues and given single writer lock, could give you similar IO-based stalls that leveldb is known for due to it&#39;s background compaction.</p>
<p>I&#39;ll repeat this is all theoretical but I&#39;d want to understand a lot more detail like this before I used LMDB in a critical application.</p>
<h4 id="disk-reclamation">Disk Reclamation</h4>
<p>Deleting a large part of the DB does not free any disk space for other DBs or applications in LMDB. Indeed there is no built in feature or any tools I&#39;ve seen that will help you re-optimise the DB after a major change, nor help migrate one DB to another to reclaim the space. </p>
<p>This may be a moot point for many but for practical systems, having to solve these issues in the application might add significant work for the developer and operations teams where others (leveldb) would eventually reclaim the space naturally with no effort.</p>
<h2 id="summary">Summary</h2>
<p>I feel to counter the potentially negative tone I may have struck here, I should sum up by saying LMDB looks like a great project. I&#39;m genuinely interested in the design and performance of all the options in this space.</p>
<p>I would suggest that a real understanding of the strengths <em>and weaknesses</em> of each option is an important factor in making real progress in the field. I&#39;d humbly suggest that, if the author of LMDB was so inclined, including at least some discussion of some of these issues in the docs and benchmarks would benefit all. </p>
<p>I&#39;ll say it again if Howard or anyone else who&#39;s played with LMDB would like to comment on any of these issues, I&#39;m looking forward to learning more.</p>
<p>So is LMDB a leveldb killer? I&#39;d say it seems good, but more data required.</p>
]]></description><link>https://banksco.de/p/lmdb-the-leveldb-killer.html</link><guid isPermaLink="true">https://banksco.de/p/lmdb-the-leveldb-killer.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Thu, 15 Aug 2013 00:00:00 GMT</pubDate></item><item><title><![CDATA[Meet Handlebars.js]]></title><description><![CDATA[<p><strong>In <a href="http://banksco.de/p/fancy-new-blog.html">making this blog</a> I ended up using <a href="http://handlebarsjs.com">Yehuda Katz&#39; Handlebars.js</a> for templating. It has some intersting features I&#39;ll introduce here, but arguably dilutes <a href="http://mustache.github.com">Mustache&#39;s</a> basic philosophy somewhat.</strong></p>
<p>I found Handlebars to be a powerful extension to Mustache but I want to note up-front that it quite possibly isn&#39;t the best option in every case. Certainly if you need implementations outside of Javascript it&#39;s not (yet) for you, however I&#39;m also aware that the extra power added comes with a potential cost: you can certainly undo many of the benefits of separating logic and template.</p>
<p>With that note in place. I&#39;ll introduce the library.</p>
<h2 id="why-handlebars-">Why Handlebars?</h2>
<p>Yehuda has already outlined his <a href="http://yehudakatz.com/2010/09/09/announcing-handlebars-js/">rationale for creating Handlebars</a> so I won&#39;t go into too much detail here. The important goals can be summed up as:</p>
<ul>
<li><p><strong>Global, contextual helpers</strong> &mdash; Mustache allows helper methods in views but they must be defined in the view object (Yehuda calls this the &quot;context&quot; object so I&#39;ll keep that terminology from now on). Further, there is intentionally no way to pass arguments to these methods so even if they are defined globally and &quot;mixed-in&quot; of inherited into each view, they are fairly limited in scope.</p>
</li>
<li><p><strong>More flexibility with accessing data from parent contexts</strong> &mdash; inside blocks, Mustache makes it tricky to access properties of the parent scope outside the block.</p>
</li>
<li><p><strong>Precompilation support</strong> &mdash; you can pre-compile templates into native JS code. In browser context this saves the from client the string parsing overhead.</p>
</li>
</ul>
<p>I encourage you to read his article for a lot more detail and explanation of those points but we&#39;ll crack on for now.</p>
<p>I won&#39;t cover all the features here. You can read them <a href="http://handlebarsjs.com">in the documentation</a>. For now I want to highlight the power (and possible danger) of helpers.</p>
<p>In the case of <a href="http://banksco.de/p/fancy-new-blog.html">my static site generation system</a>, my main goal was to have a very thin layer of logic on top of simple content-with-meta-data files with some simple naming conventions. I wanted flexibility in the templating system so that I could generate menus or listings of content without writing extra code for each case.</p>
<p>With Mustache, this flexibility had to happen in the view layer and so became a little clumsy to express in a general and extensible way the data sets required for any page.</p>
<p>It turned out to be much neater and require a lot less &quot;magic&quot; code to be able to make the templates a little more expressive. Helpers were the key.</p>
<h2 id="helpers">Helpers</h2>
<p>Handlebars adds to Mustache the ability to register helpers that can accept contextual arguments. Helpers are simply callbacks that are used to render <code>{{mustaches}}</code> or <code>{{#blocks}}{{/blocks}}</code>. They can be registered globally or locally in a specific view. We&#39;ll use global registration here to keep examples clearer.</p>
<p>Here&#39;s a basic example of a block helper that could be used for rendering list markup.</p>
<pre><code>&lt;h1>{{title}}&lt;/h1>
{{<span class="comment">#list links}}</span>
    &lt;a href=<span class="string">"{{url}}"</span>>{{name}}&lt;/a>
{{/<span class="keyword">list</span>}}</code></pre>
<p>Here&#39;s the context used</p>
<pre><code>{
    title: &#39;An example&#39;,
    links: [
        {url: &#39;http://example.com/one&#39;, name: &#39;First one&#39;},
        {url: &#39;http://example.com/two&#39;, name: &#39;Second one&#39;}
    ]
}</code></pre>
<p>And here is the <code>list</code> helper definition:</p>
<pre><code>Handlebars.registerHelper(<span class="string">'list'</span>, <span class="keyword">function</span>(links, options){
    <span class="keyword">var</span> html = <span class="string">"&lt;ul>\n"</span>;
    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; links.length; i++) {
        html += <span class="string">"\t&lt;li>"</span> + options.fn(links[i]) + <span class="string">"&lt;/li>\n"</span>;
    }
    <span class="keyword">return</span> html + <span class="string">"&lt;/ul>\n"</span>;
});</code></pre>
<p>When you compile this and render with the context data above, you would get the following output:</p>
<pre><code>&lt;h1>An example&lt;/h1>
&lt;ul>
    &lt;li>&lt;a href="http://example.com/one">First one&lt;/a>&lt;/li>
    &lt;li>&lt;a href="http://example.com/two">Second one&lt;/a>&lt;/li>
&lt;/ul></code></pre>
<p>You can read similar examples in <a href="http://handlebarsjs.com">the documentation</a> which have much more complete explanations of the details here but the basics should be clear:</p>
<ul>
<li>The helper is called like a regular Mustache expression &mdash; in this case it&#39;s a block but non-blocks work too.</li>
<li>The <code>links</code> array from the context data is passed as an argument. Handlebars allows passing more than one argument or no arguments. The options arg is always present as the last one, any others before that are positional, passed through from the template expression. (you can also use non-positional <a href="http://handlebarsjs.com/block_helpers.html#hash-arguments">hash arguments</a>.)</li>
<li>The <code>options</code> arg is passed a hash containing a few things. Most significant here is <code>options.fn</code> which is the compiled template function for the block&#39;s content. That means you can call it with either the current context <code>this</code> or some other data context. In this example we are passing <code>links[i]</code> which means the inner block can use <code>{{url}}</code> and <code>{{name}}</code> directly form the current link&#39;s context.</li>
</ul>
<p>With that very brief overview example, I want to move on to more interesting examples. If you want to read more about the specifics about what happened there then I&#39;d encourage <a href="http://handlebarsjs.com/block_helpers.html">reading the block helpers documentation</a>.</p>
<h2 id="helpers-for-content-selection">Helpers for Content Selection</h2>
<p>Before I continue, I need to acknowledge that what follows breaks everything you know about MVC separation of concerns. I know. Bear with me for now.</p>
<p>My site generation system builds the site files based on filesystem naming conventions. For things like the blog home page I wanted to show the 5 most recent blog posts.</p>
<p>Internally the system reads the whole content file structure and builds an in-memory model of the content. Each directory has two indices: one for all articles with a date in the file name (most recent first) and an index of all other article files in alphabetical order. You can then get the object representing that directory and list the articles in either the date-based or name-based index.</p>
<p>For convenience, I developed an internal API that made this easy using &quot;content URLs&quot; for example <code>Content.get(&#39;/p/?type=date&amp;limit=5&#39;)</code> which will return the most recent 5 dated articles in the <code>/p/</code> directory.</p>
<p>From there it is pretty simple to be able to make a block helper that allows templates like this:</p>
<pre><code>&lt;ul>
{{<span class="comment">#pages '/p/?type=date&amp;limit=5'}}</span>
    &lt;li>&lt;a href=<span class="string">"{{url}}"</span>>{{title}}&lt;/a>&lt;/li>
{{/pages}} 
&lt;/ul></code></pre>
<ul>
<li>The <code>pages</code> helper accepts a string argument (the internal content URL) and uses it to fetch the relevant page objects from the content model.</li>
<li>In this case <code>options.fn</code> is passed the page object itself so can render any property of the page.</li>
</ul>
<h3 id="next-and-previous">Next and Previous</h3>
<p>But listings aren&#39;t the only case this is useful. On the bottom of each blog article I have links to next/previous articles (if they exist) and these need the URL and title of the neighbouring items in the dated index.</p>
<p>I did this with another couple of block helpers. The blog template looks a bit like this:</p>
<pre><code>&lt;h1>{{title}}&lt;h1>
{{{content}}}
&lt;footer>
    {{<span class="comment">#prev_page}}</span>
        &lt;a href=<span class="string">"{{url}}"</span>>&amp;laquo; {{title}}&lt;/a>
    {{/prev_page}}
    {{<span class="comment">#next_page}}</span>
        &lt;a href=<span class="string">"{{url}}"</span>>{{title}} &amp;raquo;&lt;/a>
    {{/next_page}}
&lt;/footer></code></pre>
<p>The helper itself uses <code>this</code> which is the current context (in this case the main blog article being displayed). It then looks up in the content index the article&#39;s parent directory, and locates the previous or next item in the index relative to the current one. It then calls <code>options.fn</code> with the neighbouring article object as context.</p>
<h2 id="pushing-the-boundaries">Pushing the Boundaries</h2>
<p>From here there is a lot of grey areas you could probe with this powerful construct. For example, let&#39;s assume you have different modules of your app rendering themselves and then being combined by some layout controller and rendered into a layout.</p>
<p>What if you wanted to have the module&#39;s external CSS or JS requirements actually defined in the template that really has the dependency. Right off the bat, I&#39;ll say I can&#39;t think of a real reason you&#39;d want this and not have it taken care of outside of the templating layer, but…</p>
<p>You could have a helper for ensuring the correct CSS is loaded up-stream in the template like:</p>
<pre><code>{{add_css <span class="string">'widget.css'</span>}}
&lt;div <span class="keyword">class</span>=<span class="string">"widget"</span>>
    ...
&lt;/div></code></pre>
<p>And then have the helper defined such that it adds the arguments passed to the layout controller and returns nothing to be rendered.</p>
<p>Then the layout rendering might link those CSS assets in the head.</p>
<p>You&#39;re right. This is almost certainly a bad idea. I mention it because it was something that occurred to me for a second before I recognised that is was an example of probably dangerous usage. When you get the hang of a powerful concept like this it&#39;s easy to start seeing every problem that can be possibly solved with it as a good candidate.</p>
<p>As with all powerful programming concepts and libraries, there are many things you <em>can</em> do with Handlebars helpers that are really bad ideas. Hence my note of caution at the start.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I&#39;m quite happy with the extra power Handlebars has given me in this context. But I&#39;m certain that with the extra power comes the inevitable responsibility. It is certainly possible to write crazy and unmaintainable code if you get too creative with helpers without thought.</p>
<p>The examples here are probably not best practice for an MVC web-app context. But here in a site generation script with an already in-memory content model, it allowed me to extend the expressiveness of the system without hard-coding a lot of specific logic for different cases in the model layer.</p>
<p>Handlebars.js has many more features than I have touched on here. Check it out. It may just be what you are looking for if you really like Mustache&#39;s philosophy but have a need (and the discipline) to make more expressive helpers.</p>
]]></description><link>https://banksco.de/p/meet-handlebars-js.html</link><guid isPermaLink="true">https://banksco.de/p/meet-handlebars-js.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 31 Dec 2012 00:00:00 GMT</pubDate></item><item><title><![CDATA[Fancy New Blog]]></title><description><![CDATA[<p><strong>Same poor content, new styling (and backend)</strong></p>
<p>I made my blog a few years ago as a <a href="http://banksco.de/p/on-the-bandwagon">way to learn Rails</a> and after a year in which I posted only two new articles of very low value, I got inspired to give it a revamp.</p>
<p>This article is a long-and-yet-brief overview of the changes..</p>
<h2 id="design">Design</h2>
<p>The style just suits my tastes better. When I made the last version, I was much more focussed on learning Rails and the aesthetics of the site became somewhat secondary. I was inspired by some beautiful and elegant sites I&#39;ve seen recently and this design was the result (for now). I have dreams of adding beautiful imagery and other fancy things to some articles too, but we&#39;ll see.</p>
<p>Fonts are from <a href="http://www.google.com/webfonts">Google&#39;s Webfonts</a> rather than <a href="https://typekit.com/">TypeKit&#39;s</a> free plan because there is much more freedom without fees. I also get to download the fonts I use here for offline use.</p>
<h2 id="technology">Technology</h2>
<p>I went back to basics for this. Since I made the last version of this blog, my tastes in tech have changed a bit. I&#39;ve come to value simplicity and efficiency more and more. Having a full Rails stack, web servers, proxies, database, user authentication, SSL certificates etc. suddenly seems like a really ugly solution for what is essentially a simple, static site only updated by me.</p>
<p>So this site <em>is</em> a static site.</p>
<p>After I finished a lot of the work on this new system described below, I came across an article from a friend of mine about <a href="http://jekor.com/article/towards-a-lifelong-content-management-system">his CMS solution</a>. It turns out he had a lot of the same ideas and he does a great job of expressing his rationale for moving away from Wordpress-like apps for CMS. I link to that now to save you from more clumsy words from me repeating many of the same things less eloquently.</p>
<h2 id="managing-static-content">Managing Static Content</h2>
<p>So this site is just HTML files served by good old Apache. Nginx probably would be my first choice on a dedicated server but I&#39;m enjoying my current stay on <a href="http://www.webfaction.com">Webfaction</a> and this is the most appropriate configuration here.</p>
<p>Managing a static site by hand is so 1990s, clearly we can do better than that.</p>
<p>There are actually a bunch of great static CMSs out there that would have been great, <a href="https://help.github.com/articles/using-jekyll-with-pages">Jekyll (Github Pages)</a>, <a href="http://statamic.com/">Statamic (Commercial)</a> and <a href="http://getkirby.com/">Kirby</a> being the main ones I came across. Typically, I ended up building my own for no terribly good reason other than it being a good excuse to learn something and end up with exactly the features I need.</p>
<p>The site generation is done by a <a href="http://nodejs.org/">Node.js</a> app. The content is managed through the file system with a simple naming scheme allowing for articles to participate in ordered indices. For example, if the file name begins with a <code>YYYY-MM-DD</code> date format then it will be added to a newest-first by-date index for that directory. More on these indices later.</p>
<p>The content files themselves are then simply <a href="http://daringfireball.net/projects/markdown/">Markdown</a> files with <a href="https://github.com/mojombo/jekyll/wiki/YAML-Front-Matter">yaml-front-matter</a> to add some meta-data to each. Meta-data typically includes the title (so it can be re-used for page title and in listings/RSS) and a template file to use to render that page.</p>
<p>Templating uses <a href="http://handlebarsjs.com">Handlebars</a> which is Mustache with a little more flexibility. This extra flexibility becomes really useful in conjunction with the content indices I mentioned before. For example, all the posts on this blog are dated files in the <code>/p/</code> directory. To generate the listing on the front page of the site I just need to make a static page called <code>/index.md</code> with meta-data assigning a template that does something like:</p>
<pre><code>{{<span class="comment">#pages '/p/?type=date&amp;limit=5'}}</span>
    &lt;article>
        {{> blog_post_body.mu }}
    &lt;/article>
{{/pages}}</code></pre>
<p>And my custom <code>pages</code> helper can go and find the date index for the <code>/p/</code> directory and pull out most recent five articles.</p>
<p>As well as being defined per file in YAML front matter, meta-data defaults for a whole directory can be set in a <code>defaults.yml</code> file (e.g. all blog posts use the same template so it is declared once in <code>/p/defaults.yml</code>) and these defaults are inherited through the content directory hierarchy.</p>
<p>There is another special content file naming convention for specifying RSS feeds (e.g. <code>/blog.rss.yml -&gt; /blog.rss.xml</code>) where the feed meta-data and an internal &quot;content URL&quot; like the one in the template example above are used to generate an XML RSS feed.</p>
<p>Finally, any files that are not <code>.md</code> or <code>.yml</code> in the content directory are copied directly (symlinked) into the final public document root, so that all static assets like images, JS and CSS can be kept versioned with the rest of the content and the entire document root is managed by the generator script.</p>
<h2 id="publishing">Publishing</h2>
<p>Content is edited through file system and kept version-controlled in a git repository along with the templates and (currently) the node app that generates the site.</p>
<p>I installed a <code>post-update</code> hook in the git repo on the web-server that automatically checks out HEAD and re-runs the generation script. So I can deploy changes by editing files locally, committing, and then running <code>git push production</code>.</p>
<p>I have toyed with the idea of building a web interface for editing. In fact I did have a working prototype using <a href="http://oscargodson.github.com/EpicEditor/">EpicEditor</a> and a node.js REST API (using <a href="http://mcavage.github.com/node-restify/">restify</a>) for editing in an earlier version of the system. But, having settled on the simplicity of fully version-controlled content and no daemons or security to worry about on the server, I&#39;m sticking with local edit and git-push deployment for now.</p>
<p>I am using <a href="http://mouapp.com/">Mou</a> to write this right now with instant, correctly-styled preview. It works really well, especially when <a href="http://theablefew.com/blog/sublime-text-2-as-a-markdown-editor">tied it into Sublime Text 2</a> which I am using to edit the rest of the templates and js files.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I like it. It&#39;s been fun to think about and build and has lots of potential for future tinkering. </p>
<p>I may even stick a skeleton version of the site with generation scripts etc. on github although I doubt anyone could have a real desire to use this over one of the more widely used and much better-tested options I listed above.</p>
<p>Now I just need to try to focus on producing some interesting content…</p>
]]></description><link>https://banksco.de/p/fancy-new-blog.html</link><guid isPermaLink="true">https://banksco.de/p/fancy-new-blog.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 29 Dec 2012 00:00:00 GMT</pubDate></item><item><title><![CDATA[PHP Arrays (Again)]]></title><description><![CDATA[<p><strong>I have mentioned PHP array inefficiency a <a href="http://blog.banksdesigns.co.uk/post/when-not-to-use-arrays-in-php">few</a> <a href="http://blog.banksdesigns.co.uk/post/more-efficient-php-arrays">times</a> on this blog.</strong></p>
<p>Discussing it at work today someone linked me to <a href="http://nikic.github.com/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html">a much more thorough review of the topic</a> that is interesting and readable.</p>
<p>I&#39;m finding myself so much more interested in this level of stuff than the typical PHP programmer which I guess is why I spend my free time playing with other, generally statically typed, languages...</p>
]]></description><link>https://banksco.de/p/php-arrays-again.html</link><guid isPermaLink="true">https://banksco.de/p/php-arrays-again.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Thu, 15 Nov 2012 00:00:00 GMT</pubDate></item><item><title><![CDATA[Moving Data and Telling People About It]]></title><description><![CDATA[<p><strong>I published an article for work on <a href="http://dt.deviantart.com/journal/Moving-6-Billion-Messages-Without-Being-Noticed-285571516">our recent database migration</a> that I was involved with. </strong></p>
<p>It was an unorthodox approach which seemed to work well for this particular dataset and hardware/time constraints but certianly not perfect. Some interesting discussion followed.</p>
<p>I&#39;m also secretly quite proud I got a mention on <a href="http://highscalability.com/blog/2012/2/24/stuff-the-internet-says-on-scalability-for-february-24-2012.html">highscalability.com&#39;s weekly roundup</a>. Thanks Todd!</p>
]]></description><link>https://banksco.de/p/moving-data-and-telling-people-about-it.html</link><guid isPermaLink="true">https://banksco.de/p/moving-data-and-telling-people-about-it.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 25 Feb 2012 00:00:00 GMT</pubDate></item><item><title><![CDATA[Catch Up]]></title><description><![CDATA[<p><strong>I&#39;ve not posted for ages. So here is a summary of a bunch of stuff I&#39;ve been looking at for fun.</strong></p>
<h3 id="machine-learning">Machine Learning</h3>
<p>First up, after finishing the <a href="http://blog.banksdesigns.co.uk/post/go-back-to-uni-at-google">MIT Introduction to Algorithms</a> lectures, I was excited to hear about <a href="http://www.openculture.com/2008/09/free_stanford_computer_science_engineering_courses_now_online.html">Stanford&#39;s free computer science courses</a>. They are full, taught and (machine) assessed university modules for free! I&#39;m studying <a href="http://www.ml-class.org">Machine Learning</a> and I am really impressed with the quality of the teaching. Thanks Stanford.</p>
<p>There is of course speculation that this is a trial for a new paid remote service. To be honest I feel the quality of the course I&#39;ve done would be worth paying for if they could find a way to acredit something as a real qualification without proper human assessment.</p>
<h3 id="c-experiments">C++ Experiments</h3>
<p>Following on from <a href="http://blog.banksdesigns.co.uk/post/leveldb-fun">my experiments with LevelDB</a>, I have played around with creating a C++ gossip implementation <a href="http://wiki.apache.org/cassandra/ArchitectureGossip">based on Cassandra&#39;s</a> using <a href="http://www.zeromq.org/">ZeroMQ</a>. I spent a lot of time getting a really basic grasp on the intricacies of threading vs event driven style + message passing etc. Ended up with multiple processes on same machine (different ports) gossiping and effectively sharing cluster state. Didn&#39;t get around to implementing the full <a href="http://nosql.mypopescu.com/post/3479538825/distributed-systems-the-phi-accrual-failure-detector">phi accrual failure detection</a> for machine/up down inference and I&#39;m sure the code would need to be torn apart and re-written for anythign resembling real use, but a good learning exercise.</p>
<p>I&#39;ve now moved on to fiddling about with on-disk data structures. So far I&#39;m mostly just learning. I&#39;ve read through the specs for <a href="http://www.sqlite.org/fileformat2.html">SQLite&#39;s db file</a> and some articles on <a href="http://guide.couchdb.org/draft/btree.html">CouchDB&#39;s Copy-on-write B-tree</a> (not to mention LevelDB/Cassandra&#39;s <a href="http://nosqlsummer.org/paper/lsm-tree">LSM trees</a>). I&#39;ve also read <a href="http://www.acunu.com/blogs/andy-twigg/stratified-btrees/">Acuna&#39;s paper on Stratified B-Trees</a> which is all really interesting stuff. Not quite sure what I want to implement now but I may start with trying to get a basic block and free-list allocator working. Just the experience of actually working with C++ and &quot;real&quot; algorithms is fascinating for me, a lowly PHP developer.</p>
<p>In summary then, I&#39;m still doing loads of geeky computer stuff, just forgetting to write about any of it.</p>
]]></description><link>https://banksco.de/p/catch-up.html</link><guid isPermaLink="true">https://banksco.de/p/catch-up.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Wed, 09 Nov 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[LevelDB Fun]]></title><description><![CDATA[<p><strong>Google recenetly open-sourced <a href="http://code.google.com/p/leveldb/">LevelDB</a> which is &quot;a fast key-value storage library&quot;. I&#39;ve used it as an excuse to play about in C++.</strong></p>
<p>There is nothing new or exciting to report to the tech world here - just that I&#39;ve enjoyed playing about in a language I&#39;ve not worked much with in the past. </p>
<p>So far I have hooked up <a href="http://monkey.org/~provos/libevent/">libevent</a> to LevelDB and made my own little Key-Value database server that can accept multiple clients.</p>
<p>I&#39;ve also written a C++ client library to talk to it and made up my own Ascii-based data transfer format.</p>
<p>None of this is useful to anyone other than me - it&#39;s great to actually play around with a language like this and to get a feel for it. Much more productive that code tutorials or algorithm exercises.</p>
]]></description><link>https://banksco.de/p/leveldb-fun.html</link><guid isPermaLink="true">https://banksco.de/p/leveldb-fun.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 17 Sep 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[More Efficient PHP Arrays]]></title><description><![CDATA[<p><strong>One of my first posts here was about <a href="http://blog.banksdesigns.co.uk/post/when-not-to-use-arrays-in-php">how surprisingly inefficient PHP arrays can get</a>. Today I learned of a solution that is probably a lot better than my PHP string serialisation. It&#39;s an extension called <a href="https://github.com/dynamoid/intarray">intarray</a>.</strong></p>
<p>The extension exposes integer-only arrays as strings to PHP but provides <a href="https://github.com/dynamoid/intarray/blob/master/intarray.php">several useful methods for interacting with them</a> such as sort, slice and binary search. This means if you are using PHP arrays to store sets of integers, you will likely see a very large improvement in speed and memory usage using this extension.</p>
<p>I&#39;ve yet to do any real benchmarking but I thought I&#39;d post this as a follow-up from my original post. I know at least one very large site who has used this extension in production with no issue although I obviously urge anyone to evaluate stability etc of any software themselves before deploying.</p>
]]></description><link>https://banksco.de/p/more-efficient-php-arrays.html</link><guid isPermaLink="true">https://banksco.de/p/more-efficient-php-arrays.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Wed, 24 Aug 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[PHPUnit's Expensive SetUp]]></title><description><![CDATA[<p><strong>I&#39;ve been working a lot with <a href="https://github.com/sebastianbergmann/phpunit/">PHPUnit 3.5</a> recently. It&#39;s good in many ways but it is not fast. That&#39;s understandable perhaps given the feature set but there is one apparently obvious oversight which totally ruins the experience.</strong></p>
<p>The problem I&#39;m talking about I&#39;ve <a href="https://github.com/sebastianbergmann/phpunit/issues/261">reported as a possible bug</a> and yet it has gotten zero attention in over two months. I&#39;ll describe it again here.</p>
<h3 id="the-problem">The Problem</h3>
<p>PHPUnit has a whole multitude of ways to construct a test suite and pick which test to run. Using the command line runner, you can specify specific test case files or dirs and you can use <code>filter</code> and <code>group</code> options to further restrict.</p>
<p>The problem is that, whatever you pass as <code>filter</code> or <code>group</code> arguments, all <code>setUp()</code> and <code>setUpBeforeClass()</code> methods in all test cases loaded will be run. That&#39;s because <a href="https://github.com/sebastianbergmann/phpunit/blob/3.5/PHPUnit/Framework/TestSuite.php#L653">filtering is applied after setup methods called</a>. I really don&#39;t see the rationale behind that decision.</p>
<p>At work we have a large test suite. One part of it is for our database layer and as such has some very expensive setup routines which setup an entire test environment in our test db. Even when you limit the runner to a specific test case, that may mean this very expensive setup operation has to run for every test in the file - even when you are just trying to work with a single test method.</p>
<p>But we shouldn&#39;t have to fiddle about with specifying specific test cases. The <code>filter</code> and <code>group</code> options are powerful and (should be) very useful for cherry picking from a suite. This seemingly obvious error totally ruins them and makes working with big test suites decidedly awkward.</p>
<p>Even more confusing is the fact that no-one else I&#39;ve seen online seems to think this is a problem. I&#39;ve found no other mention of the behaviour and zero interest in my ticket. Did I miss something here? Is there an obvious reason that setup should be run all the time even when filtering tests? All my colleges and other PHP developers I&#39;ve mentioned this to personally seem to agree it is very odd behaviour. I&#39;d have expected many people to be using PHPUnit with large suites. Does no one else wonder why running a single simple test can take minutes?</p>
<p>I hope I can update this post when something changes, but I&#39;ve not been encouraged by the response to my ticket so far.</p>
]]></description><link>https://banksco.de/p/phpunits-expensive-setup.html</link><guid isPermaLink="true">https://banksco.de/p/phpunits-expensive-setup.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 09 Aug 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[Opera's fixed position problem]]></title><description><![CDATA[<p><strong>Opera has a bug with <code>node.offsetTop</code> when the node has a fixed position ancestor. That has been <a href="http://www.greywyvern.com/code/opera/bugs/PositionFixedoffsetTop">know about for a while</a>. I didn&#39;t think it would take me three separate days of pain to get a handle on.</strong></p>
<p>It turns out that it&#39;s quite a lot more complex than that page linked above suggests. At work we have an old utility library called <code>Ruler.js</code> which does a lot of things relating to measuring element positions relative to all sorts of things. While trying to fix a JS positioning issue caused by this Opera bug I though I could simply correct it by compensating for Opera&#39;s extra scroll pixels for fixed position nodes in the offset hierarchy.</p>
<p>The problem is that Opera isn&#39;t even consistently wrong. It only breaks for elements with <code>display: inline</code> or <code>inline-block</code> (as far as I can tell) and only if they are positioned relatively (either explicitly or implicitly).</p>
<p>What is more, if there is any other element in the offset hierarchy between the element you are measuring and the fixed position one, then the results change. In some cases an explicit <code>position:relative</code> fixes the behaviour completely.</p>
<p>A <a href="http://jsfiddle.net/XgyWV/5/">totally non-exhaustive demo</a> shows how odd some results can be. Note that this doesn&#39;t really demo the extent of the problems when trying to walk up the offset tree and correct for scroll position etc which was what made the real diagnostics so much more complex.</p>
<p>Here is the output in Safari 5 and Opera 11.10 side by side: </p>
<p><img src="http://cl.ly/3B3b0P0c2b171j1p3M3C/content" alt="Screen shot of jsFiddle demo"></p>
<p>So there turned out to be no sensible way to even detect if the position had been mangled by Opera in JS. I resorted to having to add <code>position:relative</code> to a parent element where it had no other affect to resolve this case. That also means I&#39;ll probably run into this again in the future so i thought I&#39;d document it here!</p>
]]></description><link>https://banksco.de/p/operas-fixed-position-problem.html</link><guid isPermaLink="true">https://banksco.de/p/operas-fixed-position-problem.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 17 May 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[Trying to make JS go OO]]></title><description><![CDATA[<p><strong>At work, we use a version of <a href="http://dean.edwards.name/weblog/2006/03/base/">Base.js by Dean Edwards</a> to standardise object inheritance and make our JavaScript somewhat more Object Oriented. Today I came across a quirk.</strong></p>
<p>Now the problem I found isn&#39;t with Base.js really - it&#39;s an inherent feature of JS&#39;s prototyping and object model, however it was made more confusing by Base.js apparently giving you &#39;class&#39; like definition of objects. After discussing some unintuitive behaviour with <a href="http://dt.deviantart.com">my colleagues</a> it became clear that this is basic JavaScript behaviour despite being somewhat confusing at first. </p>
<p>I&#39;m sure this issue has been brought up in other Base.js discussions before, in fact Dean&#39;s latest version may even have solved it - we are using a somewhat legacy version. But the underlying JS issue was interesting to me so I thought I&#39;d write it up for future reference.</p>
<h3 id="instance-properties">Instance properties</h3>
<p>If you don&#39;t know what Base.js does, read about it on <a href="http://dean.edwards.name/weblog/2006/03/base/">Dean&#39;s blog</a>. This basic example shows the creation of a &#39;Class&#39; with a property which behaves as you would expect:</p>
<pre><code>::javascript::
<span class="keyword">var</span> TestClass = Base.extend({
    prop: <span class="keyword">null</span>,
});
<span class="keyword">var</span> a = <span class="keyword">new</span> TestClass, b = <span class="keyword">new</span> TestClass;
a.prop = <span class="string">'A'</span>;
console.log(a.prop, b.prop); <span class="comment">// Log: A null</span></code></pre>
<p>But what if your property was an array?</p>
<pre><code>::javascript::
<span class="keyword">var</span> TestClass = Base.extend({
    prop: [],
});
<span class="keyword">var</span> a = <span class="keyword">new</span> TestClass, b = <span class="keyword">new</span> TestClass;
a.prop.push(<span class="string">'A'</span>);
b.prop.push(<span class="string">'B'</span>);
console.log(a.prop, b.prop); <span class="comment">// Log: ["A", "B"] ["A", "B"]</span></code></pre>
<p>Wait, what happened there?</p>
<p>Well if you think about what Base.js is doing, it is kind of obvious. JavaScript ALWAYS points to references of objects. That is, any variable that is not a primitive type is a reference.</p>
<p>Consider the non-Base.js equivalent of above (roughy the same as what Base.js is doing under the hood):</p>
<pre><code>::javascript::
<span class="keyword">var</span> TestClass = <span class="keyword">function</span>(){};
TestClass.prototype.prop = []; <span class="comment">// Assigning a pointer to this specific empty array</span>
<span class="keyword">var</span> a = <span class="keyword">new</span> TestClass, b = <span class="keyword">new</span> TestClass;
a.prop.push(<span class="string">'A'</span>);
b.prop.push(<span class="string">'B'</span>);
console.log(a.prop, b.prop); <span class="comment">// Log: ["A", "B"] ["A", "B"]</span></code></pre>
<p>Here it is somewhat more obvious what happens. Each instance &#39;inherits&#39; the <code>prop</code> property from it&#39;s prototype but that isn&#39;t <em>an</em> empty array, it is a pointer to the <em>specific</em> array the prototype was initialised with.</p>
<p>So the solution is to do this initial assignment in the constructor:</p>
<pre><code>::javascript::
<span class="keyword">var</span> TestClass = Base.extend({
    prop: [],
    constructor: <span class="keyword">function</span>(){
        <span class="keyword">this</span>.prop = []; <span class="comment">// this is now this instance, creating a new array just for this instance</span>
    }
});
<span class="keyword">var</span> a = <span class="keyword">new</span> TestClass, b = <span class="keyword">new</span> TestClass;
a.prop.push(<span class="string">'A'</span>);
b.prop.push(<span class="string">'B'</span>);
console.log(a.prop, b.prop); <span class="comment">// Log: ["A"] ["B"]</span></code></pre>
<p>Or the equivalent non-base code:</p>
<pre><code>::javascript::
<span class="keyword">var</span> TestClass = <span class="keyword">function</span>(){
    <span class="keyword">this</span>.prop = [];
};
<span class="keyword">var</span> a = <span class="keyword">new</span> TestClass, b = <span class="keyword">new</span> TestClass;
a.prop.push(<span class="string">'A'</span>);
b.prop.push(<span class="string">'B'</span>);
console.log(a.prop, b.prop); <span class="comment">// Log: ["A"] ["B"]</span></code></pre>
<h3 id="back-to-basics">Back to basics</h3>
<p>This is really very basic Javascript but pseudo-OO frameworks like Base.js (which are great in many ways) can make this behaviour seem even more unintuitive. My take-away is that understanding JavaScript properly is as important as ever despite the great abstractions and frameworks that let us ignore many of the details of how it works most of the time.</p>
]]></description><link>https://banksco.de/p/trying-to-make-js-go-oo.html</link><guid isPermaLink="true">https://banksco.de/p/trying-to-make-js-go-oo.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Thu, 12 May 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[Learning to program properly]]></title><description><![CDATA[<p><strong>Being inspired by <a href="http://www.catonmat.net/series/mit-introduction-to-algorithms">MIT&#39;s introduction to algorithms</a> I&#39;ve decided to put some of my newly learnt stuff into practice. And there is not a lot of point in implementing this stuff a language like PHP or JS.</strong></p>
<p>So I&#39;m re-learning C. I learnt some very basics as part of my degree and have worked with Objective-C a fair bit so it&#39;s not completely alien. It&#39;s taken me a lot longer than it was suggested it should, but I&#39;ve finally got a working implementation of skip lists. </p>
<p>Getting my head back around pointer arithmetic and memory management is a good exercise.</p>
<p>I feel like despite all the cool new languages around, most real infrastructure and interesting technology is still written in real languages like C.</p>
]]></description><link>https://banksco.de/p/learning-to-program-properly.html</link><guid isPermaLink="true">https://banksco.de/p/learning-to-program-properly.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 21 Feb 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[jQuery 1.5 Beats Monster Callbacks Into Shape]]></title><description><![CDATA[<p><strong>This is a shameless re-blog of <a href="http://www.erichynds.com/jquery/using-deferreds-in-jquery/">Eric Hynds&#39; article on jQuery deferreds</a>. It&#39;s a great read.</strong></p>
<p><a href="http://jquery.com/">jQuery 1.5</a> was out yesterday and includes several changes as one might expect. Deferreds are a new concept for me although reading Eric&#39;s great article above reveals a powerful and elegant new paradigm for handling callbacks in jQuery.</p>
<p>Essentially jQuery <code>$.ajax</code> functions (and most other functions with observable results) now return a deferred object which contains a promise. You can then hook callbacks to the success or failure of that promise and they will all be triggered when the promise is fulfilled. That means you can manage multiple bits of code that depend on an AJAX fetch separately and if you hook up a callback to the request after it has completed, it will be fired immediately.</p>
<p>Moreover, the API is very clean and simple with good semantic verbs for hooking things together. That makes the concept arguably easier to understand than plain function being passed callbacks, despite the extra power and decoupling.</p>
<p>There is quite a bit more to it than I&#39;ve described though and Eric does a great job of explaining how and why you might want to use this powerful technique.</p>
]]></description><link>https://banksco.de/p/jquery-15-beats-monster-callbacks-into-shape.html</link><guid isPermaLink="true">https://banksco.de/p/jquery-15-beats-monster-callbacks-into-shape.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 01 Feb 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[More from MIT: Red-Black Trees are Cool]]></title><description><![CDATA[<p><strong>I mentioned <a href="http://blog.banksdesigns.co.uk/post/go-back-to-uni-at-google">a while back</a> that I had found the lecture videos and notes for MIT&#39;s Introduction to algorithms course on <a href="http://www.catonmat.net/series/mit-introduction-to-algorithms">Peter Krumins&#39; blog</a>. I&#39;m still watching them, and they keep getting better.</strong></p>
<p>I don&#39;t have anything particularly sophisticated to say about them other than being really impressed by  <a href="http://en.wikipedia.org/wiki/Red-black_trees">Red-Black trees</a>.</p>
<p>I&#39;ve found the lectures have not only taught me a lot of things my formal education has lacked regarding algorithms, but it has helped change the way I view problems and enhanced my analytical skills, even without the problem sets, recitation, and &quot;quizzes&quot;. You can probably see that by my <a href="http://blog.banksdesigns.co.uk/post/quick-benchmarks-with-jsfiddle">over-analysis of a simple JS algorithm</a> in my last post.</p>
<p>If you are interested in programming and you didn&#39;t learn this stuff at Uni, (or even if you did) I&#39;d highly recommend the lectures once again</p>
]]></description><link>https://banksco.de/p/more-from-mit-red-black-trees-are-cool.html</link><guid isPermaLink="true">https://banksco.de/p/more-from-mit-red-black-trees-are-cool.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 29 Jan 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[Quick benchmarks with jsFiddle]]></title><description><![CDATA[<p><strong>At work this week a colleague asked if anyone could think of an optimisation for extracting a rectangular subset of pixel data from an HTML 5 <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#canvaspixelarray">CanvasPixelArray</a>. I tried a few things with <a href="http://www.jsfiddle.net">jsFiddle</a>.</strong></p>
<p>My main idea was that rather than iterating through every pixel and comparing coordinates (<code>O(n)</code> running time), you could loop through rows of pixels and remove just the selected ones with <code>Array.slice()</code>.</p>
<p>I put together a quick test case with a simplified integer array and tried this. Turns out that although there are fewer iterations, using JS array <code>slice()</code> and <code>concat()</code> is much much slower probably due to multiple memory copies needed to satisfy them.</p>
<p>You can see and play with <a href="http://jsfiddle.net/pUY7u/2/">my test case on jsFiddle</a>.</p>
<p>Note that you can make significant savings over the completely naive <code>O(n)</code> case by selecting loop boundaries such that only required rows are iterated and then, only required x value extracted with a nested loop. The running time of this case becomes something like <code>O(k)</code> where <code>k</code> is the number of pixels within the required selection which is strictly <code>&lt;= n</code> but probably significantly smaller in most use-cases.</p>
<p>In algorithmic terms this is not a particularly surprising or ground-breaking result. My colleague has probably already found a better solution anyway. My take away was: jsFiddle is great for quick benchmarking and prototyping of solutions. </p>
<p>It makes it trivial to construct test cases and share and develop them with others. I did have one glitch triggered by my JS code getting too long for the textarea and causing the UI to &#39;scroll&#39; but with no way to get it back. But even then a cut, refresh and paste got me back on my feet. And given it&#39;s &#39;alpha&#39; status this is a relatively small complaint.</p>
]]></description><link>https://banksco.de/p/quick-benchmarks-with-jsfiddle.html</link><guid isPermaLink="true">https://banksco.de/p/quick-benchmarks-with-jsfiddle.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 29 Jan 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[Learning Common Lisp]]></title><description><![CDATA[<p><strong>I love to learn new programming languages. Common Lisp is a great language to learn just to broaden one&#39;s horizons.</strong></p>
<p>It may not be particularly cool or popular right now and you may find the syntax ugly but there are so many ideas that really don&#39;t come up in other languages. You&#39;ll soon appeeciate why the syntax is like it is and why that is so powerful. </p>
<p>Especially if you are from a fairly rigid OO background, the emphasis on a more functional approach and the concepts of treating code as data are fascinating and may offer a new way to look at problems. But Common Lisp isn&#39;t truly functional and has a powerful object system too.</p>
<p>You do almost inevitably have to get over using Emacs as an editor but don&#39;t let that stop you from just learning and playing. Just the theory is enough to make me think in whole new ways about problems. </p>
<p>There are many resources at different levels but by far the best I&#39;ve found is <a href="http://gigamonkeys.com/book/">Practicle Common Lisp</a> which has the added bonus of being available free online!</p>
]]></description><link>https://banksco.de/p/learning-common-lisp.html</link><guid isPermaLink="true">https://banksco.de/p/learning-common-lisp.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 02 Jan 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[MacBook Pro: a cooling tip to ignore]]></title><description><![CDATA[<p><strong>My main machine these days is still my trusty four-year-old MacBook Pro. I&#39;ve used it with the battery removed for a while to reduce heat and fan noise when in desktop use. Turns out to be a terrible idea. </strong></p>
<p>It may not be a surprise to you but after spending hours last week trying to work out why my machine was so much slower than my colleages, I stumbled across the fact that MacBook Pros throttle their CPU to 1GHz when the battery is removed. This seems extraordinary. Turns out the 90W power supply isn&#39;t deemed enough to run at full speed so with the batty unavailable to provide burst power, you get crippled CPU performance. </p>
<p>I originally removed the battery as it appeared to aid cooling when my machine was in desktop mode. Now it is hard to tell if it actually was a thermal benefit or whether the cooler temperatures were only because of the crippled performance. </p>
<p>Either way here&#39;s a tip: don&#39;t work without a battery on an apple notebook unless severly reduced performance is enough for you. </p>
]]></description><link>https://banksco.de/p/macbook-pro-a-cooling-tip-to-ignore.html</link><guid isPermaLink="true">https://banksco.de/p/macbook-pro-a-cooling-tip-to-ignore.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 02 Jan 2011 00:00:00 GMT</pubDate></item><item><title><![CDATA[Living it LArge]]></title><description><![CDATA[<p><strong>I&#39;ve just got back (well technically not back yet) from my first trip to LA to meet my co-workers in person!</strong></p>
<p>I really enjoyed it. The hospitality, food and party was great but actually I also really valued being able to talk work face-to-face with my colleagues for the first time. Such subtleties such as facial expression and body language have given me a much clearer idea of what people are like and how they are likely to respond. I&#39;m sure it will make future online discussion significantly easier.</p>
<p>So there isn&#39;t much to say here other than I had a great time.</p>
]]></description><link>https://banksco.de/p/living-it-large.html</link><guid isPermaLink="true">https://banksco.de/p/living-it-large.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 19 Dec 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Go Back To Uni at Google]]></title><description><![CDATA[<p><strong>If you read this blog you&#39;ll be aware that I am a geek and love finding new resources to learn more about geeky things online for free. I&#39;ve lately found two great resources which will keep me interested for a while.</strong></p>
<p>First is a set of lectures for an entire module on Analysis of Algorithms from MIT which is available from <a href="http://www.catonmat.net/blog/mit-introduction-to-algorithms-part-one">Peteris Krumins&#39; blog</a> (the videos were released under CC license). Fascinating and a great resource - made me realise how much I missed learning real subjects from real academics!</p>
<p>Second resource is probably more well-known but new to me. It&#39;s <a href="http://code.google.com/edu/">Google&#39;s Code University</a> which seems to be a great resource listing many courses and materials on a wide range of computer science subjects.</p>
<p>It like christmas come early!</p>
]]></description><link>https://banksco.de/p/go-back-to-uni-at-google.html</link><guid isPermaLink="true">https://banksco.de/p/go-back-to-uni-at-google.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 28 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[PHP 'Mixins' Coming Soon!]]></title><description><![CDATA[<p><strong>I posted a while back about <a href="">PHP&#39;s lack of decent support for multiple inheritance</a>, and concluded that Mixin like behaviour just wasn&#39;t natural to PHP as it stands. PHP 5.4 looks like it will change that with the addition of traits.</strong></p>
<p>Simas Toleikis <a href="http://simas.posterous.com/new-to-php-54-traits">introduces traits</a> in a great blog post. I&#39;m excited, it looks like it could solve many of the issues I bemoaned PHP as lacking.</p>
<p>Since I have no first hand experience, I&#39;ll regurgitate this example from Simas&#39; post above to whet your appetite.</p>
<pre><code>::php::
trait Singleton {
    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">function</span> getInstance() { ... }
}

<span class="keyword">class</span> A {
    <span class="keyword">use</span> Singleton;
    <span class="comment">// ...</span>
}

<span class="keyword">class</span> B <span class="keyword">extends</span> ArrayObject {
    <span class="keyword">use</span> Singleton;
    <span class="comment">// ...</span>
}

<span class="comment">// Singleton method is now available for both classes</span>
A::getInstance();
B::getInstance();</code></pre>
<p>This is a major win for PHP.</p>
]]></description><link>https://banksco.de/p/php-mixins-coming-soon.html</link><guid isPermaLink="true">https://banksco.de/p/php-mixins-coming-soon.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 22 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Facebook ditches Cassandra for HBase]]></title><description><![CDATA[<p><strong><a href="http://cassandra.apache.org/">Cassandra</a> is an open source distributed database implementation that started life at Facebook as a solution to their message inbox search and storage. Facebook <a href="http://blog.facebook.com/blog.php?post=452288242130">announced the next generation of messaging</a> this week, and it&#39;s powered by <a href="http://hbase.apache.org">HBase</a>.</strong></p>
<p><a href="http://highscalability.com/blog/2010/11/16/facebooks-new-real-time-messaging-system-hbase-to-store-135.html">Highscalability.com</a> have a good article about the announcement and technicalities generally. I was particularly interested having recently read <a href="http://www.roadtofailure.com/2009/10/29/hbase-vs-cassandra-nosql-battle/">Bradford&#39;s comparison of the two</a>.</p>
<p>What I take from this is a firm reminder that different NoSQL solutions have different engineering trade-offs, and that picking the right tool for any one application is more important that brand loyalty.</p>
]]></description><link>https://banksco.de/p/facebook-ditches-cassandra-for-hbase.html</link><guid isPermaLink="true">https://banksco.de/p/facebook-ditches-cassandra-for-hbase.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 20 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[CDE: very cool]]></title><description><![CDATA[<p><strong>Just got pointed to <a href="http://www.stanford.edu/~pgbovine/cde.html">a very cool project</a> at stanford to allow linux command executions to be trivially packaged up with all dependencies on one machine and executed on another with no install/dependency issues.</strong></p>
<p>Not tried it yet but it looks like a great and thoroughly useful little tool!</p>
]]></description><link>https://banksco.de/p/cde-very-cool.html</link><guid isPermaLink="true">https://banksco.de/p/cde-very-cool.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 15 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[When Buzzwords Can't Save You]]></title><description><![CDATA[<p><strong>Ooops! Github was down yesterday for several hours and I was expecting one of those &quot;some complex as-yet-unidentified quirk of replication caused our sharded NoSQL cluster to drop every record with exactly 13 words in the title&quot; type incident reports. Turns out <a href="https://github.com/blog/744-today-s-outage">a developer just deleted their production DB accidentally</a>.</strong></p>
<p>Fair play to them for the honest post though. This sort of thing does happen to everyone to a lesser or greater extent and I feel for the guy responsible. It does go to show though that  Continuous Integration, Test Driven Development, Rails and all the other associated buzzwords don&#39;t always save you from the inevitable!</p>
<p>Lesson to learn: don&#39;t allow write access to production databases from dev environments. I&#39;d have thought that with all their infrastructure and expertise, that should never have happened.</p>
]]></description><link>https://banksco.de/p/when-buzzwords-cant-save-you.html</link><guid isPermaLink="true">https://banksco.de/p/when-buzzwords-cant-save-you.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 15 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Google: Infrastructure Challenges Lecture]]></title><description><![CDATA[<p><strong>Found a great link for <a href="http://videolectures.net/wsdm09_dean_cblirs/">a lecture by Jeffrey Dean</a> from Google on the challenges of scaling their search product.</strong></p>
<p>Some fascinating details including their byte encoding scheme for their index and many other wonderful bits of info!</p>
]]></description><link>https://banksco.de/p/google-infrastructure-challenges-lecture.html</link><guid isPermaLink="true">https://banksco.de/p/google-infrastructure-challenges-lecture.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 14 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[PHP Gotcha: Strings are Arrays Too]]></title><description><![CDATA[<p><strong>Actually the title is misleading - but they can at times <em>seem</em> like arrays. This just came up at work and although it is one of those things which seems obvious after, it highlights a potentially dangerous and error-prone design pattern.</strong></p>
<p>Basically we had a function that looked essentially like this:</p>
<pre><code>::php::
<span class="keyword">function</span> error_prone(<span class="variable">$options</span>) {
    <span class="keyword">if</span> ( ! <span class="keyword">isset</span>(<span class="variable">$options</span>[<span class="string">'required_key'</span>])) {
        <span class="comment">// throw error</span>
    }

    <span class="comment">// Manipulate $options['keys'] and return a result</span>
}</code></pre>
<p>At first glance this looks fair enough - while not completely robust, if a badly formed array (without required key) or a non-array is passed it should throw an error right?</p>
<p>Wrong. Due to PHP&#39;s doubling up of square brackets to work as character manipulation of strings.</p>
<p>If you don&#39;t know what I mean, try this:</p>
<pre><code>::php::
<span class="variable">$string</span> = <span class="string">'Hello World!'</span>;
<span class="keyword">echo</span> <span class="variable">$string</span>[<span class="number">0</span>]; <span class="comment">// prints: H</span>
<span class="keyword">echo</span> <span class="variable">$string</span>[<span class="string">'1'</span>]; <span class="comment">// prints: e</span></code></pre>
<p>Now the really unintuitive bit is highlighted on the last line. When you are specifying your character offset, PHP in all it&#39;s type-mangling wisdom, allows any variable type and casts to an int. </p>
<p>What does this mean for our function above? Well, in some bad cases, $options was being passed a string instead of an array. This was due to another error - but at first glance it seems our error checking should have caught that. What actually happens when a string is passed is:</p>
<ol>
<li><code>$options[&#39;required_key&#39;]</code> return first char of <code>$options</code> string since <code>(int) &#39;required_key&#39;</code> is <code>0</code></li>
<li><code>isset($options[&#39;required_key&#39;])</code> therefore returns true!</li>
<li>Code below mangles up some terrible return value based on chars in the string (mostly the first one) rather than actual options.</li>
<li>Final result is baffling and actual source of error is obfuscated</li>
</ol>
<h3 id="solution">Solution</h3>
<p>It really isn&#39;t hard to fix: either type hint the function declaration:</p>
<pre><code>::php::
<span class="keyword">function</span> not_so_error_prone(<span class="keyword">array</span> <span class="variable">$options</span>)</code></pre>
<p>And handle the errors/exceptions nicely, or actually explicitly test arrayness with <code>is_array()</code>.</p>
<p>This is a silly mistake but one that can be easily overlooked when reviewing code unless you pay close attention.</p>
]]></description><link>https://banksco.de/p/php-gotcha-strings-are-arrays-too.html</link><guid isPermaLink="true">https://banksco.de/p/php-gotcha-strings-are-arrays-too.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Wed, 10 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[CoffeeScript: another language to not learn]]></title><description><![CDATA[<p><strong>My attention was drawn to <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> recently. I really like it, I think the author has made some changes that <em>if</em> they were part of javascript proper would make it somewhat nicer to work with. But it is completely pointless.</strong></p>
<p>I mean no disrespect - if it solves a problem for the author then I can&#39;t argue. All I can say is that I completely missed the point. It isn&#39;t even fundamentally changing the way javascript works, no original programming paradigm or domain-specifc problem solving tools.</p>
<p>What it&#39;s ended up as is some syntax sugar taken variously from several popular languages around at the moment. It doesn&#39;t technically improve your javascript app at all and it adds a learning curve and complicates development and deployment by adding a compile phase.</p>
<blockquote>
<p>CoffeeScript is just for fun</p>
</blockquote>
<p>Fair enough. I can&#39;t slam anyone for doing something for fun. And no-one has claimed this to be the new best thing or a must-use tool so I&#39;m not going to start my flamethrower without real provocation!</p>
<p>To the author: I think the syntax is nice, the features I can see being nice to have and you&#39;ve done a really excellent job on the site/docs. In general though, this seems like a huge amount of effort for basically no gain.</p>
]]></description><link>https://banksco.de/p/coffeescript-another-language-to-not-learn.html</link><guid isPermaLink="true">https://banksco.de/p/coffeescript-another-language-to-not-learn.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 09 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Yet Another Facebook MySQL Tech Talk Re-post]]></title><description><![CDATA[<p><strong>You&#39;ve probably read it already but Facebook released a <a href="http://www.livestream.com/facebookevents/video?clipId=flv_cc08bf93-7013-41e3-81c9-bfc906ef8442">MySQL Tech Talk</a> with loads of juicy database porn for those of us facinated by web scalability.</strong></p>
<p>I&#39;ve not got a lot to add other than it&#39;s pretty interesting.</p>
]]></description><link>https://banksco.de/p/yet-another-facebook-mysql-tech-talk-re-post.html</link><guid isPermaLink="true">https://banksco.de/p/yet-another-facebook-mysql-tech-talk-re-post.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 09 Nov 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[PHP and the XOR swap trick]]></title><description><![CDATA[<p><strong>An exercise most programmers are shown when first being introduced to bit arithmetic is how to swap the values of variables without using a third. The answer is the XOR (eXclusive OR) trick.</strong> </p>
<p>For some reason this came to mind this morning and I wondered - what happens in PHP if you try to XOR non integer data types? I could probably have looked it up but a 2 minute script showed me the answer: PHP casts whatever value to an int before performing the operation. So no, you can&#39;t neatly swap two arrays or objects or even strings without a temporary variable. Oh well.</p>
<p>For those who&#39;ve not come across it before. Here is the magic I&#39;m talking about. If you don&#39;t believe it works at first, grab a pencil and paper and work through the binary maths for yourself...</p>
<pre><code>::php::
<span class="variable">$a</span> = <span class="number">1</span>;
<span class="variable">$b</span> = <span class="number">2</span>;

<span class="keyword">echo</span> <span class="string">"a: "</span>.<span class="variable">$a</span>.<span class="string">", b: "</span>.<span class="variable">$b</span>.<span class="string">"\n"</span>;

<span class="comment">// Do the swap</span>
<span class="variable">$a</span> ^= <span class="variable">$b</span>;
<span class="variable">$b</span> ^= <span class="variable">$a</span>;
<span class="variable">$a</span> ^= <span class="variable">$b</span>;

<span class="comment">// All done</span>
<span class="keyword">echo</span> <span class="string">"a: "</span>.<span class="variable">$a</span>.<span class="string">", b: "</span>.<span class="variable">$b</span>.<span class="string">"\n"</span>;</code></pre>
<p>Result:</p>
<pre><code>a: 1, b: 2
a: 2, b: 1</code></pre>
]]></description><link>https://banksco.de/p/php-and-the-xor-swap-trick.html</link><guid isPermaLink="true">https://banksco.de/p/php-and-the-xor-swap-trick.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Thu, 30 Sep 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[A Change of Scenery]]></title><description><![CDATA[<p><strong>My wife Chloe and I are soon going to moving to pastures new. We have decided to escape city life and see how we fare in a more rural setting in Devon. That has meant me moving on to work for a different company too.</strong></p>
<p>It was with some reluctance that I said goodbye to <a href="http://www.ents24.com">Ents24.com</a> two weeks ago. It has been a great couple of years for me working there and I got on really well with all the staff.</p>
<p>My new challenge involves working remotely for the US-based art community <a href="http://www.deviantart.com">deviantART</a>. Working with a bigger team, remotely and across timezones are all new challenges for me but after two weeks I seem to be getting into the swing of things surprisingly easily.</p>
<p>Technically it is very different with many more visitors and a much more write-intensive and interactive emphasis. Lots more servers! The code base is also bigger, changes quicker and is no better documented than previous ones I&#39;ve worked with. This is a little daunting at first although I&#39;m already beginning to feel like I understand broadly how a lot of things work.</p>
]]></description><link>https://banksco.de/p/a-change-of-scenery.html</link><guid isPermaLink="true">https://banksco.de/p/a-change-of-scenery.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Fri, 24 Sep 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[+1 to Textmate]]></title><description><![CDATA[<p><strong>I posted <a href="http://blog.banksdesigns.co.uk/post/the-era-of-komodo-edit">a little while back</a> about my trialling of Komodo edit as an IDE. It&#39;s good, but just a couple of things bugged me enough that I thought I&#39;d see if I could live with the major change that is switching to <a href="http://macromates.com/">TextMate</a>.</strong></p>
<p>Now to be completely fair, most of my gripes with Komodo edit were minor and were more to do with what I&#39;m used to than it being a bad product. Since starting a new job (more to come soon) I discovered a few really useful tools had been written for our codebase for the latest beta of Komodo Edit (v6) so I switched to that.</p>
<p>The thing which made me try TextMate instead was actually that Komodo Edit 6 kept eating my CPU time for no real reason. After using it for a bit, even when I was doing nothing and there was no indication of background activity, it&#39;s CPU usage would sit at around 30% which over a while slowed my Mac right down and got it really hot (and loud). If I quit and restarted it would be fine again for a while but eventually would come back up.</p>
<p>This isn&#39;t all that surprising especially considering it is a beta version but it was annoying enough to make me consider alternatives again. Especially since TextMate is also favoured by other devs at my new place of work.</p>
<p>Actually I like it. It is less limited than I first thought and writing bundles is powerful and could allow me to reproduce many of the simpler features I miss from other editors. Full code completion isn&#39;t there but actually it does do basic PHP and same-file completion which covers a relatively large part of my needs. And I really love the speed and OSXiness.</p>
<p>So the Jury&#39;s still out. I&#39;ll see how I get on.</p>
]]></description><link>https://banksco.de/p/plus-1-to-textmate.html</link><guid isPermaLink="true">https://banksco.de/p/plus-1-to-textmate.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Thu, 23 Sep 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Xeround: no to NoSQL]]></title><description><![CDATA[<p><strong>Just a quick note to point out an interesting developement in the &#39;distributed database&#39; field. <a href="http://www.xeround.com">Xeround</a> are developing a MySQL storage engine that has all the elasticity, redundancy and scalability of some of the popular NoSQL solutions with a 100% compatible MySQL interface.</strong></p>
<p>This could be really interesting if it works as well as advertised since any MySQL app can migrate to it with <em>no code change</em>.</p>
<p>I do feel though that their <a href="http://www.xeround.com/developers/white-paper.html">technical whitepaper</a> reads more like a marketing brochure than an academic discussion of the technology - there are no mentions of any downsides or tradeoffs in the design. Specifically, there is no mention of how much slower distributed joins and aggregation are than normal MySQL. just allusions to &#39;low latency&#39;.</p>
<p>Essentially they have written a front end that does all the complex stuff you application would have to do with another NoSQL solution and then put a MySQL interface on it. If it works and really is fast then it is a very compelling solution. In the absence of benchmarks or real-world discussions though, I&#39;m somewhat sceptical about whether this will really work well for complex queries on actually big data sets. I unfortunately don&#39;t have time (or data) to try it for myself but I will keep an eye out...</p>
]]></description><link>https://banksco.de/p/xeround-no-to-nosql.html</link><guid isPermaLink="true">https://banksco.de/p/xeround-no-to-nosql.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Wed, 15 Sep 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Why NoSQL is great and geek fights aren't]]></title><description><![CDATA[<p><strong>I&#39;ve been reading a lot about the recent stream of RDBMs alternatives that are getting a lot of attention at the moment. I find the subject fascinating and many of the solutions and technologies coming out make me want to go and summon hundreds of EC2 instances just to distribute some random data over.</strong></p>
<p>My 30 second NoSQL overview: relational databases can become unwieldy once you need to scale beyond the capacity of a single server. Some applications can easily take advantage of multiple read slaves but with enough write traffic things need to get more exotic. Enter <a href="http://en.wikipedia.org/wiki/Shard_\(database_architecture\">sharding</a>). If you want to read more about sharding, go ahead. Suffice it to say that once your data is split over separate physical machines, a substantial portion of what makes relational databases and SQL great goes out the window. No more joins, aggregate queries etc. </p>
<p>Given that the relational part is now severely impaired, people like Google and Amazon have come up with massively distributed systems that are effectively just glorified key-value stores or hash tables. They purposely don&#39;t support these more exotic relational features but they can handle petabytes of data and millions of users. The <a href="http://labs.google.com/papers/bigtable.html">Google BigTable</a> and <a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html">Amazon Dynamo</a> papers are a great read.</p>
<p>NoSQL encompasses these sorts of solutions as well as document-oriented databases like <a href="http://www.mongodb.org/">MongoDB</a> and <a href="http://couchdb.apache.org/">CouchDB</a> and stricter KV stores like <a href="http://code.google.com/p/redis/">Reddis</a> or <a href="http://project-voldemort.com/">Project Voldemort</a>.</p>
<h3 id="so-is-sql-dead-">So is SQL dead?</h3>
<p>As with so many things in our industry, NoSQL has caused a lot of hype and a lot of unnecessary angst. I was prompted to write this by a <a href="http://www.readwriteweb.com/cloud/2010/09/an-amusing-take-mysql-diehard.php">recent article on readwriteweb</a> which links to a video someone has made. The video itself is somewhat amusing and makes some good points although could have done so much more succinctly and with less profanity in my opinion.</p>
<p>It would be great to see a little more sensible discussion about real-world use cases for new technology and much fewer turf wars. NoSQL is really interesting and, though it&#39;s tempting to assume new things are a silver bullet for all the current problems in a domain, we all know this is not the reality. As engineers we should take a great interest in new technology but ultimately we should pick the right tools for the job. For now SQL is probably the best overall tool for the majority of web applications.</p>
<p>NoSQL solutions can solve some interesting problems however these will probably be limited to big-data, big-traffic sites. 99.99% of web apps written are never going to get near to having those sorts of problems and abandoning a mature, proven technology like SQL should not be taken lightly.</p>
<p>So I&#39;m going to continue to enjoy learning about new ways to do things, use them where they actually help, and steer clear of pointless time-wasting arguments.</p>
]]></description><link>https://banksco.de/p/why-nosql-is-great-and-geek-fights-arent.html</link><guid isPermaLink="true">https://banksco.de/p/why-nosql-is-great-and-geek-fights-arent.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 12 Sep 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[PHP Gotcha: are MD5 hashes numeric?]]></title><description><![CDATA[<p><strong>A bizarre bug just came up at work: a query in a cron script failed last night for no apparent reason even though thousands of queries are run by the same bit of code every day. The reason: an MD5 hash being incorrectly identified as a number in exponential form.</strong></p>
<p>Firstly I guess I should point out that yes MD5 hashes <em>are</em> numeric, however in PHP <code>md5()</code> returns a string containing the hex digest. For this reason MD5 hashes are generally considered and used as strings in PHP.</p>
<p>We have a Database API at work that provides automatic escaping of values based on their type. It uses PHPs <code>is_numeric()</code> to determine if the value should be left unquoted as an integer or float.</p>
<p>One thing that isn&#39;t likely to come up much (but typically just did) is that <code>is_numeric()</code> also recognises numbers in exponential form <code>1234e34</code>. We had an issue where we were inserting an MD5 hash (a string) into a varchar field. But got an error from MySQL:</p>
<pre><code>Illegal double &#39;937e3019763158166689073439699767&#39; value found during parsing</code></pre>
<p>I took a look at this for a bit and then realised that the value was unquoted and contained only digits and &#39;e&#39;.</p>
<p>We&#39;ve put in a little more logic now that assumes that any string of exactly 32 chars and containing only hex digits (hint: <code>ctype_xdigit()</code>) is treated as a string!</p>
]]></description><link>https://banksco.de/p/php-gotcha-are-md5-hashes-numeric.html</link><guid isPermaLink="true">https://banksco.de/p/php-gotcha-are-md5-hashes-numeric.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 07 Sep 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[To PHP or not to PHP?]]></title><description><![CDATA[<p><strong>I&#39;ve recently run up against the limitations of PHP&#39;s OO features in many different projects. While there are some potential solutions, I&#39;m in two minds about whether they are a good idea or not.</strong></p>
<p>For example, languages like Ruby and JavaScript allow &#39;Monkey Patching&#39; or modifying classes/object&#39;s methods at run time. While some complain that this can cause terrible code and bugs that are very hard to track down, it allows things like behaviors (i.e. mixins for multiple inheritance) which can be a very powerful way of keeping code modular. </p>
<p>Also, <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming">AOP</a> is a powerful tool for reducing code coupling and increasing code reuse. In JS or Ruby you could implement this easily by altering methods at run-time, in Java you can do it by altering methods at compile-time. In PHP you&#39;re stuck unless you add an additional &#39;compile&#39; step into your workflow, negating most of the benefits of using an interpreted language.</p>
<p>In PHP, the closest we get (natively) is to use magic methods like <code>__call()</code> to intercept object method calls and do something else instead. There are two major problems with this</p>
<ol>
<li><p>You have to fudge the scope about - there is no non-hacky way to add a method to a class from outside it and be able to use <code>$this</code> and other object properties as expected.</p>
</li>
<li><p><code>__call()</code> is very slow even compared to standard PHP function calls. This <em>can</em> be a real issue if you are using it extensively and may have thousands of calls in a single page load.</p>
</li>
<li><p>It&#39;s not native - you end up having to add code to all your objects, or artificially alter the inheritance tree or wrap all your objects in proxy object or similar to get this to work.</p>
</li>
</ol>
<h3 id="-enter-runkit-">(Enter Runkit)</h3>
<p><a href="http://pecl.php.net/package/runkit">Runkit</a> is a PECL extension that adds a few interesting methods to PHP that allow methods to be added/removed/copied between objects dynamically at runtime. The solutions to all the problems above? I&#39;m not so sure.</p>
<p>The (new) problems:</p>
<ol>
<li><p>It&#39;s non-standard. Goodbye to code portability. This will never be maintstream and so neither will all the work you put into classes/libraries.</p>
</li>
<li><p>It&#39;s experimental. It seems not enough interest has been shown in runkit and so, despite it being around for a while (at least 5 years!), it is still not recommended for production applications.</p>
</li>
<li><p>I can find no information about performance (and haven&#39;t had time to benchmark myself since it would mean recompiling PHP on my machine). I&#39;d be very surprised if it didn&#39;t reduce the effectiveness of op-code caching substantially.</p>
</li>
</ol>
<p>Pretty major downsides, but my question goes beyond this. I&#39;m still really torn about whether it is even right to <em>want</em> this in PHP. If I really want ruby-like syntax and mixins, why don&#39;t I just write in Ruby?</p>
<p>Every language has it&#39;s strengths and weaknesses, I wonder if spending a lot of time and effort trying to emulate constructs possible in other languages is just bad PHP programming. Is it a flaw in PHP that it can&#39;t support neat mixins (without hacks or ugly code)? I&#39;m not sure.</p>
<p>I&#39;ve been interested in the decision to drop behavior support in <a href="http://www.doctrine-project.org">Doctrine 2</a> because it was too much of a hack and caused nightmare bugs. It was one of the features I most sought to emulate in other similar projects but ran into many of the same problems as the Doctrine team.</p>
<p>On the one hand, I&#39;d really like to able to neatly and efficiently solve problems like multiple inheritance and providing &#39;magic&#39; interfaces to ORM objects without restricting class inheritance etc but on the other hand, if it feels to much like a hack I end up feeling like I&#39;m just using the wrong tools.</p>
<p>If you read this and have any thoughts, I&#39;d love to hear what you think.</p>
]]></description><link>https://banksco.de/p/to-php-or-not-to-php.html</link><guid isPermaLink="true">https://banksco.de/p/to-php-or-not-to-php.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 30 Aug 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Managing iPhone SDK versions and targeting]]></title><description><![CDATA[<p><strong>There are many subtleties when deploying apps with the iPhone SDK. One I have spent much time fiddling with in the past and actually got to the bottom of today is the difference between <em>Base SDK</em> and <em>Deployment Target</em>.</strong></p>
<p>I spent an hour or so today jumping through the familiar hoops of getting some updates into our iPhone app at work. The latest updates involve dealing with background state transitions which requires accessing new API methods added in iOS 4.</p>
<p>The SDK docs do describe well how to ensure that API methods exist before calling version specific methods (using respondsToSelector).</p>
<p>The problem came when compiling for distribution. We ended up with an error saying:</p>
<pre><code>undeclared UIApplicationWillEnterForegroundNotification</code></pre>
<p>This was because, in an attempt to make the application as widely usable as possible I&#39;d set the <em>Base SDK</em> setting to iPhone 3.</p>
<p>Clearly this means you can&#39;t use iOS 4 specific API calls. The trick is to set the <em>Base SDK</em> to the <em>latest</em> version and then set the <em>iPhone OS Deployment Target</em> option to be the lowest version you wish to support. This way you can (conditionally) use all the latest API calls. </p>
<p>In this configuration, newer APIs are weakly linked which means that, provided you check APIs exist before accessing them as mentioned above, you app will still run on older OS versions with no compile or runtime errors.</p>
<p>With hindsight it seems obvious but it was one of those things that took a bit of effort to grasp.</p>
]]></description><link>https://banksco.de/p/managing-iphone-sdk-versions-and-targeting.html</link><guid isPermaLink="true">https://banksco.de/p/managing-iphone-sdk-versions-and-targeting.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Fri, 20 Aug 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[The Era of Komodo Edit]]></title><description><![CDATA[<p>I&#39;m reconfiguring a whole bunch of things on my machine. In the process, I couldn&#39;t bear to install Aptana 1.5 again. I&#39;ve been using it for a year or so since ZDE went over to Eclipse and became even more horrible to use.</p>
<p>Aptana is also Eclipse based which doesn&#39;t fill me with Joy but 1.5 did have excellent PHP support. My love affair with it was not long lived though as the 2.0 release last year completely decimated everything that had made me move from ZDE by dropping Aptana&#39;s PHP plugin for PDT. I&#39;ve also recently had a complete nightmare helping colleagues getting Aptana 1.5 to work on Ubuntu.</p>
<p>I&#39;d really love something lighter. TextMate is sleek, simple and beautiful but just doesn&#39;t cut it for me when it comes to code completion - I&#39;ve come to rely on that for bigger projects and it&#39;s just too hard to go back! Netbeans is actually surprisingly good now although it is Java and getting close to being Eclipse-like.</p>
<p>In the end, I&#39;ve been pretty impressed with <a href="http://www.activestate.com/komodo-edit">Komodo Edit</a>. <del>Still Java I guess but</del> [Not Java so] it feels a lot lighter than Eclipse, supports pretty much all the main features I use constantly in Aptana and generally seems good.</p>
<p>I&#39;ll stick it out for a bit and see how it holds up once I start doing serious work.</p>
]]></description><link>https://banksco.de/p/the-era-of-komodo-edit.html</link><guid isPermaLink="true">https://banksco.de/p/the-era-of-komodo-edit.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sat, 14 Aug 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[Getting Social]]></title><description><![CDATA[<p>I&#39;ve enabled comments on the blog using <a href="http://disqus.com">DISQUS</a>. Sure I could have written my own into my lovely little rails app but that would be a lot of effort once moderation, spam control, user signup, OpenID integration etc. are included.</p>
<p>DISQUS actually seems to be quite a neat solution for now and will hopefully make this content slightly more interesting once I start getting a bit of traffic through.</p>
<p>I still have a couple of things to add to the blog (including more content) before I make more of an effort to get spidered and promoted at large on the web.</p>
]]></description><link>https://banksco.de/p/getting-social.html</link><guid isPermaLink="true">https://banksco.de/p/getting-social.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Tue, 10 Aug 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[JS on the server?]]></title><description><![CDATA[<p>Server-side javascript is something that I have been dimly aware of for a while now. At first, I thought it was yet another pointless attempt to use technology in ways it wasn&#39;t designed to be used, but recently it&#39;s been starting to make a little more sense to me.</p>
<p>I won&#39;t go into too much detail here because <a href="http://www.readwriteweb.com">ReadWriteWeb</a> have <a href="http://www.readwriteweb.com/archives/server-side_javascript_back_with_a_vengeance.php">done it better</a>. Also of interest, Felix Geisendörfer (a former CakePHP contributor) also <a href="http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb">explains why he&#39;s more interested in Node.js now</a>.</p>
<p>The most interesting point for me is this: JS is currently getting a lot of attention (read millions of dollars) from many of the biggest players in the industry: Google, Apple, Mozilla and Microsoft. That means it is being optimized and getting faster at a rate that other server side languages can only dream of.</p>
<p>I&#39;ve heard (but not verified) that some bits of Node.js&#39; C++ runtime have actually been re-written in JS because there was no performance difference!</p>
<p>Now I love JS as a language, it is getting seriously quick, and we are getting closer to having a stable and relatively mature stack to write applications with. It probably isn&#39;t going to power the next twitter but this is certainly worth looking into.</p>
]]></description><link>https://banksco.de/p/js-on-the-server.html</link><guid isPermaLink="true">https://banksco.de/p/js-on-the-server.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 09 Aug 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[When not to use arrays in PHP]]></title><description><![CDATA[<p><strong>Arrays in PHP are actually pretty inefficient at storing lots of small bits of data.</strong></p>
<p>I think I read that a single integer in an array uses 58 bytes of memory. Now that is not worth thinking about in most PHP applications, but it can matter when your arrays get big.</p>
<p>At work, I&#39;ve recently been working on a system for highly customisable targeting in email newsletters. Part of the challenge here is writing the newsletter sender capable of sending 400,000+ emails with each one potentially targeted at the specific user efficiently.</p>
<p>For speed, we ended up pre-calculating which bits of content got rendered for each user to avoid the query overhead in the sending loop. This required storing a two-dimensional array, indexed by user ID, with an array of content IDs applicable to each user. It looked something like this:</p>
<pre><code>::php::
<span class="keyword">array</span>(
    <span class="number">1</span> => <span class="keyword">array</span>(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>),
    <span class="number">2</span> => <span class="keyword">array</span>(<span class="number">2</span>, <span class="number">4</span>, <span class="number">3</span>, <span class="number">5</span>),
    ...
);</code></pre>
<p>But with around 400,000 elements. I was amazed that this array alone took up over 400MB of memory!</p>
<p>I did some benchmarks and found some quite surprising things.</p>
<p>If I changed the array so each user had a comma separated string instead of an array, it shrank the memory requirements down by around 75%.</p>
<p>I suspected though that I would pay for this saving in execution speed - surely it is much slower to have to explode each value manipulate the array and implode again than just direct access right? </p>
<p>Actually, no! I can only guess as to why that might be - less RAM to read/write/seek perhaps? It is actually over 60% quicker to use strings in this case!</p>
<p>You probably don&#39;t quite believe me so <a href="http://gist.github.com/505177">here is a little script</a> to illustrate the point. Feel free to run it yourself.</p>
<p>And the result:</p>
<pre><code>Memory <span class="keyword">for</span> <span class="number">2</span>D:        <span class="number">107.81</span>MB
Memory strings:        <span class="number">23.89</span>MB
Time <span class="keyword">for</span> <span class="number">2</span>D:        <span class="number">6.47</span> seconds
Time strings:        <span class="number">2.32</span> seconds</code></pre>
]]></description><link>https://banksco.de/p/when-not-to-use-arrays-in-php.html</link><guid isPermaLink="true">https://banksco.de/p/when-not-to-use-arrays-in-php.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Mon, 02 Aug 2010 00:00:00 GMT</pubDate></item><item><title><![CDATA[On the bandwagon]]></title><description><![CDATA[<p><strong>I&#39;m a PHP developer by profession but this blog is a bit of a departure for me - it&#39;s a <a href="http://rubyonrails.org/">Ruby on Rails</a> app.</strong></p>
<p>I could have used pretty much any open source blog package out there, but I wanted to have a go at producing something real that worked with rails. There are also a few features I didn&#39;t find elsewhere (mostly formatting related).</p>
<p>My verdict: Ruby is a fantastic language. Rails is a great framework, but there is a little too much magic and opinion in it for my taste. I like to understand exactly what is going on at all levels in my apps but rails makes that incredibly hard because of all the monkey patching and the sheer size of the stack.</p>
<p>That&#39;s not really much of a criticism though and I think at least some of that will be much better in rails 3 having taken onboard the merb philosophy of decoupling core components.</p>
<p>I&#39;ll certainly keep working with Ruby and probably rails - there is something so elegant about the language that it makes going back to PHP a little disappointing. Who knows, one day I might be completely converted.</p>
<p>Expect me to post my web-related discoveries and opinions here in the future.</p>
]]></description><link>https://banksco.de/p/on-the-bandwagon.html</link><guid isPermaLink="true">https://banksco.de/p/on-the-bandwagon.html</guid><dc:creator><![CDATA[Paul Banks]]></dc:creator><pubDate>Sun, 01 Aug 2010 00:00:00 GMT</pubDate></item></channel></rss>