Saturday, July 10, 2010

Book Review: Growing Object-Oriented Software, Guided by Tests

Recently, I read Growing Object-Oriented Software, Guided by Tests by Steve Freeman and Nat Pryce. Amongst excellent discussions of other TDD topics, it sheds a lot of light on good ways to use mock objects.

Personally, I can remember reading Martin Fowler's Mocks Aren't Stubs quite a while ago and concluding that I'd be a "classicist."

Some time later, I started working with mocks as a way to isolate unit tests from "slow" dependencies, such as databases, trying to make them run more quickly. I didn't have much success, though, because I was still writing my tests in a classicist style.

This book helped open my eyes to how the "mockist" style really works, and why it can be a good thing. I absolutely recommend it to any programmer who is doing TDD (or writing unit tests), but who still feels like when it comes to being a mockist, they just don't get it.

I also think a great complement to the book is the video of J. B. Rainsberger's presentation Integration Tests Are A Scam.

As a note on how to read the book, I got a bit bogged down in the middle section, with the worked example. I ended up skipping to the final section and came back to the middle after. Reading it like that worked just fine. I also think it could be interesting to alternate chapters of the middle section with those of the final section.

Saturday, April 24, 2010

Do Unit Tests and Quality Code Result in Fewer Bugs?

At the end of my team's last release, I set out to prove that unit tests and quality code lead to fewer bugs.

Here are the tools I used.

Jira

The first thing to know is that the team I'm on keeps its features in Jira, and when we commit code to Subversion, we include the Jira ID in the comments.

Below, you'll see how this helped me relate code to features.

The second thing to know is when we find bugs in a feature during its development, in Jira we link those bugs back to the parent feature.

This allowed me to measure how many bugs had been reported for each feature at release.

SvnPlot

There's an open source project called svnplot that allows you to export the information stored in svn to a SQLite database. To do this, follow the instructions in Step 1 of the Quick Start.

You end up with a couple tables that include rows for each revision, including the comment and the files that were added, removed, and changed.

ANTLR

I used ANTLR C# grammar to help map the files changed to classes.

NCover

I used NCover to measure unit test coverage of the added and changed classes.

NDepend

And finally, I used NDepend to measure code quality of those classes, as well as to query the coverage metrics.

Results

This is the part where I'd love to show some fancy graphs proving my point. Unfortunately, the results weren't exactly conclusive.

I ended up dropping the idea of trying to correlate code quality to number of bugs altogether, because I just ended up with a mess.

The results for how unit test coverage related to bugs is sort-of presentable, at least, but they don't show a nice correlation:

Feature LOC Changed / Bug Average Coverage (%)
1 521 65
2 290 38
3 165 0
4 140 54
5 125 21
6 76 25
7 74 77
8 59 30
9 2 80

I'd like to think I'll try again another day, but given those results, I just don't know. I can come up with many reasons why things didn’t come out the way I'd hoped:

  • The amount of change for each feature was very diverse. Some features involved lots of code changes and others involved very few, so that the features may not really be comparable in this way.
  • Some features involved mostly changing UI code, where the coverage can't be high, because we don't currently have a good way to unit test our UI code.
  • Some features, especially Feature 9, had high test coverage, but the unit tests were very low on actual assertions.
  • There's just not enough data.

In the end, if my argument to the business is that unit tests and code quality are important because they reduce the number of bugs, results like these won't help me make my case.

So, if you know of more persuasive results—either your own or stuff out there in the literature—I'd love to hear about it :-)

Monday, March 08, 2010

Using the Windows Findstr Command to Find Text, Files and Folders

Currently, I like the findstr command better than other ways to search files in Windows.

Prerequisite: Open Command Window Here
For XP, it's part of Microsoft PowerToys for Windows XP.

For Vista and Windows 7, apparently you hold down the hold down the shift key and right click.

Finding File Contents
Once you have a command window open at the directory you want to search within, you  can do something like this, which will return all lines containing "MyText" in all subdirectories of the current one, case-insensitive, and only searching files that contain printable characters:

findstr /s /i /p "MyText" *.*

It turns out that "MyText" is treated as a regular expression, which is great. But if you don't want it treated as a regular expression, you can use the /l or /c: options.

Finding File & Folder Names
Instead of giving findstr files to search, you can pipe text to it from another command, so to search for file or folder names, you can give it the results of the dir command to search:

dir /s /b | findstr /i "MyFileName.txt"

Combining the Two
Say you want to find all the lines containing "MyText", except you don't want those that are part of a subversion directory. You can do this, where the /v option means only return lines that don't match:

findstr /s /i /p "MyText" *.* | findstr /v /l ".svn"

Thursday, February 18, 2010

Software Development Career Paths: Up or Out?

Continued from Software-Development Career Paths: Organizational Quality.

Moving Up
For this option, mostly I can only repeat the traditional oft-heard worries: your tech skills will get rusty and you'll be stuck in middle-management forever.

On the other hand, I don't think developers who like to code should dismiss moving up out of hand. If you get a chance, try it. Who knows, you might like it.

There's a nice discussion about staying technical as a manager over on Rands In Repose: Technicality. If you keep your technical skills sharp, then hopefully if it turns out that you hate being a manager, you can still go back to being a developer.

Moving Out
Lately I have a new perspective on moving out, thanks to the software craftsmanship movement. How many books and articles have you read lately that use the word "journeyman?" There's a reason the word "jouney" is in there.

In parts of Europe… spending time as a journeyman, moving from one town to another to gain experience of different workshops, was an important part of the training of an aspirant master. [Wikipedia, Journeyman]

Although I don't think it's a perfect book, Apprenticeship Patterns by Dave Hoover and Adewale Oshineye is currently the best reference I know for thinking about different ways to approach a career as a software craftsman from the perspective of an individual developer rather than that of a manager.

Another Option: Stay Small, Maybe Even Really Small
Keep in mind that not all organizations force you to choose between coding and managing. Smaller companies often don't have "Eiffel Tower corporate hierarchies." If you're moving around, you might find more satisfaction sticking with smaller companies, especially since that way you're more likely to personally provide value to customers, as described by Cameron Purdy in his great article Eight Theses.

Don't forget that you can go it on your own. Recently at DDD8, Liam Westley gave a talk about owning your own software development company. Of course, the talk assumed that you already "have commercial ideas, clients, or sales leads." I have no idea how to get to that point, but the fact that Liam was there giving the talk is a reminder that people actually do manage it.

Staying Motivated
Whether you literally become a journeyman by moving among companies or you stay for a long time at a single company, if you don't want to move up, you may need to look for non-traditional ways to keep yourself up-to-date technically and otherwise generally motivated, especially if you find yourself occasionally working at places that treat you as an interchangeable coding machine.

Apprenticeship Patterns gives some ideas about how to do this. Obviously, there are always things like learning new languages, participating in either local or virtual developer communities, and in open source projects.

Interestingly, all of those things follow a general leadership-followership pattern that's pointed out in The Art of Followership:

[An] example, which is becoming increasingly common in developed countries, occurs with employees who have extensive professional education. These employees can often perform their work assignments without relying on technical guidance from their hierarchical superiors. Their education often includes a strong socialization component, instilling in them a desire for autonomous, self-controlling behavior and the tendency to look to their professional colleagues for support and recognition. This often occurs with university professors who are highly educated and tenured. These individuals often view their university as a place to practice their teaching and research skills with little interference by administrators. They work with and obtain feedback from colleagues, they read academic journals for up-to-date information on their field, and they derive intrinsic satisfaction from their publications and recognition at academic conferences. Similar tendencies exist in firms that provide consulting and accounting services. In these instances, professional education and socialization can replace or substitute for a leader's direction and supportive behavior. [Chapter 3, Three Perspectives on Followership by Howell and Mendez]

I don't think the software development profession has necessarily quite reached this point yet, but it's an interesting perspective to keep in mind. Ideally, you can get "support and recognition" from your "hierarchical superiors" as well as your peers. Anything else is draining. However, in a pinch, don't forget to look out as well as up to get the sustenance you need to nurture your craft.

Tuesday, February 16, 2010

Software-Development Career Paths: Organizational Quality

A developer-friend of mine, Tom Wessels, recently asked the computer-age-old question:

I just want to be a programmer. But can I?

He follows up the question with a great quote from the great and still-relevant book Peopleware by DeMarco and Lister, which points the career path encouraged, or at least tolerated, by many organizations: If you're not on your way up, you'd best be on your way out.

To be fair, DeMarco and Lister follow up this description with a contrasting one, "The Mentality of Permanence:"

Over the years, we have been privileged to work and consult for a few companies with extraordinarily low turnover. You won't be surprised to learn that low turnover is not the only good thing about these companies. Indeed, they seem to excel at many or most of the people-conscious qualities discussed in these pages. They are the best…. In the best organizations, the short term is not the only thing that matters. What matters more is being the best. And that's a long-term concept.

DeMarco and Lister go on to describe ways in which these companies invest in their employees, fostering a culture of learning, professional improvement, permanence, and organizational excellence.

To answer the question, I think you need to look at your career along a few different dimensions. One of which is the quality of the organizations at which you will work.

It might be possible, to get a job at one of these "best organizations" and be comfortable for some time with one of the options Tom presents:

You reach a point where you just accept that you're at a good company, you get to write code in a somewhat enjoyable fashion, and you leave it at that.

Hooray! Yes, I think it would be good for everyone to at least have that option for a few years at some point in their careers.

But a couple things stand in the way.

First, it can be hard to get a job at an organization like that, not only because its bar to entry might be pretty high, but also because from the outside, it can be hard even to identify which companies are truly the best. Or maybe you just don't happen to live near the offices of any of those best organizations and aren't able to move.

Second, nothing lasts forever, including "being the best." I'm not sure the great organizations DeMarco and Lister use to demonstrate their "mentality of permanence" are still considered to be the best now that it's 10-20 years later: Reader's Digest, Hewlett-Packard, Pacific Bell? Even the lean software development movement's favourite company, Toyota, has recently shown signs of falling off the "being the best" pedestal.

In short, the mentality of permanence may not be permanent. If you're lucky enough to find yourself working for one of these best organizations, that's super. Enjoy it while it lasts, or for as long as you're comfortable staying. But don't be shocked if it doesn't last forever.

Which brings us to the next dimension. Given that you might find yourself working at lower-quality, "up or out" organizations during your career, should you move up or should you move out?

Continued in Software Development Career Paths: Up or Out?

Sunday, December 06, 2009

A Year Of London Developer Events

Today marks a year since I moved to London from Chicago. So far, my favourite thing about being here is the trains run like clockwork the vibrant software developer community.

Here is a list of events I've attended, all of which I highly recommend:

Tuesday, October 27, 2009

Misadventures in DDD With Not-So-Ubiquitous Language

Lots of people have been talking about DDD (Domain-Driven Design) lately, and my friend Tom just discussed it over on his blog in the article Refactoring Toward Deeper Insight. So, I thought I'd share one way not to do DDD.

Once upon a time, shortly after the big blue book was published, I saw it in the store and thought it looked interesting. I bought it and read through the first section about knowledge crunching and ubiquitous language. And it all made so much sense—where I worked, the business analysts and software developers already worked together to crunch knowledge into a domain model they both understood (or so I thought). The trouble was, even though when they talked together, they used that language, when the developers actually wrote the code, they used their own. Why? Well, I didn't know—mostly just because we usually thought our names for things were better, I supposed. Trying to keep the language the same just wasn't something we'd thought about much.

So, I decided that on the project I was working on, we'd start doing DDD by using the names from the business language for the classes in our code. I didn't discuss it with the business people, since I didn't think it involved them much—they didn't need to change their language, we developers just needed to use it.

Everything went fine for most of the project. Then, a couple days before release, the business decided that they wanted to rename one of our core domain concepts—and that was okay, right, because it was just changing a few labels on a few screens?

And that's when I learned that if you want to do DDD, it helps to get buy-in from the business.

So, happy DDD-ing everybody—because I do think lots of the ideas are great and worth exploring—just make sure you let the business know what you're up to and you'll avoid my rookie mistake.

Monday, October 26, 2009

Estimating is Like Measuring the Coast of Great Britain

Earlier today, Liz Keogh tweeted this, which I couldn't agree with more, as long as she's saying what I think she's saying:

Thinking about fractal estimation—estimates grow as scale shrinks—and wondering what dimension current projects have.
A while back, every time I started doing technical estimates for a release, I began to think more and more of the illustrations along the side of this Wikipedia article: How Long Is the Coast of Britain? Statistical Self-Similarity and Fractional Dimension.

The situation was, that as a developer in a waterfall process, when I was trying to estimate how long it would take to code something, even with the requirements supposedly "fixed," unless I examined the code I was proposing to change in so much detail that I was basically writing it—and that's not estimating anymore—I'd always miss things that would make coding take longer than I'd estimated. In essence, there were always craggy little details that upon actually writing the code, became significant or added up with others to become significant.

Now, I know that if your architecture and code are clean, this should happen less. But I still think it's generally true that until you actually write the code, you really don't know how long it will take, and the amount of time will usually be longer than you think when analyzing it at higher levels.

Then, I thought of this problem again when I attended a talk on Scope Budgeting. There, the general issue is that in Agile, if you write a user story, estimate it, put it in your backlog, and only elaborate it when you pull it back out to implement it, you may find that the size of the story grows at elaboration-time.

According to Liz's fractal estimation rule, that makes complete sense and should be expected. I agree. Whenever I have worked with user proxies to move from general functional requirements to specifics, the estimate has always increased. The amount of work needed to address all the details we discover always grows beyond the original estimate. If we made commitments based on that estimate, the only way to keep them is to prioritize and remove some of the details.

I can think of a few ways to address this problem, if we want to consider it to be a problem:

  1. Just be aware of it and deal with it as needed, which is a lot better than not being aware of it at all.
  2. Start measuring it, so you can factor it into your future estimates. This might be taken care of by comparing estimates to actuals and factoring that into future estimates. You'll need to decide whether the time it takes to do this is worth the return, though.
  3. Move toward techniques like Kanban that de-emphasize estimation. Whether or not this works for you will depend on your current situation, but it's always worth questioning whether you're estimating because you truly need to or just because that's what you're used to.


Update Sept, 2010:

Sunday, September 06, 2009

Pair Programming for Flow

A while ago, I attended the workshop Debugging Pair Programming by Matt Wynne .

Matt gave the same workshop at Agile 2009. That website has a good write-up of how it worked.

After the first part, where we discussed how to convince different developer personas why they should cooperate with pair programming, we moved on to the second part, where we paired up and interviewed each other about good experiences pair programming or collaborating in other ways.

I was paired with Tom ten Thij , who said something really interesting about pair programming.

He said that pairing can make it easier to get into flow.

This was completely the opposite of what I'd heard before about pair programming. Before, I'd heard it can be difficult to achieve flow while pairing—that you might even have to give up on flow, but that the increased code quality is probably worth the trade-off.

But Tom's point was that while pairing, you're less likely to procrastinate getting into your coding task. In other words, having a partner helps force the "activation energy" that flow activities can require.

So, as long as your pair works well together, and you keep everyone engaged by doing something like ping-pong programming, you might be able to achieve flow after all.

Saturday, August 08, 2009

Misadventures In BDD With NBehave

From my previous post, you might have picked up that I like the idea of BDD's given-when-then construct for describing scenarios.

For a while, I've been wanting to use this syntax in unit/integration tests to make them clearer. But I've been hoping to do that without switching languages or unit-testing frameworks. Toward that end, I tried out NBehave.

Here's some test code that demonstrates my worst fears about why NBehave might not be right for me:

public void Execute()
{
    var story = new Story("Search Contacts by Relationship Strength")
        .AsA("User")
        .IWant("To search on the Strength field")
        .SoThat("I can find Contacts who have a given Strength");

    Scenario scenario = story
        .WithScenario("Find Contacts with Strength of 50");

    scenario.Given("The database contains a Contact with a Strength of 50")
        .And("a search results view", GivenResultsInfo)
        .And("a query for Contacts with Strength of 50",
            GivenQueryForContactsWithStrengthOf50)
        .When("The search is run", WhenRunSearch)
        .Then("The results contain Contacts with Strength of 50",
            ThenShouldContainResultsWithStrengthOf50);
}

private void GivenResultsInfo()
{
    var resultsView = new ReadOnlyResultsView(
        ExtendableEntity.Person, SortType.Ascending, 
        new[] { Column }, Column);
    ResultsInfo = new ResultsInfo(resultsView);
}
private void GivenQueryForContactsWithStrengthOf50()
{
    var condition = 
        new DecimalCondition(Column, ComparisonOperation.EqualTo);
    condition.DataField.Value = 5;

    _query = TypeHelper.GetAdvancedQuery(_entityType);
    _listManager.AddListToAdvancedQuery(_query);
    _query.MainConditionGroup.AddCondition(condition);
}
private void WhenRunSearch()
{
    ISearchService service = TypeHelper.GetSearchService(_entityType);
    ISearchResults results = service.GetResults(_query, ResultsInfo);
    _resultsData = results.Results;
}
private void ThenShouldContainResultsWithStrengthOf50()
{
    Assert.Greater(_resultsData.Rows.Count, 0);

    foreach (DataRow row in _resultsData.Rows)
        Assert.AreEqual(5, (decimal)row[Column.Name]);
}

But for me, creating reports of the text descriptions wasn't the main point. The main point was just to better organize the test. When I started writing the code, I thought maybe I'd just skip the text, but then I thought, "Oh well, I might as well do it."

And that was fine, but when the requirements changed, I had trouble keeping the text synchronized with the code.

After I wrote the initial code, the team decided that instead of having strength on a scale from 0-60, we'd have it on a scale from 0.0-6.0. And when I changed the code, I was in a hurry, since that change hadn't been part of the original estimate, and consequently threatened our timeline.

So I ended up with text that said 50 and code that said 5.