[Author's note: The blogosphere has plenty to say about cloud computing, but most content targets the business, CIO, or IT crowds. Information for developers who want to produce software friendly to cloud computing exists, but it's more scattered and doesn't match the SEO profile that obsesses much of the industry. As a result, I believe that many developers have only hazy ideas about how they can leverage the power of the cloud to provide radical improvements in scale, responsiveness, and connectivity for their customers.
This ought to change. Cloud computing isn't just interesting to datacenter managers; it enables many new technological strategies. Cloud-savvy engineering can boldly go where no software has gone before—if we're smart enough to take it there.
This post is the first in a series that teaches developers how to "cloudify"their designs and code. Please subscribe, follow me on twitter or Google+, and check back weekly to explore the topic in full.]
One of the central themes in Orson Scott Card’s novel, Ender’s Game, is that you can’t effectively compete in battle until you truly view situations through the eyes of your enemy. You must anticipate the assumptions they will make, the sacrifices that feel rational to them, and the value system that informs their tradeoffs.
This is a tall order, when you’re not fighting Homo sapiens. Ender is a military commander who’s forced to get inside the mind of an enemy that doesn’t think like humans. The buggers have a queen. They communicate telepathically. The individual is incidental. They have a hivemind.
Until Ender takes over, this alien Weltanschauung is causing humanity to lose the war. Badly.
How does this relate to cloudifying software? Well, to do a good job of adapting software to the cloud, developers have to learn to think differently. The cloud’s not the enemy, but it certainly turns much conventional wisdom on its head. For example:
In cloudthink, applications outlive machines.
In traditional software development, it’s more common to think of the ecosystem that hosts your application as static, configured once with great care, and living longer than your application. In the brave new world, machines are clonable, disposable units that come and go fluidly. So do VLANs, firewalls, load balancers, databases… This ties directly to the idea that software should be subscribable, rather than involving major capital expense and long rollouts, and it changes our view of what is an acceptable “install” experience. We stopped shipping a box of CDs and a manual a decade ago; now it’s time to embrace a model where the software bootstraps itself into the cloud and automatically brings components online—or takes them offline—using smart policy.
In cloudthink, latency requires careful planning.
Hard-core performance zealots might argue that this has always been true, but in traditional models, rules of thumb were usually adequate guidelines for decision-making. RAM was faster than spindles, which were faster than the network, which was faster than unsync’ed tape, which was faster than deep archive.
We’ve now grown up. A cloud-savvy application might have half a dozen different network pipes that it uses, each of which might have a unique performance profile. Saving something to “disk” might involve various interesting network hops and/or virtualization layers; reading it back might use a totally different path. AWS-style provisioned IOPS allow you to rent the throughput you need, and may even give you the option of bursting during peak hours. (And speaking of peak hours—the global nature of distributed clouds and CDNs complicates one-timezone assumptions that used to drive maintenance windows. More latency wrinkles…)
The intersection between cloud and big data makes this latency all the more central to software design. Applications can no longer assume that the data sets they depend upon are at least as mobile as the servers that crunch them. The sheer scale made tractable by cloud precludes it.
In cloudthink, failures are routine rather than catastrophic.
Traditional applications often have a centralized brain, and go to great lengths to protect it. The brain can’t go down, because the entire system grinds to a halt if it does. This leads to incredibly expensive strategies for high availability. It also leads to many fragile assumptions about errors, monitoring, failsafes, and recovery procedures.
Cloudified software knows better. As Werner Vogels, CTO at Amazon, is fond of saying, “Everything fails, all the time.“ If you want to write for cloud, you make plans to tolerate hiccups. This means decomposing your app into smaller and more independent pieces that have high internal cohesion, but that can be coupled only by tenuous network links. An article by the designers of zeromq is typical of the mindset.
Cloudified software is comfortable with eventual consistency—because it’s made a careful analysis of the latency implications. It tends to implement state changes as idempotent operations that can be retried, so that two independent actors don’t corrupt the system if they unwittingly attempt similar work. It is pathological about checking for timeouts and other errors, and it is built with strategies to recover from them. (These strategies don’t have to be overly complex; Erlang’s “let it fail and try again” mantra might be just what the doctor ordered. The key characteristic is that the need for an answer is explicitly addressed.)
Where We’re Headed
In my next few blog posts, I’ll pull apart these themes and describe patterns of software construction that exhibit cloud-friendly thinking. In the meantime, I invite you to tackle Ender’s homework. He spent a great deal of time pondering how his adversary thought. Spend some time thinking about the assumptions in your own software artifacts, and how those assumptions might change if you’re career’s trajectory had begun when cloud was pervasive. You’ll probably find other themes besides the ones I’ve called out here. I’m interested in your comments.