lns is an old-school Perl utility that unbreaks the command order of ln -s.
If you’ve got a file called a.txt and you want to make a symbolic link b.txt, you can type lns a.txt b.txt or lns b.txt a.txt and it’ll do the intelligent thing. This is really handy. It won’t overwrite anything. It won’t break shit. It’s in my ~/bin/ forever now.
I think Jeremy is conflating declarative with fault tolerant here. HTML and CSS are declarative and fault tolerant. SQL is declarative and decidedly fault intolerant (and quite hard to master to boot). PHP’s type system is a lot more permissive and tolerant (“weak”, one might say) than a language like Python. The former is great for newbies and non-programmers, because adding 1 + "1" (that is, adding a string and an integer together) will give you 2, or at least something that when printed to screen looks vaguely like a two, though under the covers it may be Cthulhu.1 And the behaviour of something like Python is great for jaded old gits like me who don’t want the system to magically convert strings into integers but to blow up as quickly as possible so that it can be fixed before all this nastiness gets stitched together with the rest of the code and causes some real major bugs. The same principle applies on a grander scale with stricter type systems like Java or the broad ML family (including things like Scala, F#, Haskell etc.).
Again, depends on the language. PHP is pretty permissive. If you make a very minor mistake, you can often just carry on and keep going. If you are feeling particularly careless about your errors, you prefix your expression with an @ sign and then security people get to laugh at you. I hesitate to say this was “designed” but it was at the very least chosen as a behaviour in PHP.
This error handling model, this permissiveness of web technologies, isn’t a side-effect of being declarative. It’s actually a property of them being designed for the web, of human choice by the creators. There is a cost to this. It has been incredibly hard for us to secure the web. Permissive error handling can and has enabled a whole class of security vulnerabilities.
If Postel’s Law gives you the ability to use border-radius in your CSS or aside in your HTML and some terrible old version of Internet Explorer happily ignoring it without vomiting XML warnings all across your screen, then Postel’s Law also comes with the cost of having to worry about downgrade attacks. We collectively left SSLv2 running long after it should have been dead and we got DROWN. We did the same with SSLv3 and we got POODLE. These are examples of ungraceful degradation and the sad cost is your server being vulnerable to being pwned.2
With the last few attacks on SSL/TLS, it wasn’t just nasty old versions of Internet Explorer on Windows XP getting shut out of the web, it was non-browser apps that talked to HTTPS-based APIs. The Logjam attack meant that a lot of people upgraded their servers to not serve DH keypairs that are below 1024-bit. For most current day browsers, this was not an issue. Apple, Mozilla, Google, Microsoft and others released patches for their current browsers. Java 6 didn’t get a patch for a very long time. If you had a Java desktop app that consumed an HTTPS-based RESTful API which had patched Logjam, that broke with no graceful degradation, and the general solution was to upgrade to a new version of Java. On OS X, Java used to be distributed by Apple, albeit as something of a reluctant afterthought. Upgrading every desktop Java user on OS X was a bit of a faff. (My particular Java Logjam issue was with… JOSM, the Java OpenStreetMap editor.)
Postel’s Law giveth and it taketh away. One could give this kind of rather pedantic counterexample to Jeremy’s account of Postel’s Law and then conclude hastily “given how badly the web is at solving these security problems, the grass on the native apps side of the fence might just be a little bit greener and yummier”. Oh dear. Just you wait. When every app on a platform is basically reimplementing a site-specific client, you might actually get more fragility. Consider our recent vulnerabilities with SSL/TLS. After something like Logjam, the bat signal went out: fix your servers, fix your clients. On the server side, generally it meant changing a config file for Apache or Nginx in a fairly trivial way and then restarting the web server process. On the client side, it meant downloading a patch for Chrome or Firefox or Safari or whatever. That may have just been rolled into the general system update (Safari) or rolled into the release cycle (Chrome) without the end user even being aware of it. The long tail3 of slightly oddball stuff like Java desktop apps, which tends to affect enterprise users, assorted weirdos like me, and niche use cases, took a bit longer to fix.
If every (client-server) app4 that could be in a browser, in the case of a security fail, fixing all those apps would be as simple as fixing the browser (and the server, but that’s a separate issue). If everything were a native app, you have to hope they are all using the system-level implementations of things like HTTP, TLS and JSON parsing, otherwise you have a hell of a job keeping them secure after vulnerabilities. We already see things going on in native-app-land (Napland?) that would cause a browser to throw a big stonking error: user data being sent in cleartext rather than over TLS being more common than I care to think about. But the native app won’t scream and shout and say “this is a bad, very wrong, no good idea, stop it unless you really really really want to”, because the UI was developed by the person who created the security issue to start with.
The downside to Postel’s Law5 is sometimes the graceful degradation is pretty damn graceless. Sadly, the least graceful degradation is often security-related. The web might still be better at mitigating those than all but the most attentive native app developers, or not. Browser manufacturers may be better at enforcing security policies retroactively than app stores, or they might not. We shall have to wait and see.
Sausage typing: if it looks like a sausage, and tastes like a sausage, try not to think about what it really is. ↩
At risk of giving technical backing to rising reactionary movements, perhaps the modern day variation of Postel’s Law might be: “Be conservative in what you send, and be liberal in what you accept, to the degree that you can avoid catastrophic security failures.” ↩
Wow, it’s been a long time since we talked about them… ↩
Let’s leave aside the semantics of what is or isn’t an app. Incidentally, I was in a pub the other day and saw a few minutes of a football game. There was a big advert during the game from a major UK retail brand that said “DOWNLOAD THE [brand name] APP”. Why? I don’t know. We are back at the ghastly “VISIT OUR WEBSITE, WE WON’T TELL YOU WHY” stage with native mobile apps. I’m waiting for a soft drink brand to exhort me to download their app for no reason on the side of a bottle. ↩
I claim no originality in this observation. See here and here. Interestingly, if you take a look at RFC 760, where Postel’s Law is originally described, it has a rather less soundbitey remark just before it:
The implementation of a protocol must be robust. Each implementation must expect to interoperate with others created by different individuals. While the goal of this specification is to be explicit about the protocol there is the possibility of differing interpretations. In general, an implementation should be conservative in its sending behavior, and liberal in its receiving behavior. That is, it should be careful to send well-formed datagrams, but should accept any datagram that it can interpret (e.g., not object to technical errors where the meaning is still clear).
TIL: Vagrant doesn’t do any kind of error recovery when a VM (.box) download fails/stalls. This gets boring the third or fourth time it happens.
If you happen to be using a sporadic or error-prone Internet connection (and if you are using a London DSL connection, that definitely counts) you can get around this by manually downloading the box file (using wget, say) and then using vagrant box add boxname ~/Downloads/name_of_vm.box (see this StackOverflow answer for details of the manual box adding process). This may also be of use if you are behind particularly fiddly or developer-unfriendly corporate firewalls.
Of course, in an ideal world, we’d have languages that are sensible enough that you don’t need to download a Linux distribution for each project you work on in said language.
There was an old lady who swallowed a fly. No, no, hold it, she didn’t swallow a spider or a bird or a dog. Firstly, that’s stupid and irresponsible and a form of animal cruelty. Plus, we’re in the twenty-first century. We’ve got technology and cyber and stuff.
She got a programmable nanobot off some darknet knockoff of Alibaba that sells experimental biohacking gear and put it in a capsule. She swallowed the capsule. Now, of course, she needed something to control the nanobot. So she wrote a server script. The nanobot would talk to the server which would do it all. Who needs spiders and birds to catch flies when you have REST?
She wrote the script in Python. Because Python is lovely. She tried Django and Flask and Pyramid too. This script would stop the flies. And of course, she needed a database. Only PostgreSQL. I mean, there ain’t no MongoDB controlling my programmable nanobots, thank you very much. And a message queue and a few other things.
But then where to run the server? She couldn’t host it at home because BT provided her Internet connection (and that’s less reliable than a pair of baked-bean cans and a piece of string), so she decided to host it in the Cloud. But, of course, you can’t just set up a server individually for this. What if it needed to scale? So she decided to do some DevOps®.
She wrote a script to spin up an AWS EC2 server. Then she wrote an Ansible playbook to deploy it and a monitrc to ensure the servers were up. Then she set up Capistrano to deploy the script to the server. Then she set up Sentry to catch any exceptions. Better tie that into PagerDuty so she could programatically modify the notifications for when monit and Sentry had something to tell her.
Then she discovered Docker. Then she ended up on Hacker News reading about Kubernetes and decided that the whole thing really needed a microservices architecture.
And the fly is still inside her. Because the server never got deployed and the scripts never got written because she went down the pub instead.
Perhaps she’ll die. Or she’ll just crank it out in PHP.
You may think that pi is a constant like 3.14159 (etc.), but that is because you learned mathematics in school. You learn a lot more once you enter the world of work.
As a software developer, you have to get used to the fact that pi is whatever management have decided it to be this week. For one project, pi might be 3.14159, but in other projects management may decide that pi is actually the integer 4, an API call to an old system that you need to use Java Remote Method Invocation to access, an XML document that is inside a Word file in an email account you don’t have access too, or it might be green, except on Thursday when it is furry and invisible. That’s what they sold the client, so that’s what it is.
You might think that if pi is being redefined, someone might file an issue about it or raise it with you in a meeting. No, they’ll mention it to you off-hand and indirectly, or they’ll put it on page 53 of a PowerPoint slide deck with a filename like CLIENT PRESENTATION DRAFT FINAL MAYBE? CHECK WITH CAROL (1).pptx that they CC to you, except the subject line says “Drinks on Friday” and the body is about the birthday party for Steve in accounting. Or, worse, they’ll upload it to Confluence, because it has to be useful for something. When you persist with your school-derived belief that pi is 3.14159 (or the value of java.lang.Math.PI and equivalent), you will be upbraided for not keeping up with the rapidly changing needs of a growing enterprise.
When you have learned to live with the fact that pi could be anything from one day to another, and once you have learned to listen patiently to the idiot telling you that pi is actually a Labrador puppy, suppressing your strong desire to grab him by the lapels and throw him down a ricin-laced lift shaft, you have progressed to the point where you can become a senior developer, a project manager or a consultant.
None of this means that pi is anything but 3.14159. It is a mathematical constant—your maths teacher is right. If you need to deal with the cognitive dissonance, step away from your computer, have a nice holiday—or a good gin and tonic, or dance your tits off in a nightclub or whatever hedonism gets you through life. Once you’ve coped with the dissonance, pretending pi and many other similar things aren’t constants makes dealing with companies much easier. Deadlines, requirements and functional specs are mostly make believe, so why can’t mathematical constants be fictional too?
Got a startup idea? That and some cash is all you need to get a fully functional app built for you by Gigster. Launching today, Gigster is a full-service development shop, rather than a marketplace where you have to manage the talent you find.
Oh, you mean like hundreds of other software development companies?
Just go to Gigster’s site, instant message with a sales engineer, tell them what you want built, and in 10 minutes you get a guaranteed quote for what it will cost and how long it will take.
10 minutes for a fully estimated project plan: that’s the biggest load of bilge I’ve ever heard.
Once you get your project back, Gigster will even maintain the code, and you can pay to add upgrades or new features.
You bet. Can you get anyone else to add upgrades or features? Or do they have any IP interest or right of first refusal? Those sort of questions are things a journalist might ask. But, oh, this is tech journalism.
And “maintain”. Bit more detail required.
Gigster fixes [management issues] by assigning a project manager to handle 100 percent of the management of your developers and be your sole point of contact. If the project is behind schedule, Gigster just assigns more developers to it or fires under-performing ones so it gets done on time.
Yeah, let’s ignore that the Mythical Man Month problem is a thing. Chuck more developers at the problem! “Beatings will continue until morale improves” is not a good management philosophy.
I’m sure that when your motivation is “get this shit out the door and get cash money now” and your clients are the sort of idiots who believe that they can hire coders like they do Uber cabs, you’ll produce reliable, well-tested and secure code. Right? I mean, no motivation to cut corners or anything.
The Gigsters come from companies like Google or Stripe that are looking for some extra projects
I’m sure they don’t have any no-compete or employer-owns-all-employee-produced-IP constraints in their contracts. Should work out just fine, right up until the client finds out that Google or Facebook owns a whole bunch of their IP.
10 minutes for full project costings? Mythical Man Month solved? This snake oil sure is deee-licious.
The idea that a guy who has built a whole bunch of Facebook apps is going to wave a magic wand and make software development cheap, predictable and with the kind of modularity and simplicity of booking a cab is such a laughable notion that the only people I can see believing it are tech journalists.
The naming convention for the majority of the people in my country is the paradigm case and nobody really does anything differently.
Names are all representable in US ASCII.
Unicode has properly solved the problem of language encoding.
Gender is immutable and fits cleanly into an enumerated list of two options.
A person’s legal name is how they identify to the world.
In general, openness is preferable to privacy.
Postcodes or ZIP codes are a good way to identify the location someone is in rather than an arbitrary string used for routing mail.
Everyone has a phone number and that phone numbers map 1-to-1 with people.
Objects of any size can be delivered to one’s home at any time.
Users give a fuck about security.
The tech industry is a meritocracy.
The tech industry is magically free of the prejudices of wider society.
Date and times are precise rather than vague.
We now have the one true data representation format: JSON.
Names can be easily categorised by gender.
Single sign-on services reduce complexity and ease user registration.
Users have a single sign-on for the single sign-on provider.
There is a meaningful distinction between an HTTP resource that has been called an API and one that serves HTML.
A web app is a distinct and meaningfully different animal than a web site.
CSS can be “object-oriented” or “functional” rather than a declarative rules language with a moderately complex inheritance model.
Unit tests catch all the problems that type checkers or static analysers would.
Writing unit tests is fun rather than a tiresome necessity.
Getting 100% test coverage ensures bug free software.
A methodology propagated primarily through expensive training courses will lead to the production of significantly better software.
Reformulating an understandable bug report (“the Froobnicator class throws an uncaught exception when the input contains UTF-8”) into a long-winded user story (“as a developer, I want to be able to run this software without seeing a 500 line stack trace when…”) will magically make it easier to plan work.
Having people wholly unfamiliar with a code base performing a quick review of code style and variable naming practices will ensure that bugs are caught.
Having team members unfamiliar with a particular facet of a code base come up with arbitrary estimates based on their hunches will solve all estimation woes.
“Rock stars” will fix all problems.
This cool new thing you saw on Hacker News will solve all your problems and can be put directly into production with no issues.
Security is simply a “layer” one need add to a piece of software.
GPS signals are usually reasonably accurate in most circumstances.
Only mobile devices need to provide geolocation support.
Anything that runs Windows, Mac OS X or non-Android flavours of Linux should not be thought of as a mobile device even if it is a teeny ultraportable laptop you carry around with you everywhere.
Mobile devices are used on the move with low bandwidth, even if they are being used by someone sitting on a sofa watching TV.
Syncing over the Internet rather than directly between two computers is the simplest and most efficient way to share data.
Distributed version control is made even more awesome by having GitHub as a single point of failure.
There are no technical fixes to societal problems.
Bitcoin is a technical fix for a societal problem.
apt-get install bitcoin-qt solves the usability problems of Bitcoin. (I’m not making this one up.)
People basically act rationally. (Don’t worry, the majority of economists believe this one too in spite of the existence of astrologers, homeopaths, theologians, the National Lottery, and psychics claiming to be able to talk to your dead pets.)
People update their software frequently.
If you have too many options in your software, you just hide them away in a “hamburger” menu and the problem is solved.
The social networks used by programmers in the Western world broadly reflect the social networks used by people around the world.
My behaviour-driven development tool’s fancy colourful feature list HTML output is ever looked at by non-technical management.
Being able to check code in at 30,000 feet using Git (or Mercurial etc.) is a feature I shall use, rather than taking advantage of all the free alcohol on the plane to make air travel slightly more tolerable.
Seconds since epoch is a sensible date format. (And there is a commonly agreed epoch.)
amatch looks like a ludicrously useful Ruby library for string matching. It implements a variety of algorithms including Levenshtein, Hamming, longest subsequence, longest substring and Jaro/Jaro-Winkler. Jaro-Winkler is particularly useful for short strings like business names because it weighs matches at the start of the string higher than at the end. Amatch also lets you set up options for matching including custom case sensitivity.
Here’s the difference illustrated:
Imagine you have your target string “McDonalds”, here are the results Amatch will give you using Levenshtein and Jaro-Winkler.
Note the difference in the second case.
HP Labs have a very interesting paper on company name matching. Their problem space is somewhat different from mine: they are trying to match company names solely based on strings and then clustering, while I have other factors I can use (namely, address, postcode and geographic location). A Jaro-Winkler similarity of >0.8 combined with a distance of under 50m is pretty much all I need to conclude a match.
Update: Jellyfish looks like a good Python library for the same job.
Take your mouse or trackpad or whatever, slide it over to that little wi-fi control in the corner of your screen, click and choose “Turn Wi-Fi Off” or whatever the equivalent is.
Now start a new project in your favourite programming language, framework, IDE or whatever. Can you do it?
This isn’t some macho “how much of an awesome hacker dude are you?” test. It’s not a test of you, it’s a test of your tools.
In most cases, the answer will be “not as easy as it should be”.
In an ideal world, I shouldn’t have to have Google at my beck and call in order to hack.
IDEs should make this easier. But the IDEs are not yet quite as simple as they could be. This evening, I’ve been working on a project to take two XML files, churn through them and basically merge the two (yeah, the XML community sold everyone a bill of goods on that; try RDF if you want a data model that trivially merges together). This shouldn’t be too difficult, right?
I have IntelliJ installed and I have Eclipse installed. I fire up Eclipse and realise that I don’t have the Scala module installed. I’m on a lousy 3G connection. I fire up IntelliJ, and everything has been buggered around with since I last used it for Scala development, and it doesn’t want to properly talk to Maven. Hate.
I could start a Java project, but I actually want to spend my time using the XML I’ve parsed rather than setting up an XML parser.
I eventually resort to just firing up MacVim and a Scala REPL and cmd-tabbing between the two. I’ll turn the results into a proper Maven project when I get home. But it’s still sort of a compromise.
I could have used Ruby and Nokogiri. The query I’m running on this XML is complex and slow enough as it is without wanting the penalty of Ruby’s shitty GC.
Ruby has lost a lot of the offline hackability that it once had. It used to be when you installed gems, RubyGems would generate RDocs. You could fire up gem serve and browse them in your browser offline.
And documentation is necessary in dynamic land. Consider something like this:
That seems pretty straightforward, right? Well, what does it take? A file name? A file handler object or reference? Something that satisfies some arbitrary and unspecified file-like interface (it has a readlines method, maybe)? A URL that it will proceed to load from the Internet? Damnit, documentation needed. If we were in a language like Java or Scala, we’d get documentation in the form of the type annotation:
But without that type annotation, we need documentation. So where is it?
On the Internet, obviously. You know, the Internet you can’t access reliably when you aren’t either at home or in the office. The Internet we rely on for all our cloud services but which stops working when we’re inside train tunnels.
If I run gem serve, almost all of the gems have no documentation. I bet Bundler has been set by default not to store documentation because the process of downloading or compiling the RDoc is “too slow” or something. Well, what’s more slow than that? Not being able to do any programming because you can’t actually figure out the calling syntax of a method you are trying to use.
Python gets a lot closer. The help() function in Python’s REPL is pretty damn compelling. If you are hacking away in the REPL, you don’t have to shift context to use the help function.
Is it too much to ask that I can read documentation for the standard libraries of the programming languages I’m using on my own computer when I’m connected to the Internet? Is it too much to ask that offline documentation should be a default?
One thing I’ve noticed recently with tech community events is the assumption that everyone who attends a hack day is doing so in order to start a business. Or that developers wish to be entrepreneurs or run startups.
Well, confession time: I don’t want to be an entrepreneur and I don’t want to run a startup.
I quite like being a programmer. I take a certain amount of intrinsic satisfaction from solving interesting problems. I like writing code for the same reason I like writing prose: it gives me an opportunity to be logical and expressive. I like paying attention to small details and fiddly problems. I like learning new things, and I take pleasure from using goodtools. I like the intellectual process of conceptual analysis; I like taking real world concepts that are rough, vague and hand-wavy and turning them into code.
The sort of things necessary to run a startup or be an entrepreneur are different. Broad, sweeping visions, that ever-present phrase “disruption”, a certain amount of pig-headed, extroverted arrogance (which isn’t necessarily a bad thing), the ability to be a good salesman. Sorry, that’s not me.
I don’t actually care about becoming ultra-rich. Sure, it’d be nice if I didn’t ever have to worry about money again, but there are other priorities in my life: family, friends, learning and intellectual fulfilment, romantic love and sex, health, good food, fun, contributing to shared community projects, fighting for a better society. (I’d suggest that at least some of those things are, for most non-sociopaths, as important or more important than money.) Money is a means to some of those goals. Obviously, money is useful to buy property to live in, and money lets you buy books and travel to places and buy nice gifts for boyfriends or partners and so on. But I’m not interested in becoming Bill Gates or Steve Jobs or Warren Buffett level rich. Once you reach a comfortable level of income, getting more money doesn’t actually make you happy. Respect and admiration are what makes people happy, and having large amounts of money only helps somewhat towards that goal.
This isn’t to knock entrepreneurs or entrepreneurship: in order to actually have projects to work on, we need people to actually come up with ideas and be crazy enough to try and go through with them. And it’s not even to say that programmers don’t want to become entrepreneurs. Many do. And good luck to them. But some of us don’t. We just like writing code and solving technical problems. Please don’t assume that we all want to be entrepreneurs.
Started 5 years ago, by Rob Pike and Ken Thompson.
Wanted to write a C replacement that’s a lot more modern.
Type-safe, type inference.
Memory safe, can’t C-style buffer overflows.
Garbage collected: allocate memory, but it collects it.
Strong concurrency primitives.
Has pointers but no pointer arithmetic. Pass-by-value.
Objects but no classes or inheritance. No class level methods (statics). Does have interfaces: specify that an object behaves a certain way.
Syntax design is designed around being really fast to compile and very easy for the compiler to optimise. “Seems ass-backwards”: bit of a tradeoff, but it doesn’t feel that big of a deal.
Unlike Java or C, there isn’t the compile overhead.
Statically-linked by default. Everything gets compiled in. Compiles to a zero-dependency binary. Don’t have to install a Go runtime. Nice for deployment.
Who should use it? Anyone who wants a C replacement. For the sort of things you want to write in C but don’t because it’s really difficult. Has been more popular with Ruby and Python programmers but want performance. (There’s an interesting post by Ken Thompson.)
Has package and import statements like Java.
HTTP server: net/http library has NodeJS style function binding.
Objects in Go are structs with defined functions. Functions with receivers (which come before the function name) are the equivalent of methods. You can define a method on an integer. (“Quite weird and unusual, can’t quite get my head around it.”)
Interfaces are like in Java: type keyword. (Tom sez: kind of like Scala’s structural typing.)
That I can push out new version of Ferocity while on the bus is something I rather like.
That I’ve finally removed the last trace of CoffeeScript bullshit from my application is also quite pleasing to me.
But it isn’t worth the cost. The cost is additional complexity. It means more stuff to learn, more stuff to keep in one’s head. And for what, so you can omit a few curly braces?
From now on, all Rails applications I build shall be --no-coffee. If I find the CoffeeScript gem in my Gemfile, I’m removing it.
The fact that CoffeeScript has become popular shows that people give far more of a shit about style over substance. That it is a default in Rails, well, I like Rails, but it can be too fucking hipster by half sometimes.
I had a strange revelation today while referring to the Wikipedia article ‘Central processing unit’. It is better than any technical literature I had to read as a precocious nerdy kid. And it’s a C-class article. (Wikipedia articles are rated on a scale: Stub, Start, C, B, GA, FA.)
I had a book on BASIC, a book on using the BBC Micro’s disk drive, and a book on C. No C compiler, mind, so that wasn’t that interesting. And no concept of what a compiler was. I did have a FORTH interpreter (although I didn’t know what an interpreter was either, it was just a programme on a tape), but no FORTH manual, so that was a bit pointless too.
Now, Wikipedia has better technical documentation that’s free-as-in-beer-and-freedom than anything I could have gotten my hands on before I first experimented on the web in 1995.
I’ve just started playing around with SMS. A lot of people use Twitter for this, but that means using the increasingly restrictive and complex Twitter API (read: OAuth, which is probably useful if you are writing a smartphone client, if you are writing an 20 line Python script, it’s a pain in the ass).
Clockwork SMS is amazingly simple: they provide libraries for PHP, C#, Ruby and Java, plus you can just use curl to send messages. Each message costs 5p and a new developer account comes with 10p of credit. You do have to pay VAT, so it is actually a bit more than 5p per message.
A lot of the SMS providers I’ve seen have promised “solutions” and lots of business speak, but Clockwork actually seem to do the damn job. If I was sending hundreds or thousands of SMSes, I’d probably be more willing to look in more detail, but for a few messages a week for job control notifications and stuff, 5p+VAT and a ridiculously simple API wins for me.