Now that I have finished a major component of my PodCast client, I feel as though I have reached a transition point. I have managed to create a useful (albeit small) program and I have become much more productive when I use WPF, Python and the .Net frameworks. So I thought it prudent to take a moment and reflect on some of the lessons which I have learned over the course of the last few weeks. After all, learning doesn't necessarily happen in the struggle and frustration of the moment, but in the quiet reflection which comes after.
While there were many specific things I wish I had known (for example, that the Win32 API is complicated), there were a few general items that I thought particularly helpful. As a result, this post is going to be painted in the broad swash of generalities. A few specific things I would like to touch on are: setting goals and measuring progress, following schedules while maintaining flexibility, working on a real (practical) project, trying new things out, limiting the number of dependencies, and seeking high quality examples and references.
Figure 1 - Right. User interface of the fully functional IronPython Download Manager. Major features include the ability to run downloads in the background without affecting foreground application performance and the ability to pause and resume downloads.
With all the major pieces in place, this article will focus on some of the smaller details which transform a rudimentary download manager into a functional one. The files for this article can be found here.
Everything should be made as simple as possible, but no simpler.
- Albert Einstein
I had an epiphany today. It came early this afternoon when I was sitting and trying to do something easy. Like all easy things, it turned out to be monstrously difficult. There is, of course, a back-story so let me expound.
For the past several days, I have been trying to finish up my little download manager, and I've made a lot of progress. Then I got stuck. But I was stuck for a good reason: I was trying to make my program pretty.
I thought it would be cool to display an icon in the download table after a file download finishes. I mean, just a list of files with the times the download finished was boring. Shouldn't be hard at all. I'm not writing advanced image processing software, after all. There's just two steps: you retrieve the proper file icon from the file types and then you put it in a little box. It gives the world color and excitement, it might even restore a sense of wonder. Firefox does it, Safari does it; I mean … how hard could it possibly be?
Thinking these and other naïve thoughts, I turned to the great oracle of Google and wasted a ponderous amount of time. I searched for every logical combination of keywords I could think of (and quite of few that were not so logical). I even discovered that Google ignores expletives and other creative language (who would have thought?).
Google, Yahoo Search and even Windows Live Search all failed to find anything helpful (though Windows Live doesn't ignore colorful language). Following my second failure, I pulled out all the stops. I started reading the MSDN community boards. While most of the results were about as helpful as gangrene or tetanus; I did find this. And after an additional hour of searching through some of Google's more obscure search results, I found this little gem as well (on search page 118). I don't understand either example, but that is neither here nor there.
By this point, I was locked in an obsessive need to finish what I had started. So … I created a custom class to retrieve the file icon. It is 66 lines of code long and I have little idea of what it actually does. I resorted to a tried strategy: copy and paste followed by lookup of the compiler output. About half way through, I even got the computer to stop beeping. What's even more surprising, though, is that it worked. I was able to retrieve the icon for my file type. Never mind that the output is 32 x 32 pixels, about half the size I need.
But that isn't really important. What is important is that I finished my download manager … and after struggling with the Win32 APIs, it was a spoiled moment. Now back to my epiphany. This experience made me think of Einstein. He understood an essential truth: things should be simple, elegant and clean. 66 lines of code are not simple, elegant or clean. It is an absolute shame that simple requires so much work. No wonder the world overflows with caring and compassion.
Now that the background and semi-theoretical parts about BITS, multithreading, and downloads have been dealt with; it's time to start wrapping up ends and build a useable program. In this post, I will be looking at how to connect my multithreaded BackgroundWorker Object and SharpBITS to a functioning user interface that notifies the user of the download's progress. For those wishing to follow along, the source files and assemblies for this article can be found here.
In the first three entries to this series, I have looked at the IronPython language; introduced the project which will help me learn Python and .Net frameworks; and wrote a multithreaded "Hello World" app. Seen in hindsight, these accomplishments seem small … but, for the first time in the last few months, I feel as though I have a foundation. Things which were once unfathomably difficult have started to become possible. I have even come to appreciate the structure of the MSDN documentation, which is an utterly horrifying development! Given my somewhat slow progress, I am very happy to say that this little tutorial will show how to do something useful: download files!
In this and the next article in this series, I will continue to work on my multithreaded download manager for PodCatcher (my WPF based podcast aggregator). As a way of quick review, there are several things that I would like in this download manager. First, it should allow for multiple downloads at once, with each download on a separate thread. Second, the user should be able to pause and resume downloads. The interface should be straightforward and elegant, yet provide the user with a great number of details including download progress, file name, etc. After reviewing a number of programs, I decided to use the Firefox download manager as a model for the GUI and functionality. I intend to use the Background Intelligent Transfer Service (BITS), available in Windows Vista and XP, as the download engine. This article will focus on the "guts", namely: Interfacing with BITS through an OpenSource C# Wrapper, called SharpBITS.
After a great deal of chatter, we finally arrive at the meat of this series. We can start talking about code and some specific things that I have started to pick up. For those coming late to the party though, it might be good to briefly summarize what I've already blogged about. In Part 1 of this series, I talked about my recent decision to begin learning IronPython and some benefits over other options. In Part 2, I briefly introduced the project which I will be working on. This article (as well as the next two in this series) will focus on my efforts to develop a Podcast download manager using Windows Presentation Foundation (WPF) and IronPython. For those following along, the source files for the article can be downloaded here.
All messes have to begin somewhere. It is unfortunate that they often begin as a simple and elegant idea. It's only somewhere near the middle that we recognize the simplicity and elegance of our initial thoughts for what they are: half-baked schemes which will eventually fall apart.
When I struck out to learn IronPython, I certainly never intended for that process to become a mess. But ... it did. A simple first project became unnecessarily complicated and then later necessarily complicated. That level of complexity (for argument's sake, let's call it sophistication) resulted in a first level of dependencies. Those dependencies then led to a few more and in such a fashion, the scope of my original project mushroomed. So, I have found myself learning about multithreaded applications when all I really wanted to do was write Hello World. There is a bright side here, the big complicated mess has led to something that, while sophisticated, will also became useful (eventually). Allow me to explain.
There are certain times for confessions, and now seems like such a time so … here goes: My name is Rob, and I'm an addict. I am addicted to Matlab. If I didn't have Matlab, my productivity would go to near-zero. For this reason, like any good junkie, I tolerate its expensive fees, obnoxious quirks and serious limitations. That is, until recently.
Some recent events, however, have forced me to start looking for alternatives. After casting around, speaking to friends and colleagues, I have came up with a number of alternatives. These include the "open-source Matlab", Octave; a programming language called Ruby; and a language called Python. All of these languages have the benefit of being OpenSource, enjoy the support of strong communities, and are relatively easy to learn. So after careful thought and consideration (okay … so some thought and consideration), I have made a serious decision: I am going to learn Python!