PragPub 2010-08: Issue #14

Table of Contents

Features

All Your Context

by Andy Hunt

Context is king, but context extends further than you think. Here are some subtle biases that might affect your judgement.

Great Expectations

by Paul Butcher

Improve your tests with custom expectations

In Defense of Mediocrity

by Ben Scofield

There are different levels of expertise, and it’s smart to know what level to aspire to.

Page Objects in Python

by Adam Goucher

The Page Object pattern is the key to implementing smart automated checks. Here’s how Python programmers can make use of it.

When Did That Happen?

by Dan Wohlbruck

This month marks the anniversary of the first computer in space.

Departments

Up Front

by Michael Swaine

You are a product of your times.

Choice Bits

A little knowledge that is perfectly safe.

The Quiz

by Michael Swaine

A monthly diversion at least peripherally related to programming.

Calendar

Author sightings, partner events, and other notable happenings.

Shady Illuminations

by John Shade

John surveys the leading examples of software development manifestos and makes some suggestions.

Except where otherwise indicated, entire contents copyright © 2010 The Pragmatic Programmers.

Feel free to distribute this magazine (in whole, and for free) to anyone you want. However, you may not sell this magazine or its content, nor extract and use more than a paragraph of content in some other publication without our permission.

Published monthly in PDF, mobi, and epub formats by The Pragmatic Programmers, LLC, Dallas, TX, and Raleigh, NC. E-Mail support@pragprog.com, phone +1-800-699-7764. The editor is Michael Swaine (mailto:michael@pragprog.com). Visit us at http://pragprog.com

ISSN: 1948-3562

Up Front

It’s All About Context

by Michael Swaine

In putting together these monthly issues, we try to hit the right balance. We always want to give you hands-on examples of how people solved programming problems, but we also want to challenge you with thoughtful essays on subjects every software developer needs to think about. We want to address the issues you’re dealing with on a daily basis, but also season the dish with new languages and paradigms that you haven’t yet tasted. And along the way we hope to entertain and inform.

Our lead article for this issue is a thought-provoking essay by Pragmatic Programmer Andy Hunt on the ways in which your context influences you.

“You are a product of your times,” Andy explains, “perhaps much more so than you think. The attitudes, philosophies, and values of your parents and your cohorts have a tremendous impact on your values, attitudes, and perceptions. Folks born at different times will experience the world in very different ways.”

In another assumption-challenging essay, Ben Scofield argues that we may be setting ourselves up for disappointment by reaching for mastery in areas where it is not appropriate. Sometimes, as computer executive and philosopher Adam Osborne famously said, “adequacy is sufficient.”

We have two code-rich articles, too. Adam Goucher brings the Page Object pattern to Python programming. And Paul Butcher shows some clever techniques for automated testing, coding them in both Ruby and Scala.

Dan Wohlbruck takes us back to the early days of the space program with an article on the first computer in space. And John Shade reflects on the propensity for software developers to issue manifestos—and concludes that they aren’t going far enough.

As always, we include a calendar of events and a collection of odd things overheard in twitterspace.

We think we did a decent job of hitting that balance with this issue. But let us know what you think.

Choice Bits

He Said What?

A few selected sips from the Twitter stream.

What’s Hot

Top-Ten lists are passé—ours goes to 11. These are the top titles that folks are interested in currently, along with their rank from last month. This is based solely on direct sales from our online store.

1 | 1 | Agile Web Development with Rails
2^ | NEW | HTML5 and CSS3
3^ | NEW | Test Driven Development
4^ | 5 | Hello, Android
5v | 3 | The RSpec Book
6v | 4 | iPad Programming
7^ | 8 | Seven Languages in Seven Weeks
8^ | NEW | Driving Technical Change
9^ | 10 | Programming Ruby 1.9
10v | 7 | The Agile Samurai
11^ | NEW | Rails Test Prescriptions

Enjoy this full-on double rainbow of hues and cries from the likes of Kent Beck, Emily Chang, David Conrad, Fred Davis, Jeri Ellsworth, Nigel Fenwick, Chad Fowler, Bill Gates, Tom Hanks, Simon Harris, Andy Hunt, Jennifer Jenkins, Mitch Kapor, Steven Levy, Brian Marick, Staffan Nöteberg, Michael Nygard, Conan O’Brien, Chris Oliver, Priscilla Oppenheimer, Brett Schuchert, Dave Thomas, Dori Smith, and Gina Trapani. Also enjoy their individual choices in spelling and punctuation. Because isn’t tweeting a warts-and-all kinda thing?

Twitter Is the Wellspring of Wisdom

Beware disciplined people who live in a fantasy world. — @marick

Android vs iPhone is like command line vs Windows. IPhone: wysiayg-what you see is all you get. Android: "you get what you can find" — @pragdave

Give someone a program, frustrate them for a day. Teach someone to program, frustrate them for a lifetime. — @excid3

The Yoda Methodology: "Do, or Do Not. There is no Try." Note that "Do Not" is a perfectly valid, if underutilized, approach. — @PragmaticAndy

The first tweet from a new computer is like first light for a new telescope, if a telescope was a vuvuzela. — @daiconrad

the problem with categories is that often what i'm looking for isn't one of them — @emilychang

Chinese Spell Checkers Make You Lose Your Marbles

Thinking about creating DoICapitalizeTheWInMacworld.com (or maybe IsTheWInMacworldCapitalized.com?). Plz, tell me someone's already done it — @dori

Rmove a sngle vwel frm ech wrd n headlnes t sty currnt wth technlogy trnds lke flickr nd tumblr. — @FakeAPStylebook

Being a good writer is 3% talent, 97% not being distracted by the internet. — @NigelFenwick

Sigh. iPad spell correct turned "eval" into "veal". #nothelpful — @PragmaticAndy

When You Have Eliminated the Impossible, You May Have Thrown Out the Best Part

Sitting in a quiet zone. There's a guy talking to both his son and on cell phone. His voice goes: whisper LOUD whisper LOUD. — @Marick

Just explained TCP/IP metaphorically to a 6 years old -- including packet loss and resend. Now we're at the same knowledge level. — @staffannoteberg

When you think about it, humans must have co-existed with dinosaurs otherwise how would we know what they were called? — @haruki_zaemon

We're the first generation in history to deny our own culture to ourselves. #ORGcon — @elmyra

I have faith in my logic. And the dot product of faith and logic is 0. — @schuchert

My dog was born in Washington of Australian ancestors. When she wants to lie down she doesn’t know whether to turn clockwise or counter-clockwise. — @pragpub

A Thin Line Between Love and Raisins

Considering whether to cook The Pit of Unbearable Stench when @testobsessed comes by to pair. — @marick

I think one of my teammates is on drugs. Related: it's fun to make someone say "muscle relaxants" who's on them. — @mtnygard

by not solving problems people bring up, i collect frustration energy that i can use to motivate development — @KentBeck

The problem with a band showing up with ukulele and accordion is that expectations are set unreasonably high. Guaranteed disappointment. — @chadfowler

Sometimes I think the chinchillas only love us because we give them *r*a*i*s*i*n*s* — @marick

"You run like a blogger" — @ginatrapani

The Bugs, Dear Brutus, Are not in our Stars, but in Ourselves

Hey Appple, bad idea starting off your press conference by saying your competitors are flawed, too — @freddavis

BP's capped the well and Apple's giving away free iPhone sleeves. I sure picked the wrong week to invest in duct tape futures. — @pragpub

Increasingly, I'm valuing my unit test suites most for their ability to make me rethink settled decisions. Must see that frm end-to-end tsts — @mariock

I found a huge design flaw in my new iPhone. People get angry when I talk on it during a funeral. — @ConanOBrien

And Now for the Good News

99 percent of the way to #polio eradication. Learn why we cannot lose this battle. http://bit.ly/9iNjef — @BillGates

Can't wait for the semantic web (aka Web 3.0) so I'm building some of it now. We must find the meaning lost in the vast sea of information! — @freddavis

Planning on making a light gun controlled pinball machine tonight. Nintendo zapper with IR emitter and photo transistors near each flipper. — @jeriellsworth

Copyright office makes clear it's legal to jailbreak your phone & circumvent DVD encryption for fair use http://bit.ly/9BI3uU — @mkapor

Geeks rejoice! Original MacPaint and QuickDraw source code now up at Computer History Msm. Congrats BIll & Andy! — @stevenjayl

15 Developer/Hacker Women to Follow on Twitter. Please follow me too :-) — @priscillaoppy

Wanna buy my old Prius – hacked for MAX mpg? $ go to Welcome Back Veterans. Auction. http://tinyurl.com/3ahnu2d — @tomhanks

Yeah, we follow some odd tweeters, and you can follow us on twitter.

All Your Context

You are a product of your times.

by Andy Hunt

Are you a phophet, a nomad, a hero, or an artist? Andy explores how your generation shapes your thinking.

Anything that is in the world when you’re born is normal and ordinary and is just a natural part of the way the world works. Anything that’s invented between when you’re fifteen and thirty-five is new and exciting and revolutionary and you can probably get a career in it. Anything invented after you’re thirty-five is against the natural order of things.

—Douglas Adams, The Salmon of Doubt

Have you ever viewed a new technology suspiciously and felt it went “against the natural order of things?” Are you stunned and sorely amazed that your parents and/or older siblings have so much trouble with simple things such as email, or the difference between a Word document and a JPG image?

Douglas Adams captures the symptoms of the problem very concisely. Depending on when you are born and when you are introduced to certain technologies, they’ll seem completely normal or utterly foreign. Those things you’re introduced to early in your life you consider “natural”—you can’t imagine a world without them, because they’ve always been there (to you). You have some capacity to embrace the new and master it, for a while, but then that wears thin and it’s just too much new weird stuff.

Why is that?

I’m always reminding people to be aware of the context. Everything that happens does so within some context—that is, all of the circumstances that form the setting of some idea or event. But “all of the circumstances” that affect an event covers a huge area.

There’s the obvious local context, of course: particulars of your current job and project, the tools and languages in use, your recent professional experience and so on. All of that influences you, but the effective context stretches far beyond that, to your values and attitudes that are so ingrained you wouldn’t even think to question them. But these values can dramatically affect your judgment and your perception: from what counts as “good” or not, to what counts as “cool” as opposed to “unnatural.”

For example, some folks value the stability of their job at the expense of any amount of abuse from their boss. Other folks will pack up and quit at the slightest perceived offense. Folks who are driven to work all hours can’t understand the folks who cheerfully pack up at 5 p.m. and head home to be with their family, and vice versa.

You can assign many of these value differences to individual variation. People are people, and we’re a messed up and diverse lot. But despite that inherent diversity, when you look at large groups of people, some commonality emerges.

You are a product of your times—perhaps much more so than you think. The attitudes, philosophies, and values of your parents and your cohorts (those born about the same time as you; your peers throughout school and in the workplace; members of your generation) have a tremendous impact on your values, attitudes, and perceptions. Folks born at different times will experience the world in very different ways.

For instance, as far as the freshman classes these days are concerned, MTV has never featured music videos (in case you haven’t been paying attention for the last decade, MTV focuses on reality TV shows, celebrity gossip, and news). Russia has always had multiple political parties. Stadiums have always been named for corporations.

They’ve never “rolled down” a car window or “dialed” a phone. Johnny Carson has never been on live TV; Pete Rose has never played baseball. The Web has always been around; so has Dilbert.

These differences in viewpoint can cause some very funny misunderstandings. A few years ago, a babysitter we had hired gazed in wonder at our kitchen phone. “Mr. Hunt, what a wonderful idea,” she said, “to tie up your phone so people won’t walk away with it! Just like the pens at the bank.”

She had no idea why else you’d have a cord on a phone. It’s typical in her generation’s world experience that all phones are cordless landlines, or cell. The idea of a corded phone as a technological necessity was alien to her.

The Four Archetypes

Each generation has its own quirks, but there’s a pattern. There are only four distinct kinds of generations, and the cycle of four repeats.

According to researchers Neil Howe and William Strauss (see Generations: The History of America’s Future, 1584 to 2069 and a nice summary in The Next 20 Years: How Customer and Workforce Attitudes Will Evolve), if you look back through American history in the United States and Anglo-American history in Europe all the way back to the Renaissance, you’ll find only four prototypical, generational archetypes.

These four types repeat over and over again, in a continuing cycle. For the last twenty or so generations in America since the Pilgrim-laden Mayflower landed here in the 1620s, there was only one exception: Following the Civil War, one generation was so badly damaged that they never took their place in society, and the adjoining generations (especially the older generation) filled in the gap.

These generational generalizations help us understand why people value the things they do, and remind us that not everyone shares your core values or your view of the world.

Here are the four generational archetypes and their dominant characteristics:

Prophet: Vision, values

Nomad: Liberty, survival, honor

Hero: Community, affluence

Artist: Pluralism, expertise, due process

Strauss and Howe’s research explores how each archetypical generation can create the next: archetypes create opposing archetypes in a typical example of the “generation gap.” But that generation then creates one that opposes it, and so on.

We’ll ignore the under-twenty set for the time being and take a closer look at each of the grown-up generations in turn.

The GI Generation, 1901–1924 (Hero)

This generation produced the first Miss America and propagated the idea of the all-American athlete. They built the suburbs and moon rockets, and they fought valiantly in World War II.

The command-and-control, rigidly hierarchical military metaphor for business—and then for software development—has its roots here.

The Silent Generation, 1925–1942 (Artist)

Next up, the gray-flannel conformists. This generation vastly expanded the legal system and continues a distinct focus on due process but not necessarily on decisive action.

As a possible example, consider a recent Iraq Study Group report, staffed largely by folks in this age group, which listed seventy-nine recommendations but not a single action item.

This group generated—and enjoyed—unprecedented affluence.

The Baby Boom Generation, 1943–1960 (Prophet)

Ah, the Baby Boomers. Perhaps the most recognizable—and largest—generation, formed in the heyday of post—World War II optimism.

This group engendered a dramatic increase in crime rates, substance abuse, and risk taking in general. The tendency for this generation is to see themselves as arbiters of national values; they have always wanted to “teach the world to sing.” (Remember the 1970s Coca Cola commercial?)

But this inherent desire to save the world doesn’t manifest itself in particularly realistic or pragmatic ways. This group is less interested in outcome and more interested in approach. Their moralizing, which reflects their all-important values, may sound preachy to other generations.

Generation X, 1961–1981 (Nomad)

One of the best descriptions I’ve read of Gen X described them as being “raised by wolves.” These are free agents, with an inherent distrust of institutions. They form the greatest entrepreneurial generation in U.S. history.

Fiercely individualistic, and perhaps a bit on the dark side, they’ll just quit and move on if there’s a problem at work. They resist being labeled at all costs. They might be viewed as undisciplined by other generations, or they might be accused of not playing by the rules.

This group is less interested in civics, believing that one-on-one involvement is more effective. They are quite pragmatic, working for a positive outcome regardless of any particular ideology or approach.

Millennial Generation, 1982–2005 (Hero)

In this generation, the pendulum swings away from individualism toward greater team-based work; there’s a decrease in risky behaviors and a noticeably less edgy approach than their Gen X or Boomer predecessors. They are loyal to the organization and not nearly as entrepreneurial as the Gen X’ers.

Although they don’t set out to save the world, they do have a greater emphasis on civics, and they expect that those in authority will fix the problem.

All Together Now

In today’s culture, we have a unique situation, one that has not happened before. We have all these generations present in the workplace at the same time, interacting with each other, getting along—and sometimes not.

While working at a large Fortune 10 company that shall remain nameless, I had the good fortune to be mentored by an older professional who took an interest in me. Even though it was early in my career, I had significant skills in Unix that my peers did not, and so this fellow saw—and adopted—a kindred spirit.

For several years we worked together; he showed me undocumented, arcane tricks and tips, and I showed him advanced theory from my then-recent degree. But the day came when I announced I was leaving that company. He basically never spoke to me again.

He was of the Silent generation that valued company loyalty—for life. My departure was an unpardonable sin to him. Although that attitude seems quaint and old-fashioned now, it was widely held at the time. I was seen by many in the organization to be a troublemaker—a disloyal maverick who wasn’t playing by the rules. In fact, I was just acting as a typical X-er ready to move on, having learned what I wanted to learn and having tired of the commute.

Today, of course, the prevailing cultural attitude has shifted. It’s not generally expected that you should stay with one company for more than a few years. But that will change. The Millennial generation may well come to embrace loyalty, favoring hierarchical, strong organizations. They will react to their collective perception that the Boomers are preachy and impractical and the X-ers are lazy and undisciplined.

Each generation’s reaction to the perceived weakness of the immediately preceding generations creates a repeating pattern over time. In this case, the generations after the Millennials will react to their values, and the cycle repeats.

And I think the most striking thing to me personally is to realize that not everyone sees the world the way I do. Although I can see the Boomers’ point of view on many levels, that group’s ascribed lack of pragmatism—often placing their own values ahead of practicality—frustrates me. Not everyone values pragmatism; this group values ideals more. My approach to pragmatism can be seen as “cheating,” as in “You’re just doing that because it works.”

Well, that is the general idea, as far as I’m concerned. Do it because it works.

But that’s my viewpoint, probably typical of my generation and probably not typical of others. Each generation faces these kinds of conflicting approaches with adjacent generations. And members of each generation will tend to defend their inherent approach above others.

How This Affects You

Not everyone shares your deep-seated values, and that doesn’t mean you’re right or they’re wrong. Instead, look at the context.

Context remains king; sometimes it may be more appropriate to stick to your principles regardless of consequences, as a Boomer might. In other situations it is clearly better to take a pragmatic approach, as an X-er. Command and control hierarchies have their place and can be quite effective; that’s why they are popular (and not just with the GI generation). But in other circumstances, such as many commercial software development projects, a rigid hierarchy is disastrous.

It’s likely that you will naturally prefer an approach that has values favored by your generation. But realize where this influence is coming from. Perhaps your fierce individualism isn’t a trait unique to yourself. Perhaps many of the characteristics you admire in other people and aspire to attain in yourself don’t come from any deep reasoning or logical basis but instead from the times in which you were born.

Bear that in mind as you passionately argue for or against a topic. Are you making a logical argument, an emotional one, or just a familiar one? Is it the right argument in this particular context? Have you really considered other points of view? Does their opinion make more sense when viewed through the lens of generational bias?

The best way to keep from falling victim to your generation’s particular set of biases is to embrace diversity on your project team. If you and your team all think alike, you might see your reinforced collective viewpoint as the only viable one. It’s not. Just because you treasure your approach, your individualism, or your teamwork doesn’t mean that younger or older folks will share that view or that it’s the right answer in this context.

But as with many things, feedback is the final arbitrator. Whatever you do, get feedback on how it’s doing, and do so very quickly. Whether it’s unit tests for code, or goals for a meeting, or the warm glow of happy users from a demo, don’t trust in your own biases to prove you right. Put the proposed solution in context, and see if it really works.

Because context, after all, is king.

Andy Hunt is a Pragmatic Programmer and the author of Pragmatic Thinking and Learning.

Send the author your feedback or discuss the article in the magazine forum.

Great Expectations

Better Testing Through DSLs with Ruby and Scala

by Paul Butcher

Paul explores how to improve your tests with custom expectations, and does so using parallel implementations in Ruby and Scala.

Domain Specific Languages (DSLs) have become a hot topic in development recently. And deservedly so, because when done well they allow us to raise the level of abstraction at which we work, achieving more while simultaneously improving quality and saving effort.

DSLs can help with all sorts of problems, including testing. I recently came across a great example, where by investing the time to create custom expectations that encode knowledge about my problem domain, I could dramatically improve the expressiveness of my tests.

Thanks to Rails, DSLs are probably best associated with Ruby. But Ruby certainly isn’t the only language that can play this trick. Scala is a language that’s rapidly gaining in popularity, not least thanks to its DSL support.

As a PragPub reader, I’m guessing that you’re probably at least somewhat familiar with Ruby, but maybe not with Scala. So I thought that I’d challenge you by presenting the same solution implemented in both languages. They’re interesting both for their similarities and for their differences.

If you’re not interested in Scala, you can skip over the Scala sections without losing anything.

Versions

I’ve used Ruby 1.8.7 and Test::Unit for the Ruby examples. The general approach should certainly work for other Ruby test frameworks like RSpec, however.

The Scala examples use version 2.8 and the ScalaTest framework.

All the code for this article is available for download here.

The Problem

I recently found myself writing tests for a body of code that performs statistical analysis of large bodies of data. One of the key data structures was a weighted list, which is a list of items, together with their associated weight, ordered from highest weight to lowest.

You won’t be surprised to learn that many of our tests take the general form:

Set up a particular test dataset

Analyze that dataset

Verify that the resulting weighted list matches our expectations

It is the last of these three steps that we’ll concentrate on.

A Naïve Solution

Here’s what a test might look like in Ruby:

| def test_naive
| items = Items.abc
| assert_equal(3, items.length) // Line 1
| assert_equal("a", items[0].name) // Line 2
| assert_equal("b", items[1].name)
| assert_equal("c", items[2].name)
| weights = items.collect(&:weight) // Line 3
| assert_equal(weights, weights.sort.reverse, "unsorted weights")
| end

The call to Items.abc on Line 1 returns:

[("a", 0.7), ("b", 0.2), ("c", 0.1)]

At Line 2 we verify that exactly 3 items are returned, and that they are “a,” “b,” and “c” in that order.

At Line 3 we verify that the items are returned in weight order by comparing a list of weights with a sorted version of itself (the call to reverse is necessary because we need to sort from highest to lowest).

Fine as far as it goes. But we’re going to have to do this kind of thing for pretty much every test that looks at a weighted list (and we have a lot of tests). Surely we can do better?

Naïvety in Scala

Before we look at what we can do to improve things, let’s take a look at what the same test might look like in Scala:

| def testNaive {
| val items = Items.abc
| expect(3) { items.length } // Line 1
| expect("a") { items(0).name }
| expect("b") { items(1).name }
| expect("c") { items(2).name }
| val weights = items.map(_.weight) // Line 2
| // Line 3:
| assert(weights.sortWith(_ > _) sameElements weights, "unsorted weights")
| }

Pretty similar to the Ruby version.

The call to expect at Line 1 is basically just an assertion. In fact, we could have written:

assert(3 == items.length)

but (like Test::Unit’s assert_equal) ScalaTest’s expect allows more helpful error messages to be displayed when an expectation fails.

The call to map at Line 2 is similar to Ruby’s collect—it passes each element of items to the supplied function and returns the resulting collection. But what does _.weight mean?

Well, we could have written this instead:

items.map(i => i.weight)

The argument to map is an anonymous function that, given an item, returns its weight. In many ways it’s very similar to a Ruby block, for instance:

items.collect { |i| i.weight }

Scala allows us to simplify this, however. First, it allows us to avoid giving an explicit name to our anonymous function’s parameters by using _:

items.map(_ => _.weight)

which we can then further shorten by removing the _ =>.

The same thing is going on with the argument to sortWith at Line 3. This is equivalent to:

weights.sortWith((_, _) => _ > _)

which in turn is equivalent to:

weights.sortWith((a, b) => a > b)

Something else a little odd is going on at Line 3. Scala’s sameElements method compares two collections and returns true if they contain the same elements. Scala allows us to use methods as though they were operators, however, so:

x sameElements y

is equivalent to:

x.sameElements(y)

Getting Smarter

How cool would it be to encode all of our knowledge about what a weighted list should look like in a single assertion? Something that we can use like this:

assert_items(["a", "b", "c"], Items.abc)

Well, it turns out that we can do exactly that:

| def assert_items(expected, actual)
| actual_names = actual.collect(&:name) // Line 1
| actual_weights = actual.collect(&:weight) // Line 2
| // Line 3:
| assert(expected == actual_names &&
| actual_weights == actual_weights.sort.reverse,
| "Expected [#{expected.join ', '}] but got [#{actual.join ', '}]")
| end

At Line 1 and Line 2 we split our weighted list into a list of names and a list of weights. Then at Line 3 we verify two things—that the names match the expected list, and that the weights are ordered correctly.

We’ve not only gained brevity, we’ve also improved our reporting when a test fails. For example:

assert_items(["a", "b", "c"], Items.abc_unsorted)

gives us:

Expected [a, b, c] but got [(a, 0.2), (b, 0.7), (c, 0.1)].

Smarter Scala

Here’s what using our custom expectation looks like in Scala:

expectItems("a", "b", "c") { Items.abc }

and here’s how it’s implemented:

| def expectItems(expected: String*)(actual: Seq[Item]) { // Line 1
| val actualNames = actual.map(_.name)
| val actualWeights = actual.map(_.weight)
| val sortedWeights = actualWeights.sortWith(_ > _)
| assert((expected sameElements actualNames) &&
| (actualWeights sameElements sortedWeights),
| "Expected "+ format(expected) +" but got "+ format(actual))
| }

Most of this should be pretty obvious, given what you’ve already seen, but Line 1 introduces a few new things.

Firstly, we need to give types for our function parameters. Notice however that, unlike Java, the compiler can infer types in most cases. So, for example, it can work out that the type of actualNames is Seq[String] (a sequence of String) without us telling it explicitly.

Secondly, the type of the expected parameter is String*. This means that the function can be called with any number of string arguments—expected can then be used as though it were a Seq[String] containing all of the parameters.

Finally, our function takes two parameter lists. This is a trick commonly used in functional programming languages called currying. expectItems is actually a function that takes zero or more string arguments and returns another function which takes a sequence of Item objects as its argument.

Other than that, it follows pretty much the same structure as the Ruby equivalent.

But We Can Do Better

Our assert_items method is certainly an improvement over what we had before, but we can do better. For example, Items.abcdef returns:

[("a", 0.6), ("b", 0.1), ("c", 0.1), ("d", 0.1), ("e", 0.06), ("f", 0.04)]

Testing it with:

assert_items(["a", "b", "c", "d", "e", "f"], Items.abcdef)

would over-specify, because the “b,” “c,” and “d” items all have the same weight and could, therefore, be returned in any order.

We can address this by enhancing assert_items to allow it to be called like this:

assert_items(["a", ["b", "c", "d"], "e", "f"], Items.abcdef)

Here’s the implementation:

| def assert_items(expected, actual)
| assert(matching_items(expected, actual),
| "Expected [#{format(expected)}] but got [#{actual.join ', '}]")
| end

The heavy lifting has been moved to matching_items:

| def matching_items(expected, actual, last_weight = 1.0)
| if expected.empty? // Line 1
| actual.empty?
| else
| e = expected.first
| case e // Line 2
| when Array:
| n = e.length
| a = actual.take(n)
| w = a.first.weight
| a.all? { |i| i.weight == w } &&
| w < last_weight &&
| e.sort == a.collect(&:name).sort &&
| matching_items(expected.drop(1), actual.drop(n), w)
| else
| a = actual.first
| w = a.weight
| w < last_weight &&
| e == a.name &&
| matching_items(expected.drop(1), actual.drop(1), w)
| end
| end
| end

This is a recursive function that handles the first element of its expected argument and then calls itself to handle the remainder.

As with any recursive function we need to handle termination, which happens at Line 1, where we confirm that if we’ve run out of expected items, we also have no remaining actual items.

The heart of the function is the case statement at Line 2, which determines whether or not we’re dealing with an array.

If we are, we take the appropriate number of items from actual, verify that they all have the same weight, that that weight is less than the last we saw and that the names match what we’re expecting (sorting both so we can compare easily). We then recurse, passing the remainder again.

Otherwise, we take the first element of the actual array, verify that its weight is less than the last weight we saw and that its name equals the one we’re expecting. We then recurse, passing the remainder of expected and actual.

Doing Better in Scala

We could create a Scala implementation of expectItems that, like Ruby, takes a mixture of strings and arrays. But because Scala is statically typed, this isn’t the natural approach and not the one we’ll take.

Instead, we’re going to create a new class ItemSet that represents a set of equally weighted items:

| class ItemSet(names: Seq[String]) { // Line 1
| val sortedNames = names.sorted
| val size = names.size
| def matches(actual: Seq[Item], weight: Double) =
| (sortedNames sameElements actual.map(_.name).sorted) &&
| actual.forall(_.weight == weight)
| }

Scala’s constructors are specified rather differently from Ruby or Java—the arguments are given as parameters to the class (Line 1).

Our class has two fields, sortedNames and size and a method matches that returns true if its actual argument matches the items supplied when this object was created and they all have the supplied weight.

Here’s the implementation of expectItems:

| def expectItems(expected: ItemSet*)(actual: Seq[Item]) {
| assert(matches(expected, actual),
| "Expected "+ format(expected) +" but got "+ format(actual))
| }

As in the Ruby implementation, the heavy lifting is performed by a recursive matches function:

| def matches(expected: Seq[ItemSet], actual: Seq[Item],
| lastWeight: Double = 1.0) : Boolean =
| if (expected.isEmpty)
| actual.isEmpty
| else {
| val (eh, et) = (expected.head, expected.tail) // Line 1
| val (ah, at) = actual.splitAt(eh.size) // Line 2
| val w = ah.head.weight
| w < lastWeight && eh.matches(ah, w) && matches(et, at, w) // Line 3
| }

At Line 1, we split expected into its head element (eh) and tail (et) and at Line 2, we split actual into two lists, one with the same number of elements as eh, the other containing the remainder.

Finally at Line 3, we verify that the weight is less than the last we saw, that the expected items match the actual, and recurse.

We now have something that can be called like this:

| expectItems(new ItemSet(Seq("a")),
| new ItemSet(Seq("b", "c", "d")),
| new ItemSet(Seq("e")),
| new ItemSet(Seq("f")) {
| Items.abcdef
| }

which will work, but is rather more verbose than we would prefer.

Happily, we can do much better by defining a couple of helper functions:

| implicit def stringToItemSet(s: String) = new ItemSet(Seq(s))
| def ^(strings: String*) = new ItemSet(strings)

stringToItemSet converts a single String to an ItemSet. The trick is the implicit modifier, which means that the compiler will automatically call this function for us whenever we use a String where an ItemSet is required.

The ^ method takes a sequence of String parameters and converts them to an ItemSet.

So now we can call expectItems like this:

expectItems("a", ^("b", "c", "d"), "e", "f") { Items.abcdef }

Much better!

Wrapping Up

Let’s review what we’ve achieved. We’ve created a custom expectation that allows us to write:

assert_items(["a", ["b", "c", "d"], "e", "f"], Items.abcdef)

which asserts that:

The returned sequence contains exactly 6 elements.

The returned sequence is sorted in descending weight order.

The first item is “a.”

The next 3 items are “b,” “c,” and “d,” but these may be returned in any order.

The weight associated with these three items is equal.

The last two items are “e” and “f” in that order.

Not bad for a single line of code.

We’ve also seen that we can achieve the same effect in Scala, a statically typed and compiled language, just as easily as we can in Ruby, a dynamically typed and interpreted language.

Paul Butcher has worked in diverse fields at all levels of abstraction, from microcode on bit-slice processors to high-level declarative programming, and all points in between. Paul’s experience comes from working for startups, where he’s had the privilege of collaborating with several great teams on cutting-edge technology. He is the author of Debug It!: Find, Repair, and Prevent Bugs in Your Code..

Send the author your feedback or discuss the article in the magazine forum.

In Defense of Mediocrity

Is Your Personal Best the Enemy of Your Personal Good?

by Ben Scofield

Ben confesses to mediocrity and explains why you should, too.

I am a thoroughly mediocre chess player.

There, I’ve said it. Whew! That’s a weight off my shoulders.

I am a thoroughly mediocre chess player. And I’m mediocre at baseball. Tai Chi? Mediocre. When you get right down to it, I’m mediocre at a lot of things, and I accept that.

Competency Porn

Why was that so hard to say? I think it’s because we’re constantly surrounded by a cultural obsession with mastery and excellence. Our entertainment is built in large part on watching people be excellent at things—heck, the USA and TNT networks have built entire schedules around “competency porn,” with shows like “Burn Notice,” “Leverage” and “White Collar.” I know I love watching someone be the best there is at whatever it is they happen to be doing.

I also love a good training montage. I saw the remake of The Karate Kid about a month ago, and my favorite scenes were the ones where the young, impressionable youth was made to pick up his jacket, hang it up, take it down, put it on, and do other mundane tasks for an interminable amount of time (in the timeline of the movie, it was probably a month or so), all so that he could find out—just as he was about to quit!—that he’d been implicitly training his body to adopt proper kung fu positions. Once he made that leap, the training really picked up.

No, I mean it literally picked up and moved. Next thing you know, he’s training atop the Great Wall and climbing endless steps to a peaceful temple in the mountains. Of course, it all culminates in a battle with his nemesis, and his two months of unconventional training end up allowing him to defeat someone with years of arduous practice under his sash.

Wait, what?

See, this is the problem. We love watching people be excellent, and we love watching them attain mastery, but television and movies lie to us. The training montage is a lie. It takes years of effort to achieve the highest levels of performance, but we’ve been convinced that all it really takes is a wise, somewhat damaged guru and a few months of unexpected work.

This leads us to think badly of ourselves and others for not trying to achieve mastery.

Understanding Mastery

To get rid of this stigma, we have to revise our understanding of mastery. To start with, mastery is a journey, not a destination. Whether you agree with Anders Ericsson’s suddenly-popular research that says mastery requires 10,000 hours of deliberate practice or not, it’s clear that no one becomes the absolute best they can be without a huge investment of time and effort.

That investment isn’t just hours and sweat, though; it’s deliberate practice, which by now we all know to be the following steps:

Set a goal that’s just beyond your current abilities.

Try to reach it (and fail, most likely).

Gather feedback (this is why even professional athletes still have coaches).

Incorporate that feedback into your next attempt.

I like to say that deliberate practice is a string of nearly continuous failure punctuated by the occasional short-lived success. It’s mentally (and often physically) draining work, which means that there’s a pretty hard limit to how much of it you can fit into a day. Let’s be generous and say that you can do 3 hours of this sort of practice in a day, and that you can keep that level of exertion every day. If the 10,000-hour rule is correct, that means it would take you over 9 years of daily practice to achieve your potential in some domain.

The average person lives somewhere between 70 and 85 years. If you started practicing when you were, say, 7 years old, then you might be able to reach and maintain mastery in five or six different domains. I don’t know about you, but in the course of a single week I might easily touch the following realms, all of which seem to be potential targets of mastery: relationships, parenting, psychology, software development, writing, speaking, philosophy, volleyball, art, and various games—that’s at least nine different areas, and at different points in my life I’ve been interested in wildly different domains (physics, music, architecture, evolutionary biology, fiction writing, and more come to mind). Clearly, there’s just not enough time to master everything that we do.

Beyond even that practical consideration, however, there’s another aspect to mastery that we need to explore: motivation. I already pointed out that the path to mastery is paved with failure, and that’s not a great deal of fun. You also can’t rely on the joy of performance to get you through the rough patches, since the things you focus on while displaying your skills (playing in a band, for instance) are very different from those you focus on while practicing to improve. How many times have you heard a guitarist stop and restart a song while in concert? Performance just isn’t practice.

And finally, mastery isn’t even really required for much. Out of all the potential jobs and activities in the world, mastery is a prerequisite for a vanishingly small fraction of them. All-Star in a professional sport, certain positions in academia and government—those are about all I can think of that really require people to be the best they can possibly be. There just aren’t external pressures motivating people to attain mastery.

Instead, there’s internal motivation. A student practices her martial art for hours every day because she is driven internally to better herself; a chess master spends an equivalent amount of time reviewing historical matches and traditional chess problems for the very same reason. This drive is wonderful, but when you dig deep enough, it’s actually quite rare.

Stages of Expertise

So, if mastery’s so difficult, takes so long, and isn’t even required for most things, what are we left with? I typically split up the continuum into four stages: mediocrity, adequacy, excellence, and mastery.

Mediocrity is the baseline of performance. Once you know the rules and how things generally work, you’re mediocre. I mentioned above that I am a mediocre chess player. That’s because I know how the pieces move and I’ve picked up jargon and a smattering of strategy (really only enough to confuse myself) via osmosis over the years, but I lose much more often than I win—and when I do win, it’s most likely the result of luck or a terrible mistake by my opponent. When you think about it, most of us are mediocre in a huge range of skills.

Adequacy is very interesting. For one thing, adequate performers win more often than they lose. At work, for instance, the inadequate are fired for their failures. The adequate survive. Most people have a fairly wide set of adequacies.

The most interesting thing about adequacy, though, is that there are a couple of different paths to attain it. You can become adequate by being in the early stages of the path to mastery, with some (but not too much) deliberate practice under your belt.

The other path is easier: repetition. If you just do something over and over again, you can get better at it. If you’ve heard the years of experience joke—do you have 10 years of experience, or one year repeated 10 times?—then you’ve heard the textbook definition of adequacy via repetition.

Strive for Excellence

I call the range between adequacy and mastery excellence. This is the hardest state to identify, because it’s enormously wide. If mediocrity is the result of no practice and adequacy is the result of minimal (or non-deliberate) practice, then excellence is some amount of deliberate practice less than that required for mastery. I think of excellence as the ultimate choice: if you’ve decided to settle (and how pejorative is that word?) for excellent instead of continuing towards mastery, then you can stop at whatever point along the path you like.

And really, that’s the goal I think we should all strive for most of the time. It’s easy to get caught up in the obsession with mastery, to think that we’re inadequate if we aren’t actively trying to improve every skill we have. But in fact, we just don’t have the time or the energy to master everything we do. The right thing to do is to make informed, intentional choices about where we want to spend our limited time and effort. It might very well be that I choose to be mediocre at chess and baseball, merely adequate as a volleyball player and a philosopher, and strive for increasing excellence as a parent, speaker, and software developer—the key is that we should all make those decisions consciously, instead of falling into them by accident.

Ben Scofield is a developer, speaker, and author living in Durham, NC, where he is the Technology Director for Viget Labs’ Durham office. He’s been with Viget for nearly five years, during which time he’s worked with a number of startups in a variety of roles, from project management to usability analysis, but with a focus on system architecture and development.

Send the author your feedback or discuss the article in the magazine forum.

Page Objects in Python

Automating Page Checking without Brittleness

by Adam Goucher

The Page Object pattern is the key to implementing smart automated checks. Here’s how Python programmers can make use of it.

Automating checks[1] at the UI level has earned a bad reputation in certain circles, primarily due to the associated maintenance costs. The bad reputation is deserved, in large part. Almost everyone who has done UI automation has done some variation of the familiar “the UI folks changed the username box to the loginname box and now everything has broken” dance. Elements on the page are always in a state of change—and should be. If they aren’t, then your product has stopped evolving. The challenge is to respond to those changes in a way that decreases the maintenance burden.

As an automation practitioner and consultant, I find that the easiest way to handle these changes is to bundle up oft-used clusters of commands and operations into functions. Your script then becomes a mix of framework calls and application-specific functions that abstract operations.

Brittle or Better?

Compare these two snippets of Python from a Selenium script.

Brittle:

| s.open("/login")
| s.type("username", "pragmatic")
| s.type("password", "magazine")
| s.click("login")
| s.wait_for_page_to_load("30000")

Better:

| def login(s, username, password):
| s.type("username", username)
| s.type("password", password)
| s.click("login")
| s.wait_for_page_to_load("30000")
| #
| s.open("/login")
| s.login(s, "pragmatic", "magazine")

When things are working properly, the Brittle example is actually more efficient, as there is one less function call. But as soon as either of the fields or the button changes or the flow otherwise changes, the Better example becomes so much better. Especially when you reuse the login function across all your tests. One change, multiple fixed scripts: it’s automation maintenance nirvana.

Helper functions should not be limited to just actions. They can also be used for interactions with list boxes, radio button groups, etc.

| def select_country_by_label(s, label):
| s.select("country", "label=%s" % label)

This style of script design lends itself naturally to scripting languages like Perl, Ruby, and Python, which are traditionally more functionally oriented, but less to more OO languages like C# or Java.

Enter the Page Object.

The Page Object Pattern

The Page Object pattern comes out of the WebDriver project[2] as a way of encapsulating the intent of and interaction with an individual page in your application in a single object. The original implementation of the Page Object pattern was in Java, but recently reference implementations have appeared for Java, C#, and Ruby. But to the best of my knowledge, Python did not have such an example. Until now. The remainder of this article shows how I have successfully used the Page Object pattern in Python (using Selenium, but the approach is driver neutral).

The first thing we do is to distinguish between the page itself and the elements on that page. This difference in turn will determine our inheritance model.

Pages contain both actions implemented as methods (example: login_page.submit()) and web elements, which are themselves separate objects.

Web Elements are the parts of the page that are interacted with to either set up an action or to check the result of one—such as check boxes, text fields, radio buttons, etc.

With these two branches determined, and throwing in the desire to do asserts on pages as well as to make use of as much encapsulation as possible, we arrive at this tree:

| Object
| +-- unittest.TestCase
| +-- BasePageObject
| +-- BasePageElement

This is a good time to detour slightly around how things get organized on disk. When implementing Page Objects in Python, I have found it useful to make use of Packages to organize things. So with our two base classes, things look like this:

| pageobjects/
| __init__.py
| basepageobject.py
| basepageelement.py

Right now, the basePageObject class need not do anything other than exist. What the baseWebElement class looks like will be cleared up shortly.

| import unittest
| class basePageObject(unittest.TestCase):
| pass

This allows us to use it as a super class to our actual Page Objects and get all the asserts that come with a TestCase. Here is a Page Object that exists in a majority of systems: the login page.

| from pageobjects import locators, selenium_server_connection
| from pageobjects.basepageobject import BasePageObject
| from pageobjects.basepageelement import BasePageElement
| class UsernameElement(BasePageElement):
| #
| def __init__(self):
| self.locator = locators["login.username"]
| #
| def __set__(self, obj, val):
| se = selenium_server_connection.connection
| se.type(self.locator, val)
| #
| class PasswordElement(BasePageElement):
| #
| def __init__(self):
| self.locator = locators["login.password"]
| #
| def __set__(self, obj, val):
| se = selenium_server_connection.connection
| se.type(self.locator, val)
| #
| class LoginPageObject(BasePageObject):
| #
| username = UsernameElement()
| password = PasswordElement()
| #
| def __init__(self, se):
| self.se = se
| self.se.open("/login")
| self.assertEqual("My Application - Login", self.se.get_title())
| #
| def submit(self):
| wait_for =
| "selenium.browserbot.getCurrentWindow().document.getElementById
| ('LogoutButton')"
| self.se.click(locators["login.submit"])
| self.se.wait_for_condition(wait_for, "30000")

Don’t write all the element classes for your page up front. Instead, do them incrementally on an as-needed basis so even though the login page might have a clear button and forgot password functionality, neither is defined, as no script needs them yet.

Working from bottom to top, the LoginPageObject has a submit action, which is defined as a class method. When called, it will click a button and wait for another button to appear. Which button Selenium “clicks” is part of the reason for organizing Page Objects into packages.

Python packages give us a nice dotted notation to refer to modules within the package, but if you want something to be in the main namespace, you put it in the package’s __init__.py. One of the things that should be in there is a dictionary of all the locators throughout your application. Yes, it will get large, but it also means they are in a single spot when they need editing.

| locators = {}
| locators["login.username"] = "username"
| locators["login.password"] = "password"
| locators["login.submit"] = "login"

Because there will be a lot of them, a good habit to get into is to use page.thing as the key. And make the key something that describes the intent of the field, as the key should not change once it is used. Its value will, however, change at the whims of the UI developers.

These two entries happen to be using the Selenium identifier locator (the default), but they could have been an xpath or css locator string as well.

The LoginPageObject also has its own custom constructor that takes a connection to the Selenium RC server (which was created in the original script) and sets it as a class attribute. It will also navigate to the login page. Another way to write this page navigation is to check whether you are on the page already, and skip it if you are.

| def __init__(self, se):
| self.se = se
| try:
| self.assertEqual("My Application - Login", self.se.get_title())
| except AssertionError:
| self.se.open("/login")
| self.se.wait_for_page_to_load("30000")
| self.assertEqual("My Application - Login", self.se.get_title())

This second style of constructor can be more efficient for pages that are navigated to from within your application rather than pages you access directly.

The Magic

The two lines that define the username and password attributes of our class are where things start to get really interesting. Note that we define them not as strings or integers but as descriptor objects. Simply, a descriptor is an object that has had its get, set, and delete behavior overridden. This overriding is the magic of Page Objects in Python.

Looking at the UsernameElement class, we see that it too has a custom constructor, whose purpose is to set locally the locator the object refers to. The __set__ method gets run any time the value of LoginPageObject.username is assigned, and rather than storing that value, it will type it in the field on the page. Because UsernameElement has BasePageElement as its super class, and there isn’t anything special about this particular element, we can rely on BasePageElement’s get and delete implementations.

| from pageobjects import selenium_server_connection
| #
| class BasePageElement(object):
| #
| def __get__(self, obj, cls=None):
| selenium_server_connection.get_text(self.locator)
| #
| def __delete__(self, obj):
| pass

In your BasePageElement class, have the __get__ use whichever field is most prominent in your application. For this purpose, we’ll pretend that most in this application are text fields.

Warning: If you are trying to do a get operation on one of the descriptors and it is not a text field, you will have to define the __get__ behaviour in the specific element class itself.

Just as an element’s set behaviour is to interact with the browser and insert text onto the page, the get behaviour is to read it from the page.

The final bit of infrastructure needed by this implementation of the pattern is to be able to share the connection to the Selenium server between objects that might not normally have access to it. This is best illustrated by first showing a pyunit script that makes use of the Page Objects defined so far.

| from pageobjects.login import LoginPageObject
| from pageobjects import selenium_server_connection
| #
| import sys, unittest, re, time, os.path, logging
| #
| class PageObjectExample(unittest.TestCase):
| #
| def setUp(self):
| self.log = logging.getLogger("pragmatic.pageobjectexample")
| self.verificationErrors = []
| self.selenium =
| selenium_server_connection.connect("localhost", 4444, "*chrome",
| "http://some.test.site")
| self.selenium.start()
| #
| def testLogin(self)
| lpo = LoginPageObject(self.selenium)
| lpo.username = "adam@element34.ca"
| lpo.password = "password"
| lpo.submit()
| #
| def tearDown(self):
| self.selenium.stop()
| self.assertEqual([], self.verificationErrors)
| #
| if __name__ == "__main__":
| unittest.main()

This is a pretty standard-looking Selenium/pyunit script, except in the way that the Selenium server is accessed has been overridden with one that will create a singleton local to our package.

To achieve this there is code in two places. In pageobjects/__init__.py:

| from pageobjects.seleniumwrapper import SeleniumWrapper
| #
| selenium_server_connection = SeleniumWrapper()

and in pageobjects/seleniumwrapper.py, where the actual connection establishment is buried.

| from selenium import selenium
| #
| class SeleniumWrapper(object):
| # singleton
| _instance = None
| #
| def __new__(cls, *args, **kwargs):
| if not cls._instance:
| cls._instance =
| super(SeleniumWrapper, cls).__new__(cls, *args, **kwargs)
| return cls._instance
| #
| def connect(self, host, port, browser, server):
| self.connection = selenium(host, port, browser, server)
| return self.connection

With all this in place, let’s walk through the execution of this script as a way of tying all the code bits together.

Taking It Step by Step

The Python interpreter parses the file, checking for syntax errors, imports a bunch of stuff into scope and learns how to create a PageObjectExample class that has unittest.TestCase as a super class.

It also determines that what it is supposed to execute is unittest.main(), which is when the fun starts.

The pyunit framework scans the file for TestCase classes and when it finds them looks at whether they have any methods that begin with “test.”

Since PageObjectExample has testLogin, it then executes the setUp method, which does a few things, but most importantly uses our wrapper around the Selenium server connection to establish communication with the running Selenium RC server.

Then the actual test method is called, the first line of which creates a LoginPageObject, which in turn causes the creation of UsernameElement and PasswordElement objects.

The next two lines trigger the __set__ methods of the UsernameElement and PassswordElement objects to enter the username and password into the page.

The page is then submitted.

If this were a real script, there would be some assertions and checks into the database to ensure things behaved as expected.

Now that the test method is complete, the tearDown method is executed.

And lastly, since there are no other methods prefixed with “test,” results are displayed to the user.

Page Objects are definitely coming to the fore as a way of managing the maintenance costs of testing at the UI level, but there is a non-trivial technology cost associated with them. For people new to programming, I might still steer them towards just abstracting things into functions rather than objects. But for people with OO understanding and knowledge, or if you are automating an application that undergoes constant disruptive change, then Page Objects is absolutely a pattern worth considering.

Adam Goucher has been testing professionally for over 12 years at a range of organizations from national banks to startups. A large part of that time has been spent augmenting his exploratory testing with automation. He is the maintainer of Selenium IDE and consults on automation through his company, Element 34.

Send the author your feedback or discuss the article in the magazine forum.

Footnotes

[1]

Think of a check as a test done purely to confirm an assumption, which means that it is probably easy to do by machine—see this DevelopSense explanation.

[2]

Which in 2009 merged with Selenium to form the basis of Selenium 2.

When Did That Happen?

The First Computer in Space

by Dan Wohlbruck

The latest installment of Dan’s series on computer history recalls the early days of off-earth computing.

On August 31, 1963, the first computer in space, the Gemini Digital Computer, began its final testing phase. Under contract to build 20 such machines for the 10 manned Gemini missions, IBM started the project in April 1962, at its Space Guidance Center in Owego, N.Y. NASA’s first manned space flights, the Mercury program, were launched without onboard computers. In fact, on May 25, 1961, when President Kennedy spoke about a moon landing before the end of the 1960s, only two humans had flown in space: Yuri Gagarin and Alan Shepard. Men, at least, had gone there—computers had not.  

Gemini

The Gemini program was intended to bridge the gap between the single-man Mercury space capsule and the proposed three-man Apollo version. As such, the Gemini space capsule was built to accommodate two astronauts and it was the co-pilot’s job, among many other things, to operate the computer. IBM engineers built a 59-pound machine that, once installed in an unpressurized equipment bay to the left of the Gemini commander’s seat, would help the crew maneuver the Gemini capsule while in orbit. The Gemini Data Computer’s pushbutton and display devices were mounted on the co-pilot’s instrument panel. The IBM archive reports, “Using the push buttons, the co-pilot entered new navigation data into the computer or commanded the computer to display flight information.”  

The NASA web site gives the following account of the systems and programming effort that went into the Gemini Data Computer: “Development of the Gemini software was a learning experience for both NASA and IBM. It was, of course, the first on-board software for a manned spacecraft and was certainly a more sophisticated system than any that had flown on unmanned spacecraft to that point. When the time came to write the software for Gemini, programmers envisioned a single software load containing all the code for the flight, with new unique programs to be developed for each mission. Soon it became obvious that certain parts of the program were relatively unchanged from mission to mission, such as the ascent guidance backup. Designers then introduced modernizations, with some modules becoming parts of several software loads.  

“Another reason for modularization is the fact that the programs developed for Gemini quickly exceeded the memory available for them. Some were stored on the Auxiliary Tape Memory until needed. The problem of poor estimation of total memory requirements has plagued each manned spacecraft computer system. In the case of Gemini, changed requirements and attempts to squeeze the programs into the allotted space resulted in nine different versions of the software.”  

After two unmanned Gemini test flights, Gemini III lifted off on March 25, 1965 with Gus Grissom commanding, John Young in the co-pilot’s seat, and the Gemini Data Computer nestled in between them. Just before 4:00 in the afternoon, after completing its first orbit, Gemini III accomplished the first orbital maneuver by a manned spacecraft. For the first time man had done more than being flown into space—man flew and maneuvered in space. Grissom piloted the capsule, Young (the world’s first space-based computer operator) entered the data, and the little computer that could, did.  

Apollo

The last of the 20 Gemini Data Computers was delivered to NASA in December 1965. By then, the Apollo program was well underway. Apollo’s onboard guidance computer (the AGC) was developed by MIT and it used integrated circuitry instead of transistors. The AGC ultimately used 34 instructions as compared to Gemini’s 16 and it had its own operating system. The Apollo Guidance System became the first computer on the moon in July 1969 when it landed with Armstrong and Aldrin.  

After Apollo’s last mission, attention turned to the space shuttle. The space shuttle uses five General Processing Computers and, although the system has been continuously upgraded since its maiden voyage in 1981, it was and remains one of the most “computationally intensive spacecrafts ever built.”

In July 2010, NASA was authorized to make its last shuttle mission early in 2011. When that mission is completed, what started in 1961 with President Kennedy’s challenge will end. After that, no more Americans or their computers are scheduled to fly in space. All of it has taken exactly 50 years—and that’s when it happened.

Dan Wohlbruck has over 30 years of experience with computers, with over 25 years of business and project management experience in the life and health insurance industry. He has written articles for a variety of trade magazines and websites. He is currently hard at work on a book on the history of data processing.

Send the author your feedback or discuss the article in the magazine forum.

The Quiz

What’s the Word?

by Michael Swaine

Many of the technical terms that we use every day in programming also have a common meaning more or less unrelated to their programming meaning.

A bit is something you use to control a horse; a fork is something you eat with; inheritance explains where you got those blue eyes or that white elephant.

This issue’s quiz presents ten lists of programming words that have a different meaning in ordinary conversation. All the words have been run through our handy-dandy Anagram Machine, so they may not be immediately recognizable.

Kcyucyo

Qvoa

Jnqa

Vxjzli

Sckivin

Aucjli

Hafxas

Dliu

Ulwg

Rvwjlin

Kslwg

Viwzcjawjxia

Vhhapksn

Slvuai

Scyg

Uicmai

Jiaa

Savr

Illj

Qnjzly

Ivp

Mcixh

Dlip

Kxo

Ixkn

Wvjwz

Jzild

Kvha

Ulxksa

Hdcyo

Jvo

Zcj

Ixy

Aiili

Ucvslo

Uawsvivjcly

Atqiahhcly

Vioxpayj

Wlppayj

Hpvssjvsg

Scyj

Hqlls

Jziavu

Hjicyo

Sllq

Qvjwz

Wvhj

Vwjli

Wzvivwjai

Hwicqj

Pvhg

Hvyuklt

Hdcyo

Qlq

Wllgcah

Qvjz

Raywaqlhj

Hjiavp

Rslvj

Ovikvoa

Uxpq

Zavq

Jivhz

We’ve organized the words into these ten lists as an aid to solving. In each list, the words—taken in their ordinary meaning rather than their programming meaning—share a common theme. The themes, in no particular order, are:

Animal, Vegetable, Mineral;

Baseball Been Very, Very Good to Me;

Construction;

Conversation;

Discards;

Grab Bag;

Kid Stuff;

Sew What;

Theater; and

The Write Stuff.

You may have trouble finding a wedge into this quiz, since there are none of the usual aids to anagram solving, like words with apostrophes or one-letter words or a three-letter word that appears frequently and so might be the. But all the words share the same anagram mapping, so every one you figure out will help you with the others. If you can find that wedge, you should be all right. The trick is to find the wedge. Good luck!

Solution to Last Issue’s Quiz

Last issue we gave you a chance to find out how familiar you are with the titles of Pragmatic Bookshelf books. Or how good you are at solving Hangman-style puzzles. Or both. Here are the seven titles you found if you solved the quiz completely:

Arduino

Ubuntu Kung Fu

TextMate

Rails Recipes

Hello Android

Core Data

Agile Coaching

That’s right: the letter that occurred five times in a twelve-letter book title is u. Not your first guess, eh?

Calendar

Author sightings, partner events, and other notable happenings.

A good url to check for events of interest to Rubyists.

Author Appearances

Aug 9–13, Agile 2010, Orlando, FL

“Improving Customer Conversations” and “Manager as Work System Designer: 13 Essential Questions”

Esther Derby, author of Behind Closed Doors: Secrets of Great Management; Agile Retrospectives: Making Good Teams Great

Aug 9–13, Agile 2010, Orlando, FL

“Agile Coaches Dojo” and “Refactor Your Retrospectives”

Rachel Davies, author of Agile Coaching

Aug 9–13, Agile 2010, Orlando, FL

“Exploring Coaching From Multiple Dimensions and Levels,” “Agile Managers: The Essence of Leadership,” and “Agile Program Management: Another Approach to Large Projects”

Johanna Rothman, the author of Manage Your Project Portfolio: Increase Your Capacity and Finish More Projects, Manage It!: Your Guide to Modern, Pragmatic Project Management, and Behind Closed Doors: Secrets of Great Management

Aug 10, Kansas City Ruby, Kansas City, MO

“An Introduction to Node.js (with a Side of CoffeeScript)”

Travis Swicegood, author of Pragmatic Version Control using Git

August 10, Uniforum Chicago

In his “Crash Course in Git,” Andy will be using Travis Swicegood’s slides as source material and giving away a copy of his book.

Andy Lester, author of Land the Tech Job You Love

Aug 17–20, Pragmatic Studios, Santa Clara, CA

“iPhone Studio”

Daniel Steinberg, co-author of iPad Programming: A Quick-Start Guide for iPhone Developers and author of Cocoa Programming: A Quick-Start Guide for Developers, and former Apple iPhone evangelist Matt Drance

Aug 18–20, Pragmatic Studios, Santa Clara, CA

“Rails Studio”

Dave Thomas and Chad Fowler, the author of The Passionate Programmer: Creating a Remarkable Career in Software Development

Aug 26–28, Lone Star Ruby Conference, Austin, TX

“Mary Poppins meets the Matrix”

Bruce Tate, author of Seven Languages in Seven Weeks

Aug 28, RubyKaigi 2010, Tsukuba, Ibaraki, Japan

“A Metaprogramming Spell Book (for Ruby and Rails)”

Paolo Perrotta, author of Metaprogramming Ruby: Program Like the Ruby Pros

Aug 30–Sept 2, Obtiva, Chicago, IL

“Advanced Ruby on Rails”

Noel Rappin, author of Rails Test Prescriptions: Keeping Your Application Healthy

Sept 3–4, Ruby Hoedown, Nashville, TN

“There’s A Wheel For That Already—Hidden ‘gems’ in the Ruby Standard Library”

Brian Hogan, author of Web Design for Developers: A Programmer's Guide to Design Tools and Techniques

Sept 10, miniSPA, London, UK

“Retrospectives Refactored”

Rachel Davies, author of Agile Coaching

Sept 11, WindyCityRails, Chicago, IL

“Testing in a Legacy Environment”

Noel Rappin, author of Rails Test Prescriptions: Keeping Your Application Healthy

Sept 20, MongoDB Conference, Boston, MA

“From MySQL to MongoDB at Sluggy.com,” “Scala + Mongo for Java Developers who don’t know Scala,” and “Python Development with MongoDB”

Brendan McAdams, author of the forthcoming MongoDB: A Quick Start Guide

Sept 22–24, Pragmatic Studios, Reston, VA

“Rails Studio”

Dave Thomas and Chad Fowler, the author of The Passionate Programmer: Creating a Remarkable Career in Software Development

Sept 27–28, JAX, London, UK

“Coaching Teams over Acceptance Testing Hurdles”

Rachel Davies, author of Agile Coaching

Sept 27–29, iPhone/iPad Dev Con, San Diego, CA

“Advanced Core Data: Building Your Own NSFetchedResultsController” and “Advanced Core Data: Importing and Exporting Data Efficiently”

Marcus Zarra, author of Core Data: Apple's API for Persisting Data on Mac OS X

Sept 27–29, iPhone/iPad Dev Con, San Diego, CA

“Coming Up to Speed on Objective-C and Model-View-Controller,” “Mastering iPhone OS 4.0: What’s New, What’s Changed,” “Moving to the iPad: What You Need to Know,” “Building Killer Universal Apps for iPhones and iPads”

Daniel Steinberg, co-author of iPad Programming: A Quick-Start Guide for iPhone Developers and author of Cocoa Programming: A Quick-Start Guide for Developers

Oct 5–6, Agile Business Conference, London, UK

“Building a Culture of Trust”

Rachel Davies, author of Agile Coaching

Oct 14–15, Strange Loop, St. Louis, MO

“Mary Poppins meets the Matrix”

Bruce Tate, author of Seven Languages in Seven Weeks

Oct 18, Pacific Northwest Software Quality Conference (PNSQC), Portland, OR

“Document Your Software Project”

Ian Dees, co-author of Using JRuby and author of Scripted GUI Testing With Ruby

Oct 20, MongoDB Conference, Chicago, IL

“PyMongo and Python Development”

Brendan McAdams, author of the forthcoming MongoDB: A Quick Start Guide

Oct 25–28, Pragmatic Studios, Chicago, IL

“iPhone Studio”

Daniel Steinberg, co-author of iPad Programming: A Quick-Start Guide for iPhone Developers and author of Cocoa Programming: A Quick-Start Guide for Developers

USENIX Events

Aug 11–13, 19th USENIX Security Symposium, Washington, D.C.

Whether you’re a researcher, a system administrator, or a policy wonk, come to USENIX Security ’10 to find out how changes in computer security are going to affect you. The 3-day program includes an innovative technical program, starting with a keynote address by Roger G. Johnston of the Vulnerability Assessment Team at Argonne National Laboratory; invited talks, including “Toward an Open and Secure Platform for Using the Web,” by Will Drewry, Google; a refereed papers track, including 30 papers presenting the newest advances; and a Poster session displaying the latest preliminary research. Gain valuable knowledge on a variety of subject areas, including detection of network attacks, privacy, Internet security, Web security, and more.

O’Reilly Events

Sept 7–8, Gov 2.0 Summit, Washington, D.C.

O’Reilly’s Gov 2.0 Summit happens in Washington D.C. Last year's event was sold out. Submit your request today and reserve your seat at the table with leaders and decision makers to refine the concept of government-as-platform.

Sept 27–30, Web 2.0 Expo, New York

O’Reilly’s Web 2.0 Expo New York happens at the Sheraton New York Hotel & Towers. Early Registration is open and you can save $350 if you register before August 5. This year, Web 2.0 Expo New York focuses on Platforms for Growth, diving into the platform opportunities for the whole web ecosystem, particularly mobile, real-time, and the social web.

Other Happenings

Aug 9

Alfred Aho, co-creator of AWK language, is 69.

Aug 11

Steve Wozniak is 60.

Aug 20

Game developer John Carmack is 40.

Aug 21

Linus Torvalds announces Linux project, 1991.

Aug 29

Boy genius Stephen Wolfram is 51.

Sept 1

This month the GNU Project turns 27.

Sept 2

First message sent over Internet, 1969.

Sept 2

sendmail creator Eric Allman is 55.

Sept 4

LISP creator and AI pioneer John McCarthy is 83.

Sept 9

C creator Dennis Ritchie is 69.

Sept 10

Space tourist Charles Simonyi is 62.

Sept 27

Perl creator Larry Wall is 56.

Oct 2

The Great Quux is 56.

Oct 4

The Free Software Foundation is 35.

Oct 4

Birthday of John Vincent Atanasoff, one of the inventors of the computer.

Oct 5

Linux is 19.

Oct 6

Adobe co-founder John Warnock is 70.

Oct 12

Birthday of Ole-Johan Dahl, co-creator of the Simula language and thus of object-oriented programming.

Oct 15

David Heinemeier Hansson is now over 30, hence not to be trusted.

Oct 16

Mike Muuss, who invented Ping, was born on this date in 1958.

Oct 17

October Manifesto issued by Tsar Nicholas II in an unsuccessful attempt to undermine the Russian Revolution. (October 30 according to the Gregorian Calendar.)

Oct 25

Peter Naur, the N in BNF, is 82.

Oct 28

Former software executive Bill Gates is 55.

Oct 29

On this date in 1969, ARPAnet first linked Doug Engelbart’s lab at SRI with Leonard Kleinrock’s at UCLA.

Oct 31

The traditional date for the leaking of confidential internal Microsoft documents outlining strategies for undermining open source software.

Shady Illuminations

Toward a Better Class of Manifestos

by John Shade

John surveys the leading examples of software development manifestos and makes some suggestions.

A manifesto is a communication made to the whole world, whose only pretension is to the discovery of an instant cure for political, astronomical, artistic, parliamentary, agronomical and literary syphilis.

—Tristan Tzara

Software development has the pox. On that I think we can all agree. We may differ on just which organs are affected and how dire the prognosis is without drastic treatment, but there can be no doubt that the patient is sick as a dog. Fortunately, an instant cure is as close as your keyboard. All that’s needed is a stiff dose of manifesto.

And there is no lack of software development manifestos.

Uh-huh, but what is a manifesto, really? I don’t pretend that I can improve on Tristan Tzara’s definition, but I’d like to remind you—OK, myself—what manifestos are for and what they are like. Maybe then I can avoid mixing them up with sermons or municipal ordinances or antipatterns. (If you mix up an antipattern and a manifesto, do you get antipasto?)

Let’s look at some examples:

The Gnu Manifesto is Richard Stallman’s invitation to other programmers to help him write an operating system. It’s his equivalent of Linus Torvalds’s comp.os.minix Usenet posting. It is also RMS’s declaration of independence from MIT: “I could not remain in an institution where such things are done for me against my will.” It diagnoses the disease—un-free software—and prescribes the remedy: re-inventing Unix. It references Kant. It advocate a nonstandard pronunciation of the word “gnu.” All these things make it a fine example of a manifesto. A couple of things that would make it a better manifesto are a list of Principles and a list of signers.

The Agile Manifesto has both of these, and as a bonus it has a fuzzy photograph of the signers in a semi-circle apparently engaging in some arcane rite like sacrificing a small animal that was insufficiently agile. In a codicil to the main document, one of the signers points out that most of the other signers mispronounce the word “agile.” Disputes over the pronunciation of the subject of the manifesto in the manifesto itself are a frequent feature of true manifestos. So, another fine example.

The Cluetrain Manifesto clearly demonstrates one of the primary purposes of a manifesto: to renounce outmoded thinking and replace it with the new thinking that only the signers have truly grokked. Embracing this new thinking, the manifesto says, will force one to behave in radically different ways. The Cluetrain Manifesto has 95 theses, just like Martin Luther’s document that launched the Protestant Reformation, and it begins, “People of earth...,” just like Conan O’Brien’s farewell letter to NBC. While it doesn’t advocate mispronunciation, it more than makes up for it with the word “cluetrain.” A third fine example of a manifesto.

The Waterfall Manifesto has a sufficiently dogmatic list of principles (“The best architectures, requirements and designs emerge from nowhere and should be send back there as soon as you detect them.”) But it doesn’t propose to change the world (the opposite, really) and doesn’t mandate any non-standard pronunciation. It’s not really as good an example of a manifesto as the three I just described, but I’m willing to cut it some slack for mentioning beer and pizza.

As you see, these these manifesti have several things in common. They diagnose a problem and prescribe a solution. Usually they include a list of principles in dogmatic language. They reject the past and embrace the future. A specific future, defined in the manifesto. This, they say, is the right way to act. Your true manifesto is a call to action. It is intended to be signed, or at least initialled. You agree to a manifesto, you promise to follow its principles.

And it frequently advocates a non-standard pronunciation.

I don’t really understand why “Agile Manifesto” isn’t an oxymoron, but I guess any manifesto that doesn’t have a touch of inconsistency probably isn’t a real manifesto. Consistency, as Ralph Waldo Emerson said, is the hobgoblin of little minds.

And why, now that I think of it, did he say that? I mean, hobgoblin? Really, Ralph? Is hobgoblin really the word you were searching for? A mischievious sprite? I know you’re probably the world’s most famous essayist and this is a famous saying of yours and you’re dead and all, but there are a ton of things that consistency could be to a small mind, like bane or taskmaster or mantra, any of which would make more sense than hobgoblin. Antipasto would make more sense than hobgoblin. “A foolish consistency is the antipasto of small minds.” See? Better. I think you just threw a random word in there, Like Laurie Anderson composing a song, and gullible people rewarded you for it.

You make me want to issue a manifesto.

A Manifesto for Software Manifestos?

If any of these software manifestos had managed to cure software development pox, we wouldn’t need the rest of them. The proliferation of remedies is evidence of their inefficacy, as Ralph Waldo Emerson might have said if he’d ever served on an ANSI committee.

But apparently you don’t have to give up an existing software development manifesto to embrace another one. The manifesto paradigm supports multiple inheritance. Agile Software Manifesto signer Alistair Cockburn has written his own Cooperative Game Manifesto for Software Development. It’s not about game software development, it’s about software development as a game. I have to admit I’m drawn to any manifesto that says it’s all a game, whatever the it is. I’d been expecting something more prickly from this Cockburn guy, though, and then I found out that he isn’t the Cockburn who writes Counterpunch.

Anyway, clearly what is needed is one truly excellent software development manifesto. How to come up with that excellent manifesto I have no idea, except to point out that there are many examples of what a manifesto should be outside the realm of software.

In The Checklist Manifesto, a whole book about writing checklists, the author reveals the melancholy truths that (1) today’s professionals inevitably make mistakes, and (2) these are not mistakes of ignorance but of ineptitude. For most of the things you screw up, you should have known better. The fact that the author is a surgeon is not cause for celebration.

So maybe we know how to make an excellent manifesto but we’re just screwing it up. If we just made checklists, maybe we’d do better. Or maybe, taking our cue from the world’s most awesome CEO, we should focus on style.

Manifesto Style

There is a style that any pronouncement aspiring to manifestoness should adhere to. A manifesto is never tentative or shy. A manifesto never vacillates. A manifesto is not a statement, but an action. It intends to change the world. Here’s a characteristic bit of manifesto style:

“Let the good incendiaries with charred fingers come! Here they are! Heap up the fire to the shelves of the libraries! Divert the canals to flood the cellars of the museums! Let the glorious canvases swim ashore! Take the picks and hammers!”

-The Futurist Manifesto

Most manifestos don’t rise to this level of eloquence. But that doesn’t mean they aren’t conceived as forceful acts.

The Port Huron Statement starts out sort of okay: “We are people of this generation, bred in at least modest comfort, housed now in universities, looking uncomfortably to the world we inherit.” But pretty soon it’s larded over with language like “the permeating and victimizing fact of human degradation” and “a discontinuous and truncated understanding... of the surrounding social order.” Yet it served to launch Students for a Democratic Society (SDS).

The Communist Manifesto lays out the kind of world its author desired, and clearly states that these “ends can be attained only by the forcible overthrow of all existing social conditions. Let the ruling classes tremble....”

Now that’s what I’m talking about.

Who’s Your Dada?

Political manifestos sometimes rise to this “You have nothing to lose but your chains” level, but really the best manifestos are the founding documents of futurist movements in art. For some reason, the authors of art manifestos don’t limit themselves to art, but encompass food, politics, and anything else anybody ever had an opinion about. I guess it’s a characteristic of manifesto writing to overgeneralize, but artists do it the best.

The Futurists made a fetish of publishing manifestos, and got very skilled at it. The wrote manifestos on painting, architecture, religion, clothing, and cooking. In every case they expressed their disdain for the past, for harmony, for playing it safe, and praised originality, “however daring, however violent.” The Dadaists in Paris in the 20s spent half their time writing manifestos and half their time pushing the limits of art and/or sanity. Seems like they were having a lot of fun.

If software development is an art, its manifestos ought to be modeled after the best manifestos: those from the arts. I want a Surreal Software Manifesto, a Dada Developer Manifesto. A Cannibal Coder Manifesto. Now that would be a real manifesto. Does some Python coder have in in him or her to write something like this:

Only Cannibalism unites us. Socially. Economically. Philosophically. The unique law of the world. The disguised expression of all individualisms, all collectivisms.... It’s because we never had grammatical structures or collections of old vegetables.... Screenplays. Screenplays. Screenplays. Screenplays. Screenplays. Screenplays. Screenplays.

—Oswald de Andrade, Brazilian Modernist artist, in The Cannibal Manifesto

Who could argue with that?

More Manifestos

Here are a few more manifestos from the field of software development, mostly from left field: A Software Design Manifesto by Terry Winograd, Ethical Software Design Manifesto (posted at Nordic Battle Group), The Rugged Software Manifesto, A New Software Manifesto for India, The Boring Software Manifesto, The Boring Accounting Software Manifesto, The Open Cloud Manifesto, Rebooting Manifesto, The Complex Manifesto for Software Development, The Introversion Software Manifesto

John Shade was born in Montreux, Switzerland on a cloudy day in 1962, where, we have it on good authority, he was “raised by wolves.” Although subsequent internment in a series of obscure institutions of ostensibly higher learning did nothing to brighten his outlook, John nevertheless wishes to share this enlightening daily affimation.

Send the author your feedback or discuss the article in the magazine forum.