
I know I've said this before, but VirtualBox kicks ass. It has that whole "it just WORKS" feel to it. I realise that repeating yourself is supposedly one of the hallmarks of a bad blog, but please indulge me this once; VirtualBox deserves your attention. The image to your right shows virtualbox running windows XP - I'm installing Qt4.4 in the hope that some of the bugs I mentioned in my previous post have been cleaned up.
I'm also compiling the latest KDE4, which is where a multi-core system would be really nice. Until then, I'll continue to struggle with my old box.
virtualbox rocks
Twitter Submission
I posted previously that I just didn't "get" twitter. I guess this sums up my objections pretty well; unless you have anything interesting to say, stay silent. Do we really need one more idiot blathering on about the most mundane details of his life? I think not.
Even some of my most respected peers seem to be reduced to complete morons when it comes to their twitter feeds.
However, it turns out that the cost of my stubbornness to jump on the twit bandwagon has grown to the point where I am now on twitter. That's right, I'm bowing to peer pressure, and have officially jumped on the twit wagon - You can see my last twitter updates on the right, or you can follow me on twitter.
Now the entire world can join me in my mindless ramblings... of course, if you're reading this then you've already had that pleasure!
Buffalo Routers Rock!
Waaaaay back in Janurary I mentioned that I might build my own wireless router. Well, like most of my projects I got half way then got distracted. The other day i got fed up with the lack of wireless (I needed to get my Wii online, apart from anything else), so I splashed out and bought a Buffalo Air-Station (£45).
This baby comes pre-loaded with the open source dd-wrt firmware. It was dead-easy to set up, and boy, what a difference the open firmware makes! This is easily the best router firmware I have ever seen - it boasts more feature than you can shake a stick at. Better yet - it's aimed at people who know what they're doing, and doesn't try to hide it's functionality behind restrictive setup "wizards".
All in all, I'm a very happy man with my new wireless network ;)
pointer quiz
One of my pet peeves with regards to C++ is how very few people understand how the delete operator handles NULL pointers. Let's see if you pass the test!
Question: What happens when you do this:
myType *ptr = NULL;
delete ptr;
Well? Your choices are:
a) Crash, bang, boom, your computer is now a very heavy paperweight.
b) Nothing - the delete line ignores the ptr to be deleted.
It turns out that deleting a null pointer is safe. Section 5.3.5/2 of the C++ standard states that:
"In either alternative, if the value of the operand of delete is the
null pointer the operation has no effect."
This has been a pet peeve of mine for a while now. I can't count the number of times I've seen programmers write something like this in class destructors or cleanup methods:
if (pMyPtr)
delete pMyPtr;
This is stupid for several reasons. For a start, the if statement is redundant - if the pointer is NULL the delete will do nothing. Secondly, the programmer never sets the pointer to NULL after deleting it, which means that if this code were to be called again, you would definitely experience problems.
In order to avoid these issues, and avoid angering me if I ever see your code, you should:
- Always initialize pointers to NULL if you're not going to set them to something else straight away (i.e.- if the pointer is not always used).
- Always set them to NULL after you delete them, especially if there's a chance that the delete can be called twice.
piwup: A Picasaweb Image Uploader for Linux
There is a kipi plugin that is supposed to be able to do this, but it has not yet hit the Linux distribution I am using, and I'm not about to start compiling plugins from source. Besides, half the fun is in making the application!
This is definitely not a finished application! I got it to the point where I could upload my images in a batch, but it needs more work before it's useful to anyone else. Here's a few sample screen shots:
Uploading the first image.The application still has a long way to go. Just some of the things yet to complete are:
- Remove hard coded items from the code (account details, service host, album name), and make these configurable via a nice configuration dialog. Make sure password is stored in a secure form - via the KDE wallet perhaps.
- Make the GUI half-decent. Originally I just wanted something to work - I need to go back and do it again with a proper menu and image thumbnail support.
- Bug fixes too numerous to mention here... this is some rouch, cheap and nasty code!
Perhaps, once I get all this done I will attempt to get it officially released into some distros. I think it's a useful application, and the kipi plugin version doesn't seem to be moving along much. Yes, I realize that I'd be better off spending my time improving the kipi plugin, but to be honest I can't be bothered right now - this was a learning experiment for me as much as it was about making an application that solved one of my problems.
The entire application is written in C++ and Qt4. The more I use Qt the more I like it. This application was simplicity itself to make, and I look forward to continued development.
Problem with pimpls
That's "pimpl", not "pimple" - I'm talking about opaque pointers, these beauties help protect your public interfaces from changing implementation. This useful technique has a few drawbacks that aren't so well publicised. In order to prevent others making the same mistakes I have, I thought I'd outline the general use of the pimpl pointer, and some of it's drawbacks:
Here's an example of a first-pass class to encapsulate a user account (I'm making this up on the fly, so bear with me):
class
userAccount
{
public:
// public methods go here
private:
// private data members:
unsigned int accountId;
std::string username;
std::string realName;
};
This will work just fine, but there's a problem. If you need to change the implementation (say you want to store the user's real name in two fields instead of one), unless you're very careful you will end up changing the size and / or the declaration of the class.
Changing the size of the class is a big problem if you're trying to maintain binary compatibility. Changing the declaration of the class is a problem because (some) compilers will now recompile every file that includes your changed header file, even if the changes make no difference to the binary output.
The solution comes in the form of an opaque pointer, or "pointer to implementation" (which is where we get the charming "pimpl" name from). The idea is that the implementation details are put in a separate class that is forward declared in the header file, and fully declared in the cpp file. Your external interface now only contains a single pointer - you can change the size of your implementation class to your hearts content, and you will never change the size or declaration of your external interface. The class above refactored to use a pimpl pointer looks like this:
Header File:
// forward declare implementation class:
class
userCountImpl;
class
userAccount
{
public:
userAccount();
// public methods go here
private:
// private data members:
userAccountImpl *pimpl;
};
Source File:
class
userAccountImpl
{
public:
unsigned int accountId;
std::string username;
std::string realName;
};
userAccount::userAccount()
: pimpl(new userAccountImpl)
{
}
Now any data members can be accesed via the private implementation class. There are several things you can do to extend the example above (using a shard_ptr is a start), but I want to keep things simple for the sake of the example.
Until recently, I took this method for granted and used it as often as I could. As so often happens when I learn something new I rush to use it in every possible situation, including ones where it doesn't make sense. The pimpl idiom has a few problems associated with it, which I will outline here:
- Your object's memory footprint is now split into more than one place in memory. This may not be a huge problem for 90% of classes, but consider a small utility class that contains only standard data types:
class colour
{
public:
// public methods go here
private:
unsigned char red;
unsigned char green;
unsigned char blue;
};
In order to serialise this into a buffer (like a file), you can get away with using a memcpy or similar technique. Since your object's memory footprint is contiguos, copying the entire object into a file is simple (Yes yes, I know: there are many reasons why this isn't a good idea, but let's face it - this happens all the time). Once you start using pimpl pointers it gets a bit more difficult. Since your implementation class is private to the .cpp file, the code to do the copying needs to be in the same cpp file (otherwise it doesn't have access to the definition of the implementation class). This is relatively easy to work around, but the trouble doesn't stop there - consider what you need to do to un-serialise an object from a buffer. You can no longer be cheeky and use a reinterpret-cast like so:colour *pCol = (colour*) pBuffer;Again - I realise that this isn't the best idea in the world, but when you're programming with constraints sometimes this is the best way to do things. - The default new and delete operators are expensive. I never realized just how expensive they can be. In a recent bout of performance testing on some real-time software I saw the default new operator take 55ms to allocate a block of 4B of memory. That's way too slow for the real-time application i was working on, and may be too slow for other applications as well. What's more, the times get worse the more memory you allocate - so using the pimpl pointer may not be a good idea at all, since it adds the overhead of a new call to each constructor, and a delete to each destructor. ouch!
If you're looking for more info on the pimpl idiom, Sutter wrote a good article on the pimpl pointer, and a more recent article that talks about some of the performance issues associated with pimpl pointers. This technique is worth using - it can save many attacks of "code cheese" in the future, just be careful where you us it, or you may end up with some nasty performance issues you didn't expect!
Apathy, Apples and Understanding
Inspiration struck the other day when Jeff Atwood posted an interesting article on his blog. "Dealing With Bad Apples" talks about how single members of a programming team can be difficult, often working against the rest of the team.
Atwood quotes Robert Miesen:
I was part of a team writing an web-based job application and screeningJeff then goes on to suggest that perhaps the problem here is a "bad apple" - a team member that is doing more harm than good in a team. He's probably right, but I have a slightly different angle.
system (a job kiosk the customer called it) and my team and our
customer signed on to implementing this job kiosk using Windows,
Apache, PHP5, and the ZendFramework -- everyone except one of our team
members, who I will refer to as "Joe". Joe kept advocating the use of
JavaScript throughout the technology deliberation phase, even though
the customer made it quite clear that he expected the vast majority of
the job kiosk to be implemented using a server-side technology and all
the validation should be done using server-side technology.The fact that the customer signed off on this, however, did nothing
to deter Joe from advocating JavaScript -- abrasively. Every time our
project hit a bump in the road, Joe would go off on some tirade on how
much easier our lives would be if we were only writing this job kiosk
in JavaScript. Joe would constantly bicker about how we were all doing
this all wrong because we weren't doing it in JavaScript, not even
bother to learn the technologies we were actually using, and, whenever
fellow teammates would try and gently bring him back into the fold
(usually via email), Joe would just flame the poor guy. At the height
of Joe's pro-JavaScript bigotry, he would regularly belt off comments
like, "Well, if we had only done it in JavaScript," to such an extent
that the team would have been better off if he had just quit (or was
reassigned or fired.)
Perhaps the real problem here is poor team leadership / management? Without meeting "Joe" personally, I cannot make any accurate assessment of the situation, but it seems to me that perhaps Joe feels undervalued in his team? I say this because i recognize that behavior pattern - in myself.
In any team of programmers, each member will have different backgrounds, strengths and weaknesses. Joe obviously has experience using Javascript, and feels the need to share his expertise in that field. I'm not saying that this is a good thing, but perhaps the underlying problem is a lack of cohesion and understanding between team members?
So, further to Atwood's list of warning signs for detecting "bad apples", I have a list of actions team leaders could consider taking when dealing with a so-called "bad apple":
- Listen to them. Most geeks (I use the term with all possible affection) are reasonable people. If a team member is repeating themselves, perhaps they feel that their point was never seriously considered in the first place? I can't count the number of times I've made contributions in meetings that were ignored, only to hear (usually six weeks later) "hey, we should have done X, what a pity it's too late now...". It always seems petty to point out that I suggested X from the start. Bear with me here - I'm certainly not suggesting that I'm always right - far from it; my point is that you ignore contributions from your team members at your own risk!
Finally, I'm not suggesting that team leaders always act on suggestions from their team members, but listening is a good start. - Once you start listening to bad apples, you may find that some of your team members have strengths you didn't expect. Can you use these strengths in the future? This depends a lot on your business model and workload. From my own experience I can understand that programming code that doesn't interest you week in - week out can be incredibly draining. Perhaps bad-apples can be encouraged to pull together with the team?
- Finally - I don't know what the IT job market is like where Jeff lives, but you can't fire programmers and expect to get a replacement any time soon. Jeff writes:
You should never be afraid to remove -- or even fire -- people who do not have the best interests of the team at heart. You can develop skill, but you can't develop a positive attitude.
I say "bollocks" to that - it's incredibly expensive to fire and replace someone. Not only is there the cost of looking for, and hiring someone new, but there's the training overhead, and there's no guarantee that you can find someone with the appropriate skill set any time soon. From where I'm sitting it looks like we have to wait around 6-8 weeks between looking for, and hiring a new programmer. That's almost two months of productivity down the drain! Suggesting that you can't develop a positive attitude in your team-members is incredibly negative and close-minded. I'm certainly glad I'm not on a team with a leader like that!
That said and done, I do hope that the current skill shortage in this country develops a greater appreciation of the worker. I suspect that most companies vastly underestimate the value of their skilled (and unskilled) workers.
Next time you have a problem with someone, consider the massive cost of replacing them, and - more importantly - consider the huge amounts of good work they've done, before you concentrate on the bad.
