Friday, November 30, 2012

Real Discoverability

An important aspect of languages and toolkits is discoverability. The ability to answer questions like:

What other code (including display code, configuration) uses this method/class?
What code or behavior does this configuration option reflect?
Where is this text displayed?
Where is this data from this DTO used?  What business logic does it impact, or is it just display?

This is a property that dynamically typed languages can lose as a result of that dynamic typing. (That's not to say that statically typed languages preserve it in all, or even most, cases -- more on that later). One way to think about it is to compare the difference in result to searching for string matches on "getName(" and comparing that result with the reality of the codebase.  Some problems will include:

False positives: the text search picks up calls to methods on other objects that happen to have the same name
Stupid false negatives: you need to be a little sophisticated to get both "methodName(" and "methodName (" etc.
Method overloading causes more problems: If you're looking for the method that takes a string, not the one that takes a Customer, that's tricky to do by text searching alone. You'll have to go through them by hand.
Metaprogramming totally wrecks your string search. Assigning the method to a variable then passing that off to something else to be executed hoses your text search.

Statically typed languages aren't a whole lot better, actually. As soon as you add an interface, you've abstracted the call to the method. Even though it's a useful abstraction, you can't tell what happens in practice. And static languages' reflection attributes wreck things as surely as function pointers.

What if the virtual machine recorded things for you, and piped that data back to your IDE? Assuming you're running this in either production or a test environment that has good coverage, that could make it clear what paths are frequent and what sections are never called -- in production meaning they're unused, and in test code meaning untested. For example, a Ruby IDE could use this to generate many of the features of statically typed langauges, like automated refactoring, and to the point of this article: call hierarchy discovery, without all the headaches above.

This same approach might be viable at the framework level. Rather than trying to derive from the code and the configuration where data is displayed, use testing or production to record it in practice. The former is like proving code correct -- technically possible, but very very difficult. The latter is much like the real-world testing we do: rather than trying to construct a proof of correctness of the button, just push the button and see what happens. In this case, we record what did happen and use it to inform the rest of the system and our tools.

Thursday, July 05, 2012

Acceptance Testing: what is it good for?

Overview

Acceptance Testing is an approach to providing fast feedback based on business scenarios.  It helps teams avoid the brittleness and long delays associated with automated GUI testing.  I'll also look at a specific tool, Gherkin, and explore in detail how its approach allows us to build automation steps that are business-readable, very reusable, and potentially even allow non-technical people to author tests with no development involvement.

What puts the "Acceptance" in "Acceptance Testing?"

First, let's get the context right: the word Acceptance here is the same as the Acceptance in Acceptance Criteria, the "back of the card" additional details on on a User Story that the team needs to estimate the work.  It's unrelated to the Acceptance in User Acceptance Testing, except maybe at some overarching goal of making people happy.

The Acceptance in Acceptance Criteria does relate to the ceremony at the end of the work where the Product Owner decides whether to accept the work or not.   Our Acceptance Criteria then, are the Criteria that the Product Owner will use to make that decision.  (Or at least some of the criteria -- not intended to be a contract).

Acceptance Testing is expressing those criteria as tests.  At this level, it could be anything that the Product Owner can dream up.  All of that should be tested, but not all of it can be automated.  This puts it squarely in Q2 of the testing quadrants that are at the heart of Agile Testing by Lisa Crispin and Janet Gregory:






Behavior Driven Development with Gherkin

With all this in mind, let's look at a User Story, some Acceptance Criteria, and a Gherkin test.  We'll use the User Story format of "As a .. I want to ... so that ..", and add Acceptance Criteria as bullet points afterward.
As a nurse,
I want to scan a patient's id and get a list of prescribed medications
so that I give the correct medication to the correct patient
    • Patient's name and current room number is displayed
    • List of all currently prescribed medication list is displayed, ordered alphabetically
    • Medications already administered are indicated in red.
    • If the patient is not found, a message is displayed with the info from the scanned id
Let's look at another format, the Gherkin BDD format.
Given precondition
When actor + action
Then observable result
This standard format, like the standard User Story format, is a lot like the tool pegboard that you have in your garage:  It tells you where to put things so you can find them quickly, and tells you when something is missing.

Extending the garage metaphor, Gherkin itself is only a tool -- it can be used for many purposes including Unit Testing, GUI testing, load testing, etc.  Let's look at how to use Gherkin to create  Acceptance Tests from our Acceptance Criteria.

Our first Criteria is that the patient's current room and floor is displayed.  Let's first re-word that in the Gherkin format, called a Scenario:

Given a patient is in a particular room
When the nurse scans the patient's id
Then the patient's room and floor is displayed.
Okay, big whoop.  This isn't very helpful -- it's just wordier.  In this case, when the actor and action are the same as the user story, it's not very interesting.  But let's add some specific examples to it:
Given a patient with id 1234 named Kevin Klinemeier is in room 305B
When the nurse scans patient id 1234
Then Kevin Klinemeier and 305B is displayed
Now that we have specifics in place, this is an Acceptance Test.  This looks like the kind of thing we could actually automate, and it begins to suggest some other scenarios:  What happens if the wrong patient id is scanned?  Can there be two patients with the same ID?  Can there be two patients in the same room?  But first, this is just English-- how does it get automated?

Each step in the BDD Scenario is implemented by a developer.  If we were working with a user interface, it might look like this:

First choose the variable parts, described here by underlines:
Given a patient with id 1234 named Kevin Klinemeier is in room 305B
Then write some "wiring and glue" code to put the variables into place, described here as a UI-automation pseudocode:

 public void givenAPatient(patientID, patientName, roomNumber) {  
   window.open(PATIENT_ENTRY_SCREEN)  
   writeIntoTextBox("patient_id", patientID)  
   writeIntoTextBox("patient_name",patientName)  
   writeIntoTextBox("room_number", roomNumber)  
 }  

Great, that makes sense.  Except it stinks!  Our goal as Agile Testers is to provide fast feedback, right?  But now we can't run our test until the GUI is finished.  Furthermore, automated GUI testing is itself notoriously brittle.  Instead of a simple writeIntoTextBox method, we're more likely to have something that looks like this:

 writeIntoTextBox("xpath:=/html/body/div/div[2]/div/div/form/label/input[1]",patientID);  

That's xpath in there, and it's specifying an input box on a particular place on the page.  If the page changes the order of the fields, the test breaks.  If it changes the location of the fields, the test breaks, if it removes something that is above the fields, the test breaks.  You get the idea.

Instead, we avoid the problems of GUI automation by testing in the "middle".  The unit test level is too early, and as a result is too technical and doesn't speak to the business.  The GUI layer is too late, it doesn't allow the team feedback on both behavior and design at a time when it can be resolved.  The sweet spot is to test services, and hence design services for this kind of testing.  This is best described by Mike Cohn's testing pyramid:


Part of the feedback we are providing is on whether a given software design is Testable.  There are many roadblocks to testability in GUI, but much less at the service level.  Furthermore, when we provide these BDD Scenarios as the starting place for testing at the service level, our services as a result are not only testable, but based on the underlying business concepts, and that's just what we want out of a good service layer.

To complete the example, let's look at a service-layer implementation for the step we have above:

Given a patient with id 1234 namedKevin Klinemeier is in room 305B
 public void givenAPatient(patientID, patientName, roomNumber) {  
   patientEntryService.createPatient(patientID,patientName,roomNumber);  
 }  

When the nurse scans patient id 1234
 public void scanPatientId(patientID) {  
    result = patientScanService.scan(patientID);  
 }  

Then Kevin Klinemeier and 305B is displayed
 public void shouldContainPatientNameAndRomNumber(patientName, roomNumber) {  
    assert.that(result.getName).isEqualTo(patientName);  
    assert.that(result.getRoomNumber).isEqualTo(roomNumber);  
 }  

BDD and Building Blocks

We now have one working example: the patient scan.  It looks like maybe a lot of work.  The exciting part of BDD, and the thing that makes this all a scalable part of long-term software development processes, is what happens when we move on to the next Scenario.  Let's pick one of the other Scenarios we came up with before: scanning a patient that doesn't exist.  First let's write it with Given .. When .. Then:

Given a patient with id 5678 named Joe Justice is in room 205A
When the nurse scans patient id 0001
Then an error is displayed

 I've highlighted the first two steps in green: they're free!  Well, we already paid for them, but they're free to re-use in this new scenario.  The only new wiring to write is looking at the error that is returned.

Once we have a few of these basic building blocks, we can really take that development effort and amplify it through everyone else on the team who can create these near-english Scenarios:  QA, BA, Product Owner, perhaps even Customers and Users.  As an example, with just the four different steps we've completed so far, we can create and automatically run all the following test Scenarios without further development help:

Scenario:  Duplicate patient ID
Given a patient with id 2838 named Bill Bates is in room 203D
And a patient with id 2838 named Clay Cummings is in room 405F

When the nurse scans patient id 2838
Then an error is displayed 
Scenario:  Multiple patients in room
Given a patient with id 8432 named Amelia Anderson is in room 403B
And a patient with id 9392 named Nelly Newborn is in room 403B

When the nurse scans patient id 2838

Then Amelia Anderson and 403B is displayed

And Nelly Newborn and 403B is displayed

These scenarios might also drive discussion:  should we be able to tell the difference between an error for a patient id that is missing vs an error for a patient id with multiple entries?  And that's just the kind of business-level input we are looking to provide feedback for, delivered before the GUI is even started.  

Summary

Acceptance tests that express business concepts are powerful, but automation at the GUI level is problematic and waiting for the GUI layer to be built introduces long delays for testing.  Instead, provide faster feedback by automating these tests at the "middle" layer (service layer) where the business concepts can be expressed, but the GUI details are not yet in the way.
Using the BDD Gherkin format to write tests creates tests that are not only automatable, but also creates small building blocks that reduces the overall cost of automation and allows non-technical team members to extend the automated test suite. 

Wednesday, April 11, 2012

BDD and big datasets

One of the challenges that I hear in my classes on Agile Testing is around Behavior Driven Development and big datasets.  The intro to a lot of BDD tools looks something like this:

Given a customer named 'John Smith' who is 45 years old
When I execute a check for retirement eligibility
Then the result should be false

This is, of course, the Gherkin language from Cucumber, which has implementations in many languages including Ruby, Java, and .Net.  It's pretty compelling -- succinctly describes preconditions, actions, and expected results.  Until you think about applying it, then the trouble starts.

In this post, I'll talk about big datasets.  In the above example, assuming that we can insert a customer with only two attributes (name and age) is what stands out as being too simple.  In practice, our customer records have dozens or in some cases almost a hundred fields.  Gherkin has the ability to do tables by using the vertical pipe symbol, so do we create something like this?

Given a customer with these fields:
     |  name  |  age | street 1 | street 2 | city | state | zip | ssn | credit card | ccExpiry | signupDate | currentBalance | blah | blah | blah |
    | john smith | 42 | 4823 third | | seattle | wa | 98173 | 592-93-5382 | 4324 4322 3345 2838 | 11/15 | 04/12 | 438.27 | moo | beep | foo |

When I execute a check for retirement eligibility
Then the result should be false

I hope not, because that stinks.  It pretty quickly strips away most of the readability benefit that we were getting from this tool in the first place.  From a data point of view, it's also a mess because the tabular format requires us to flatten a lot of our dataset, making it harder to maintain.  And from a communication point of view, it requires us to really pan for gold -- some of these columns have an impact on whether the customer is eligible for retirement, and some of them are just boilerplate junk that we have to provide in order to create a customer.  Which is which?

The distinction (impactful vs boilerplate) is especially important when we try to maintain the test.  If 80% of the fields are boilerplate, we get into the habit of changing data to make the test pass.  Which makes it very easy to make a 'maintenance' change to the test that actually makes the test invalid.  In our example above, it might be reasonable to assume that it's just name and age.  But what if it was address, too?  It's possible that retirement eligibility (whatever that means) varies by state or county.  We need to  remove these attributes from the test, and have the test focus only on the details that impact the outcome.

The first step is to listen.  How do our product owner or businesspeople talk about the customers?  I mean beyond calling them big fat jerks when they're at the bar after work.  Are there certain classes of customers that we can specify?  Let's try that:

Given a West Coast customer aged 45,

When I execute a check for retirement eligibility
Then the result should be false

But what does West Coast customer mean?  This definition is contained in the step definition, and includes a set of Reasonable Defaults.  Every customer needs a name, so the system makes one.  And within the context of our West Coast Customer class, it makes up an address in one of the western coastal states.  This makes it clear what the real dependencies are in our test:  The address should be somewhere on the West Coast, and a particular age.  Everything else about the customer is irrelevant to this test.

On the step definition side, there are some decisions to be made.  First is what to parameterize.  In the beginning, do the Simplest Thing That Could Possibly work and parameterize none of it:

     @Given("a West Coast customer aged (.*)") ...

If, as I would expect, we end up with several different additional datapoints that we want to 'override' about our West Coast Customer, then the Builder pattern will be useful.  Specifically Builder rather than Factory, so that we avoid combinatorial explosion of the options for overrides.  The WestCoastCustomerBuilder might look like this after some time:

   public class WestCoastCustomerBuilder {
      public void BuildAndInsertCustomer();
      public void SetAge(int age);
      public void SetSSN(string ssn);
      public void SetCurrentBalance(double balance);
   }

And here's how it might be used in several step definitions:


    @Given("a West Coast customer aged (.*)")
        public void BuildWestCoastWithAge(int age) {
           builder.SetAge(age);
           builder.BuildAndInsertCustomer();
        }

    @Given("a West Coast customer aged (.*) with ssn (.*)")
    public void BuildWestCoastWithSSN(int age, string ssn) {
            builder.SetSSN(ssn);
            builder.SetAge(age);
            builder.BuildAndInsertCustomer();
    }

This shows the re-use of the builder pattern.  Critics will point out that we could also just have the second definition call the first, or avoid the need altogether with an optional clause in the step definition.  True, but doesn't provide as good an example of re-use.

The defaults could either be static data (all WestCoast addresses are my house), a random selection of a given dataset (choose a random address among these 50) or a pure random generation (make up an address on a numbered street in a west coast city).  As with all things, do the simplest first and see if that works for you.

In summary: whenever our 'required' datasets start to harm the readability (and hence maintainability) we should refactor the test to define only those inputs that affect the observed result.  All the boilerplate should be handled by generalized step definitions that are capable of supplying reasonable defaults.  This ensures that the test stays clear and focused, while creating clear and reusable step definitions.

Tuesday, February 02, 2010

Relative estimates are like a stagecoach

If you're having trouble getting across the idea of relative estimates (story points) vs velocity to your management, try this approach:

Estimate stories using a distance measure. Furlongs for fun, miles if you're a boring American, kilometers if you're a boring person on the rest of the planet.

Your team velocity is measured in furlongs-per-sprint. This makes clear the separation between how much work needs to be done and how fast a team can complete it. It calls out the knobs that management can turn immediately: go faster, do less work.

For the vehicle, consider a stagecoach. Every new horse added to a stagecoach adds to its potential speed. Four horses is better and faster than one horse, but not four times better. There's a point where you're better off with two stagecoaches.

Breakdowns:
Another popular analogy is rocks-in-a-box. Your velocity is called capacity, and described as a box for the Product Owner to fill with rocks. Rock size is estimated by the team. Lots of small rocks do a better job of filling up the box. This point, that small well-understood stories are easier to complete, is missing from the stagecoach analogy. (If the miles are short, they go by faster? Doesn't quite work.)

Monday, November 09, 2009

Questions to ask when you want something

Can I have it now?

No.

Can you tell when I can have it?

No.

When can you tell me when I can have it?

I don't know.

Do you need something from me?

No.

Bullshit.

Maybe this should be a flowchart.

Wednesday, August 26, 2009

Testing with Moxy

Overview
Build proxies that pass through most requests, but create mock results on well-known data.

Our situation

We needed to be able to verify the behavior for error conditions from our Selenium (web) tests. We had already created mock services that would return these results. We then had to manage when we connected to which endpoint, which put the expectation about behavior outside the test and in the server configuration. In order to do a single regression pass, we had to stop and reconfigure the server.

Our solution
We created Moxies (mock proxies), which most of the time are just a plain passthrough to the real endpoint from our vendors' test systems. For a well known set of data (addresses in Broken Arrow, Oklahoma) the Moxy returns error conditions. Those addresses and their expectations are defined in a single class, shared both by the Moxy implementation and the tests.

Benefits
Test real success and mock failure in same server configuration.
Data and its expectation is in sync (shared classes).
Code is explicit about which tests depend on which Moxies, and which specific behaviors.

Future
With the same solution we expect to create a set of test cases that do not rely on the availability of the vendor test systems, based on similar conventions. (Eureka, CA)

Other implementations
We considered using wrapper objects injected via Spring to accomplish the same thing with less monkeying around with endpoints. This would avoid needing to deploy a real http mock service, and avoid issues around certificate verification and authentication. However, an injected solution would require deploying the mock software on all the client machines, and tweaking its configuration so that the wrapper bean is injected in our test environment, but not production. The injection solution also doesn't test the parsing of the error response, though that should probably be done in unit tests anyway.

If we were using a ESB like Mule, we could have configured Mule to redirect the requests based on the data, and used our mock services unchanged, and the test system configuration also unchanged.

Some solutions avoid having to use key data in the request object by manipulating http header info instead. This wasn't an option for us, unless we create some kind of signal for that header all the way through to our public pages. That seemed too invasive for our situation.

Closing
It works for us, and has a cool name*. What more could you want?

* Yes, you could probably more accurately describe this as a decorator. But Mockorator isn't nearly so awesome a name.

Monday, August 03, 2009

Leading Self Organized Teams

Self Organization, Collaboration != Fire Your Leadership

One of the questions I've tackled with the agile teams I've worked with is how to find a balance between the need for direction and quick decisions with the open and self-organizing approaches that are recommended for teams practicing agile processes. A lot of this perceived conflict comes from people overstating the basics. In particular:
Self Organization != No Leadership. Collaborative Approach != Everyone Votes On Everything.

Core Values:

Self Organization: Invite owners and participants rather than assigning people to teams

Transparency: Discuss topics openly, rather than among a separate team.

Collaboration: The point of the self-organized group

Direction: The owner is responsible for driving to dates, providing major guidance (sometimes from above), and deadlock resolution.

Review: Periodic review of practices and applications is key to success.

Example: Spacely Sprockets Quality Issue

Problem: All the sprockets we've got are throwing NullPointerExceptions.

The Development Director in this case wants to delegate this task to the team. In order to do that, she asks for volunteers to be the "owner" for this issue, and Olaf steps up. After consulting with the Development Director for parameters (due dates, budget, etc) the first thing Olaf does is send an invitation: (Self Organization)

  • To: yourWholeTeam
  • Subject: Spacely Sprockets Quality Issue
  • Hello Team,
  • We need to determine whether to stay with Spacely Sprockets, change to Cogswell Cogs, or pursue some third option. if you're interested in participating, send me an email and I'll include you in tomorrow's meeting.
  • -Olaf

The group meets a couple of times (Collaboration), trades emails (via whole team mailing list, for Transparency) and works towards a recommendation. One participant suggests Gary's Gears, but Olaf shares that Gary's Gears are outside the budget for the project. (Direction). Absent of that option, the group finds consensus on staying with Spacely after an impassioned speech by George J., one of their salesmen. Olaf shares that recommendation with the rest of the team, then the Development Director, who puts the recommendation into place after a few additional questions/clarifications (more Direction).

Common Problems

Self Organization Problem: nobody signs on

Often you'll be expecting "the usual suspects" to show up when you invite people to collaborate. Sometimes you'll be surprised to find no responses to your hot topic. As the owner, this gives you the opportunity to find out why. This may be for many reasons:

  • People are busier than expected
  • People are tired of working with the issue
  • People feel that the solution is obvious
  • People feel that the recommendation won't result in change.

What to do:

Talk to your usual suspects with these possibilities in mind. The major advantage of the process in this case is that as the owner you are aware of these problems at the beginning rather than the end of the process.

Self Organization Problem: everybody signs on

Instead of "the usual suspects", you get the whole department. Reasons for this include:

  • Concern that some aspects of the issue are being ignored or are unknown to the group
  • Concern about "the expected outcome"
  • Size/Impact of recommendation

What to do:

Hold a first meeting and have a round-table where you invite each participant to share what motivated them to participate.

People who feel that they're alone in a concern have an opportunity to share it, and can hear others if they exist. Those who are worried about an "expected outcome" can share their point of view. If the source is that the impact of the recommendation is huge, then team members have an opportunity to voice general concerns and witness for themselves the process by which the recommendation is being made. Sometimes just having the preliminary session is enough -- the team can identify when enough of each viewpoint exists and will drop out satisfied that their viewpoint is represented.

Another approach is to assure the team as a whole that there will be an opportunity to review the recommendation before it is "ratified." This can make team members feel less urgency about allowing others to tackle a difficult or contentious issue.

You may be tempted as the Owner to be aggressive in this case about reducing team size. Be sure that you are keeping in mind that the real goal is not to simply make a recommendation, but to have it understood and implemented by the entire team. To this end, it may be more effective to allow for some up-front "inefficiency" in order to get everyone on the same page and reach the real desired outcome faster as a result.

Direction Problem: small project

Sometimes this all seems like a lot of effort, with more time spent sending invitations and setting up meetings than it would take to do the work.

What to do:

Use IM and/or email for self-organization. Set a deadline for response (self-organization), and list your planned actions by that deadline (Direction, Transparency). Ex:

  • To: yourWholeTeam
  • Subject: I hate the PMD "use if x==y not if x!=y" rule

  • Hey all, Can someone tell me why I shouldn't hate this rule? If nobody objects, I'll remove it on Wednesday.

  • -Developer Danielle

Collaboration Problem: can't reach consensus

Rational people can disagree on a subject. Time doesn't always allow all avenues to be examined.

What to do:

This is the "big job" of the owner. It's the owner's responsibility not only to identify when it's time to just make the call, but to also make all the participants feel that they've been heard even if they haven't been agreed with.

Every time the process is used without the need for this outcome are like money in the bank. That money (trust, really) is expended in these situations. If you've got a positive balance, then this is just a a problem. If you're overdrawn, then this situation can become a fiasco. Team members must feel that the situations where the owner makes the call without consensus are rare, and due to issues that are a toss-up, or due to outside pressure. If you're doing a lot of this, it's probably an issue that should be considered in the process review.

Transparency Problem: When should I include everybody?

Is copying yourWholeTeam on *everything* really the recommendation? What if they're unlikely to care and it's just noise?

What to do:

Use a restating of the golden rule to determine what to send to the whole group: If you weren't an active participant, would you want to know about this part of the discussion? Err on the side of Transparency.

Criteria For Review

These criteria help determine success of this approach and your specific practices:

  • Does everyone feel they understand the approach?
  • Does everyone feel that quality recommendations are being made?
  • Do team members feel involved, not dictated to?
  • Are recommendations timely and within expected parameters, ie conforming to Leadership's direction?
Last Words

To restate a problem from above, it's important to keep in mind that the end goal isn't a decision, its a decision whose spirit is implemented and upheld team wide. I use this approach not because it makes everyone feel good, but because it's the most effective way to get real results.

Wednesday, April 15, 2009

Rails Hates me

So, I've got a little extra time, and I figured it was time to get back to my rails project. I've half written this character-timeline-thingy maybe three or four times but never quite completed it. As I recall, I had it almost-completely-working maybe a year and a half ago, so I thought I'd take it out for a spin on my new macbook with its built-in rails mojo.

I grabbed my old files off of my external hard drive and: No love. No mysql. Oh, of course. Installed mysql and a visual editor, felt warm and fuzzy about that process. Created the tables with the table-creation script I created when I used this last time, made another mental note to look into rails' migrations and

$ rake...

Fail. My tests are talking about fixtures that have some kind of problem. This is fixed, and something else doesn't work, a nil where I didn't expect it. Oookay, bwuh? Maybe this is just old and I'll start over. It's got deprecation warnings in it too, so meh.

$ mv timemachine timemachineOldAndBusted
$ rails timemachine
$ rake

Fail again. The mysql gem isn't installed by default anymore. Okay, so:

$ sudo gem install mysql

Fail again. some crap about headers and native extensions. I turn to google, and go through a lot of gymnastics around installing stuff from source, upgrading gems itself, etc. etc. I follow all the directions I see in a pretty helpful article, everything seems to be passing and:

$ mv timemachine timemachineFail
$ rails -d mysql timemachine
$ rake

Fail. Now it says that the mysql gem isn't installed, but gem list says it is. Back to google, now the suggestion is to do some trickery with 64-bit mysql vs 32-bit mysql and binary hacking the broken mysql.bundle file to fix the problem.

This all feels like why Java and platform independence is still important. I'm tired of mucking with building from source into my operating system. AppEngine supports Java, right?

Wednesday, March 25, 2009

Easy self-improvement

What's the easiest thing you can do to improve yourself? Take a compliment, and make it twice as true.

What's your favorite compliment of all time, or of the last year? Chances are, your complimentor has identified something that comes easily to you, a natural gift of yours that was appreciated. It may be more valuable to improve something that you're already pretty good at than try to rebuild yourself in something that is difficult.

Let's say it's some mode of communication, maybe written communication. Where else can you use this skill? How could you be even better at it? What is it that makes you good, exactly?

These kinds of questions, when asked about something you're already doing well have a much lower "effort." If you've picked an area you're good at, that you're excited about, you may find that they return energy to your day instead of subtract it.

Monday, February 09, 2009

Cut n Paste to lower communication barriers

At work, we have a weekly newsletter. I used to read it, but I don't anymore. It used to just be in email, and I'd skim some of it as it came by before I deleted it.

Now, it's a document attached to an email. It requires just one more click to see it, and I don't do it. It had some nice information in it -- new hires, birthdays, other company news. Stuff I could read "incidentally". Clicking that link feels like committing to reading the whole document, rather than just skimming over what's already in my box.

I've been thinking about how I can lower barriers when I communicate as well. The easy one is that instead of just mailing a link (which most people won't click on), I paste the whole document into my email.

The same thinking has led to a lot of physical printouts in our office. This strikes some people as funny -- we're a tech company, yet much of our process is documented on giant sticky notes. Yet the results are clear: a giant sticky note next to the fridge communicates much more effectively than email, or a diagram in a folder in Sharepoint.

But what other barriers exist in our group that I'm not aware of? We've worked pretty hard to reduce them: we move desks when we reorganize teams so members can sit together, we aggressively encourage pair programming, our scrum process has its standups, etc.

A better question might be: how do we identify them? I'm not aware of a metric that I can rely on. Things come up in the retrospective, but that's just once every three weeks. Perhaps the real story here is about using all channels of communication.

In my email example, I have only one channel so I need to make sure it's as effective as possible. Even then, I don't really expect everyone to get the information I'm sharing.

When I give presentations, I try to say my point three times, and in three different ways: Once in text, once with a picture, and once verbally. Maybe there's a correlation there when I'm looking to drive change in our office (or just hold us to changes we've already agreed on): A poster, an email, and a verbal reminder during standup.

I'm going to look for things where I'm using only one mode of communication, and either reduce my expectations around that message or increase my modes. (make a poster, send an email, include it in our standups)

Tuesday, September 16, 2008

Scrum Baseball

When talking about Scrum, the question often comes up about "customization." Each team is expected to customize things to their environment. But when you're adopting it for the first time, how far is too far? I've heard other analogies surrounding baseball, here's mine:

What is baseball? Softball is still pretty much baseball. T-ball is still pretty much baseball. What about Cricket? While it has bats and balls and running around, it isn't baseball.

My "short list" for scrum is:

Work is stack ranked in a product backlog, sized relatively
Work may begin before product backlog is "complete"
Work done in iterations
Daily standups for status

Tuesday, January 08, 2008

Code Coverage for Eclipse redeux: EclEmma

In a previous entry, I lamented that I couldn't get instant feedback for the coverage results of my unit tests in eclipse. A coworker (David Koontz of SolutionsIQ) pointed me at EclEmma. In a nutshell, it works.

It gives me line-by-line coverage, highlighted in green, yellow, and red like the coverage reports I get from Cobertura. In addition to file-by-file coverage, EclEmma also summarizes coverage reports for an entire project in an Eclipse view much like the Cobertura's roll-up behavior.

It plugs into Eclipse smoothly via update site, and works with all my tests including configuration details with Spring, Hibernate, HSQL, etc. Usage was simple: if I had a JUnit execution defined in Eclipse (generated automatically via runAs .. unit test), then I can reuse it with EclEmma. Run As ... Coverage Test is also available.

My only complaint is some strange behavior around code that throws exceptions. If a block of code throws an exception partway through, EclEmma counts that entire block as untested. The authors point to this being a limitation of the Emma code coverage tool. My code doesn't generally throw a lot of expected exceptions, so it hasn't been a major issue.


In general, happy as a clam am I!

Wednesday, August 29, 2007

Integration Testing more important than Unit Testing

When I'm learning a new framework, strict unit testing isn't very helpful. To illustrate, here's an example:

I want to write a command object of some sort that interacts with jbpm. Jbpm is a workflow engine, with nodes and transitions. I need to look up a process (a collection of nodes and transitions), select a node and tell it to take a particular transition.

If I use EasyMock to ensure that I'm testing only my code, I can test whether the code is doing what I expect. However, that doesn't answer the most important question: Am I doing this the right way?

In my example, there are a couple of ways to look up nodes, and a couple of situations where the framework behaves differently than I expect. I can't find any of that until I do integration testing.

The paradox is that the authors of the framework don't have questions about which approach in their own framework is the correct one. Hence, testing integrations with the framework isn't attempted, and anything not attempted isn't factored into the design.

Bottom Line: Easy integration testing is key for rapid framework adoption.

Wednesday, May 30, 2007

Eclipse instant code coverage?

In general, I've drunk all the test-first kool-aid there is. My development is a constant cycle of write test, run test, write code, run test. Repeat until I think I'm done.

I really like code coverage tools, as they let you know if you're as done as you think you are. Are you testing that else clause or that exception case? Good stuff.

So why can't Eclipse show me which lines were covered by my *last* test run? I think that would be pretty useful, and it seems like the pieces are there to make it happen.

Tuesday, May 22, 2007

The Deal with Documents

When working up some process documentation, our group had a little bit of a revelation:

Documents exist to make a decision.

This single statement really helped us streamline what we were doing with our documentation, and our process itself. At each stage, we asked "What decision is trying to be made? What information is needed for that decision?" Everything else was junk, and we cut it out of the document.

Every time I write a document now, I ask myself that question.

Tuesday, April 24, 2007

LinkedIn end-run.

I was contacted today, by phone, by Dan Payne from Opsware. He "found" my information via LinkedIn. This was surprising to me, since I don't know Dan and was under the impression that LinkedIn worked by restricting people 's access to you through their invitation approach. What I'm pretty sure happened here is that the combination of real name + company name + google was quite enough to dig up my email address and to call up my employer and get to my direct line.

I hate that. That's not the permission I gave him, and it irritates me that LinkedIn made it possible. So, I sent a note to LinkedIn customer support complaining about this inappropriate usage. I'll keep you posted with how that turns out, but it sure seems like it should be in their best interests to keep people from using them to mine other people's personal data. We'll see how that turns out.

Friday, January 26, 2007

When is a property not a property?

There's a lot of talk about property support in Java 7. Some of the proposals allow you (like C#) to access the get/set methods without using the method name:

foo.bar //actually calls Foo.getBar() or a reasonable facsimile

Except now you've made a distinction between accessing it as a 'property' and accessing it via a method. What's the difference? Richard Blair says "read the docs", but I think that's the wrong answer. The language has made a distinction by allowing two ways to access code that makes multiple modifications to an object's state. If the distinction is meaningless, then it adds clutter. Any access to a 'property' needs to appear to be a method call to client code, because that sets expectations accordingly.

Thursday, November 30, 2006

Always and Never

The first thing I have to explain to business people when they're trying to give me requirements is that there are two kinds of "never". There's the business/real-world never, and then there's developer never. What regular people usually mean when they say never is "not very often".

In order to get the point across, and to clarify what people want when they say "never", I explain the repercussions: "Okay, you say this never happens. Is it okay if the program asks the user to contact support and then exits if it does happen?" That tends to get us to the right answer pretty quickly.

Trickier is "always". It has the same problem of being far more precice in software than it is in English. What's worse is that it's often implied or inferred in an otherwise reasonable requirement. "The software will send an email when an order is placed." Is that an always statement? Asking this question can be very illuminating. Typical responses can be "Well, not if there's been a problem -- then we want to call." or "Yes, if they've given us an email address".

Friday, November 17, 2006

Do (our) users want broken features?

So, I've completely drunk the testing Kool-Aid. I've taken it as my personal goal to incorporate automated testing in my entire process, and have seen it work. I've had multiple releases go through QA with no functional bugs*. I preach test-first development to everyone that will listen.

The problem is that our users actually want buggy features.

This was pointed out to me by some of my coworkers in a code review where we discovered a class that was fairly complex, but had no unit tests. We talked about why this came to be, and the answer given was that if the project goes to QA but has bugs, nobody gets in trouble. If it goes to QA, has no bugs, but has fewer than expected features, then the project "slips", people panic, and we have PMs and above at our desks wringing their hands and asking "what went wrong." The pressure shifts from dev to pump stuff out to QA to give the approval. And I fall into this trap every time.

However, I've said "my users", but it isn't my users that are giving me pressure on the release dates. It's my project management. Maybe I should say:

My project managment actually wants buggy features.

For those of you following along at home, this isn't specific to my current place of employment. Now that I consider it, I think I've seen this everywhere I've worked. The only time I didn't feel it was on the two projects where we had a reputation for quality in our QA releases. I feel like lightning has to strike in order to build up this kind of reputation, and I haven't been able to make a tall enough rod on my current projects.

What's worse is that we clearly increase the amount of time between when the bug is written and when it is discovered. That means the bugs take longer to fix, which ultimately means that the project takes longer, even though we've "hit our dates." This is clearly because there's an expectation of a long time in QA that can't be well estimated.

I think the Agile folks would suggest that the problem is with "QA resources" in general. I have a tough time letting go of that specialization. Test plans are difficult to write well, and even more difficult to execute with consistency and an eye for detail.

Maybe the right answer for us (if this can't be addressed by talking to the various date-concerned entities) is to not expose a QA handoff date, but incorporate QA into the dev team itself as partners in the ultimate deliverable date. XP would seem to suggest this as the way to go. We would have more flexibility (agility?) in giving sections to QA when they're testable, and optimally we could even test things earlier in our cycle than we currently do.

I worry that some parts of the team leadership may hyperventillate at the idea that there isn't an official QA handoff date that they can track and put a checkmark next to, or put less snarkily, have less information with which to schedule QA resources.

I still don't know if I can reconcile those needs, but I know that I don't like the behaviors that the current process encourages.

* functional bugs are what you get when QA says, "should it do this?" and Dev says, "oops, no." There are tons of other kinds of bugs, like usability issues or miscommunication issues. Most of those aren't addressed by automated testing.

Tuesday, November 14, 2006

Phidgets: the Beginning

So, I'm a total hardware n00b. I've written software for a decade, and happy talking about inheritence, encapsulation, polymorphism and tossing around newer buzzwords like dependency injection and all that.

But I decided to start a hardware project. I'm not going to give away the ending, mostly because I'll probably never get there. Remind me to tell you the story about the coffee table I was going to make once.

Anyway, I bought an 8/8/8 Interface Kit from Phidgets.com. It's a smallish thing, about the size of a deck of cards, and about a hundred bucks delivered. It's designed to pass inputs and outputs through USB to a computer, where software running there actually makes the decision about what to do when. Plus, one of the hojillion languages they support is Java, so that feels right at home.

I've got the thing on my desk now, and am installing the software. Except it needs the .net framework, blah blah blah. It's nice enough to redirect me to the download page, and after getting confused about my 64 bit proc but 32 bit operating system I'm good. That done, their software installs fine. While .Net was .downloading I got eclipse set up with their Java examples, and once the software was installed and the device connected their InterfaceKit example ran right out of the box. Granted, I have nothing hooked up to it, so I don't know if it's doing anything, but it prints lots of stuff to the screen. I grabbed a wire and jammed it between the ground and the different inputs, and successfully made stuff print to the screen. Cool!

Next up is outputs. For that I have an LED that I clipped off of a defunct printer screen. I'd have desoldered it, but Nicole just bought the desoldering iron, and I wanted her to be the first to use it. I hook it up, and nothing happens. So I hit their website, which has the "n00b manual for InterfaceKit", which is six pages long. I've read manuals that are 20 pages and have less useful information. There happens to be a section on "hooking up LEDs to your InterfaceKit", and by section I mean a page. It mentions anodes and cathodes. Which I look up on wikipedia, turn my LED around and it works.

Sort of. I've written my own software to turn input #1 on for 2 seconds, then off. The LED responds by shining bright and steady in the "on" state, but instead of being off for the "off" state, it flashes. I vaguely remember that "digital" outputs have some kind of square wave mojo going on below a certain hobgoblin threshhold or something, but all that information is eleven years old, and there is a lot of beer and parties standing between my CE 101 class and today's attempt. I also suspect that the answer is actually on the LED page of the manual, but again too much inebriation between those symbols and the present day.

So, I've got a flashing LED. The software has been fairly straightforward to this point, and while they don't release the sourcecode to their Java libraries, they do have a reasonably well written Javadoc. Moreover, to this point things are written in a pretty straightforward manner. To turn the LED on and off, I've written these lines:

interfaceKit.setOutputState(1,true);
interfaceKit.setOutputState(1,false);

(with sleep statements in between)

So, I'm reasonably sure I haven't screwed that up. I even have system.out.printlns in between, which of course make me feel dirty, but I'm ignoring that for now.

I'm not the only hardware n00b connected to the global inter-tubes, so I sign up for their forums. I could complain about the way the forums insist on mailing me a generated password as though I'm going to be doing stock trading on this thing or something, but that's really just sniping at this point. I shut up about the password thing, and enter "flashing LED" into the forums.

No luck there, I think now that the problem has to do with the shoddy wire I'm using (cut out of an old phone cable, stripped with a kitchen knife, and not a solid wire but twisted copper). I changed the LED to another output, and this time off was off, but on was flashing. I went to change it again, and dropped the LED off the end of the wire (I just had it wrapped, not soldered or anything), and have decided to declare that to be the problem, and call it a night.

Next time: wire strippers and real wire!