tag:quandyfactory.com,2013-5-20:/2013520 2013-5-20T12:00:00Z Quandy Factory Newsfeed - All Quandy Factory is the personal website of Ryan McGreal in Hamilton, Ontario, Canada.. http://quandyfactory.com/projects/74/solitaire 2013-05-08T12:00:00Z Solitaire <p>This is a version of solitaire I hacked up using HTML, CSS, javascript with <a href="http://jquery.com">jQuery</a>, <a href="http://jqueryui.com/">jQUery-UI</a> draggable, the <a href="https://github.com/DanielRapp/Noisy">Noisy</a> jQuery plugin, and only one small image. It's pretty nasty, but I wanted to get a feel for the draggable jquery-UI functionality. </p> <p><strong>Demo</strong>: <a href="http://quandyfactory.com/static/solitaire/solitaire.html">http://quandyfactory.com/static/solitaire/solitaire.html</a></p> <p><strong>Source</strong>: <a href="https://github.com/quandyfactory/Solitaire">https://github.com/quandyfactory/Solitaire</a></p> <p><strong>Update</strong>: You can play this game live, courtesy of PythonAnywhere:</p> <ul> <li><a href="https://www.pythonanywhere.com/gists/459573/rps.py/ipython2/">https://www.pythonanywhere.com/gists/459573/rps.py/ipython2/</a></li> </ul> Ryan McGreal 2 http://quandyfactory.com/blog/118/why_bloomberg_is_wrong_about_terrorism_response 2013-04-23T12:00:00Z Why Bloomberg is Wrong About Terrorism Response <p>There's quite a bit to like about New York City Mayor Mike Bloomberg, especially if you like walking, cycling and living in a lively city. But at the same time, Bloomberg's inclination to technocratic paternalism has a dark side that surfaces from time to time. </p> <p>In the wake of the Boston Marathon bombings, <a href="http://politicker.com/2013/04/bloomberg-says-post-boston-interpretation-of-the-constitution-will-have-to-change/">Bloomberg warned</a> that the country's "interpretation of the Constitution" will "have to change".</p> <blockquote> <p>"Look, we live in a very dangerous world. We know there are people who want to take away our freedoms. New Yorkers probably know that as much if not more than anybody else after the terrible tragedy of 9/11," he said.</p> <p>"We have to understand that in the world going forward, we're going to have more cameras and that kind of stuff. That's good in some sense, but it's different from what we are used to," he said.</p> </blockquote> <p>There's a glaring problem with Bloomberg's assessment of both the problem and the solution: the world is no more dangerous today than it was when the US Constitution was written. </p> <p>In fact, by every conceivable measure - including violence of all kinds - it is vastly <em>less</em> dangerous today than just about any time in history.</p> <p>More to the point, most of the danger we do face today does not come from terrorists. Terrorists are not as interested in taking lives as they are in capturing the public attention - more specifically, the public's <em>panicky</em> attention. </p> <p>Humans are notoriously subject to a cognitive bias called the <a href="http://en.wikipedia.org/wiki/Availability_heuristic">availability heuristic</a>, by which we evaluate how likely or common something is by how easily we can call examples of it to memory.</p> <p>Terrorism plays on this cognitive bias because terrorist attacks are extremely dramatic and high-profile, and thus imprint themselves strongly on our memory. </p> <p>When the news media, politicians and commentators pile on by focusing disproportionately on such events, they can trigger an <a href="http://en.wikipedia.org/wiki/Availability_cascade">availability cascade</a> - a self-reinforcing cycle in which more focus on an event motivates people to think more about it, which in turn leads people to focus more on it.</p> <p>Reactions like Bloomberg's, in which he argues that Americans need to reinterpret their Constitution to accept a loss of rights in the face of the threat of terrorism, are precisely the wrong way to approach the matter.</p> <p>There are a few <a href="https://chronicle.com/article/Era-in-Ideas-Terrorism/128490">important facts about terrorism</a> that should put our fear in context:</p> <ul> <li><p>Muslim-American terrorism has been <a href="http://tcths.sanford.duke.edu/documents/Kurzman_Muslim-American_Terrorism_final2013.pdf">in steady decline</a> for the past decade. The risk is getting smaller, not bigger.</p></li> <li><p>More generally, terrorist organizations tend to collapse over time, through various combinations of frustration, attrition and overreach.</p></li> <li><p>Terrorists themselves tend to be inept, amateurish and incompetent.</p></li> <li><p>The preferred methods of terrorism - like homemade IEDs built from pressure cookers - tend to be highly ineffective at killing people.</p></li> </ul> <p>On the same day that three people were killed in the Boston Marathon bombings, approximately 40 Americans country-wide were murdered for various non-terrorist reasons. </p> <p>Also on the same day, approximately 140 Americans died via guns (this includes suicides, which make up two-thirds of the total, and accidental deaths).</p> <p>We can keep going. On an average day in the United States, approximately 85 people are killed in automobile accidents, 16 people are killed in falls, 14 people are killed from accidental poisoning, and ten people are killed in home fires.</p> <p>My point is that the fear that we feel about terrorism is vastly disproportionate to the risk that we will experience it - especially compared to the kinds of things we rarely think about but really should worry about.</p> <p>Bruce Schneier <a href="https://www.schneier.com/blog/archives/2005/05/should_terroris_1.html">put it best</a> in a 2005 essay when he wrote:</p> <blockquote> <p>If a risk is in the news, then it's probably not worth worrying about. When something is no longer reported -- automobile deaths, domestic violence -- when it's so common that it's not news, then you should start worrying.</p> </blockquote> <p>By no means do I mean to dismiss or demean or make light of the trauma, injury and death experienced by the people who experienced the Boston Marathon terror attack. </p> <p>However, it will only compound the tragedy if we allow such an event to transform our civilization from one that esteems liberty, autonomy and privacy into one that sacrifices those things for needless and counterproductive expedience.</p> <p>The appropriate way to respond to terrorism is the same as it has always been: through effective, targeted law enforcement measures that build on <a href="http://www.thestar.com/opinion/commentary/2013/04/25/muslims_hold_key_to_fighting_terror.html">good community relationships</a> and do not violate the civil liberties of innocent citizens.</p> Ryan McGreal 2 http://quandyfactory.com/blog/94/adria_richards_and_the_allocation_of_outrage 2013-03-28T12:00:00Z Adria Richards and the Allocation of Outrage <p>One of the most glaring observations in light of the Adria Richards fiasco has been the allocation of outrage by the tech community:</p> <p class="centered"> <img src="http://i.imgur.com/9Jg2brL.png" alt="Allocation of Outrage" title="Allocation of Outrage" style="max-width: 100%"> </p> <p>The so-called "discussion" about whether Richards did the right thing when she tweeted a photo of two Python Conference attendees telling sexual jokes in violation of the event's Code of Conduct hasn't been much of a debate. </p> <p>Rather, it has been a general piling-on with a generous helping of condescension and chauvinism. There has been only a smattering of disagreement and it has been summarily dismissed with a combination of the most perfunctory hand-waving and sheer shouting-down.</p> <p>Meanwhile, the avalanche of rape threats, death threats, insults, intimidation, mockery and so on get by with, at best, a passing and semi-apologetic mention: <em>Of course death threats are wrong, but...</em></p> <p>Worse, the tech community immediately and decisively latched onto a convenient portrait of Richards as an underhanded, incompetent, cowardly, race-baiting, gender-baiting fraud with a manipulative agenda to aggrandize herself at the expense of everyone around her. This, despite almost none of the participants to this condemnation knowing anything about her. </p> <p>It was a classic <a href="https://en.wikipedia.org/wiki/Availability_cascade">availability cascade</a>, with each iteration of outraged commentary boiling the portrait into a cruder and uglier pastiche. </p> <p>No amount of counter-evidence could make a dent in this depiction - the very same depiction, incidentally, that is immediately <a href="http://www.buzzfeed.com/courtneystanton/a-woman-walks-into-a-tech-conference">slapped onto every woman</a> who dares to speak up about gender issues in the tech industry:</p> <blockquote> <p>A woman in the tech community identified people violating the stated Code of Conduct of the group. She was summarily run out of the community. Oh, wait, that wasn't just this week, that was <a href="https://lists.ubuntu.com/archives/ubuntu-women/2007-March/000727.html">six years ago</a>.</p> <p>A woman in the tech community takes her blog offline and stops speaking publicly after receiving death threats for a month. That was also <a href="http://web.archive.org/web/20070503012914/http://headrush.typepad.com/whathappened.html">six years ago</a>.</p> <p>A man attending a festival for the tech community harassed and attempted sexual assault on multiple women in attendance. That was <a href="http://geekfeminism.wikia.com/wiki/Sexual_assault_at_Southeast_LinuxFest">three years ago</a>.</p> <p>A man attending a high-profile invite-only tech event groped and harassed multiple women in attendance. That was also <a href="http://geekfeminism.wikia.com/wiki/Groping_at_FOO_Camp">three years ago</a>.</p> <p>A very high-profile man in the tech community is arrested for multiple counts of sexual assault. The tech community assumes loudly and repeatedly that the women reporting the assaults are lying. Again, this was <a href="http://tigerbeatdown.com/2010/12/15/mooreandme-on-dude-progressives-rape-apologism-and-the-little-guy/">three years ago</a>.</p> <p>A woman representing her employer at a large tech event was physically assaulted by a man attending the event. That was <a href="http://geekfeminism.wikia.com/wiki/Assault_at_OSCON">two years ago</a>.</p> <p>A sponsored hackathon lists "friendly (female) event staff" delivering beer to participants as a "great perk" of participating. That was <a href="http://thenextweb.com/us/2012/03/20/sqoot-loses-sponsors-following-misogynistic-description-of-their-api-jam-event/">last year</a>.</p> <p>A prominent man in the tech community was hired by a large computer manufacturer to be its master of ceremonies at a customer summit, where he said things like, "Men have invented everything worthwhile. All we can thank women for is the rolling pin." That was also <a href="http://web.archive.org/web/20120705070446/http://news.cnet.com/8301-31322_3-57431869-256/why-we-need-to-keep-talking-about-women-in-tech/">last year</a>.</p> <p>A woman who produces online feminist educational content ran a Kickstarter campaign to examine tropes about women in video games. In response, avid gamers sent her rape and death threats, vandalized her Wikipedia page, and created a game that allowed the player to "beat up" the woman's image. Again, this was only <a href="http://www.feministfrequency.com/2012/07/image-based-harassment-and-visual-misogyny/">last year</a>.</p> </blockquote> <p>Everyone circulated and referred to a <a href="http://amandablumwords.wordpress.com/2013/03/21/3/">post by Amanda Blum</a> that started with the statement, "I don't like Adria Richards," called her a "bully" and suggested that her action was part of a pattern of creating drama about gender issues to drive traffic to <a href="http://butyoureagirl.com">her blog</a>. </p> <p>The same people mostly ignored Gayle Laakmann McDowell's <a href="http://www.technologywoman.com/2013/03/24/digging-beneath-the-surface-that-amanda-blum-article-on-adria-richards-is-not-what-it-seems/">detailed review of the instances Blum cited</a> that cast them in a far more reasonable and less sinister light. But that detailed analysis got little play because it didn't fit into the convenient caricature.</p> <p>Also ignored was an <a href="http://www.dogsandshoes.com/2013/03/adria.html">article</a> by Sarah Milstein in which she called Richards a "model speaker, seeking and taking feedback on her presentation, showing flexibility in the logistics around her talks, and on one occasion, giving a high-pressure talk as she was still recovering from a bout of food poisoning".</p> <p>No matter how you try to parse it, it's unambiguously clear that our community whipped itself into an apoplectic firestorm of outrage when a woman complained about behaviour in a conference that violated the conference's code of conduct, but at best shrugged and at worst said she deserved it when that very firestorm of outrage overflowed into a forward panic of the most vile, vitriolic and disgusting abuse, insults, threats and mockery against her.</p> <p>That says something most disturbing about our community, and the collective unwillingness even to <em>acknowledge</em> it, let alone come to terms with it, should be all the evidence we need that this industry's blind spot on gender issues is as pervasive as ever.</p> Ryan McGreal 2 http://quandyfactory.com/blog/93/misogyny_in_the_tech_industry 2013-03-25T12:00:00Z Misogyny in the Tech Industry <p>The tech industry has spoken loud and clear:</p> <p>If a woman sees, hears or experiences inappropriate and/or sexist behaviour from her colleagues and/or peers, she should keep her mouth shut and not make such a big deal out of it.</p> <p>But if a man is called out for inappropriate and/or sexist behaviour, everyone will rise up in a vast eruption of righteous indignation - against the woman who had the nerve to speak up. </p> <p>She will be insulted, abused and threatened with assault and rape. Her motives will be subjected to the ugliest, most damning judgments. Her history will be dragged over for anything that makes her look hypocritical or hysterical.</p> <p>Her employer will readily sacrifice her to assuage the angry mob that launched a denial of service attack on its servers.</p> <p>And far too many people who may not actually be deliberately misogynist will nevertheless pile on, blaming her for 'getting one of the developers fired' and providing cover for the vicious personal attacks against her.</p> <p>Today I am ashamed to work in this industry.</p> <p><a href="https://www.facebook.com/SendGrid/posts/10151502570463967">https://www.facebook.com/SendGrid/posts/10151502570463967</a></p> <p><a href="http://blog.sendgrid.com/a-difficult-situation/">http://blog.sendgrid.com/a-difficult-situation/</a></p> <p>Background:</p> <p><a href="http://butyoureagirl.com/14015/forking-and-dongle-jokes-dont-belong-at-tech-conferences/">http://butyoureagirl.com/14015/forking-and-dongle-jokes-dont-belong-at-tech-conferences/</a></p> <p><strong>Update 2013-03-21 9:07 PM:</strong></p> <p>In case you're wondering what I'm talking about, here is just a recent sample of tweets that come up in a realtime search. I didn't have to dig far - at all, really - to find them. These are literally from the past <em>20 minutes</em>.</p> <p>Warning: these are extremely ugly, mean-spirited, dismissive and offensive. Some of them use the most degrading words the English language can hurl at a woman.</p> <ul> <li><a href="https://twitter.com/danithesexbomb/status/314904366555492352">https://twitter.com/danithesexbomb/status/314904366555492352</a></li> <li><a href="https://twitter.com/hashtagalamo/status/314904308632150017">https://twitter.com/hashtagalamo/status/314904308632150017</a></li> <li><a href="https://twitter.com/theinboxofchris/status/314903792116187138">https://twitter.com/theinboxofchris/status/314903792116187138</a></li> <li><a href="https://twitter.com/Hoo7on/status/314903535231840256">https://twitter.com/Hoo7on/status/314903535231840256</a></li> <li><a href="https://twitter.com/RandallFlagg66/status/314903275558273024">https://twitter.com/RandallFlagg66/status/314903275558273024</a></li> <li><a href="https://twitter.com/AaronFesser/status/314902526099062784">https://twitter.com/AaronFesser/status/314902526099062784</a></li> <li><a href="https://twitter.com/That_SpenceGuy/status/314902445312577537">https://twitter.com/That_SpenceGuy/status/314902445312577537</a></li> <li><a href="https://twitter.com/Ambious/status/314902632189816832">https://twitter.com/Ambious/status/314902632189816832</a></li> <li><a href="https://twitter.com/ConcernedHumanB/status/314902402300006400">https://twitter.com/ConcernedHumanB/status/314902402300006400</a></li> <li><a href="https://twitter.com/NGC_6611/status/314901944890187776">https://twitter.com/NGC_6611/status/314901944890187776</a></li> <li><a href="https://twitter.com/JoonasPder/status/314901596821651458">https://twitter.com/JoonasPder/status/314901596821651458</a></li> <li><a href="https://twitter.com/JUANBANE/status/314901550537506816">https://twitter.com/JUANBANE/status/314901550537506816</a></li> <li><a href="https://twitter.com/stellar476/status/314901330927947777">https://twitter.com/stellar476/status/314901330927947777</a></li> <li><a href="https://twitter.com/NGC_6611/status/314901073435426818">https://twitter.com/NGC_6611/status/314901073435426818</a></li> </ul> <p><strong>Update 2013-03-25 6:34 AM:</strong></p> <p>Some excellent write-ups around the web:</p> <ul> <li>Courtney Stanton, <a href="http://www.buzzfeed.com/courtneystanton/a-woman-walks-into-a-tech-conference">A Woman Walks Into A Tech Conference</a></li> <li>Sarah Milstein, <a href="http://www.dogsandshoes.com/2013/03/adria.html">I Have a Few Things to Say About Adria</a></li> <li>Gayle Laakmann McDowell, <a href="http://www.technologywoman.com/2013/03/24/digging-beneath-the-surface-that-amanda-blum-article-on-adria-richards-is-not-what-it-seems/">Digging Beneath the Surface: That Amanda Blum Article on Adria Richards is Not What It Seems</a></li> <li>Matt LeMay, <a href="http://mattlemay.tumblr.com/post/46004653389/on-pycon">On PyCon</a></li> </ul> Ryan McGreal 2 http://quandyfactory.com/blog/103/on_crimes_and_punishments:_the_cruel_and_unusual_threat_against_aaron_swartz 2013-01-18T12:00:00Z On Crimes and Punishments: The Cruel and Unusual Threat against Aaron Swartz <p>In the aftermath of <a href="http://raisethehammer.org/blog/2634/rip_aaron_swartz">Aaron Swartz' tragic suicide</a>, I've been finding myself thinking that it's time for American lawmakers and prosecutors to re-read Cesare Beccaria's <em>Of Crimes and Punishments</em>. </p> <p>After its publication in 1764, the framers of the US Constitution were persuaded by its reasoning to amend the Constitution to include a prohibition on "excessive fines" and "cruel and unusual punishments".</p> <p>It's important to note that "cruel and unusual" did not mean that such punishments were uncommon. At the time the book was written, every European civilization still routinely used the most barbaric, sadistic and horrific methods for the most appalling ends: torturing suspected criminals until they confessed their crimes, and inflicting appalling physical and psychological torments on the convicted.</p> <p>It's easy to forget, today, that Europe once made widespread, unremarked use of flogging, stocks, breaking on the wheel, burning at the stake, the heretic's fork, knee splitters, the rack, the thumbscrew, and various other sadistic forms of punishment for a staggering array of crimes, including both victimless offenses like blasphemy and imaginary offenses like witchcraft.</p> <p>When Beccaria decried such practices, he argued not that they were uncommon - after all, it was their very commonness to which he objected - but rather that they were offensive to contemporary Enlightenment ideas about fairness, civility and efficacy in the administration of justice.</p> <p>In the case of Aaron Swartz, the threat of 50 years in federal prison and a million dollars in fines for downloading a bunch of academic papers cannot reasonably be considered to be anything other than "excessive" or "cruel and unusual". </p> <p>Apologists for the US prosecutors who brought the case against him are arguing that he was offered a plea bargain that would likely result in only six months of prison time. </p> <p>Carmen M. Ortiz, the US Attorney for Massachusetts who brought the case against Swartz, issued a <a href="http://blogs.wsj.com/law/2013/01/17/us-attorney-statement-on-the-prosecution-of-aaron-swartz/">public statement</a> yesterday that defended her office's actions on the grounds that the plea bargain offered "sought an appropriate sentence that matched the alleged conduct."</p> <p>Ortiz insisted, "At no time did this office ever seek - or ever tell Mr. Swartz's attorneys that it intended to seek - maximum penalties under the law."</p> <p>However, this spectacularly misses the point: Swartz would only be entitled to a reasonable expectation of leniancy <em>in exchange for pleading guilty.</em> </p> <p>I will set aside the <a href="http://io9.com/5975592/aaron-swartz-died-innocent-++-here-is-the-evidence">contention</a> that even a day of time in a federal prison is disproportionate for what amounts to a TOS violation, and instead focus on the fact that a short prison term would only come with a guilty plea.</p> <p>The prosecutor used the threat of 35-50 years in prison to get Aaron to accept a guilty plea. If he chose to plead not guilty and attempt to defend himself, it would cost well over a million dollars in legal fees, and if he were found guilty anyway, the judge would be strongly predisposed to make an example of him by giving him a very long, punitive sentence.</p> <p>A prosecutor forcing someone to admit guilt by threatening a life-destroying cruel and unusual punishment if they do not admit it - why, that is the very essence of using torture to extract a confession!</p> Ryan McGreal 2 http://quandyfactory.com/blog/101/bill_c-38 2012-06-29T12:00:00Z Bill C-38 <p>On June 19, 2012, I sent the following email to the members of the Canadian Senate:</p> <blockquote> <p>Dear Senators,</p> <p>If ever a piece of legislation cried out for sober second thought, it is Bill C-38: a sprawling omnibus bill that makes so many changes at once, it's almost impossible for Parliament, let alone the electorate, to get their heads around it.</p> <ul> <li><p>It is not sound governance to replace clear, consistent rules with discretionary ministerial regulations that are susceptible to political interference and regulatory capture.</p></li> <li><p>It is not prudent stewardship to cut back the Fisheries Act so that it only pertains to commercial fish stocks. If the collapse of the Atlantic cod industry has taught us anything, it is that a commercial stock cannot survive without the broader ecosystem that supports it.</p></li> <li><p>It is profoundly anti-democratic for a government to attempt to impose a chill on non-profit organizations that challenge its agenda. It is only through vigorous, open debate that the best public policy can prevail.</p></li> <li><p>It sets a dangerous precedent to grant the Immigration Minister the power to overrule national immigration policy and reject applicants to Canada whose applications meet the rules. Will we be governed by the rule of law or by the caprice of de facto letters patent?</p></li> <li><p>Similarly, it is dangerous and capricious to grant the government the power to overrule the rulings of the National Energy Board in order to expedite energy and resource projects. Combined with the narrowing of the mandate of environmental assessments and the exclusion of non-business stakeholders, this all but guarantees that resource extraction projects will be determined on the basis of narrow private interest, not the broader public interest.</p></li> </ul> <p>Even this broad swath of policy implications barely scratches the surface of Bill C-38, which crams so many changes into one package that those changes cannot be properly evaluated. Certainly they do not belong in a bill that is supposed to implement the annual budget!</p> <p>As one member of the House of Commons noted:</p> <blockquote> <p>We can agree with some of the measures but oppose others. How do we express our views and the views of our constituents when the matters are so diverse? Dividing the bill into several components would allow members to represent views of their constituents on each of the different components in the bill.</p> <p>The bill contains many distinct proposals and principles and asking members to provide simple answers to such complex questions is in contradiction to the conventions and practices of the House.</p> </blockquote> <p>That member was Stephen Harper, and his prudent appraisal of a 2005 omnibus bill is as true today.</p> </blockquote> <p>Just today, I received a reply from Senator James S. Cowan, Leader of the Opposition in the Senate:</p> <blockquote> <p>Dear Mr. McGreal:</p> <p>Thank you for your email about Bill C-38, the Harper Government's omnibus Budget Bill.</p> <p>I agree with you - the bill is highly objectionable. I too have concerns both about the substance of the bill, and the abuse of our democratic traditions in the way the bill was rushed through Parliament.</p> <p>The Bill is over 420 pages long and contains over 720 clauses. It amends or repeals some 70 statutes, including as you mentioned, Canada's environmental assessment laws and the laws that protected fish habitat. It dismantles the National Round Table on the Environment and the Economy, the National Council on Welfare, Rights and Democracy, the Public Appointments Commission, the Inspector-General that acts as a check on CSIS - the list goes on and on. It makes extensive changes to Canada's social safety net, including Employment Insurance and Old Age Security.</p> <p>These - and many other provisions in the bill - go far beyond what should be contained in a single bill, and are flatly bad public policy.</p> <p>The Conservatives have rammed it through Parliament, with as little possibility for scrutiny or input from Canadians as possible. In the House of Commons, the entire bill was sent to a single committee, the Standing Committee on Finance - and it had to deal with the entire package in 10 sitting days. Frankly, the changes to Old Age Security or Employment Insurance alone would have deserved that attention. </p> <p>Here in the Senate, the Liberal opposition was able to get the government to agree to send the subject matter of the bill to six different Senate committees for "pre-study", but even this, while better than the cursory study possible in the House of Commons, was simply inadequate to properly examine this mammoth bill. </p> <p>The Conservatives have repeatedly shut down debate and study of this bill, and this is continuing now that the Bill is before the Senate. </p> <p>My Liberal colleagues and I have tried to place on the record our concerns with both the substance and process. Our debate on the Bill - which was again cut short by the Conservatives - can be found at the following link:</p> <p><a href="http://www.parl.gc.ca/Content/Sen/Chamber/411/Debates/095db_2012-06-21-e.htm">http://www.parl.gc.ca/Content/Sen/Chamber/411/Debates/095db_2012-06-21-e.htm</a></p> <p>Although the process in the Senate is still on-going as I write, it is clear that the Harper government has no intention of allowing real debate and study. It will continue to force the bill through to final passage, over our strong objections and those of many Canadians like yourself.</p> <p>Once again, thank you for taking the time to write to me on this important issue. </p> </blockquote> <p>If you want to send a letter to the Senate, here is a list of their <a href="mailto:andrer@sen.parl.gc.ca, anguswd@sen.parl.gc.ca, atauls@sen.parl.gc.ca, bakerg@sen.parl.gc.ca, boisvp@sen.parl.gc.ca, braled@sen.parl.gc.ca, brazep@sen.parl.gc.ca, brownb@sen.parl.gc.ca, buthjo@sen.parl.gc.ca, callbc@sen.parl.gc.ca, campbel@sen.parl.gc.ca, carigc@sen.parl.gc.ca, champa@sen.parl.gc.ca, chapum@sen.parl.gc.ca, poulim@sen.parl.gc.ca, cochre@sen.parl.gc.ca, comeag@sen.parl.gc.ca, coolsa@sen.parl.gc.ca, cordyj@sen.parl.gc.ca, cowanj@sen.parl.gc.ca, dagenj@sen.parl.gc.ca, dallar@sen.parl.gc.ca, dawsod@sen.parl.gc.ca, dayja@sen.parl.gc.ca, debanp@sen.parl.gc.ca, tessil@sen.parl.gc.ca, dininc@sen.parl.gc.ca, pdowne@sen.parl.gc.ca, doylen@sen.parl.gc.ca, mikeduffy@sen.parl.gc.ca, dyckli@sen.parl.gc.ca, eatonn@sen.parl.gc.ca, egglea@sen.parl.gc.ca, fairbj@sen.parl.gc.ca, finled@sen.parl.gc.ca, fortis@sen.parl.gc.ca, frasej@sen.parl.gc.ca, fruml@sen.parl.gc.ca, fureyg@sen.parl.gc.ca, banc@sen.parl.gc.ca, greens@sen.parl.gc.ca, harbm@sen.parl.gc.ca, hervic@sen.parl.gc.ca, lacomd@sen.parl.gc.ca, hublee@sen.parl.gc.ca, jaffem@sen.parl.gc.ca, johnsj@sen.parl.gc.ca, joyals@sen.parl.gc.ca, kennyco@sen.parl.gc.ca, kinsen@sen.parl.gc.ca, langd@sen.parl.gc.ca, lebrem@sen.parl.gc.ca, losier@sen.parl.gc.ca, smithc@sen.parl.gc.ca, mahovf@sen.parl.gc.ca, maltag@sen.parl.gc.ca, mannif@sen.parl.gc.ca, marshe@sen.parl.gc.ca, martin@sen.parl.gc.ca, massip@sen.parl.gc.ca, mccoye@sen.parl.gc.ca, mercet@sen.parl.gc.ca, merchp@sen.parl.gc.ca, meredd@sen.parl.gc.ca, mitchg@sen.parl.gc.ca, mocklp@sen.parl.gc.ca, moorew@sen.parl.gc.ca, munsoj@sen.parl.gc.ca, mcgeed@sen.parl.gc.ca, neufer@sen.parl.gc.ca, nolinp@sen.parl.gc.ca, ogilvk@sen.parl.gc.ca, olived@sen.parl.gc.ca, patted@sen.parl.gc.ca, russem@sen.parl.gc.ca, plettd@sen.parl.gc.ca, poirir@sen.parl.gc.ca, poyv@sen.parl.gc.ca, rainen@sen.parl.gc.ca, ringup@sen.parl.gc.ca, rivarm@sen.parl.gc.ca, jcrivest@sen.parl.gc.ca, robicf@sen.parl.gc.ca, runcib@sen.parl.gc.ca, kfl@sen.parl.gc.ca, seidmj@sen.parl.gc.ca, setha@sen.parl.gc.ca, sibnic@sen.parl.gc.ca, smithd@sen.parl.gc.ca">email addresses</a>.</p> <hr /> <p>Update: I also received a reply from Senator Elaine McCoy.</p> <blockquote> <p>Hello, and thank you for your email about the omnibus budget bill. I just wanted to let you know that I voted against C-38, as a matter of principle, last Thursday night. A copy of my speech is attached for information. Sadly, the vote did not succeed in stopping the bill as the Conservatives overwhelmingly supported it. </p> <p>You can see the results of the standing vote (as well as other speeches against the bill) by <a href="http://www.parl.gc.ca/Content/Sen/Chamber/411/Debates/095db_2012-06-21-e.htm#59">clicking here</a> and scrolling to the section titled Jobs, Growth and Prosperity Bill.</p> <p>Although you and I have not succeeded in persuading the government to follow a different course of action in this instance, I feel it is important we continue to speak out about issues of importance to Canada. I know I will. I hope you do too. </p> <p>Warm regards, Elaine</p> <p><a href="http://www.albertasenator.ca/">Alberta Senator</a></p> </blockquote> Ryan McGreal 2 http://quandyfactory.com/blog/100/the_appification_of_computing 2012-06-28T12:00:00Z The Appification of Computing <p>The historian and philosopher Walter J. Ong drew a distinction between what he called "craft literacy" and "social literacy". The former is the kind of literacy you find in cultures that have systems of writing but do not have cheap, ubiquitous publishing - like Europe before Gutenberg's invention of movable type. </p> <p>In a culture with craft literacy, most people can't read and write and those who can - scribes - do so as a vocation. </p> <p>When a society moves toward full literacy, made possible by universal access to both reading and writing material, a number of huge social transformations occur - but one such change is that the mere ability to read and write stops being a rare skill, possessed only by professionals.</p> <p>For some time I've believed that computer literacy - by which I mean the ability to read and write computer programs - is currently at the level of craft literacy in our society. </p> <p>I've expressed the hope that we will eventually move toward social literacy in computing, in which most people routinely learn to read and write computer programs in the same way we currently learn to read and write text.</p> <h3>Computer Illiteracy</h3> <p>So a <a href="https://www.theglobeandmail.com/technology/tech-news/are-we-breeding-a-generation-of-app-loving-web-addicted-digital-illiterates/article4370982/I/">recent article</a> in the <cite>Globe and Mail</cite> gave me serious pause. Titled, "Are we breeding a generation of app-living, web-addicted digital illiterates?", the article quotes Sang-Jin Bae, a computer animation technical director and instructor at New York University's Tisch School of the Arts:</p> <blockquote> <p>"When kids come into my class they divide into three groups," he says. There are the pure geeks who love technology. There are those trying to understand. And then there is the biggest group: "Those who couldn't care less."</p> <p>As remarkable as it is to consider, this hip, articulate 36-year old computer whiz makes a heck of an argument that the computer age is entering a dark new era: the age of the digital illiterate.</p> <p>Today's teens grew up on SMS and Facebook. Everything is being presented to them all the time. Web companies love it, since kids are addicted to their products. But, he says, "They expect less and less from the Web and the software they use."</p> <p>Mr. Bae is not just talking about obscure, high-end animation tools. Instead, he sees an essential dumbing down of bedrock computing skills.</p> <p>"The kids I have, and that is roughly two dozen of the brightest young digital artists a semester, often have no idea what Microsoft Word is. They can't tell a Mac from a PC. And forget Excel," he says. He struggles to get his students to use basic computing etiquette.</p> </blockquote> <p>It appears that the relentless drive to simplicity in user interface has had the-side effect of serving as a disincentive for students to bother learning more about how computers work.</p> <h3>Knowledge-Destroying Idea</h3> <p>Lately I've been reading Edward Glaeser's book <em>Triumph of the City</em>, a sprawling tour-de-force in support of the thesis that cities are our most important engines of creativity, innovation and growth and that we would do well to understand how cities work so that we can run our cities more effectively.</p> <p>Writing about the spectacular decline of Detroit, formerly one of America's greatest cities, Glaeser argues that the seed of Detroit's failure was the invention of the assembly line:</p> <blockquote> <p>By turning a human being into a cog in a vast industrial enterprise, [Henry] Ford made it possible to be highly productive without having to know all that much. But if people need to know less, they also have less need for cities that spread knowledge. When a city creates a powerful enough knowledge-destroying idea, it sets itself up for self-destruction.</p> </blockquote> <p>I wonder if the 'app-ification' of computing is turning out to be the same thing: a powerful, knowledge-destroying idea that is actually crippling our collective ability to use computers as tools of creation rather than merely as vectors of consumption.</p> <hr /> <p><strong>Update</strong>: interesting discussion on <a href="https://news.ycombinator.com/item?id=4170927">Hacker News</a>.</p> Ryan McGreal 2 http://quandyfactory.com/blog/85/my_second_baguette 2012-04-30T12:00:00Z My Second Baguette <p>Last summer, during a grueling heat wave, I decided to <a href="/blog/81/my_first_baguette">try my hand at making baguettes</a>. The results were decent for a first try but left plenty of room for improvement, but life conspired to get in the way of a follow-up effort. </p> <p>Finally, this past weekend, I prepared a second batch and applied the lessons I took from the first attempt. I'm happy to report that the results were definitely more impressive.</p> <h3>What You'll Need</h3> <p>Every decent baguette recipe I found measured the ingredients by weight, not by volume, so make sure you have a decent kitchen scale. Here's a full list of equipment and tools:</p> <ul> <li>Kitchen scale</li> <li>Medium-size bowl</li> <li>Large bowl</li> <li>Wooden spoon</li> <li>Sharp knife</li> <li><a href="http://www.kingarthurflour.com/shop/items/bakers-couche">Baker's couche</a> or, failing that, a big, thick tea-towel and some wax paper</li> <li>Cellophane</li> <li>Large baking sheet</li> <li>Kettle for boiling water</li> <li>Medium-sized baking pan (e.g. for brownies or lasagne)</li> </ul> <h3>Poolish</h3> <p>A day before you intend to make your baguette, you first need to prepare a <a href="http://en.wikipedia.org/wiki/Poolish">poolish</a>, or a pre-ferment.</p> <h4>Ingredients</h4> <ul> <li>300 g. flour</li> <li>300 g. warm water</li> <li>1/8 tsp dry active yeast</li> </ul> <h4>Directions</h4> <ul> <li>Combine the ingredients thoroughly in a medium-sized bowl. </li> <li>Cover with a cloth and let sit overnight in a cool room (20-22 degrees Celsius is optimal).</li> </ul> <p class="image"> <img src="/static/images/baguette_02_poolish_new.jpg" alt="Combine flour, warm water and yeast to make a poolish" title="Combine flour, warm water and yeast to make a poolish"><br> Combine flour, warm water and yeast to make a poolish </p> <p>After fermenting, the poolish should look bubbly and almost liquid.</p> <p class="image"> <img src="/static/images/baguette_02_poolish_fermented.jpg" alt="After fermenting overnight, the poolish should look wet and bubbly" title="After fermenting overnight, the poolish should look wet and bubbly"><br> After fermenting overnight, the poolish should look wet and bubbly </p> <p>Here's a closeup of the fermented poolish:</p> <p class="image"> <img src="/static/images/baguette_02_poolish_fermented_closeup.jpg" alt="Closeup of fermented poolish" title="Closeup of fermented poolish"><br> Closeup of fermented poolish </p> <h3>Baguette</h3> <p>Once your poolish is mature, you can proceed to making the baguette dough.</p> <h4>Ingredients</h4> <ul> <li>The poolish you just made</li> <li>600 g. flour</li> <li>300 g. warm water</li> <li>1 Tbsp. salt</li> <li>1 tsp dry active yeast</li> </ul> <h4>Directions</h4> <ul> <li>Combine all the ingredients in a large bowl using the wooden spoon. Don't worry - there's enough water even if it doesn't seem that way at first.</li> <li><a href="http://en.wikipedia.org/wiki/Kneading">Knead</a> the dough for 15 minutes. You might need to add bits of flour to stop it from sticking to your hands.</li> <li>Form the dough into a ball. Rub it with oil and cover it with a cloth.</li> <li>Let it rise for around 2 hours, or until doubled in size.</li> </ul> <p class="image"> <img src="/static/images/baguette_02_dough_rising.jpg" alt="Dough in the process of rising" title="Dough in the process of rising"><br> Dough in the process of rising </p> <ul> <li>Once the dough is ready, cut it into four equal-sized pieces and shape each piece into a rough circle.</li> <li>Cover each piece with cellophane and let them rest for 20-30 minutes.</li> </ul> <p class="image"> <img src="/static/images/baguette_02_dough_quartered_and_shaped.jpg" alt="Dough quartered, shaped into balls and wrapped in cellophane" title="Dough quartered, shaped into balls and wrapped in cellophane"><br> Dough quartered, shaped into balls and wrapped in cellophane </p> <ul> <li>Next, shape the four dough pieces into baguette shapes.</li> <li>Fold the couche or cloth into four folds, one for each baguette, so that it holds its elongated shape during the final rising period. <strong>Note:</strong> if you're using a cloth in place of a proper couche, cover the cloth in wax paper so the dough does not stick.</li> </ul> <p class="image"> <img src="/static/images/baguette_02_in_couche.jpg" alt="Dough shaped into baguettes and folded into a makeshift couche" title="Dough shaped into baguettes and folded into a makeshift couche"><br> Dough shaped into baguettes and folded into a makeshift couche </p> <ul> <li>Cover and let rise for another around 1.5 hours.</li> <li>Now preheat the oven to 450 degrees fahrenheit.</li> <li>While the oven is heating, boil some water in a kettle. When the oven is ready, pour most of the water into your pan and place it on the bottom tray of the oven.</li> <li>Transfer the baguettes from the couche onto a large baking sheet.</li> <li>Using a sharp knife, cut several shallow, slightly diagonal scores across the top of the baguettes.</li> </ul> <p class="image"> <img src="/static/images/baguette_02_scored.jpg" alt="Baguettes placed on the baking sheet and scored with a knife" title="Baguettes placed on the baking sheet and scored with a knife"><br> Baguettes placed on the baking sheet and scored with a knife </p> <ul> <li>By now, the oven should be back up to 450 degrees and the water in the pan should be boiling energetically. Place the baking sheet with the baguettes onto the top tray of the oven. </li> <li>With the rest of the boiling water, splash it around the interior bottom and sides of the oven to get some good steam going, and then quickly close the door.</li> <li>Bake for around 20 minutes, and remove from the oven once the baguettes are golden brown.</li> </ul> <p class="image"> <img src="/static/images/baguette_02_baked.jpg" alt="Out of the oven: slightly overdone but still tasty" title="Out of the oven: slightly overdone but still tasty"><br> Out of the oven: slightly overdone but still tasty </p> <p class="image"> <img src="/static/images/baguette_02_baked_closeup.jpg" alt="Closeup of the baked baguettes" title="Closeup of the baked baguettes"><br> Closeup of the baked baguettes </p> <p>As you can see, my baguettes turned out slightly overcooked (I should have taken them out a minute or so sooner), but they were delicious: crunchy on the outside, soft and chewy on the inside, with a nice baguetty flavour. We served them as part of a French-themed dinner on Saturday night and they were well received.</p> Ryan McGreal 2 http://quandyfactory.com/blog/91/services-first:_a_better_way_to_build_a_web_application 2012-02-22T12:00:00Z Services-First: A Better Way to Build a Web Application <h3>Introduction</h3> <blockquote> <p>The best way to find yourself is to lose yourself in the service of others.</p> <p>-- Mahatma Gandhi</p> </blockquote> <p>When you're building a web application, it's a powerful design heuristic to develop your functionality as a web service and then build your application on top of your service.</p> <p>The functionality your application needs to perform should all be accessible or at least exposable as web services. This enforces a responsible design approach that will pay real dividends in maintainability, extendability and reduced technical debt.</p> <p>It may also pay unexpected dividends in generating value over and above the principal goal of your web application. By thinking about your application design as a web service, you open up the possibility that the real value you deliver is not what you thought your service was going to be, but some subsidiary or extraneous solution you develop that turns out to be a) useful to others and b) scalable/profitable.</p> <h4>The Infamous Yegge Platform Rant</h4> <p>Last October, Google engineer Steve Yegge posted a long, thoughtful rant on his public <a href="https://plus.google.com/110981030061712822816">Google+ page</a> in which he argued that Google "does everything right" - except platforms, which he argues Google still doesn't really understand. Rather, Google provides <em>products</em>, not <em>services</em>.</p> <p>Yegge's essay was directed internally at his fellow Googlers, and he took it down after realizing he had accidentally posted it publicly. Luckily for us, copies are <a href="https://plus.google.com/112678702228711889851/posts/eVeouesvaVX">still available</a> with Yegge's blessing.</p> <p>Yegge contrasted his former employer, Amazon, which overwhelmingly adopted a services-first approach after founder and CEO Jeff Bezos ordered every business unit in the company to start exposing its functions to the rest of the company as a web service. </p> <h3>Service-Oriented Architecture (SOA)</h3> <p>SOA is a methodology for developing software as a collection of <em>services</em>. Every functional unit exposes its functionality via API calls, and each unit consumes other units' services by accessing those API calls. The services are modular, exposable and 'mashable'.</p> <h4>Platforms</h4> <p>According to Yegge, Amazon recognized that a services-first approach would enable Amazon to provide a platform on which other companies can build their businesses.</p> <blockquote> <p>[T]he first big thing Bezos realized is that the infrastructure they'd built for selling and shipping books and sundry could be transformed an excellent repurposable computing platform. </p> </blockquote> <p>A platform is a system on which others can build applications and products. A product can be used, but a platform can be <em>programmed</em> and *extended. Users can create, access, modify and share resources programmatically. </p> <p>Outside developers can build applications on top of your platform. The more accessible your platform is, the more people will use it and the easier it will be to achieve critical mass and positive network externalities.</p> <p>Metcalf's Law states: <em>The value of a network is proportional to the square of the number of connected nodes.</em> As the number of people using your platform increases linearly, the overall value can increase geometrically.</p> <h4>Applications</h4> <p>Applications are programs built on top of platforms that are meant to be used directly. </p> <p>A good platform is hackable, in the sense that it is general and flexible enough to allow third parties to build applications that the platform designer might never have imagined.</p> <p>The more <strong>powerful</strong>, <strong>reliable</strong>, <strong>accessible</strong> and <strong>flexible</strong> a platform is, the more likely it is that someone will build a "killer app" - a program so useful that it makes the platform <em>indispensable</em>. Think of VisiCalc on the Apple II, Lotus 1-2-3 on the PC, or Microsoft Office on Windows.</p> <h4>Electricity Grid</h4> <p>Here's another platform that attracted killer apps: the electricity grid. When the grid was first built, it was dedicated to powering lights. There weren't even outlets: electrical lines were hard-wired to light bulbs.</p> <p>But it didn't take long for innovators to recognize that there were lots of other uses for electricity. Within a few years, electric fans, irons and toasters became extremely popular. </p> <p>The first appliances didn't have plugs: they had connectors that screwed right into light bulbs. When outlets were introduced, they provided a much safer, more flexible user interface for the power grid.</p> <p>To this day, innovators are still finding new and creative ways to build on the electricity grid. It's a beautiful platform: about as powerful, reliable, general and flexible as it gets.</p> <h4>Bootstrapping</h4> <p>When you build a robust platform, you make it easier and more attractive for developers to build on it. The more developers you have building on your platform, the more likely it is that one of those developers will build a killer app. More, better and more popular apps, in turn, make your platform more attractive to developers.</p> <p>It's a virtuous cycle if you can manage to set it in motion.</p> <h4>Dogfooding.</h4> <p>Yegge stresses the vital importance of building on your own platform: </p> <blockquote> <p>The Golden Rule of Platforms, "Eat Your Own Dogfood", can be rephrased as "Start with a Platform, and Then Use it for Everything."</p> </blockquote> <p>When you dogfood your platform, you have a direct interest in improving it, and that improvement makes it more attractive to developers. You also get to see your platform from your customers' perspective, helping you to understand their needs better. Finally, you demonstrate confidence in your own offerings.</p> <p>Microsoft built an extremely successful software business through religious dogfooding. The original Windows NT team actually developed NT using computers that ran NT - talk about an incentive to build a stable, functional platform!</p> <p>A word of warning: taken to the extreme, dogfooding leads to Not Invented Here syndrome. </p> <h4>Products v. Platforms</h4> <table> <thead><tr><th>Products</th><th>Platforms</th></tr></thead> <tbody> <tr><td>Targeted</td><td>Broad</td></tr> <tr><td>Differentiated</td><td>Integrated</td></tr> <tr><td>Fast to Market</td><td>Long-term Strategy</td></tr> <tr><td>Maximize profit</td><td>Maximize Market Share</td></tr> </tbody> </table> <p>The danger of a business model based on a product offering is that a powerful platform can surround and crowd out a product if the platform allows equivalent functionality. Since computers became widespread, the market for typewriters and calculators has collapsed.</p> <p>In general, an extensible platform will tend to win over a monolithic product. iPhone and Android crowded out Blackberry in large part because they made it easy for third party developers to extend their functionality.</p> <p>Similarly, a more open platform will tend to win over a more closed platform. As much as iPhone was more open and accessible than BB, Android is still more open and flexible - even to the point that the operating system can be installed on a variety of third party devices. Its market share has shot ahead of the iPhone.</p> <p>This is the same story that played out in the early 1980s: Microsoft won the PC operating system market mainly because of its cheap, permissive licencing model. They extended this model to Windows and the Win32 API, which was similarly more open than Mac, Amiga and other systems that were actually technically superior but more closed.</p> <p>In the 1990s, the World Wide Web crowded out and assimilated Compuserve, AOL, The Source, Prodigy, Minitel and other proprietary networks because it was an open standard with a low barrier to entry.</p> <p>The story of web servers is the same: the LAMP stack (Linux, Apache, MySQL, Perl/PHP) came to dominate web applications against competition from the proprietary IIS/ASP and .NET alternatives.</p> <h4>Products to Platforms</h4> <p>Remember, however, that the line between products and platforms is fuzzy. Products use standardized, modular components; design/manufacturing/logistic expertise transfers to new products; and products can generalize into platforms.</p> <p>Amazon and Facebook both transformed themselves from product companies to platform companies. Today, the killer app on Amazon Web Services is Amazon, and the killer app on the Facebook platform is Facebook.</p> <p>Yegge points out that it might be painful to maintain the discipline to eat your own dogfood and build services-first, but it is <em>far</em> more painful and expensive to turn a monolithic application into a platform after the fact.</p> <blockquote> <p>If you delay it, it'll be ten times as much work as just doing it correctly up front. You can't cheat. You can't have secret back doors for internal apps to get special priority access, not for ANY reason. You need to solve the hard problems up front.</p> </blockquote> <p>According to Yegge, Amazon went through the painful exercise of transforming itself from a product company into a platform company because of necessity:</p> <blockquote> <p>[I]t took an out-of-band force to make Bezos understand the need for a platform. That force was their evaporating margins; he was cornered and had to think of a way out. But all he had was a bunch of engineers and all these computers... if only they could be monetized somehow... you can see how he arrived at AWS, in hindsight.</p> </blockquote> <h4>Amazon Web Services</h4> <p>Here is how Bezos himself explained the strategy in his latest annual letter to shareholders:</p> <blockquote> <p>Our technologies are almost exclusively implemented as services: bits of logic that encapsulate the data they operate on and provide hardened interfaces as the only way to access their functionality. This approach reduces side effects and allows services to evolve at their own pace without impacting the other components of the overall system. Service-oriented architecture - or SOA - is the fundamental building abstraction for Amazon technologies.</p> </blockquote> <p>Amazon launched its first web service - Elastic Compute Cloud (EC2) - in 2006. Since then, it has followed up with a long list of additional services:</p> <ul> <li>CloudFront - low latency global CDN</li> <li>DevPay - accounts receivable service</li> <li>DynamoDB and SimpleDB - schemaless nosql key/value store</li> <li>ElastiCache - scalable in-memory cache</li> <li>Elastic MapReduce - distributed mapreduce processing for huge datasets</li> <li>Flexible Payment Service (FPS) - digital payment service</li> <li>Mechanical Turk - on-demand human intelligence market</li> <li>Relational Database Service (RDS) - relational database</li> <li>Simple Email Service (SES) - bulk and transactional email service</li> <li>Simple Notification Service (SNS) - send notifications</li> <li>Simple Storage Service (S3) - data storage and retrieval</li> <li>Route 53 - Domain Name System service</li> </ul> <p>None of these service are central to Amazon's core business, which is selling books and other consumer products directly to consumers. However, they all began life internally as essential peripheral or supporting functions. </p> <p>Today, the company can sell these web services publicly because Bezos had the foresight to insist that the company conduct its internal affairs via web services.</p> <p>The company is secretive about how much revenue it earns directly from its suite of web services, but the best estimates are that revenue reached $500 million in 2010 and $750 million in 2011. Web service revenue is expected to reach $1 billion in 2012 and $2.6 billion in 2015.</p> <h4>Platforms Express Value</h4> <p>No matter what you build, you will develop expertise in a number of related, peripheral functions that support your primary product. If you develop your product in a services-first fashion, you allow for the possibility to expose those peripheral functions to third parties.</p> <p>No initial product idea survives first contact with the market. Every successful business is successful because it was able to adjust - sometimes wildly - its product and business strategy in response to real-world feedback. Startup gurus call this "pivoting", and a founder's ability to pull it off is decisive in the survival of the business.</p> <p>Pivoting doesn't mean throwing away what you've built and starting over. Rather, it means <em>re-purposing</em> what you've built to reach a more promising market. </p> <p>Many successful startup products started out as components of larger, less focused products. In his book <em>The Lean Startup</em>, entrepreneur Eric Ries calls this the "zoom-in pivot". Other businesses started out assuming they would be selling to one market and ended up attracting interest from a different sector altogether.</p> <p>A services-first approach decouples your product from the platform it's built on, allowing you more flexibility to change it as required. It also allows you to provide the platform itself to clients as an additional source of value.</p> <h3>Designing Your Web Application</h3> <p>So when building your web application, it's a powerful design heuristic to build a web service first, and then build the application on top of it.</p> <h4>Why a Heuristic?</h4> <p>Application design is not linear or deterministic, it's open-ended, incremental and adaptive. Small changes early on can push an application in vastly different directions.</p> <p>Most important, there isn't <em>one right way</em> to do things. Ten different developers given the same problem will create ten different solutions - and any number of them can be 'good enough'.</p> <p>When you can't reason your way to a proof, you have to fall back on a less certain, more exploratory approach. A <strong>heuristic</strong> is a method of approaching the problem that tends to help you produce good solutions but falls short of being a solution itself. </p> <p>Think of a heuristic as a general rule of thumb rather than a specific prescription.</p> <h4>Design Goals</h4> <p>For the end user, a web service should be:</p> <ul> <li><strong>Useful</strong> - The most elegant web service in the world won't interest anyone if it doesn't solve real problems.</li> <li><strong>Usable</strong> - Similarly, the most useful web service won't be adopted if people can't figure out how to use it.</li> <li><strong>Explorable</strong> - The easier it is to navigate and discover what a service does and how to use it, the more it will be adopted.</li> <li><strong>Accessible</strong> - In the case of a web service, accessibility means a variety of clients can use and interact with it.</li> <li><strong>Combinable</strong> - The purpose of web APIs is so clients can combine data and functionality from a variety of sources to build new things.</li> <li><strong>Flexible</strong> - Your own product is not the only thing that can be built with your platform. Your API should be open enough to allow for use cases you couldn't imagine.</li> </ul> <p>For the web service developer, a web service should offer and/or encourage:</p> <ul> <li>Clean, consistent organization of data and functionality</li> <li>Separation of different layers in the application stack</li> <li>Flexibility to change the application built on it</li> <li>Clarity of abstractions</li> </ul> <p>Finally, the developer is also an end user and will also benefit from usefulness, usability, discoverability and so on.</p> <h4>Design Considerations</h4> <p>With these goals in mind, I propose the following design considerations. Again, since design is non-deterministic, these considerations can help you to make decisions in the open-ended design process that will tend to point you toward a better final product.</p> <h5>Design for Adoption</h5> <p>The entire purpose of an API is for people to use it. If you're not sure how to design something, use this question as a guide: <strong>What will make it easier for users to understand how this works and how to use it?</strong></p> <p>If you force yourself to be a user, you will be more inclined to look at the API from the user's perspective.</p> <h5>Design for Maintainability</h5> <p>Developers spend more time fixing, refactoring and modifying existing code than they spend creating new code. Your API should be designed in such a way that it is easy to dive in and work with existing code. One way to achieve this is through what the Rails developers call <a href="http://en.wikipedia.org/wiki/Convention_over_configuration">convention over configuration</a>. An architecture that builds on established standards will be easier to maintain.</p> <h4>Web Service APIs</h4> <p>There are two basic kinds of web service:</p> <ol> <li>Arbitrary Remote Procedure Calls (RPC)</li> <li>Hyper-Text Transfer Protocol (HTTP)</li> </ol> <h5>Remote Procedure Calls</h5> <p>RPC is a client/server model that allows a client to execute a remote procedure as if it was a local procedure. It uses HTTP as a dumb transport tunnel, and all the objects, methods and data required to call the procedure are transferred inside the message body.</p> <p>RPC is <em>arbitrary</em> in that the method of transferring data and methods over HTTP varies from one type to another. A number of competing RPC protocols emerged in the early days of the internet: CORBA, XML-RPC, MS-RPC, and so on.</p> <h5>SOAP</h5> <p>By the end of the 1990s, one format had emerged as a de facto standard: Simple Object Access Protocol (SOAP), which was a formal attempt to standardize XML-RPC.</p> <p>A SOAP web service, all methods are accessed via a single endpoint URL. Methods and data are transferred inside an XML payload, and all requests use the HTTP POST method. </p> <p>The functionality in a SOAP web service is defined in a Web Services Description List (WSDL).</p> <h5>SOAP Benefits</h5> <p>SOAP was an improvement over previous RPC approaches. Because it was more or less standardized, it allowed for push-button tooling and deployment. The WSDL allowed properly configured clients to introspect the web service's functionality and abstract away the "web" part of the transaction.</p> <h5>SOAP Problems</h5> <p>However, these benefits are not unalloyed. The XML payloads are extremely verbose and not very human-readable. The standards are arbitrary, poorly defined and have changed more or less constantly for over a decade.</p> <p>Worse, the system is designed to be interoperable, but a client in, say, C# often cannot consume a WSDL built in Java. At bottom, SOAP is a <em>leaky abstraction</em> that promises easy tooling and wide accessibility but often fails to deliver.</p> <p>But the worst problem with SOAP is that it re-invents the functionality of HTTP <em>on top</em> of HTTP. It tunnels through the web, but does not work <em>like</em> the web.</p> <h3>Hyper-Text Transfer Protocol (HTTP)</h3> <p>Often called "Representational State Transfer" (REST), an HTTP web service is a client/server model that works like the web. The client makes an HTTP request to the server, and the server sends a response back to the client.</p> <p>HTTP web services are <strong>stateless</strong>: each request contains all the information needed to process it. HTTP web services are also <strong>cacheable</strong> and can define rules around which responses can be stored locally or in an intermediate server.</p> <p>The concept was formalized in 2000 by <a href="http://roy.gbiv.com/">Roy Fielding</a>, one of the architects of Hypertext Transfer Protocol (HTTP), in his <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">doctoral dissertation</a>. It is not surprising, then, that REST and HTTP mesh very smoothly.</p> <p>A RESTful client-server system is <strong>stateless</strong>, meaning each request against the server contains all the information the server needs to process it; and <strong>cacheable</strong>, in that the server can specify whether and for how long resource representations can be cached either locally on the client or on intermediate servers between the client and the server.</p> <h4>HTTP</h4> <p>Hypertext Transfer Protocol (HTTP) is a stateless protocol based on a client requesting a resource across a network and the server providing a response. As such, an HTTP transaction entails a request and a response. The request goes from the client to the server, and the response goes from the server back to the client.</p> <h4>HTTP Requests and Responses</h4> <p>In HTTP, the client makes an <strong>HTTP request</strong> to the server and the server issues an <strong>HTTP response</strong>. </p> <h5>Requests</h5> <p>An HTTP request has three parts: </p> <ol> <li><p>The request line, which includes the HTTP method, the URL and the HTTP version: <code>GET /users/1 HTTP/1.1</code></p></li> <li><p>One or more optional HTTP headers, which are key/value pairs with metadata about the data being requested and/or provided.</p></li> <li><p>An optional message body, which is data being sent from the client to the server as part of the request. E.g. in a POST request, the message body will include the data that the server should use to create a new resource.</p></li> </ol> <h5>Response</h5> <p>An HTTP response also has three parts:</p> <ol> <li><p>The HTTP <strong>Status Code</strong>, which indicates the status of the requested resource: <code>HTTP/1.1 200 OK</code></p></li> <li><p>One or more optional HTTP headers, which are key/value pairs with metadata about the response being provided.</p></li> <li><p>An optional message body, which is a representation of the resource that was requested (hence the name "Representational State Transfer").</p></li> </ol> <h4>URLs and Resources</h4> <p>In a RESTful architecture, each URL represents a <strong>resource</strong>. This is vitally important: a resource is a noun, an object, and not the action performed on it. </p> <p>A RESTful web service has multiple endpoints - one for each resource. (Contrast SOAP, which has only one endpoint and puts everything else - objects, methods, parameters, etc. - into the XML payload.)</p> <p>If you find yourself creating URLs like <code>/create_user</code>, you're doing it wrong. Instead, create a URL like <code>/users</code> and map your user object to that URL. </p> <p>Remember: a resource is a noun, not a verb.</p> <h4>HTTP Methods</h4> <p>If a resource is a noun, the <strong>HTTP Method</strong> is the verb. What you do to the resource with your request depends on what <strong>method</strong> you use. If a URL is an object, the HTTP method is the action you execute on that object. </p> <table> <caption>HTTP Methods</caption> <thead> <tr> <th>Method</th> <th>Action</th> </tr> </thead> <tbody> <tr> <td>GET</td> <td>Retrieve a resource</td> </tr> <tr> <td>POST</td> <td>Create a new resource</td> </tr> <tr> <td>PUT</td> <td>Update an existing resource</td> </tr> <tr> <td>DELETE</td> <td>Delete an existing resource</td> </tr> </tbody> </table> <p>In our user example, execute an HTTP POST request on <code>/users</code> to create a new user. The server should respond with the specific URL of the user you created: <code>/users/1</code>. </p> <p>To view a representation of that resource, issue an HTTP GET request on the user's URL: <code>/users/1</code>. </p> <p>To update the user, issue an HTTP POST request on the user's URL with the new user data in the request body. </p> <p>To delete the user, issue an HTTP DELETE request on the user's URL.</p> <h5>GET Method</h5> <p>To retrieve a resource, issue an HTTP GET request. GET requests are idempotent (see below), which means making a GET request multiple times does not cause any change in the resource that is requested.</p> <p>GET requests do not include a message body, but GET responses usually do.</p> <h5>POST Method</h5> <p>To submit data to be processed, issue an HTTP POST request. POST requests require a message body, i.e. the data to be processed.</p> <p>For example, if there is a resource called <code>/articles</code> and you want to add a new article, issue a POST request to <code>/articles</code> with the content. The server should create a new subsidiary URI under <code>/articles</code> - for example, <code>/articles/1</code> - and assign that URL to the content you sent with your POST request.</p> <p>Important note: POST requests are <em>not</em> idempotent, meaning multiple POST requests will create multiple resources with unique identifiers.</p> <h5>PUT Method</h5> <p>To update the resource at an existing URL, issue an HTTP PUT request on that URL. For example, if there is a URL <code>/articles/1</code> and you want to replace the content served at that URL, issue a PUT request to that URL with the new content.</p> <p>Important note: PUT requests <em>are</em> idempotent, so issuing 2 or 5 or 50 identical PUT requests will have the same effect on the resource as issuing just one PUT request. Like POST requests, PUT requests include a message body (the resource to be placed at the URL).</p> <h5>DELETE Method</h5> <p>To remove a resource (and remove its accompanying URL), issue an HTTP DELETE request. DELETE requests should be idempotent, i.e. issuing 1 or 2 or 5 or 50 identical DELETE requests will delete exactly one resource. DELETE requests do not require a message body.</p> <h4>Idempotence</h4> <p>This funny-looking word is really important: a request is <strong>idempotent</strong> if making it multiple times has the same effect as making it just once. Read that again if you have to.</p> <p>A request is <em>not</em> idempotent if issuing it more than once has a different effect than issuing it once. </p> <p>For example, a POST request to add a comment to a document is not idempotent: issuing the POST request twice adds the comment twice, so that the document contains two comments with unique URLs. </p> <p>However, a PUT request to update an existing comment <em>is</em> idempotent: whether you execute the request once, twice or twenty times, the result will be exactly the same.</p> <h4>HTTP Headers</h4> <p>Both HTTP requests and responses can include optional <strong>HTTP Headers</strong>, or key/value pairs that supply meta-data about the request and the response. </p> <h5>Accept Header</h5> <p>An HTTP request can include an <code>Accept</code> header that specifies what media types the client will accept in a response.</p> <p>In a REST web service, the request should include an <code>Accept</code> header with the preferred media type - e.g. <code>application/json</code> - and the server should attempt to fulfill the client's preference in its response, given its capabilities.</p> <p>If you are willing or required support multiple formats (e.g. JSON, XML, YAML), the best way for the client to specify what format they prefer is via the <code>Accept</code> header. </p> <p>Here are some examples of Accept headers:</p> <ul> <li><p>JSON: <code>Accept: application/json</code></p></li> <li><p>XML: <code>Accept: application/xml</code></p></li> <li><p>YAML: <code>Accept: application/x-yaml</code></p></li> </ul> <p>Note: YAML has an <code>x-</code> prefix because it is not a formalized MIME type. For thoroughness, you could accept all four possibilities:</p> <pre><code>application/x-yaml, application/yaml, text/x-yaml, text/yaml </code></pre> <h4>HTTP Status Codes</h4> <p>HTTP has a great way of telling the client whether the request was successful or an error has occurred: HTTP status codes. Every HTTP response includes a <code>status</code> header with an <strong>HTTP status code</strong> that indicates the status of the request. </p> <p>This tells the client whether the request was successful or not, and what to expect by way of a response. It's important to send the right status code.</p> <p class="image"><img src="https://farm8.staticflickr.com/7148/6508023065_8dae48a30b.jpg" title="401 Unauthorized (Image Source: Flickr)"><br>401 Unauthorized (Image Source: <a href="https://secure.flickr.com/photos/girliemac/sets/72157628409467125/with/6508022985/">Flickr</a>)</p> <p>I also include HTTP status codes and error descriptions in the response body. A REST purist might call this overkill, but remember that you want to make your API as self-documenting and easy to use as possible. </p> <p>For the purposes of your web service, there are three categories of HTTP status codes you need to worry about: success codes, client error codes, and server error codes.</p> <h5>Success Codes</h5> <p>HTTP success status codes provide useful information about successful requests:</p> <ul> <li><strong>200 OK</strong> - A GET request was successful at retrieving a resource.</li> <li><strong>201 Created</strong> - A POST request was successful at creating a resource.</li> <li><strong>202 Accepted</strong> - This means the request was accepted but the response is not ready. Useful for queued or otherwise deferred processes.</li> </ul> <h5>Client Error Codes</h5> <ul> <li><strong>400 Bad Request</strong> - The request data could not be parsed properly, or a value was missing or invalid.</li> <li><strong>401 Unauthorized</strong> - The user requested an access-restricted resource but authentication either failed or was not provided.</li> <li><strong>404 Not Found</strong> - The user tried to request a resource that does not exist.</li> <li><strong>405 Method Not Allowed</strong> - User tried to execute an HTTP method on a resource that does not allow it. E.g. a POST request against <code>/users/charlie</code> instead of <code>/users</code>.</li> <li><strong>406 Not Acceptable</strong> - The request came with an <code>Accept</code> header for a media type that the server cannot provide in the response.</li> <li><strong>410 Gone</strong> - A previously available resource has been removed permanently.</li> <li><strong>429 Too Many Requests</strong> - Useful if you've rate-limited your API for a given user.</li> </ul> <h5>Server Error Codes</h5> <ul> <li><strong>500 Internal Server Error</strong> - Try to avoid this one. It generally means your web service is broken.</li> <li><strong>501 Not Implemented</strong> - User has tried to send a request method that your server doesn't recognize.</li> <li><strong>503 Service Unavailable</strong> - This tells the client the service disruption is temporary.</li> </ul> <h4>Media Types</h4> <p>In an industry known for bad acronyms, this may be the worst: <strong>Hypertext As The Engine Of Application State</strong> (HATEOAS) is a mandatory requirement for a web service to meet Roy Fielding's criteria of a "RESTful" design. </p> <p>Here's how Fielding explained it in a <a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">blog post</a> that took issue with the profusion of web services that called themselves "RESTful" but clearly weren't:</p> <blockquote> <p>A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]</p> </blockquote> <p>There, isn't that clear? </p> <p>In short, Fielding's requirement is that a client should not need <em>any</em> out-of-band information to be able to access, navigate, use and execute a web service. All it should need to know are the base URL endpoint and the media type (identified as the <code>Content-Type</code> header in the response) of the web service so it knows how to interpret the responses. </p> <p>In other words, if your web service has a custom way of identifying hypertext URLs in its responses, your web service must also have a dedicated media type that corresponds to how your service works and includes a description of how it works.</p> <p>In other words, if the client has to read your documentation to discover how your web service works, it is <em>not</em> RESTful because it depends on out-of-band information (i.e. the documentation); but if your web service has a custom media type and the client needs only to read a bunch of documentation to understand how your media type works, it <em>is</em> RESTful because it doesn't depend on out-of-band information.</p> <h3>Designing a RESTful Web Service</h3> <h4>Don't Reinvent the Wheel</h4> <p>HTTP was invented to allow clients to request resources from servers across the internet and for those servers to respond with representations of those resources. The entire internet runs on it. It's flexible, powerful and offers a clean abstraction model based on resources and methods.</p> <p>Don't re-implement what HTTP does in an ad-hoc way on top of HTTP. Just use HTTP. </p> <p>Many web services only use HTTP as a network tunneling protocol, and then pass objects, methods and parameters inside an 'envelope' that contains all the information. This type of web service architecture includes SOAP and other Remote Procedure Call (RPC) formats.</p> <p>Web services that actually use HTTP the way it was designed are called <strong>Representative State Transfer</strong> (REST) web services. Unfortunately, REST is widely misunderstood and a lot of web services that call themselves "RESTful" aren't.</p> <h4>Discoverable API</h4> <p>In a RESTful web service, a GET request on a base API URL returns a list of resources available in the API. Critically, each resource has a direct URL. This makes it very easy for developers to step into your API and figure out what is available.</p> <p>Now, you may be thinking you've seen this pattern before. You're right: it's exactly how every single website works. Go to the homepage, and what do you find? Links to the other resources on the website! </p> <p>A RESTful approach makes your URLs hackable. If your API user is looking at a URL like: <code>/cats/miss_mew</code>, they should be able to lop off the <code>/miss_mew</code> and do a GET request against <code>/cats</code> to return the base collection of cats (each with its own URL, of course).</p> <h4>REST Resource/Method Matrix</h4> <p>At a conceptual level, a RESTful web service API is a matrix of resources and methods that exposes the functionality of the service to third party applications. Below is an example of what that matrix might look like.</p> <p>Again, I will repeat that actions are not mapped to URLs. A resource is an object - a noun - and the action inheres to the HTTP method - a verb - not to the URL. </p> <p>As a result, the same resource URL can serve different responses (corresponding with different actions) depending on the HTTP method used.</p> <table> <caption>REST Resource/Method Matrix</caption> <thead> <tr> <th colspan="4">Request</th> <th colspan="3">Response</th> <th rowspan="2">Idempotent</th> </tr> <tr> <th>Resource</th> <th>URL</th> <th>Method</th> <th>Request Data</th> <th>Server Action</th> <th>Response Body</th> <th>Status Code</th> </tr> </thead> <tbody> <tr> <td>Users</td> <td>/users</td> <td>GET</td> <td></td> <td>retrieves list of users</td> <td>list of users and associated URLs</td> <td>200 OK</td> <td class="green">Yes</td> </tr> <tr> <td>Users</td> <td>/users</td> <td>POST</td> <td>user details</td> <td>creates a new user</td> <td>new URL and user representation</td> <td>201 Created</td> <td class="red">No</td> </tr> <tr> <td>User 9001</td> <td>/users/9001</td> <td>GET</td> <td></td> <td>retrieves details for user 9001</td> <td>user representation</td> <td>200 OK</td> <td class="green">Yes</td> </tr> <tr> <td>User 9001</td> <td>/users/9001</td> <td>PUT</td> <td>new user details</td> <td>updates user details</td> <td>updated user representation</td> <td>200 OK</td> <td class="green">Yes</td> </tr> <tr> <td>User 9001</td> <td>/users/9001</td> <td>DELETE</td> <td></td> <td>deletes user 9001</td> <td>returns status</td> <td>200 OK</td> <td class="green">Yes</td> </tr> <tr> <td>User 9001</td> <td>/users/9001</td> <td>GET</td> <td></td> <td>checks that user 9001 does not exist</td> <td>Not found error message</td> <td>404 Not Found</td> <td class="green">Yes</td> </tr> </tbody> </table> <h4>Use JSON</h4> <p>JavaScript Object Notation (JSON) is a data serialization format that delivers an optimal combination of the following criteria:</p> <ul> <li><strong>Lightweight</strong> - less boilerplate means less data transfered across the network</li> <li><strong>Readable</strong> - Humans can easily see and understand the content of a JSON object</li> <li><strong>Flexible</strong> - allows various nestable data types: object (dictionary), array (ordered list), string, integer, float, boolean</li> <li><strong>Interoperable</strong> - every programming language and framework under the sun can generate and consume JSON.</li> <li><strong>Convertable</strong> - JSON can be converted into a native object more easily than XML.</li> </ul> <p>Here's an example of a response to an API base URL GET request, represented in JSON:</p> <pre><code>{ "ok": true, "status_code": 200, "resources": [ { "url": "/authors", "resource": "authors" }, { "url": "/articles", "resource": "articles" }, { "url": "/blogs", "resource": "blogs" }, { "url": "/comments", "resource": "comments" }, { "url": "/events", "resource": "events" } ] } </code></pre> <p>Unless you've got a compelling business or technical reason for using a different media type, stick with JSON.</p> <p>Just remember: if you want to satisfy HATEOAS, you need to give your web service a dedicated media type, e.g.:</p> <pre><code>application/vnd.my-ad-hoc-web-service+json </code></pre> <p>Note that the <code>vnd</code> prefix refers to a vendor-specific media type, e.g. <code>application/vnd.google-earth.kml+xml</code> for Google Earth KML files.</p> <h4>Search</h4> <p>Since grammatically, "search" can be a noun as well as a verb, it's okay to have a URL called <code>/search</code>. Arguably, the best way to filter the response a server delivers to a GET request on <code>/search</code> is to use a querystring:</p> <pre><code>/search?doctype=article&keyword=hello%20world </code></pre> <p>It is possible to do this without a querystring - something like:</p> <pre><code>/search/doctype/article/keyword/hello%20world </code></pre> <p>But that's silly and pedantic - and arguably wrong, anyway. It's harder for your users to guess and it's harder for you to parse.</p> <h4>Pagination</h4> <p>When your user does a GET request on <code>/api/cats</code>, do they really want a list of 7 million cats? Do you really want to have to serve that and support the processing and bandwidth involved?</p> <p>Again, I don't think there's anything wrong with using querystrings here:</p> <pre><code>/api/cats?offset=101&limit=50 </code></pre> <p>Similarly, I don't think there's anything wrong with using terminology that is familiar to developers who work with databases. </p> <h4>Versioning</h4> <p>Your API is a contract you have made with your users. If you plan to introduce a change to your API that breaks backwards compatibility, you need to do so in such a way that it doesn't break existing clients.</p> <p>There is no easy, obvious way to do this that will make everyone happy, satisfy REST and satisfy the goal of making your API usable and discoverable.</p> <p>There are a few different ways you can version your API, all of which have pros and cons.</p> <h5>Versioning in URL</h5> <p>Many popular web APIs do this: <code>/api/v1/cats</code>. If you roll out a version 2 of your API that would break clients using version 1, you expose it at <code>api/v2/cats</code>.</p> <ul> <li>Pro: it's easy for users to understand and doesn't break existing clients.</li> <li>Con: results in multiple URLs for the same resource; locks versioning into the URL; multiplies API maintenance issues.</li> </ul> <h5>Versioning in Querystring</h5> <p>Some APIs do this: <code>api/cats?v=1</code>.</p> <ul> <li>Pro: default URL doesn't need to include version (defaults to newest version); one URL for each resource.</li> <li>Con: clients that don't explicitly specify a version will break when the API is updated.</li> </ul> <h5>Versioning in Accept header</h5> <p>REST purists recommend putting the version in a custom Accept header: <code>Accept: application/vnd.company.app-v1+json</code></p> <ul> <li>Pro: default URL doesn't need to include version; one URL for each resource; changes do not break clients; version is a formatting issue so it's the "right" place.</li> <li>Con: more esoteric and difficult for developers to discover how it works.</li> </ul> <h4>Use Secure HTTP</h4> <p>I don't want to say too much about security (though I do recommend the <a href="https://www.owasp.org/index.php/REST_Security_Cheat_Sheet">REST Security Cheat Sheet</a> - Draft document from the Open Web Application Security Project (OWASP) as a handy reference), but I will say a quick word in support of Secure HTTP - or HTTPS - rather than plaintext HTTP.</p> <p>HTTPS is a bit slower, but on a web service, you're not making multiple requests to pull down javascripts, CSS, image files and so on, so you can afford to take a small hit for an encrypted connection. </p> <p>The payback in client security is worth it.</p> <h4>Summary of Benefits</h4> <p>It's extremely easy to lose yourself in theory and get sucked into the purity movement (remember XHTML?). If REST doesn't deliver practical results, it doesn't matter how elegant, pure or canonical it claims to be.</p> <p>In short, a RESTful API is discoverable and navigable. With no background knowledge, a client can do a GET request on the root URL to get a list of resources with URLS. It's easy to dive right in and quickly figure out what is available.</p> <h5>Better URLs</h5> <p>Stable, persistent URLs allow for resource bookmarking and better search indexing. </p> <p>Sane, well-named URLs are more descriptive than arcane or arbitrarily named URLs. </p> <p>Hackable URLs allow for better resource discovery.</p> <h5>Developers Understand HTTP</h5> <p>REST is essentially just HTTP, and we already understand HTTP (with an important caveat, below). </p> <p>The API developer doesn't need to waste time and energy (badly) reinventing/re-implementing what HTTP does on top of HTTP.</p> <p>The client doesn't need to waste time and energy learning a bunch of ad hoc RPC protocols.</p> <h5>Our Tools Understand HTTP</h5> <p>Just about every programming language can natively perform an HTTP request and parse the response (with an important caveat, below).</p> <h3>Problems with REST</h3> <p>REST comes with its own issues, of course, and it would be disingenuous to gloss over them.</p> <h4>Requires Proper Understanding of HTTP</h4> <p>Much as I wrote earlier that REST is just HTTP and we all understand HTTP, the honest fact is that we don't understand HTTP <em>all that well</em>.</p> <p>It's true we've all been using it for 20 years now, but for various historical, cultural and educational reasons, there's a constant tension between understanding and using our protocols the way they were designed and knowing just enough to <em>build something that gets the job done</em>.</p> <p>That latter imperative lowers the barrier to entry into web development, but it also leads to the same avoidable mistakes being made over and over again in applications that require a more professional approach: SQL injection, XSS, hacked cleartext passwords, and so on.</p> <p>We've all heard horror stories about web applications that didn't understand HTTP and blew up when a search engine bot innocently crawled a GET request to <code>/delete_user.php?username=Ryan</code> and thereby wiped out the entire database.</p> <p>For a newbie developer who doesn't really understand HTTP very well, a web service with URLs like <code>/api/create_user</code> is more immediately obvious than a web service with URLs like <code>/api/users</code> that require a POST request to create a user.</p> <p>However, this is changing as the benefits of REST become more widely known and more developers start to take advantage of its defining characteristics.</p> <p>One thing is for certain: once you've developed and built on a REST web service, you'll finally understand HTTP inside and out. </p> <h4>Tooling</h4> <p>SOAP advocates argue that mature tooling makes it easy for a service provider to deploy a WSDL and for clients to consume it and execute web service methods as if they were local function calls.</p> <p>Of course, the reality is less rosy: leaky abstractions, incompatible data types, lack of interoperability between, say, a Java WSDL and a C# SOAP client, and so on. </p> <p>In far too many cases, I've had to hand-roll an ad-hoc SOAP client and build my own XML templates when a supposedly push-button WSDL turned out to be platform-dependent. Instead of saving time by consuming a WSDL, I was stuck painstakingly reverse-engineering the RPC formatting details that the interface tried unsuccessfully to hide.</p> <p>Still, SOAP has that enterprise-friendly turnkey appeal, even if the delivery doesn't fulfill the promise. </p> <p>REST, on the other hand, is sorely lacking in push-button tooling - on both the framework development and client side.</p> <p>Even tools that ought to know better tend to abstract away the HTTP methods from the developer and generically treat every request as a GET request - unless it comes with form data or hits a kludgy <code>/process_form</code> kind of an URL.</p> <p>We've come a long way from the <code>cgi-bin</code> form processing scripts of the '90s, but we still have a way to go. The good news is that this changing as developers come to recognize the benefits that come from understanding and using HTTP the way it was designed.</p> <h5>Frameworks</h5> <p>Most web application frameworks weren't developed with HTTP in mind, but rather with the minimal subset of HTTP that that is comprised of viewing web pages and filling out forms. Data transfer and processing, even in web applications designed for human users, tends unconsciously to follow an RPC model.</p> <p>There are already a few that have embraced the full functionality of HTTP more deeply. </p> <p>I'm not that familiar with Ruby, but I understand <a href="http://rubyonrails.org/">Rails 3</a> is designed to <a href="http://guides.rubyonrails.org/v2.3.8/routing.html">work RESTfully</a> right out of the box with its routing DSL. </p> <p>Similarly, the lightweight <a href="http://www.sinatrarb.com/">Sinatra</a> framework understands resources and methods natively and simply:</p> <pre><code>require 'sinatra' get '/users' do # show users end get '/users/1337' do # show a user end post '/users' do # create a user end put '/users/1337' do # update a user end delete '/users/1337' do # delete a user end </code></pre> <p>In Python, <a href="https://www.djangoproject.com/">Django</a> is not RESTful by design has some good <a href="http://django-rest-framework.org/">REST plugins</a>. </p> <p>The lightweight Python framework I use, <a href="http://webpy.org/">web.py</a>, is REST-friendly at its core: resources map to classes and HTTP methods map to class methods.</p> <pre><code>import web app = web.application(urls, globals()) urls = ('/users/(.*)', 'User') class User(object): def GET(self, name): # get a resource def POST(self, name): # create a resource def PUT(self, name): # update a resource def DELETE(self, name): # delete a resource </code></pre> <p>In PHP, you've got <a href="http://framework.zend.com/manual/en/zend.rest.server.html">Zend_REST</a>, <a href="http://www.recessframework.org/">Recess</a>, <a href="http://peej.github.com/tonic/">Tonic</a> and others that understand and support RESTful API design.</p> <p>The .Net framework has <a href="http://msdn.microsoft.com/en-us/netframework/aa663324">Windows Communications Foundation</a> (WCF). Java has <a href="http://www.playframework.org/">Play</a> <a href="http://www.restlet.org/">RESTlet</a>, <a href="https://jersey.dev.java.net/">Jersey</a> and so on.</p> <h5>Client Tools</h5> <p>Nearly every language understands HTTP, but too many default HTTP modules understand HTTP in a crippled, semi-literate way that reflects how most browsers use HTTP: fetch pages or fill out forms.</p> <p>In Python, there are no less than three HTTP libraries that ship with the language: <code>urllib</code>, <code>urllib2</code> and <code>httplib</code> - and none of them make the full expressiveness of HTTP particularly accessible.</p> <p>Fortunately, third party developers have stepped in with libraries like <a href="https://code.google.com/p/httplib2/">httplib2</a> and <a href="https://code.google.com/p/httplib2/">requests</a>, which do a much better job of exposing all the HTTP methods in a sane, consistent manner.</p> <p>Similarly, REST-aware clients are appearing in other languages as well. </p> <p>If you're a .net shop, you've got tools like <a href="http://restsharp.org/">RestSharp</a>. </p> <p>Of course, JavaScript understands HTTP natively, perhaps better than some other, more "mature" and "full-featured" languages - possibly because JavaScript lives in browsers and breathes HTTP.</p> <pre><code>var xmlhttp=new XMLHttpRequest(); // GET request xmlhttp.open("GET", "/users", true); xmlhttp.send(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { alert('GET request successful'); // response is in xmlhttp.responseText } } // POST request var jsonObject = {"username": "ryan", "fullName": "Ryan McGreal"}; var jsonString = JSON.stringify(jsonObject); xmlhttp.open("POST", "/users", true); xmlhttp.setRequestHeader("Content-Type","application/json"); xmlhttp.send(jsonString); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { alert('POST request successful'); // response is in xmlhttp.responseText } } // PUT request var jsonObject = {"username": "ryan", "fullName": "Ryan G. McGreal"}; var jsonString = JSON.stringify(jsonObject); xmlhttp.open("PUT", "/users/ryan", true); xmlhttp.setRequestHeader("Content-Type","application/json"); xmlhttp.send(jsonString); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { alert('PUT request successful'); // response is in xmlhttp.responseText } } // DELETE request xmlhttp.open("DELETE", "/users/ryan", true); xmlhttp.send(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { alert('DELETE request successful'); // response is in xmlhttp.responseText } } </code></pre> <p>JavaScript also has a panoply of frameworks and libraries that make HTTP requests even easier:</p> <pre><code>// yay jQuery! $.get("/users", function(response){ alert('GET request successful'); }); $.post("/users", data, function(response){ alert('POST request successful'); }); $.put("/users/ryan", data, function(response){ alert('PUT request successful'); }); $.delete("/users/ryan", function(response){ alert('PUT request successful'); }); </code></pre> <p>So the tools for creating and consuming REST web services are steadily improving, while the tools for creating and consuming SOAP web services are over-engineered and IMHO over-rated.</p> <p>In the meantime, REST makes up in discoverability and navigability what it lacks in automated tooling.</p> <h5>Browsers</h5> <p>Of all our tools for working with HTTP, the most universal is the browser. It's the easiest way to browse a web service API, particularly if it works like the web itself. After all, the URL is just a resource on a server accessible via HTTP, and browsers are specifically designed to make HTTP requests and present the responses to users.</p> <p>However, like other established HTTP-based tools, most browsers are only good at GET and POST requests, not PUT or DELETE requests. Even then, POST requests generally require an HTML form that the user can fill in and submit. </p> <p>In addition, most browsers are not good at rendering representations in formats other than HTML or XML.</p> <p>I use Firefox as my main browser (yes, I'm old-fashioned), and I've discovered a few add-ons that make exploring web APIs a lot easier:</p> <ul> <li><a href="https://addons.mozilla.org/en-US/firefox/addon/httpfox/?src=search">HttpFox</a> - an HTTP analyzer.</li> <li><a href="https://addons.mozilla.org/en-US/firefox/addon/jsonview/?src=search">JSONView</a> - pretty-prints JSON response objects in the browser window.</li> <li><a href="https://addons.mozilla.org/en-US/firefox/addon/modify-headers/?src=search">Modify Headers</a> - Add, modify and filter the HTTP request headers sent to a web server.</li> <li><a href="https://addons.mozilla.org/en-US/firefox/addon/restclient/?src=search">RESTClient</a> - Visit and test REST/WebDav services.</li> </ul> <h4>REST is a Spectrum</h4> <p>Ultimately, it makes sense to talk about an API being <em>more</em> or <em>less</em> RESTful and you probably shouldn't kill yourself to reach 100.00000%.</p> <p>Like anything else, REST purity is subject to diminishing returns. If you get the important stuff correct - URLs are resources, methods are actions, representations include URLs - you'll get to enjoy the main benefits of a REST design approach without tearing your hair out. </p> <p>For each choice, ask yourself whether the benefit of going more RESTful justifies the cost. Keep in mind that your goal is to make your API as usable and discoverable as possible.</p> <h3>References</h3> <ul> <li><p><a href="http://nordsc.com/ext/classification_of_http_based_apis.html">Classification of HTTP-based APIs</a></p> <p><a href="http://nordsc.com/ext/classification_of_http_based_apis.html">http://nordsc.com/ext/classification_of_http_based_apis.html</a></p></li> <li><p><a href="http://martinfowler.com/articles/richardsonMaturityModel.html">Richardson Maturity Model</a> - A model (developed by Leonard Richardson) that breaks down the principal elements of a REST approach into three steps. These introduce resources, http verbs, and hypermedia controls.</p> <p><a href="http://martinfowler.com/articles/richardsonMaturityModel.html">http://martinfowler.com/articles/richardsonMaturityModel.html</a></p></li> <li><p><a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">REST APIs must be hypertext-driven</a> - Roy Fielding's attempt to get people to understand what he was talking about when he defined REST.</p> <p><a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven</a></p></li> <li><p><a href="https://www.youtube.com/apigee#p/c/5/R8SIxZVaai4">RESTful API Design - Pragmatic REST</a> - Webinar by Apigee.</p> <p><a href="https://www.youtube.com/apigee#p/c/5/R8SIxZVaai4">https://www.youtube.com/apigee#p/c/5/R8SIxZVaai4</a></p></li> <li><p><a href="https://www.owasp.org/index.php/REST_Security_Cheat_Sheet">REST Security Cheat Sheet</a> - Draft document from the Open Web Application Security Project (OWASP)</p></li> <li><p><a href="https://www.ibm.com/developerworks/webservices/library/ws-restful/">RESTful Web Services: The Basics</a> - IBM developerWorks article</p> <p><a href="https://www.ibm.com/developerworks/webservices/library/ws-restful/">https://www.ibm.com/developerworks/webservices/library/ws-restful/</a></p></li> <li><p><a href="http://stackoverflow.com/a/1619677/682547">General Principles for Good URI Design</a> - StackOverflow answer</p> <p><a href="http://stackoverflow.com/a/1619677/682547">http://stackoverflow.com/a/1619677/682547</a></p></li> </ul> <h3>Video</h3> <p>Here is a video of my talk at Hamilton DemoCamp #5.</p> <div style="text-align: center"> <iframe width="560" height="315" src="http://www.youtube.com/embed/IIFyz8SndhY" frameborder="0" allowfullscreen></iframe> </div> Ryan McGreal 2 http://quandyfactory.com/blog/89/python_string_formatting_with_dictionaries 2012-01-04T12:00:00Z Python String Formatting With Dictionaries <p>My mind is duly blown. I never realized that the traditional printf-style string formatting in Python - the kind that uses the % operator - supports the use of a dictionary as well as a tuple.</p> <p>The following works:</p> <pre><code>&gt;&gt;&gt; data = { 'title': 'Python String Formatting With Dictionaries', 'author': 'Ryan McGreal', 'summary': 'In Python, you can use dictionaries instead of tuples to populate values via classic string formatting.', 'content': '&lt;p&gt;My mind is duly blown...', 'author_bio': 'Ryan McGreal lives in Hamilton with his family and works as a programmer and writer.', } &gt;&gt;&gt; template = """&lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;title&gt;<span style="color: red">%(title)s</span>&lt;/title&gt; &lt;/head&gt; &lt;body&gt; &lt;article&gt; &lt;header&gt; &lt;hgroup&gt; &lt;h1&gt;<span style="color: red">%(title)s</span>&lt;/h1&gt; &lt;h2&gt;By <span style="color: red">%(author)s</span>&lt;/h2&gt; &lt;h3&gt;<span style="color: red">%(summary)s</span>&lt;/h3&gt; &lt;hgroup&gt; &lt;/header&gt; <span style="color: red">%(content)s</span> &lt;footer&gt; <span style="color: red">%(author_bio)s</span> &lt;/footer&gt; &lt;/article&gt; &lt;/body&gt; &lt;/html&gt;""" &gt;&gt;&gt; print template % data </code></pre> <p>As an ultra-lightweight templating engine, this is pretty sweet: it's fast, simple, supports Unicode, and has no third-party dependencies.</p> Ryan McGreal 2