Home

Advertisement

Customize
October 2007   01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

Breadmakers and early feedback

Posted on 2006.01.09 at 11:50
Tags: ,

I made my first foray into the world of breadmakers last night. I have successfully made bread by hand on several previous occasions, but it's quite time consuming, and I was seduced by the idea of "put all the ingredients in, turn the machine on, and you'll have fresh bread in the morning".

So, I measured all the ingredients, put them in, and turned the machine on. Then I noticed that the paddle was sat there on the worktop, so there was no way it was going to make bread, as the ingredients would remain unmixed. Aagh! Anyway, this early feedback that the breadmaking project was going to be a disaster meant that I could cancel the current project (read: throw out the current mixture), and start again afresh whilst there was still time to get a working product (loaf of bread).

Sadly, my bread then sunk during baking, so the result is less than perfect, but I do have bread! The breadmaker comes with a list of things to do if your bread's not right, so I can take the feedback on board, and try again for the next release (tomorrow's bread).

Sometimes the best feedback is information that enables you to cancel a project or take other aversive action whilst there is still time to start again. If you don't know the outcome until the end of the project, you're a bit stuffed if it all goes wrong, because something crucial is missing from the mix.


Mocks, Interfaces, and Test-Driven Development

Posted on 2005.12.15 at 09:31
Tags:

Over the last couple of days, there's been a lot of activity over at the Test Driven Development Yahoo group, discussing the uses and benefits of mocks in unit tests. This jives with a question one of my clients asked me recently about the proliferation of interfaces in my code, so I thought I'd expound on the subject.

TDD: Top-down development

When I'm developing using TDD, then I have a specific goal in mind, and I tend to work from the outside in, starting with the UI. This means developing the UI handler code using TDD. Whether that's a website backend, or a Windows GUI doesn't really matter, it just changes the techniques.

When focusing on the UI handler class, I don't want to think about the actual domain model code, so I declare an interface that covers the responsibilities required. Sometimes, I might declare several interfaces, dividing up the responsibilities as appropriate. I can then use the self-shunt pattern to provide implementations of these interfaces as part of the test class. Of course, the API exposed by these interfaces, and indeed their very presence will be determined incrementally by the tests I write. For example, if this is a login page, and I'm testing that invalid entries show an error message, then I'm going to need something to validate the username and password, so I'll add a UserNameValidator interface.

Initially, these self-shunt implementations will be stubs, returning constant values. However, in some circumstances, they may evolve into more complex implementations, with results that depend on the history of calls. If different tests need different behaviour from the dummy (as opposed to just different fixed values), then I may extract the dummy implementations into separate classes, one for each type of response required.

Note: I would still hand-code these dummy implementations, rather than use a mocking tool; a mocking tool just seems too complex to me.

A proliferation of interfaces

When I'm ready to move on to one of the collaborators, I start the process again, except now I have an explicit interface to implement, rather than a UI. As before, I add tests for the behaviour I want that class to have, and add interfaces for responsibilities I feel belong elsewhere.

Sometimes this leads to almost as many interfaces as concrete classes. Indeed, sometimes it leads to more interfaces than concrete classes, as a single concrete class can implement several interfaces. However, it does lead to nicely decoupled designs — I can freely switch implementations of an interface, and client code remains unaffected.

This also needs to fast, well-behaved unit tests, too — this approach leads to stubbing out access to the filesystem, or database, or network all they way down until we reach an actual class that handles the external subsystem. In this case, the class in question is now a simple wrapper over the underlying API, providing simple, generic inserts and queries on a database, or simple file access, or sending raw chunks of bytes over the network — all the complex mapping between objects and queries, or handling of network protocols such as SMTP or HTTP, or parsing of file formats is dealt with in the layers above.

Summary

Interfaces are all about separation of concerns, and reducing coupling. The use of mocks, fakes and stubs when developing in a TDD style facilitates this separation of concerns. Don't be afraid of a proliferation of interfaces, but do check that they pull their weight — each interface should reflect one responsibility, and each responsibility should be represented by one interface. If your interfaces are cohesive, then a proliferation just means that your code does a lot.


New hammers

Posted on 2005.11.28 at 12:35
Tags: ,

Knob and Hole Connectors

My son has a wooden railway set. Like most such sets, the track is made of individual pieces, most of which have a knob on one end and a hole on the other, so the knobs fit in the holes, and the track stays together.

One of the pieces we have is a turntable, which has eight track connections coming off, so there are four possible ways across. Four of the connections have knobs, and four have holes. Since we got this piece, we've often encountered problems when building layouts, where you end up with two knobs together, or two holes together, so you can't close the loop. The people who make the tracks are obviously aware of this problem, since they sell pieces with a hole at each end, and pieces with a knob at each end.

Knobs, holes and new hammers

Yesterday we purchased a pack with one of each of these pieces in. When we got home, Hugh promptly started building a new track, and one of the first questions he asked was "Where can I use my new pieces?" — he very quickly ended up with a bridge that had a hole-hole piece at one end and a knob-knob piece at the other, when merely turning the bridge round would have made it fit.

When you have a new hammer, everything looks like a nail.


Testing functions that open dialog boxes

Posted on 2005.11.07 at 11:10
Tags:

Cory Foy recently posted to the Test First User Interfaces list at yahoo groups, highlighting his blog entry on Writing tests for private void classes, which discusses testing a function that asks the user to choose a font.

Cory suggests extracting a method to make the request, and then injecting a mock font dialog to verify the interactions. The route I would take is a little different, so I'm going to describe it here.

I agree with Cory that extracting a method to make the request is a good move, so we'll start there: our class now has member functions like those shown below.

private void menuItem15_Click(object sender, System.EventArgs e)
{
  rtbDisplay.Font = GetFontFromUserSelection(rtbDisplay.Font);
}

public Font GetFontFromUserSelection(Font defaultFont)
{
  Fdialog = new FontDialog();
  Fdialog.Font = defaultFont);
  if(Fdialog.ShowDialog()!= DialogResult.Cancel )
  {
    return Fdialog.Font;
  }

  return defaultFont;
}

This however, is where I part company with Cory. I feel that this GetFontFromUserSelection function does not belong here, so I would create a new class to hold this function, and move it there:

class SelectFontUsingFontDialog
{
public Font GetFontFromUserSelection(Font defaultFont)
{
  Fdialog = new FontDialog();
  Fdialog.Font = defaultFont);
  if(Fdialog.ShowDialog()!= DialogResult.Cancel )
  {
    return Fdialog.Font;
  }

  return defaultFont;
}
};

The original class can then call this new one:

private void menuItem15_Click(object sender, System.EventArgs e)
{
  rtbDisplay.Font = new SelectFontUsingFontDialog().GetFontFromUserSelection(rtbDisplay.Font);
}

If we now extract an interface (FontSelector), we can pass this in to our class constructor:

interface FontSelector
{
public Font GetFontFromUserSelection(Font defaultFont);
}

class MyForm
{
private FontSelector fFontSelector;

public MyForm(FontSelector fontSelector_)
{
  fFontSelector = fontSelector_;
  // do remaining initialization
}

private void menuItem15_Click(object sender, System.EventArgs e)
{
  rtbDisplay.Font = fFontSelector.GetFontFromUserSelection(rtbDisplay.Font);
}

}

We now have a seam where we can test the behaviour of the original class, and verify that it does indeed ask for a new font, and that it does use the new font as expected, by substituting a MockFontSelector. As shown here:

[Test]
public void UserSelectionOfANewFontShouldChangeTheDisplayFont()
{
  Font defaultFont = new Font("Arial", 16);
  Font expectedFont = new Font("Times New Roman", 14");
  MockFontSelector fontSelector = new MockFontSelector();
  fontSelector.setChosenFont(expectedFont);

  MyForm form = new MyForm(fontSelector);
  form.menuItem15_Click(null, null);
  Assert.AreEqual(expectedFont, form.Display.Font);
}

We can then test the SelectFontUsingFontDialog class separately — since it now has a simpler interface, and a clearer responsibility, this is easier than testing the original code. I might well decide that I now wanted to be able to substitute a MockFontDialog, as Cory suggests, or I might actually drive the FontDialog GUI directly — this is much easier to do now the call to open the dialog is not buried several function calls deep. I might even decide it was "too simple to break", since all it does is call a library component to select the font.

Summary

Your choice of seam when breaking dependencies can be important, and determines the shape of your solution. In particular, I feel that if you have a function that needs to ask the user for a choice here and now, in order to perform some operation, then the responsibility for obtaining the user's choice does not belong with that function, and probably doesn't belong with the function's containing class either. Therefore, this is where I would choose to locate my seam, rather than at the lower level of the dialog box called up for the purpose. Also, because the responsibility of the new class is so narrow, I have a class I can use elsewhere, if the user needs to choose a font in another form, or even another project.


Listening to customers

Posted on 2005.10.05 at 11:06
Tags:

Companies like to listen to their customers, so when a customer asks for a new feature, it often gets implemented in the next release of software. The customer is happy, as they've got what they asked for, and it probably makes their life a bit better. However, this shouldn't be done blindly.

Jon Kern has a blog entry on Stupid GUI Designs, starting with a comment by David R. on the stupidity of a "Do you want to exit?" dialog, and proceeding to rant about the things you can do in a "Save" dialog. There has probably been some customer, somewhere, who's actually asked for many of these features, and the development team have just blindly put them in.

It's not that I don't think we should listen to our customer's requests; on the contrary, I think we should listen very carefully, and ask more questions. We shouldn't blindly implement the solution that the customer proposes — we should find out what the problem is, and provide a clean solution to that.

In the case of the "Do you want to exit?" dialog, I recently had to implement such a dialog, because the customer asked for it. I should have dug further, and identified the problem. It was probably related to the customer accidentally closing the application when trying to do something else (such as close a maximised MDI child window — the two buttons can be very close together), and thus losing work in progress, and then having to restart the application, and spend time getting back to where they were. Maybe a better solution would be to provide an automatic recovery mechanism (like the SessionSaver extension for Firefox), so if the user accidentally quit, then they could resume where they left off just by restarting the application, complete with the same open documents, the same changes made, and full undo history.

Listening to customers involves more than just doing what they say they want; it means working with them to identify their needs, and produce software that satisifies those needs. It might take several prototypes to get there, as the shared understanding of the underlying need can be hard to build, and they aren't always aware of what is possible. This is a good reason for using iterative methods.


Back to bowling

Posted on 2005.10.03 at 17:14
Tags:

Someone added a comment to my post on Bowling in C++ part 2 asking for the source code. Here it is.

template<bool value>
struct Assert
{
    char assertion_failed[value];
};

template<unsigned lhs,unsigned rhs>
struct AssertEqual:
    Assert<lhs==rhs>
{};

template<typename GameState>
struct IsLastFrame
{
    static const bool value=GameState::frameCount==10;
};

template<typename GameState>
struct NextRollCounts
{
    static const bool value=GameState::ballsLeftThisFrame || 
        !IsLastFrame<GameState>::value;
};

template<typename GameState>
struct NextBallIsStartOfFrame
{
    static const bool value=NextRollCounts<GameState>::value && !GameState::ballsLeftThisFrame;
};

struct NullGame
{
    typedef NullGame PreviousGameState;
    static const bool isStrike=false;
    static const bool isSpare=false;
    static const unsigned totalScore=0;
    static const bool ballsLeftThisFrame=false;
    static const unsigned frameCount=0;
    static const unsigned roll=0;
};

template<typename GameState>
struct NextBallIsLastInFrame
{
    static const bool value=GameState::ballsLeftThisFrame;
};

template<typename GameState>
struct BonusMultiplier
{
    typedef typename GameState::PreviousGameState PreviousGameState;
    static const unsigned value=(NextRollCounts<PreviousGameState>::value && (GameState::isStrike || GameState::isSpare)) + PreviousGameState::isStrike;
};

template<typename GameState>
struct RollMultiplier
{
    static const unsigned value=BonusMultiplier<GameState>::value+NextRollCounts<GameState>::value;
};


template<typename GameState,unsigned roll_>
struct Roll
{
    typedef GameState PreviousGameState;
    static const unsigned roll=roll_;
    static const bool isSpare=GameState::ballsLeftThisFrame && ((roll+GameState::roll)==10);
    static const bool isStrike=NextBallIsStartOfFrame<GameState>::value && roll==10;
    static const bool ballsLeftThisFrame=NextBallIsStartOfFrame<GameState>::value && !isStrike;
    static const unsigned frameCount=GameState::frameCount+
        NextBallIsStartOfFrame<GameState>::value;
    static const unsigned totalScore=GameState::totalScore+
        RollMultiplier<GameState>::value*roll;
};


AssertEqual<Roll<NullGame,0>::totalScore,0> roll0Scores0;
AssertEqual<Roll<NullGame,6>::totalScore,6> roll6Scores6;
AssertEqual<Roll<Roll<NullGame,6>,3>::totalScore,9> roll63Scores9;
AssertEqual<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<
    NullGame,6>,3>,6>,3>,6>,3>,6>,3>,6>,3>,6>,3>,6>,3>,6>,3>,6>,3>,6>,3>::totalScore,90> allOpen;
AssertEqual<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<
    NullGame,6>,4>,6>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>::totalScore,22> spare;
AssertEqual<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<
    NullGame,4>,4>,2>,4>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>,0>::totalScore,14> notSpare;
AssertEqual<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<
    NullGame,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>,5>::totalScore,150> allSpares;
AssertEqual<Roll<Roll<Roll<Roll<Roll<NullGame,10>,4>,5>,3>,0>::totalScore,31> strike;
AssertEqual<Roll<Roll<Roll<Roll<NullGame,10>,10>,4>,5>::totalScore,24+19+9> doubleStrike;
AssertEqual<Roll<Roll<Roll<Roll<Roll<NullGame,10>,10>,10>,4>,5>::totalScore,30+24+19+9> tripleStrike;
AssertEqual<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<
    NullGame,10>,4>,6>,10>,4>,6>,10>,4>,6>,10>,4>,6>,10>,4>,6>,10>::totalScore,200> alternating;
typedef Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<Roll<
    NullGame,10>,10>,10>,10>,10>,10>,10>,10>,10>,10>,10>,10> PerfectGame;
AssertEqual<PerfectGame::frameCount,10> perfectFrameCount;
AssertEqual<BonusMultiplier<PerfectGame::PreviousGameState>::value,1> perfectFrameFinalBonus;
Assert<!NextRollCounts<PerfectGame::PreviousGameState>::value> perfectFrameFinalBallCounts;
AssertEqual<PerfectGame::PreviousGameState::ballsLeftThisFrame,0> perfectFrameFinalBallsLeft;
AssertEqual<PerfectGame::totalScore,300> perfect;

Designing at the Last Responsible Moment

Posted on 2005.08.18 at 09:47
Tags:

Joel Spolsky has just posted an article about the spec for his company's new product, in which he says:

"I can’t tell you how strongly I believe in Big Design Up Front, which the proponents of Extreme Programming consider anathema. I have consistently saved time and made better products by using BDUF and I’m proud to use it, no matter what the XP fanatics claim. They’re just wrong on this point and I can’t be any clearer than that."

The specific example which he uses to drive this point is a change he made to the application when reviewing the user interface. Whilst working through the details of the screens from a complicated flow chart, he realized that by eliminating one of the possibilities, the whole thing could be greatly simplified, and:

"Making this change in the spec took an hour or two. If we had made this change in code, it would have added weeks to the schedule.

I don't know about the specifics of Joel's case, but in my experience, such a finding does not point to the importance of BDUF. Instead it highlights the importance of thinking before implementing a particular bit of functionality. In agile processes, such as XP, BDUF is not replaced with "no design", but rather with design at the last responsible moment.

Before implementing these UI screens, someone would have had to think through the design. If that person had been Joel, I am sure he would have spotted the same simplification, and thus saved the same amount of time. The difference is that in an agile process, this would only happen just before the UI screens were to be implemented, rather than at the beginning of the process, and there would likely already be some parts of the software that had been designed, implemented and tested.

Joel's article also says that he had already written the flowcharts showing how the UI should work for the complicated case. Given that he then threw out the idea, this work is wasted. In an agile process, these detailed flowcharts probably wouldn't have been done up front either, but done along with the UI design, just before the code is implemented. This would provide the maximum opportunity for Joel's simplifying insight to happen in time to avoid doing the flowcharts for the complicated case as well, which would have therefore saved more time.

Designing at the last responsible moment is all about eliminating waste. Don't waste time thinking about details that you don't need now, but conversely, don't delay thinking about details you do need. If you postpone thinking about details now, and you need them later, think about them when you do need them; it won't take any more time to analyse them later, and you might have gained important information and insight in the mean time. Not only that, but you might not need them after all, as the requirements change. This is often expressed as "You aren't gonna need it" (YAGNI), but the principle is the same.


Cornish dreams part 3

Posted on 2005.07.21 at 21:52
Tags: ,

I mentioned in a previous post that I had a 2 hour drive to work since we moved to Cornwall. Well, I have now made my last daily commute; as from Monday I will be working from home as an independent software developer (and I'm not working tomorrow).

If you need some software developing, drop me a line!


Heisenbugs and Schroedinbugs

Posted on 2005.07.05 at 22:51
Tags:

I finally got around to reading the Tandem computers report on software reliability, which has been lurking on my to-read list for a while.

This report mentions Heisenbugs (which disappear when you look for them), and Bohrbugs (which are repeatable), which got my imagination going, so I googled them, to see if they were in use elsewhere. It turns out that the Jargon File has definitions (Heisenbug, Bohr bug), which reference another member of the set &mdash Schroedinbugs. These nasty creatures lie in wait, with no visible signs until someone spots them under obscure circumstances, or by looking at the source, and then they realise that the software should never have worked; sure enough it now doesn't work for anyone. I've met a few of these in my time, and they weren't pleasant.


Language Idioms

Posted on 2005.07.05 at 22:35
Tags:

Thinking about transactional operations and the C++ exception safety guarantees made me think about cross-pollination of idioms between languages.

In this case, the C++ idioms of exception safety have not been transferred to the Java world, even though, IMHO, they are equally applicable there. Admittedly, the actual implementation will generally take a different form, since Java lacks destructors, and support of exception safety in C++ often relies on the use of RAII and destructors to provide safe cleanup and rollback where appropriate.

I am sure there are also idioms that are prevalent in the Java world that are not common place in C++, as there are in any language — the idioms of a language reflect its design.

For this reason, a good software developer needs to be able to use multiple langauges, and use them well. The different idioms and ways of solving problems used in each language can help illuminate ideas and show new ways of solving problems. The Pragmatic Programmers' idea of learning a new language every year is a good one, as radically different languages can come with radically different idioms out of the box, but care needs to be taken when learning similar languages, such as C++, C# and Java, as the idioms used by experts in the language may not be immediately apparent.


Previous 10