justin․searls․co

Jasmine Tactics

Today, I had the good fortune to visit my friends at Sparkbox, where they host a Dayton JavaScript user group called Gem City JS. Today, I showed up to share some perspective on how to test JavaScript with Jasmine.

Folks have been asking me to share a screencast of how I write Jasmine tests for a few years, so I recorded the session and am providing it online, completely unedited:

This screencast (YouTube) is merely a conversation to provide an answer to the question, "Hey Justin, how would you write a test for ____ JavaScript code?" where that blank might be filled with "interacting with the DOM", or "binding user events", or "making AJAX requests". I cover each of those in a way that's similar to how I do it today; I trust that in six months, I'll have evolved and changed my tastes somewhat, but this reflects where I'm at right now.

Okay, I'm interested…

An Includes Trap

Funny how just this week I felt compelled to blog about implicit knowlege, because a terrific example of the possible consequences of too much implicit knowledge came up yesterday.

Please forgive me for the length of this post, because this is a surprisingly subtle problem. As with most subtle problems, the context and relevant background knowledge are necessary to arrive at a clear understanding of both the problem itself and the causes.

Let's dive in and find out…

Explicit vs Implicit Knowledge

We lack much of a vocabulary to describe knowledge and how code can succeed to or fail at codifying it. The points made in this post are so popular as to be self-evident, but it seems I can always use more practice in articulating them. I'll start with an example that many of us are familiar with and then swivel into an issue I ran into today.

code comments

Inline comments in code are often maligned for two reasons: (1) well-factored code can be so expressive that additional comments shouldn't be too valuable, and (2) comments often fall out of sync with reality, as only the code must change to implement new behavior.

What happens next will shock you…

Upgrading Hacked Dependencies

Today we set out to upgrade one of the third-party JavaScript dependencies on which our project relies and we inadvertently discovered that it had a number of custom hacks made against it. This blog post replays a similar experience and how we can reduce some of the risk in attempting to confidently upgrade the dependency with git diff and patch.

introducing a new dependency

It starts when we add a new 3rd party library to our project. Everything is new and exciting!

And before you knew it…

Say Hello to Lineman

We've been hard at work on a tool called Lineman that helps you create web applications in JavaScript (and CoffeeScript!), and we're really excited to share it with you!

Tonight I recorded an 8-minute screencast to show you the ropes:

As time goes on, I'll go into more detail on both our motivations in writing Lineman as well as more advanced usage like overriding configuration defaults.

In the meantime, please give Lineman a spin and tell us what you think!

Let's dive in and find out…

API Design is Hard

[Note: this post covers unreleased features of gimme, which are unreleased because of the issues described in this post. They need more time in the oven. You can peruse the feature branch on github]

Working on gimme with Mr. Karns made me realize I'd painted myself into a corner on gimme's API design. I thought I'd share here, for hope that either (a) someone will respond with an approach I like better, or (b) the topic might prove independently useful, and some good will come of this after all.

And then what happened?…

Purpose-Oriented Tests

Lately I've been thinking a lot about how we can improve our code by reflecting on our mindsets and motivations with respect to software testing. A while ago, I wrote about the huge impact that prompts have on how we grow code (even the parts of speech we use to name objects). Later, I sat down to illustrate a taxonomy of the types of tests I tend to see in the wild. Recently, I wrote a bit about our natural tendency to misplace blame when testing gets hard.

What happens next will shock you…

Blame the Code not the Test

"This test is too coupled to the implementation."

This complaint is commonly levied when—on account of test double setup—you have spec code that looks a lot like the subject's ("SUT's") implementation code. I hear this complaint most often in cases where the subject has little responsibility beyond passing a value from dependency A to dependency B and returning it.

Because isolation tests specify not only the externally observable behavior of the subject, but also the subject's contracts with its collaborators, it should be obvious that isolation testing is going to bring complex interactions with collaborators to the forefront in a way that an integrated test would not.

You'll never guess what happens next…

On Organizational Transformation

I have a lot of empathy for people that work at big companies. No one should be required to use a crappy ThinkPad loaded with sluggish, productivity-monitoring software. No one should be forced to communicate through a regimented, politicized hierarchy to do their job. No one should have their actions decided for them by someone else, especially because no one else has a better chance of determining necessary actions than the person who is closest to the work.

And then what happened?…

Language-Based User Groups Considered Boring

Has anyone else wondered whether our habit of organizing user groups around a programming language (Java, Ruby) or a technical stack (.NET, iOS) has outlived its usefulness?

Lately, a group's language preference seems to be an unhelpful way to subdivide our community's interests. JavaScript frameworks are all the rage at Ruby user groups. RubyMotion talks are about to inundate iOS user groups. And I've seen "mock objects rock" and "mock objects suck" talks at numerous groups of different languages (noting that mock confusion differs only in dialect from group to group).

Keep reading…

A Note on Feedback

Many people who practice test-driven-development completely surrender the practice when they undertake writing code for user interfaces. It's something I observe often as I try to sell people on TDD for JavaScript. The arguments I hear most often go something like, "testing DOM/jQuery/view code isn't valuable", or, "testing a view is a waste of time—I can see that it's working as quickly as I can run a test!" After all, it might take no longer to hit Cmd-R (or F5) in a browser than it takes to run a unit test.

And before you knew it…

Types of Tests

I want to spend some time documenting the different types of automated tests I encounter most often, detailing each type's distinct characteristics, advantages, and challenges. This is not a novel concept, but since many developers I interact with continue to conflate, confuse, and generally stumble over this issue, I figured it couldn't hurt to share my perspective. I'll take a first swing at this post by using the terms I prefer, but I will gladly update it in response to your feedback—after all, any taxonomy is only useful if everyone in a given group can largely agree on it.

Keep reading…

The Mythical Team Month

I was honored to present this talk at Agile and Beyond 2012 today.

Embedded below is a screencast of the talk (hosted on vimeo) as it was presented, with audio:

Embedded below is my slide deck (hosted here by my gracious friends at SpeakerDeck):

If you have any feedback—questions, comments, criticisms—I'd love it if you left a comment on this post!

jasmine-fixtures

Update 2/5/2012: replaced the jasmine-fixture description with examples using the current "affix()" API method.

One of the questions I'm frequently asked about test-driven development with Jasmine is a variation of, "how do I get my specs to see my HTML?" It's a completely fair question: JavaScript very often inspects or manipulates the DOM, so having a way to arrange the DOM's state with HTML is critical to writing tests.

My goal this morning is to explain why exactly I recommend against loading HTML fixtures from external files when writing unit tests.

And then what happened?…

iCloud is Anti-Family

My spouse and I share an Apple ID. But we also maintain separate Apple IDs. Paradox.

Why? Because nearly a decade ago, it took us all of fifteen minutes to realize that we were purchasing the same songs multiple times from our separate computers.

That realization—and the subsequent decision to share an Apple ID for purchases—has made each new Apple software upgrade increasingly complex over the years. So I made a chart!

And then what happened?…

The Limits of Metaphors

All metaphors break down with sufficient mileage.

[And they often break down quite quickly, like that car metaphor I just made.]

Because metaphors break down, it's worth pondering the fact that most of humanity only comprehends software through the use of metaphors.

  • The metaphors most users experience are graphical user interfaces (desktops, folders, round-rect app icons, back buttons, etc.)
  • The metaphors our friends and family hear include our own attempts to describe how writing software is actually quite a lot like crafting sturdy Amish furniture
  • The metaphors conveyed to business people—at least, the ones that pay to have software developed—are as boundless as they are inane (and they're usually quite inane)
  • The metaphors that software developers themselves are steeped in are perhaps too complex to ever escape. We stand on the shoulders of giants: building domain-specific metaphors that rest atop dozens of other metaphoric layers. [If you're inclined to disagree, then I suppose that implies you can yet derive the 1's & 0's backing the software you use; or the logic gates; or the assembly operations.]

My proposal today is that we start treating software metaphors with greater skepticism.

And before you knew it…

What's Wrong With Ruby's Test Doubles

Prologue

First things first: let’s square up terminology. For the sake of facilitating sane discussion on this topic, I’ve adopted the terms used in Gerard Meszaros’ XUnitPatterns book. He drew a complex table for this, but I’ll quickly summarize here:

  • Test Double — a generic term to describe an artifical stand-in for code (usually an object) upon which the subject code you’re specifying depends. Mocks, spies, stubs, fakes, etc. are all specific subtypes of test doubles.
  • Stub — a test double that can be configured to respond to certain invocations (e.g. `when(panda.poke()).thenReturn(“chuckle”)`) in order to facilitate downstream behavior within your subject code. However, a stub can’t do anything to verify that certain invocations take place.
  • Mock — a test double that can be configured to expect certain invocations in advance, raising exceptions if those interactions never occur. They add the bizarre wrinkle that if they receive any unexpected invocations, they’ll raise an exception. For convenience, the mock objects generated by most (all?) modern mock libraries can do double-duty as stubs, despite Martin Fowler’s best effort to explain all this.
  • Spy — a test double that records all of the invocations made against it, exposing some way to interrogate how it was interacted with after the fact (e.g. `verify(panda).eat(bamboo)`). Spies respond quietly when interacted with by your subject code, usually returning the bare minimum the language supports (`undefined` in JavaScript, `null` in Java, `nil` in Ruby). Of course, they respond less silently when they’ve been set up to stub an interaction, because most spies can stub too!
  • Partial Mock / Proxy — a real object for which only particular method interactions have been cherry-picked to be stubbed or expected. Partial mocks break unit test isolation (because your subject code is now interacting with a quasi-real dependency) and their controversial use has been known to incite nerdy fisticuffs.

When it comes to test doubles available to Ruby developers, something has puzzled me for a while. Many of the brightest minds in testing left Javaland to join the Ruby community. Because of this, I was shocked to find that Mockito—a test spy framework for Java—is a more expressive tool for working with generated test doubles than any of the numerous libraries available for Ruby.

To be continued…

The Power of Prompts

This post is partly in response to to this tweet, and partly a follow-up to a teaser I tweeted earlier this week.

We humans are suckers for suggestion. If you need evidence of this, consider something as seemingly innocuous as the order in which we ask people questions.

If I were to ask you: 

1. Does the following web site load properly in your browser? Make sure all the pictures load: cuteoverload.com

2. Do you support the euthanasia of stray bunnies brought to animal shelters?

Let's dive in and find out…

Open source interviewing

When someone applies to Pillar, we invite them to submit a code example that solves a particular problem. We review the code as an input early in the interview process.

It’s a helpful component of getting acquainted with a candidate, but a few things aren’t ideal:

  • For any toy project, the domain is going to be trivial enough that it isn’t likely to be very representative of a larger “real” project
  • As I review more and more submissions which solve the same handful of problems, I’m finding it harder to evaluate each with a fresh set of eyes
  • Ultimately, the code doesn’t have any utility—its lifecycle ends as soon as it has been reviewed and discussed. This despite the fact that many candidates invest a significant amount of time writing it

Here’s an idea that might address those concerns: let’s start asking candidates to submit something useful instead.

Okay, I'm interested…

Succeeding with clients that don't want to change

Hypothetical: you find what seems to be the perfect prospective client. You’ve collaborated to develop an idea with the potential to realize outstanding value. They’ve decided they trust you to capitalize on the opportunity and achieve that value via some new software system.

*But!*

But the prospect makes a point to tell you they don’t want to be trained or changed (and that you can forget about “transformed”). They compensate by emphasizing that their only objective is to produce that set of value-creating widgets the two of you dreamed up in the (much cozier, in hindsight) first paragraph.

Turns out, there's more to it…