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

ProBlogger birthday give-away

Posted on 2007.10.03 at 16:02
It's ProBlogger's birthday (Darren Rowse started ProBlogger 3 years ago), so Darren is having a $54000 Birthday Bash Give Away. Follow the link over to ProBlogger for your chance to win all sorts of stuff, from an Amazon voucher to a logo design, a $1000 donation to charity or an 8Gb iPod Nano.

ProBlogger provides a lot of information about blogging, and making money from your blog. It's well worth a read, even if you don't want to enter the give-away.

Brio buckets are evil?

Posted on 2006.02.20 at 17:54
Tags:

Over the weekend, we decided to buy a metal bucket for our son to play with. Having been happy with some of the other gardening tools Brio do, we thought we'd have a look at the Brio buckets. The Brio website refers to the buckets as "Pails", so we thought we'd search Amazon for them by that name. Imagine our surprise, when the search results came back:

Amazon.co.uk: brio pail: Search Results All Products:

We found no matches for "brio pail" . Below are results for "evil" . If you prefer, you may try another search

We were especially surprised, given that searching for "Brio bucket" finds the item in question


My new monitor, DVI troubles and DVDs.

Posted on 2006.01.11 at 16:27
Tags: ,

I have just purchased a new monitor: a Formac Gallery 1900 19-inch LCD in Raven Black.

DVI only means exactly that

After unpacking the box, I was duly impressed. The screen is considerably larger than my old 17-inch CRT monitor, and (as expected for an LCD), the desk space occupied is considerably less. One problem: the input is DVI only, and all my PCs have VGA output only. I had naively assumed that no PC-compatible monitor would ship without VGA input; I was wrong.

Ok, thinks I, I'll just get a converter. Not so fast — the connector is DVI-D, which means it only accepts Digital input. Not only does it not accept VGA input, but you cannot just buy a simple VGA-to-DVI adapter or cable, since these just output the same analogue signal on a DVI-I connector — instead you must buy a full analague-to-digital converter box, which will cost almost as much as the monitor. Ouch.

Time for a different tack — can I get a new graphics card. The answer is "Yes" for my desktop machine, and "No" for my laptop. Oh well, at least I'll be able to use the monitor, and desktop graphics cards are relatively inexpensive.

New graphics card

Ok, so a couple of days later, and I get my new graphics card — a PowerColor 9250: cheap, cheerful, and with DVI output. Plug it in, install the drivers and it works fine. So does the monitor.

Superb pictures

At last, my new monitor works. Wow! The picture is superb. It's an MVA screen, so you can view it from just about any angle — unlike my laptop, which has a very narrow range of usable viewing angles. Not only that, but the colours are vivid and clear; photos look better than I've seen on any other screen.

As an added bonus, I can now run at 1280x1024 and still read screen text, so I've now got oodles of screen real estate. Shame I can only use it on the one machine.

DVDs

Playing DVDs was a whole new game. Since I work from home, and we've packed away our television, we have occasionally used my laptop for watching DVDs, and we thought it would be nice to watch them on a larger screen.

The PC with the new graphics card in didn't have a DVD drive, but I have an external USB one, so I plugged that in, and started watching. Boy was that poor; the picture was fuzzy and it glitched all the time. After some time spent fiddling with all the configuration options of PowerDVD, I gave up. Time to try my other desktop machine, which has a built-in DVD drive. No luck there either — it point-blank refused to play DVDs at all.

Then I had a thought — the USB port on the first desktop is only USB1, so it's probably too slow for DVD playback; if I put the internal drive in this machine instead of the other one, it might work better. Sure enough, it did, though getting the drive installed, cables connected and jumper settings right was not fun. At least the playback was now glitch-free, even if I had to swap parts between the PCs to do so. My wife commented that not many people would have been confident enough to take apart a computer and swap bits around, and I have to agree. Thankfully, I'm not scared of computers, and it all worked out OK.

Conclusion

So, what have I learnt from all this?

  • Firstly, the Formac Gallery 1900 is awesome.
  • Secondly, to check compatibility first, and really pay attention to what connectors things are shipped with.
  • And finally, DVD playback requires a very high data bandwidth, and consumes lots of CPU time.

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.


Refactoring and tests

Posted on 2005.12.15 at 09:56

Yesterday I posted a comment to the eXtreme Programming mailing list, which I think bears repeating.

People generally say that you need a good set of tests to make refactoring safe. It's true that if you refactor without tests, then you risk introducing bugs. However, if you're on a team that works without unit tests, instead relying on downstream QA or customers reporting bugs, with the general attitude "bugs happen, we'll deal with them when someone reports them", then bugs will happen anyway. You're no more likely to add a bug through careful refactoring than through making any other change, and as Jeff Grigg pointed out, after refactoring you can find bugs faster, because they're glaringly obvious.


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.


Landfill is evil

Posted on 2005.10.05 at 10:47
Tags:

Every week the bin men come with their big truck, and take away our rubbish. "Thank goodness", we say, "that's got rid of that". Our house is no longer contaminated with all that rubbish, and we think no more about it; out of sight, out of mind.

However, the rubbish doesn't just disappear, it has to go somewhere, and the place that it goes is landfill. That's right — they dig a big hole in the ground, and fill it with rubbish. When it's full, they turf over it and dig a new hole somewhere else. Most of the stuff buried there won't decompose for hundreds of years, so this is now a permanently contaminated site. I wouldn't like to live next door to a landfill site, and I bet you wouldn't either.

Just imagine, for a moment, that rather than sending your waste off to landfill elsewhere, you had to bury it yourself, in your garden. How many weeks would it take for your garden to be full of rubbish? Would you fancy your children playing on it, or eating vegetables grown in it? No? Then why are we happy to send our rubbish elsewhere for this self-same treatment? Because it then becomes Somebody Else's Problem, and therefore invisible (with all due respect to Douglas Adams).

Every year, we make more waste, not less, so the rate of filling up the landfill is increasing. Eventually the whole country will be covered in landfill. Agreed, this may take a while, but it's not a direction I'm happy to be headed.

What can we do about it?

It all comes down to the three R's: Reduce, Reuse, Recycle.

Recycling

Let's start with recycling. We can all recycle more than we do, and not only that, but more of the things we throw out could be recycled, if the government would invest in appropriate facilities:

  • In the Netherlands, standard disposable nappies such as Pampers and Huggies can be recycled — fundamentally, they're just paper with special chemicals on them, so you can strip out the chemicals and recycle the paper.
  • We're all told we can't recycle the cardboard from drinks cartons because of the polythene lining — it turns out that there is actually a facility in Scotland for doing just this.

So, we can ensure we make use of the facilities available, whether that means putting glass bottles in the bottle bank, taking plastic bottles to the local recycling centre, or sending drinks cartons to Scotland. We can also send letters to our local councils asking them to provide the facilities, or provide appropriate collections.

Composting

On the theme of recycling, another thing we can do is compost our food waste. Uncooked vegetable peelings can be added to a normal compost heap, but cooked food, meat and fish generally poses a problem. The solution comes in the form of a Green Cone, a Living Soil Kitchen Waste Digester, or a Green Johanna, all of which can compost such waste.

Reuse

Rather than throwing something out, can it be used again? The classic example has to be the use of washing up liquid bottles for craft projects, but you could also take your plastic carrier bags back to the supermarket next time, and reuse them, rather than getting new ones; some supermarkets will even recycle carrier bags. Of course, the best option is to get things intended for reuse, such as a sturdy cloth carrier bag, or to buy refills for products that can go in the original container.

Reduce

The final, but best, option is to reduce the use of things that need throwing out. Buy loose vegetables, rather than cellophane-wrapped ones, buy wooden toys rather than plastic ones so they can be recycled when they break, rather than thrown out. This is the hardest option, since it generally entails making changes to the way we live, and the things we buy, but long term it has to be the way.

Landfill is evil

Landfill is not, and never has been a solution to the problem of waste, and the government should do something about it. They should make kerbside recycling collections rather than general refuse collections. They should tax people and companies that put recyclable things in general rubbish, to pay for people to sort them out. They should add a tax to everything made or imported that is not recyclable, to pay for finding ways to recycle them.

On television recently, there have been items about the location of nuclear waste dumps. This is an extreme example, but the issues are the same — just buring waste and hoping it goes away is not a solution.


Previous 10