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.
Set Goals and Measure Progress
I began this series of articles with a confession, and I think it is time for me to make another. This is not the first time that I have attempted to learn Python. It is merely the most successful. Previously, I downloaded the compiler and worked my way through some of the tutorials. A few years ago, I was so enthusiastic as to buy a fifty dollar book on the subject. In fact, when I started this little odyssey, I tried to dig it out for reference and was unable to find it.
The differences between my previous attempts to master Python and this one can be wrapped up in a single word: goals. While I had an “intention” to learn Python, I didn’t really have any definitive plans to do anything with it. I would arrive at the end of the tutorial and think, “That was cool, now what?” The rather sad answer to that question , however, was “Good question.”
This time round, however, I had very specific plans. I carefully reviewed my needs and came up with a number of projects that targeted things that I would like to do, or need to do. This assessment is where my desire for a Podcast client came from and I was able to enumerate a few specific goals that could actually be completed. It is much easier to complete a goal worded as, “Finish a multithreaded download manager” than “Learn IronPython.” The first has a discrete start and end point and can be measured. The second has no such built in way to track progress. This same distinction often differentiates good science from poorly executed science. Often in the latter, there is no way to measure or track results. This leads to discouragement and abandonment.
While setting goals and tracking progress may seem superfluous in a personal activity, I actually found them indispensable to “getting things done.” While I largely avoided a full “timetable,” I did have a goal to complete one blog post of new material every few days. This required that I spend the requisite time thinking about the next steps in my application, researching the various techniques necessary to write the code, and then spending the time to create a working implementation. Without my goals, it is possible I would not have had the personal discipline to invest the time required to make this experiment successful.
Follow Schedules While Maintaining Flexibility
While goals provided the focus of “what” to work on, it was also important that I find time to do that work. Like most people, I hopelessly commit and over-schedule myself; often to the detriment of my own projects and of those close to me. Yet, I found that learning how to work in Python was a sufficiently large undertaking that it required regular time and attention. I therefore set aside an hour or so each day for working with my given project. During this time, I would try and read different references, study ways to potentially implement an idea, or try things out with the command line interpreter. Of course, I also spent time actually writing code.
By sticking to a fairly rigid schedule, I found something else interesting; I needed to be flexible. It is very easy to underestimate the amount of time that a given task is going to require or how complicated a given task will be. In such cases, it is important to be flexible. A number of times, I was forced to re-evaluate both my goals and schedule. While this often meant spending more time than I had planned, it also meant lowering my expectations.
Work on Something Real
Spending more time than planned on a project designed for “instruction” nearly always feels like a waste. While an undergraduate student at the University of Utah, I took an introductory computer science course which focused on Java. It was an awful experience. I spent thirty hours a week doing homework and completing assignments which had little (if any) practical value. While I learned much about the Java language and frameworks, I didn’t learn much that was useful. To this day, I actively avoid doing anything in Java even though I can muddle my way through most C++ code (which is thought in some quarters to be a more difficult language).
When learning IronPython, I was hoping to avoid a similar experience. Thus … my carefully chosen projects. I have often found it easier to be excited about a given piece of software if I will be using that software myself. Far too many times I have heard about a great piece of software, only to discover that it was completely unusable. Until quite recently, a fantastic example is Seg3D, a program put out by the University of Utah Scientific Computing Institute (SCI).
In its earlier builds, Seg3D represented a application looking for a need rather than the other way round. While it did many fantastic things, it would only do so on a very finite number of test data and with a great degree of prodding from someone who had spent hours trying to get it to behave. While this has since been (somewhat) straightened out, it was only after the developers began using their own software. The developer as user paradigm is a good one as it encourages the developers to think about better ways to accomplish a given task. Amongst my serious developer friends, Visual Studio is considered to be the best general IDE in existence (rivaled, perhaps, by Eclipse). I would argue this is because its developers are also its primary users.
Working on a real piece of software that can be used (by both myself and others) gives a degree of energy and focus when confronting challenges and difficulties. Rather than a canned exercise with a specific solution, the struggles and difficulties are also real, though they may also seem larger. Even so, having a “real” project helped me to persevere and complete my work in the absence of other incentives.
Try Things Out
Unlike compiled languages, Python and other scripting languages ship with an interactive interpreter that begs to be used. When trying out the various .Net classes, I tried to apply a piece advice found in IronPython in Action.
For those new to dynamic languages, the interactive interpreter will … be a pleasant surprise. Far from being a toy, the interactive interpreter is a fantastic tool for experimenting with classes and objects at the console. You can instantiate and explore … classes live, using introspection and the built-in ‘dir’ and ‘help’ commands to see what methods and attributes are available to you. As well as experimenting with objects, you can also try out language features to see how they work … (IronPython in Action, Chapter 1).
I found the interpreter to be a fundamental part of my experimentation. As you can see from the screen shot at left, the interpreter became one of my most used programs. it even passed Microsoft Word, which is the first program I open after turning on my computer.
I often found myself transcribing interpreter commands into my code, once I had figured out how to accomplish a particularly difficult set of manipulations. In many ways, the interpreter became my de-facto composition board and I was able to avoid the write-compile-run loop equivalent which often sucks up my time when working in other languages.
Limit the Number of Dependencies
I have found that learning to program can sometimes be similar to another computer based experience. Namely, my first growing pains with Linux. I began experimenting with Linux in 2002,using the SuSE distribution. Though the initial install went beautifully, there were a number of programs I wanted to try which were not included on the installation CD. The SuSE RPM framework was still young and I hadn’t discovered the beauty which is apt-get. I therefore set about installing my software in the most difficult manner imaginable. I downloaded individual packages and attempted to install them with the package manager. This was my first real experience with packages and dependencies. I quickly discovered the state of existence referred to in the early days of Windows as “DLL Hell.”
In one unpleasant example, while trying to install a statistical package, I spent the better part of two days downloading different packages and trying to manually resolve the dependencies. This was when I first learned of something called “nested dependencies.” Or, dependencies of dependencies. At the end of the two days, I still didn’t have a functioning program, despite hours spent searching for and downloading packages. This experience drove me back to Windows ranting and raving about Linux and OpenSource in general. I was lucky to have friends and others who encouraged me to be patient and allow for the software to develop and come into its own. I am glad I did, I am now a very happy user of Ubuntu.
It is unfortunate (but still true), that learning to program can lead a very similar experience. Programming is a very sequential subject. To be able to function, it is necessary to know a lot of things. Even more disconcerting, before it is possible to understand a given piece of code, it is often necessary to understand one (or more) other ideas. This easily leads to dependencies and dependencies of dependencies. When trying to work with WPF, for example, I found that I needed to know about XAML and databinding. This involved a rather lengthy side trip before I was able to return to working with the much more elegant Python.
So, in the interest in progress, I often found myself needing to simplify. Put another way, I needed to ditch as many dependencies. I was more productive (and more satisfied) when I was working with one or two ideas rather than five or six. So, by keeping the number of technologies to a relative minimum, I was able to actually make something work, rather than uselessly waste my time.
Find High Quality Reference and Documentation
As described above, trying to learn anything as complex as Python requires good reference and documentation. While IronPython in Action proved itself invaluable, I found myself rapidly migrating away from it. After reading the first several chapters that outline Python and the .Net framework and the chapters on Windows Forms and WPF, I set it aside for other references. These included blog posts, the IronPython Cookbook, the MSDN .Net documentation, and CodeProject (not to mention Google, which is after all, a programmer’s best friend).
What I discovered, however, is that each one of these resources was of varying quality. While the IronPython Cookbook was an excellent source of IronPython recipes, much of the information on MSDN and CodeProject was either out of date or incomplete. Faced with a quandary, I began to note the names of authors and locations of material which I found helpful. I then included these names in my Google searches when looking for additional information. Using this strategy, I was able to find posts which often quoted or built upon the work of the original author. I was also often able to find additional posts by the same author. This led to uncovering examples written in C# or Visual Basic that could be translated into IronPython. Doing so taught me a great deal about how the structure of .Net programming should look and proved to be very valuable. It also taught me that I sometimes needed to widen my search.
When trying to find a good way of using a ProgressDialog, I located a C# example that used a BackgroundWorker thread. Using the ideas (and much of the code structure) in this example helped me create the ProgressDialog class in the download manager. I found the code example by a Google search that included the author’s name from a previous article.
The astute reader will note that many of these generalities do not necessarily have much to do with programming, which is true. However, I found that I was most productive and content when I attempted to follow these general guidelines. I also discovered a more important side effect: after more than a month of playing with Python, I have to admit that I am hooked. While I am still certainly very green, I feel as though I have learned a great deal. It is a fantastic language and offers more flexibility and power than Matlab. In some ways, it is Matlab “all grown up.” So, I was successful in at least one of my initial goals; I avoided a fiasco similar to my Java experience.
On a more practical note, while I will remain a student of Python for quite some time, my writing about it needs to become somewhat more … irregular and topical. I hereby retire my label of “Learning IronPython” for a simpler one: “IronPython.” While there will surely be other posts (I already have a post on data-binding half written and ideas for six or seven others), they will likely reflect the gems and nuggets I unearth as I further my adventurous exploits rather than a careful and complete documentation of my travels.