Tuesday, 9 August 2011
My Blog Has Moved
http://goodcoffeegoodcode.wordpress.com
All new articles will be will be posted there.
Monday, 13 June 2011
Windows Azure Usage Gotcha for BizSpark Members
Be warned: THESE BENEFITS ARE NOT INTERCHANGEABLE!
What I mean is, if you're on Ultimate you can use 1 Small compute for 1500 hours or 2 Small computes for 750 hours each etc. What you cannot do is use an Extra Small compute for 1500 hours or 1 Medium compute for 750 hours. The benefit is SPECIFIC to the exact type of compute size.
We got slightly stung this month, but we've learnt our lesson. Learn from our mistake, not your own!
Friday, 13 May 2011
Inside PivotViewer v2. Episode 1, Legacy Support
In this episode we'll take a deep-dive into PivotViewer v2 and look at what legacy support is available to all those that have created static, server-side cxml collections. We'll also see some great dynamic benefits that can be applied to these existing collections with v2.
Please leave comments, feedback and any suggestions for things you'd like to see in this series.
Inside PivotViewer v2. Episode 1, Legacy Support from Chris Arnold on Vimeo.
Here are the links to the references I make at the end of the video:
Tony Champion (.Net Rocker)
http://tonychampion.net
Xpert360
http://xpert360.com
Kingsley Uyi Idehen
http://twitter.com/kidehen
Friday, 15 April 2011
Making 3rd-party API Libraries more Robust
"Network requests are flaky"
Every time you make a call "across the wire" you've got to provision for errors. Everything from gateway timeouts, server faults right down to your toddler pulling the lan cable out. If it can happen, at some point, it probably will.
Most solutions are very ad-hoc and resemble this:
using (var wc = new WebClient()) { for (int i = 0; i < 5; i++) { try { wc.DownloadFile(source, target); break; } catch (Exception e) { Thread.Wait(200); } } }
This approach is fine if you only have a couple of calls in your application. In today's hyper-connected world, however, it's more likely that you'll be making lots of these requests with wildly differing signatures. Very quickly your code will become unreadable as you battle to trap all the possible exceptions and manage the retries. What we need is a pattern for easily applying this retry mechanism to any call whilst keeping our client code clean.
Real-world Example
There are a myriad of 3rd party libraries that allow you to target platform APIs e.g. Twitter, Facebook etc. At PhotoPivot.com we rely heavily on Sam and Tim's great FlickrNet library to perform an enormous number of calls to Flickr. Here's a greatly simplified bit of production code from our server-side application:public class FlickrPhotoDataDownloadService { private readonly IFlickr _flickr; public FlickrPhotoDataDownloadService(IFlickr flickr) { _flickr = flickr; } public void GetPhotoDataForUser(string userId) { var photoCollection = _flickr.PhotosGetAllNotInSet(); foreach (var photo in photoCollection) { var photoInfo = _flickr.PhotosGetInfo(photo.PhotoId); var exifs = _flickr.PhotosGetExif(photo.PhotoId); // Do something with the data... } } }Potentially, any of the calls to the IFlickr interface can result in a sporadic network error. This is a serious pain if it happens inside the foreach loop when the routine is 90% through a list of 10,000 photos. If we implemented the ad-hoc solution at the start of this post the GetPhotoDataForUser method would become very untidy and a developer's ability to read it would lessen. So, let's look at some of the related classes. Below you can see the interface that the service uses to describe its requirements. We then used the Adapter Pattern to "bring in" the interface to the main FlickrNet class.
public interface IFlickr { PhotoCollection PhotosGetAllNotInSet(); PhotoInfo PhotosGetInfo(photo.PhotoId); ExifTagCollection PhotosGetExif(photo.PhotoId); } public class FlickrEx : FlickrNet.Flickr, IFlickr { }The client code that uses the service looks like this:
var flickr = new FlickrEx(); var service = new FlickrPhotoDataDownloadService(flickr); service.GetPhotoDataForUser(userId);So, how do we encapsulate all the methods, or at least the methods we need, in the main Flickr class? We can't rely on just extending the class as it, or its methods, might be sealed. Let's start by creating a class that can keep track on failed attempts and whether a retry is possible.
using System; using System.Threading; internal abstract class RetryableBase { private readonly int _maxAttempts; private readonly TimeSpan _delay; private int _attempts; internal RetryableBase(int maxAttempts, TimeSpan delay) { _maxAttempts = maxAttempts; _delay = delay; } protected bool CanRetry(Exception e) { _attempts++; Thread.Sleep(_delay); return (_attempts < _maxAttempts); } }Next we'll extend this and, by leveraging C#'s Func<> capabilities, create a couple of classes that can wrap a function in some standardised retry routines.
using System; internal class RetryableFunc<TResult> : RetryableBase { private readonly Func<TResult> _func; public RetryableFunc(Func<TResult> func, int maxAttempts, TimeSpan delay) : base(maxAttempts, delay) { _func = func; } public TResult Call() { TResult result = default(TResult); bool success = false; while (!success) { try { result = _func(); success = true; } catch (Exception e) { if (!CanRetry(e)) throw; } } return result; } } internal class RetryableFunc<T, TResult> : RetryableBase { private readonly Func<T, TResult> _func; public RetryableFunc(Func<T, TResult> func, int maxAttempts, TimeSpan delay) : base(maxAttempts, delay) { _func = func; } public TResult Call(T t) { TResult result = default(TResult); bool success = false; while (!success) { try { result = _func(t); success = true; } catch (Exception e) { if (!CanRetry(e)) throw; } } return result; } }
You will, unfortunately, need to create a new class for each signature function call needed. For instance, the one's above will work for calls that match Func<TResult> or Func<T, TResult> only. Func<T1, T2, TResult> will need another class. Functions that don't return anything are Actions<>. You'll need separate classes for these also. Once done, though, the ROI will be huge.
We now have the capability to make calls robust but how do we 'invisibly' add this to someone else's class? We'll use the Decorator Pattern to create a new class that "is a" IFlickr but also "has a" IFlickr. By initially abstracting our service's needs to an interface we have enabled ourselves to do this very easily.public class RetryableFlickrEx : IFlickr { private readonly IFlickr _flickr; public RetryableFlickrEx(IFlickr flickr) { _flickr = flickr; } public PhotoCollection PhotosGetAllNotInSet() { var retry = new RetryableFunc<PhotoCollection>(_flickr.PhotosGetAllNotInSet); return retry.Call(); } public PhotoInfo PhotosGetInfo(string photoId) { var retry = new RetryableFunc<string, PhotoInfo>(_flickr.PhotosGetInfo); return retry.Call(photoId); } public ExifTagCollection PhotosGetExif(string photoId) { var retry = new RetryableFunc<string, ExifTagCollection>(_flickr.PhotosGetExif); return retry.Call(photoId); } }Now that we have all our pieces in place the ONLY change we need to make to our entire application is one line in the client. The service still gets the IFlickr it requires and simply doesn't care about the implementation:
var flickrBase = new FlickrEx(); // New line: Use the Decorator Pattern to extend functionality at runtime... var flickr = new RetryableFlickrEx(flickrBase); var service = new FlickrPhotoDataDownloadService(flickr); service.GetPhotoDataForUser(userId);
Please leave comments if you can see a way of enhancing this idea.
Friday, 14 January 2011
The Biggest Challenge Faced by Technical Founders
For me the biggest challenge I face as a technical founder is programming. To be more specific: stopping programming. For years I have measured my progress by ticking off features delivered, bugs fixed or user stories completed. It's a well understood system and it's easy to track, but that's not what I should be doing. My job as a founder is to find a repeatable business model that will make money, and the only route to achieving this is via validated learning.
Here's an example:
Earlier this week I was building some new server functionality for @photoPivot. I found myself working through the options of how and where to host a service and what type of communications medium was going to be the absolute best for this. Eventually I realised "Who cares? It doesn't matter!". All I needed to do was test my idea in the quickest way possible. Just stick it in a console app and off we go (sneakernet style!).
Now, this doesn't mean that you should write bad, unmanageable code. You can still test your ideas in a way that isn't going to back you into a nasty corner in the future. Just be a little pragmatic. Do enough to get it working, then step away. I know how difficult it is to know that you could make something better - it's very hard to resist being the perfect craftsman. Once you've proven your idea then you can make it elegant; but why waste your time polishing something that you don't know people want?
For technical founders, programming is chicken soup. On difficult days we find comfort there and, by the evening, we've convinced ourselves that, yes, we made good progress today. Don't be fooled by these false metrics. Test your ideas quickly and build your company.