I’ve been working on a music player for Linux. What I really wanted was foobar2000 for Linux but nothing on Linux is quite like it. There are lot of iTunes clones (Amarok, Banshee, Songbird, Rhythmbox, etc) but they are all too complicated or make copies of your music or show you lyrics and Wikipedia articles and include a web browser. I just want a simple music player. I can list the features I want one hand (I’ve only implemented the struck through items so far):
Simple interface (Most are not simple but can be configured to be simple)
Last.fm support (They all do this)
Date added and a full file path column (You would be surprised at just how many music players do not have these columns but they are so useful for sorting by)
- Moving files to the trash folder (Most can do this)
- Easy tag editing for multiple files at once (Most are ok at this)
- Move files to a particular folder and remember the last 5 folders (Useful for remembering which songs I like by putting them in a “Collection” folder. I haven’t seen any other players do this)
This is a very early version, I’ve only implemented 3 out of 6 of the proposed features. By the time I release a 1.0 version I hope to have all of these features implemented.
Tips to help you find bugs.
Turn the warning level up and turn on warnings as errors
I know, it can be a pain, but it works. It helps you produce more rhobust, forward compatible, portable code that is syntactically correct on more compilers.
Use assert …
Assert will help you find errors before you even knew there was a problem. It is 100x better if your application tells you exactly where problems are and breaks into the debugger than for your application to crash for the customer. It goes hand in hand with compile time type safety, compiler warnings and static_assert.
… and use if () return
Think of assert as flagging the problem for you to fix and if () return as guarding the application from crashing for the customer.
Print to your errors/trace file
It can be easier to read what the application did rather than stepping through it, in some cases it is not possible to step through the code at all; full screen games, embedded devices and drivers for example. Print out variables, function entrance/exit and “I am here” lines.
Comment out or remove as much code as possible. Slowly remove lines until you find the offending line. Try different ways of doing the same thing. Read your errors/trace file. If I had a dollar for every time a coworker tells me there is a bug in the library/standard library/compiler/Operating System and it is actually an error in their code and they have ignored a printed error, I would buy a Ferrari, and then I would buy them a pair of spectacles and I would say, “Use these to read these”, and point at the error message.
Write data to files and validate your files
For example XML, HTML, JSON, RSS, KML, PNG, WAV and MP3, can all be written to files and run through third party validation software. You can even setup a unit test to write these to a file and run the validator for you.
Use your debugger
Put break points on suspect lines, step through functions, find out the value of variables, look at what each thread is doing, look at the call stack.
Read the documentation for the library you are using
You may be using a library incorrectly, it may have conditions or prerequisites you didn’t know about. If it is too complex wrap it into something easier to digest. If its usage is error prone wrap it into something simpler and type safe, that only uses what you need. An optimising compiler will factor out your wrapper and it will have no run time impact.
It is there for a reason. Millions of developers have used it for almost two decades, hundreds of thousands of eyes have pored over the source code to it. Chances are that it is more capable, less bug ridden and more portable than your hodge podge collection of classes. A large percentage of bugs I have seen are in classes that could be replaced by the STL. Plus developers will “just know” what your code does because they already have experience with STL. Just use it.
sprintf(szText, "User: %s, ID: %d, Password: %s", szUser, int(userid++), szPassword);
Don’t increment and use a variable on the same line. We know, you’re very tricky, you saved a line. You also made sure that beginners to C++ don’t know what the result will be. Keep it simple stupid. Create the simplest most readable code possible, it makes skimming over code and debugging code much easier. Fixed length arrays are very prone to buffer overruns, in this example szPassword is probably only 8 characters long after calling GenerateRandomPassword, but szUser could be any length and could definitely overrun 255 characters. The best way to mitigate this problem is to use a real string class such as std::string. We can also avoid using sprintf by using a type safe string writing class, std::ostringstream. Code using std::ostringstream is also slightly more human readable.
const std::string sPassword = GenerateRandomPassword(8);
oText<<"User: "<<sUser<<", ID: "<<userid<<", Password: "<<sPassword;
std::string sText = oText.str();
There, type safe, buffer overflow safe, future proof and slightly more readable, what’s not to like?