Limiting WIP and BIP

One of the concepts of lean software engineering is limiting work in progress (WIP). If you have a team of, say, ten developers, it is better to have only three or four scenarios in active development that the team is working on than having each person work on their own scenario. What’s more, each developer should have only one active task at any given time. This could be a development task, reviewing a specific set of changes, or recycling review changes. This greatly helps focus the developer and ensure that context switching does not contribute to lost time and lower quality. When you are focused on one thing, you not only work faster, but you actually complete the task instead of leaving certain details for later that you might eventually forget about. Plus, it’s nice to get a feeling of finishing the task.

One extremely positive effect that I saw with using this approach is that reviews become a lot easier. Let’s say that I take the old approach where everyone works on a huge monolithic task and then checks things in when they feel like it. Three developers might check things in before I get my changes incorporated, and if they changed files that I was working in, the reviewer of my code might see much more than just the changes that I have made. What’s more, by overloading the reviewer with the huge amount of code checked in as well as potential other changes, it’s more likely that the reviewer will miss something. The review will take longer, so when it comes back to me, it might be fuzzy in my mind.

I had the idea this weekend to limit my books in progress (BIP). I have a penchant for non-fiction books of all sorts, but recently started running into a problem where I keep adding books and never finish them. The problem lies in switching contexts. To really get what the author is saying, I have to skim through what I have already read and load it into my mind. After realizing that I could still remember the main arguments of books that I read in college but could not recall the points of the book I started reading last month, I started taking better notes and discussing the book with others to better synthesize the ideas contained. Methods for active reading have benefitted my comprehension of the material.

But even with these better notes, there is still time and effort wasted. Basically my efforts were too diffused to finish books in a timely manner, meaning that I get somewhat bored with the books. So my current plan is to create a queue with a BIP limit of about three to allow freedom in reading but to focus efforts. Then book reviews or writeups should be done shortly thereafter to use the knowledge gained from the book before it dissipates.

Hopefully these two thought patterns (WIP and BIP) were not very disjoint. The first inspired my thinking on the second. Although I suppose that both are instances of knowledge work, it’s interesting how ideas in one field can provoke ideas in a completely different area.

Introduction to Theories

It seems like the more I read about different development models, the more I see overlap between the different paradigms. Even if you aren’t using one of them for a given project, just knowing about all of them makes your code better because you realize how to make your code more testable.

One thing that has piqued my interest of late is theories in JUnit 4.4+.

Overview

In JUnit, the still experimental theory functionality is derived from the open-source Popper project. The name comes from Karl Popper’s work on the philosophy of science. He was a major proponent of saying that something isn’t scientific unless it is falsifiable, and that theories cannot be proven correct, merely shown to have exceptions. If someone can provide an exception, it means that the theory does not match all of our observations. Theories are models of the world, so while a model may not be correct, it can still be useful.

So what are theories in software good for? When using test-driven development, the tests serve as a form of code documentation. However, there are certain properties of code that are known or assumed by the developers that are difficult to codify as simple tests. Theories provide a simple and expressive means for at least the following cases:

  • identities and data conversion
  • globally disallowed behavior
  • data that should be preserved after performing an operation or set of operations

For example, you might have a theory that data that is serialized into XML and then unserialized should always result in the original object. This seems to make sense, but it might be time-consuming or error-prone to specify all of the different tests that you have to consider. A single theory can codify this assumption.

In JUnit, theories are a special case of parameterized test. So instead of using the standard test that has no parameters, you add parameters to make testing various combinations of values shorter and easier. You can then take these parameterized tests further by specifying data points to test for by default in an expressive manner.

Example

Alright enough theory. What does a JUnit theory actually look like? Given that you have a theory about two methods on a Currency object that should be inverses of each other, one nice example is:

    @Theory public void multiplyIsInverseOfDivide(
            @TestedOn(ints={0, 5, 10}) int amount, 
            @TestedOn(ints={1, 2, 3})  int multiplier) {
        assertThat(new Currency(amount).times(multiplier).divideBy(multiplier).getAmount(), is(amount));
    }

On the first line, we declare that we are going to postulate a theory, and give it a unique name. This method would typically live in a test suite or test file of some sort. The next two lines are the parameters to the test method. The parameters are prefixed by annotations to put in sample test values. All permutations of these values will be attempted when running the theory, and the values will be reported for any failures so we know what happened when the theory failed. On the last line, we test that the functions are indeed inverses by invoking them and making sure that the original value is the same as the end value.

Going further

So big deal, we could easily just create a helper test method that does something similar and we could pass whatever values to the method that we wanted. Well, hold on a second. One thing I haven’t mentioned yet is that there are some nifty tools that support automatically inserting values in to test theories. The tools automate searching the theory space for members that fit the theory assumptions but cause the theory to fail. Something like this might be useful in detecting an off-by-one error or corner case that you hadn’t considered while implementing. Typically for development you would just run the test cases presented with the method, and then would search the theory parameter space with spare cycles. This enables you to have great power as well as having blazing unit tests, which is key for any test-driven development.

If we allow automated searching of the theory space, there is one small problem with the example theory listed above. Can you see it?

The assert attempts to multiply by the multiplier and then divide by the multiplier, so a zero value for the multiplier will cause a divide by zero error. When we use automated tools for searching the theory space, we want to say that this theory only holds when the multiplier is not zero. We can easily do this:

    @Theory public void multiplyIsInverseOfDivide(
            @TestedOn(ints={0, 5, 10}) int amount, 
            @TestedOn(ints={1, 2, 3})  int multiplier) {
        <b>assumeThat(multiplier, not(0));</b>
        assertThat(new Currency(amount).times(multiplier).divideBy(multiplier).getAmount(), is(amount));
    }

Similar expressions exist for ensuring the value is positive, and so forth. You might create a different test or theory to show the expected behavior when the multiplier is zero.

I really liked the use of Java annotations to make this code considerably more readable. You would probably need a runner of some sort to specify the values if you didn’t do it right there in the method signature.

It seems like there is some overlap between theories and contracts, but I won’t go into that at this time. Theories exert positive design pressures like tests do, in that they tend to lead to leaner code that just does what the theory asks for.

Extensions

In Ruby on Rails, it would be nice to be able to easily test methods with multiple models that you have defined. For example, you might have a theory:

  fixtures :users

  def test_admin_user_can_access_this_page
    login(users(:admin_user_1))
    get :this_page
    assert_response :success
  end

  # the previous test, but better
  def theory_that_admin_users_can_access_this_page(User user)
    assume(user.is_a? AdminUser)
    login(user)
    get :this_page
    assert_response :success
  end

So, instead of using just one user or manually going through a set of users, you could just specify a whole bunch of fixtures and go to town. This might make fixtures less brittle by pointing out subtle interactions between parameters that would cause the theory to fail. I’m not sure how the syntax would look, and I’m not sure how you could use something better than annotations in Ruby.

Another thing that might be nice would be to say: I have a theory that any strings we put to the page from the database will always be escaped. The automated theory explorer could step through the pages that you define and try once with some basic data and then start generating HTML and JavaScript garbage and ensure that nothing gets through to the users. This might be a nice way of preventing cross-site scripting attacks (although I would imagine that there are tools that already exist for just this purpose.)

I looked, but could not find a Ruby plugin to handle theories. Hmmm… :)

Further reading

Some excellent resources are: The Popper tutorial A great paper with examples of use and benefits (see the pdf on that page) General overview of Theories in JUnit [pdf]

Helpful Error Message

Oh man, I was so excited when I downloaded the newest version of Google Chrome in Chrome and it started automatically installing. Google is installing the update for me automatically like a real browser! I don’t have to do it myself, the browser just knows that I want to update it. I messed around with Chrome a long time ago, but was put off by a lack of maturity.

Then, I got this helpful error message:

The installer encountered error 4.

It kind of crushed my spirits. I mean, installation errors happen, but giving me an error code of “The installer encountered error 4” is unacceptable. Sorry, I don’t have your internal documentation on what error four does, or know what the programmer was thinking when he or she put this error message that should never happen. At least apologize to me in a lovable way or something. “Whoopsies, something unexpected happened with your installation.” After searching, it appears that I am not the only one that has run into this problem.

This is why I still use Firefox. The javascript is darn fast in Chrome, but the plugins and overall quality are just not there yet. I understand that it’s still in beta, so these things will likely come in time.

I closed down Chrome after downloading the file, and tried again, and it seemed to work this time.

Friendly tip: Alt + Print Screen just copies the currently highlighted window element to the clipboard, instead of your entire 2800 x 1050 desktop.

Lesson: ALWAYS give human-understandable descriptions of error codes.

IWST Summary

Last Friday I attended the full-day Indiana Workshops on Software Testing conference with Jen, Howard, Beth, Jeremy and about ten other people. This session was very helpful in understanding my personal knowledge of testing, learning new skills and about previously unknown technologies, and meeting people in the testing community in Indianapolis. I presented second, and discussed my experiences with Test-Driven Development on a recent Rails project that I worked on.

The first experience report probably had the most relevance to things that I have directly worked with. In the production Rails project that I worked on, we used Selenium for automated integration testing as verification of the development process. Dave Christiansen covered using Selenium to do automated integration testing on a Rails app. However, what was noteworthy to me about the approach that he took was that instead of writing and executing these tests only in the test phase of the development process, they were written and executed throughout the development lifecycle. He wrote a wrapper to generate RSpec tests from the Selenium IDE, refactored to DRY up the code, and then had the team write their own integration tests as they were developing. Since the tests were written in RSpec, they would actually be run whenever code was checked in (continuous integration.) After awhile, they built up enough helpers to stop really using Selenium at all except for replicating bugs.

This seems like a nice contrast to the approach that we took for two reasons. First, integration tests would automatically keep up with the development process because the team could run these tests within their own environment. If an integration test was broken, it would be immediately visible. Contrast that to having to rewrite tests several days after the structure changes for no apparent reason. Second, they ran a headless version of the Selenium Grid, which had the effect of getting their integration tests run in about five minutes. I remember this process taking quite a bit longer for us. Part of this was likely due to supporting IE6, IE7, and Firefox, but it seems like this still could have been sped up.

But overall, it’s nice to take the integration testing process and decentralize it. This might not work with all types of projects. Obviously having the developers in charge of their own integration tests seems like conflict of interest, but I suppose that solid reviews and other testing would reduce defects. But depending on the project, I can see that allowing the development and test stages to work more closely together is a plus.

Lunch was a nice experience, it was fun hearing about some things that people have done in the past and how that affected their current views on software development and testing.

Recurring themes

It seemed like people liked using Ruby for data munging and actual testing. Over half of the presentations given were using some form of Ruby for development, testing, or tools. You could probably get away with using Perl or something for this, but you can also probably pick up most of Ruby in a couple of days if you have used Perl before.

There was emphasis on abstracting tests to the largest degree possible to facilitate agility of development. This made a lot of sense to me, because one of the common pain points people expressed was having tests that were very brittle. When the application changed, the tests had to be scrapped. Considering testing to be a valuable software architecture practice in itself makes more sense than seeing testing as isolated.

Ideas and technologies

One interesting idea given in the “Open Season” part of each presentation was the idea of thumbnails for quick manual content tests. Instead of specifying a test that used screenshots or some sort of brittle method, instead print out an expected screenshot of each of the screens and the current screenshot on a single sheet of paper. Someone can then easily scan a whole page of these relatively quickly, as humans are naturally good at picking out differences between images and determining whether they are important or not.

Exploratory testing and pair testing were topics that were mentioned a few times, and I had never heard of them before. James Bach was suggested as a resource for this and pair testing. His site contains some newer articles that deal with these subjects.

Technologies discussed included: Ruby and Ruby on Rails Selenium Watir RSpec soapUI Groovy Hammer/QTP

Overall thoughts

I really appreciated the constructive nature of the conference. Everyone was very knowledgable and had something to contribute to the process. All questions were asked kindly and there was a feeling of building on things others had said. There was a perceptible energy in the room during the concluding processes. People said that they were fired up to go to work on Monday and solve a problem that they had been facing using new approaches and technologies.

Something that stood out to me was the vast differences in terms that people had for testing practices. Obviously I am not an expert at testing, so there were some word hangups that I had. For example, the decision to call something a unit test versus an integration test was seemingly person-specific, if they used those terms at all. I can see how having a good stream of communication with team members, especially new ones, is very important in testing. Obviously this applies to software development in general.

While I have never been a dedicated tester before, I enjoyed the problems that people presented and their creative approaches to solving those problems. I think that I walked out of the conference having a lot more respect for software testers because of the challenges they expressed, both technical and organizationally.

One meme that I took away from this was the pirate heuristic: When you are out of ideas, steal someone else’s. I was out of ideas, and hence stole this one myself.

Why Blog?

If you’re seeing this post, then my nefarious plan worked.

I had the idea of having a personal blog external to SEP after seeing that the posts and comments could not be seen by others outside of the company. Essentially it was like emailing everyone internally. More importantly, no cross-pollination with the community could happen either. It seemed like the overall value could be improved by taking a little more effort to put the ideas out there. I talked with a few people about their blogging habits and practices, and determined that this could work.

Having an external blog is nice because I can have different categories and tags and send specific posts to work so people won’t be bothered by my incessant posts on cats. It’s also pretty nice because it will establish a common place where people can see my thoughts and interact with me. This is handy for going to seminars or conferences or other general networking outside of whatever my current company happens to be.

There are some exciting things going on right now with SEP and the software community at large, so it’s great to be able to talk about them. I think that to achieve the goals that we want to achieve, it’s important to excel externally as well as internally. Hopefully relevant blogging can help with the former. I encourage you to join by blogging yourself or becoming an active participant on other blogs. You probably have experiences that would be helpful for others to know about, and it’s great to get some street cred. I was talking with a tech evangelist at Microsoft, and he said that one day someone was having a conversation with him, and the other person starting quoting one of his articles without realizing it. He said, “yeah, I know that, I wrote that.” The other person was pretty impressed. How cool is that?

You can read all of my non-work posts at www.panozzaj.com.

Don’t worry, if there’s any super-secret-confidential information, it won’t be in here. Perhaps I’ll revert to the Sharepoint blog for that.

Anyway, enough metablogging.