Archive for April, 2010

Mini-review of Freedom(tm) by Daniel Suarez

Killer ninja motorcycles chop people up. Doc Manhattan’s less-blue relative appears. Good guys win. They establish humane, John Robb-style resilient communities. Bad guys get their just deserts. Huzzahs all around. Except…

…the good guys would have gotten c-r-e-a-m-e-d were it not for the all-wise program on their side and the tech that—oddly—only it knew how to build. So, for us in a non-fiction world, this is actually a pessimistic book: the author sees a bad moon rising, but we seem to be short on inhumanly brilliant game designers to prevent it.

If you liked the previous book, you’ll like this one too.

Mocks and legacy code

While on my grand European trip, I stopped in for a day at a nice company with a fun group of people doing good work on a legacy code base. They challenged me to improve an existing test using mocks. The test was typical of those I’ve seen in legacy code situations: there was a whole lot of setup code because you couldn’t instantiate any single object without instantiating a zillion of them, and the complexity of the test made figuring out its precise purpose difficult.

After some talk, we figured out that what the test really wanted to check was that when a Quote is recalculated because it’s out-of-date, you get a brand-new Quote.

Rather than morph the test, I tried writing it afresh in my mockish style. A lot of the complexity of the test was in setting things up so that an existing quote should be retrieved. Since my style these days is to push off any hard work to a mocked-out new object, I decided we should have a QuoteFinder object that would do all that lookup for us. The test (in Ruby) would look something like this:

quote_finder = flexmock(”quote finder“)
quote = flexmock(”quote“)

during {
   some function 
}.behold! {
 quote_finder.should_receive(:find_quote).once.
              with(…whatever…).
              and_return(quote)
 
}

Next, the new quote had to be generated. The lazy way to do that would be to add that behavior to Quote itself:

quote_finder = flexmock(”quote finder“)
quote = flexmock(”quote“)

during {
   some function 
}.behold! {
  quote_finder.should_receive(:find_quote).once.
               with(…whatever…).
               and_return(quote)
  quote.should_receive(:create_revised_quote).once.
        with(…whatever…).
        and_return(”a new quote“)
}

Finally, the result of the function-under-test should be the new quote:

quote_finder = flexmock(”quote finder“)
quote = flexmock(”quote“)

during {
   some function 
}.behold! {
  quote_finder.should_receive(:find_quote).once.
               with(…whatever…).
               and_return(quote)
  quote.should_receive(:create_revised_quote).once.
        with(…whatever…).
        and_return(”a new quote“)
}

assert { @result == a new quote }

I felt a bit of a fraud, since I’d shoved a lot of important behavior into tests that would need to be written by someone else (including the original purpose of the test, making sure the next Quote was a different object than the last one.) The team, though, gave me more credit than I did. They’d had two Aha! moments. First, the idea of “finding a quote” was spread throughout the code, and it would be better localized in a QuoteFinder object. Second, they decided it really did make sense to have Quotes make new versions of themselves (rather than leave that responsibility somewhere else). So this test gave the team two paths they could take to improve their code.

In the beginning, the QuoteFinder and Quote#create_revised_quote would likely just delegate their work to the existing legacy code, but there were now two new organizational centers that could attract behavior. So this looks a lot like Strangling an App, but it avoids that trick’s potential “then a miracle occurs” problem of needing a good architecture to strangle with: instead, by following the make-an-object-when-you-hesitate strategy that mocking encourages, you can grow one.

I’ve not seen any writeup on using mocks to deal with legacy code. Have you?

P.S. It’s possible I’ve gotten details of the story wrong, but I think the essentials are correct.

TDD & Functional Testing: from collections to scalars

I’ve been fiddling around with top-down (mock-style) TDD of functional programs off-and-on for a few months. I’ve gotten obsessed with deferring the choice of data structures as long as possible. That seems appropriate in a functional language, where we should be talking about functions more than data. (And especially appropriate in Clojure, my language of choice, since Clojure lets you treat maps/dictionaries as if they were functions from keys to values.)

That is, I like to write these kinds of tests:

(example-of "saturating a terrain"
   (saturated? (... terrain ...)) => true
   (because
      (span-between-markers (... terrain ...)) => (... sub-span ...)
      (saturated? (... sub-span ...)) => true
)

… instead of committing to what a terrain or sub-span look like. That’s been working reasonably well for me.

I’ve also been saying that “maps are getters”. By that, I mean that—given that you’ve test-driven raise-position—it really makes no more sense to test-drive this:

(defn raise [terrain]
   (map raise-position terrain))

… than it does to test a getter: it’s too obvious. That leads to a nice flow of testing: I’m always testing the transformation of things to other things. I don’t have to worry, until the very end of test-driving, that the “things” are actually complex data.

The problem I’ve been running into recently, though, is handling cases where complex data structures are converted into single values. For example, I’ve been trying to show a top-down TDD of Conway’s Life. In that case, I have to reduce a set of facts about the neighborhood of a cell into a single yes-or-no decision: should that cell be alive or dead in the next iteration? But expressing that fact is rather awkward when you don’t want to say precisely what a “cell” is or how you know it’s “alive” or “dead” (other than that there’s some function from a cell and its environment to a boolean).

To be concrete, here’s something I want to claim: a cell is alive in the next iteration if (1) it is alive now and (2) exactly two of the cells in its neighborhood are alive. How do you say that while being not-specific? I’ve not found a way that makes me happy.

Part of the problem, I think, is that when you start talking about individual elements of collections, you’re moving from the Land of TDD, which is a land of functions-of-constants to a Land of Quantified Variables (like “there exists an element of the collection such that…”). That way lies madness.

informed-citizens.org

As part of my ongoing (since age 28) midlife crisis, I’ve been casting around for an ambitious product to build. I have an idea. I describe my personal motivation for it, then sketch what “it” is, on a separate blog. I encourage you to try to talk me out of it.

About “Business Value”

I’m notoriously long-winded on Twitter. Here’s what I wrote earlier today:

Bv2

Bv3

What do I mean by that?

In my research into your species, I’ve noticed that humans are social animals. With the exception of ideologues and other damaged people, you work best when your work is oriented toward other people. Not “people” (in the abstract), but actual individuals. Because you’re quite good at personifying objects—look how many of you act like your boats are people—you can also do well when oriented toward improving those object’s “lives”. (That is, you treat your software the way you treat your pets, which is not that different from the way you treat [some of] your loved ones.)

When it comes to software development, I’ve seen teams that are extremely… nurturing toward the product owner. I’ve seen teams that treat the product itself as a person to be groomed and prepared for its entry into the world. I’ve seen teams that identify strongly with the prototypical, personified, or actual end user and want to make her life easier.

Quite often these teams, especially Agile teams, seem obsessively focused on “Business Value”, but that’s in the context of personal relationships. “Business Value” is a shorthand, a way of keeping conversations from going astray, of keeping people focused. It is a term that signals or reminds of other things—it is not a thing in itself.

Increasingly these days, when I hear people theorizing about Agile and Lean, they are treating “Business Value” as a thing in itself. It is treated as an end, rather than as a means. (This is in keeping with the decline of Agile as a bottom-up team-oriented insurgency.)

Who cares? The good thing about old-style Agile is that it tamped down teams’ tendency to be overbearing while still involving them in the conversation about what makes the product better. Code is generative, and programmers could—and did—suggest directions the business could take based on what the code “naturally” “wanted” to do. This could lead to wonderful and illuminating conversations.

When Business Value is determined from On High and is a discrete thing in itself—a product of expertise not accessible to the hoi polloi—this conversation is short-circuited. Analysis (the province of Business) populates swimlanes on the Kanban board or the product backlog. When Development takes an item from the Analysis backlog or swimlane, the signal it sends upstream is “I need a new chunk of work” not “Let’s talk about the next good idea.”

That is: your species has another skill. Just like you’re good at turning objects into people, you’re good at turning people into objects. It’s easy for you to subordinate actual humans to the beauty of a System. You’re terribly prone to slip into ideology, to elevate objects to totems-to-be-deferred-to. “Business Value” is, I fear, becoming one such totem.

To forestall the inevitable comment: I know (I know!) that in a well-functioning organization with Respect for People, the ugliness I describe wouldn’t happen because wise philosopher-kings wouldn’t let it. I just believe there is a shortage of such wise philosopher-kings and—in their absence—we should cut with the grain of human nature.