Tips for Learning a New Programming Language

The folks at InformIT.com recently asked me, along with several
other Pearson authors, to answer the question What’s the best way for
a programmer to learn a new language?
We did not coordinate our
answers, but while reading through the other responses I noticed a few
themes.

Go deep. You can’t just read a little or toy around with a language
to really learn it.

Be real. Pick a project for which the language is suited and try
to build it.

Iterate. Don’t stop with the first solution that works. Work to
understand whether it is the best solution.

Read all 19 responses at InfomIT.com for more detailed tips.

you gotta love backwards compatibility

A friend of mine recently found an old floppy disk created under OS 8
or 9 in the early 1990’s. There was a letter on the disk that she wanted
copied off, but she doesn’t have a Mac any more.

No problem, I figured. I did a little research and found hfsutils,
and thought all I would need to do is stick the disk in my Linux box and
grab the files. No such luck, since I don’t have a floppy drive in any
of my systems
.

After a little more thought, I remembered the old rawwrite.exe
utility for creating bootable floppies under DOS. Sure enough, there’s a
rawread.exe and I was able to make an image of the floppy disk on a
Windows box.

Although the next step was going to be to copy that image file to a
Linux system to try to mount it, I decided to try to open it on my Mac
(running Leopard) first, just for grins. I renamed the file to end .img,
and it mounted right up. All of her files were there and Finder even
acknowledged the layout of the icons in the folders.

Of course, the files themselves were created with some version of
WordPerfect that no longer exists, so our data recovery efforts only
went so far as to get the text of the letter without its formatting. I’m
still impressed that a modern Mac that doesn’t even have a floppy drive
could open the old disk image to begin with.

Switching development contexts with virtualenvwrapper

Optimizing repetitive operations is one of my obsessions. I can’t
stand following long sequences of steps to make the computer do what I
want. The whole point of computers is to have them do more work for
us, right?

As a developer with several ongoing projects, I frequently find myself
switching contexts as one project becomes blocked (read: I lose
interest) and I want to move on another. Typically that means unloading
a bunch of files from my editor and loading others. Some IDEs, and even
editors such as TextMate, use a “project” file to manage the files that
belong to a project. Some go so far as to use the project file as a hint
for how to build the library or application.

Using a project file typically involves pre-defining the members of a
project, and then managing the project file as another artifact of the
project itself. To switch contexts, you simply close one project file
and all of its related code files, then open another. A good editor will
even remember which files were open when the project was last in use,
and restore your workspace to the same state. A great editor will let
you automate the steps needed to switch contexts by loading different
project files.

emacs desktop-mode

I’ve been an emacs user for something like 10 years now. I use vi
frequently, and TextMate regularly as well, but most of the time I live
in emacs for text editing and development tasks. The implementation of
project files I use with emacs is desktop-mode. I like desktop-mode
because instead of forcing me to pre-declare all of the files in my
project, it assumes that all open buffers should be remembered. There
are alternatives (there are always alternatives in emacs, right?).

Setup of desktop-mode is straightforward:

  1. Run customize-group on the “desktop” group.
  2. Turn desktop-save-mode on to enable the minor mode.

3. Optionally change the base name for desktop files in
desktop-base-file-name. I like using “emacs.desktop” so the file is
not hidden and I know exactly what it contains.

4. Set a default search path for the desktop file in desktop-path.
I set my path to include ~/emacs, but this is only the default. We
will be saving a separate desktop in each virtualenv.

5. Set desktop-save to “Always save”. There are other values that
work, but some require interaction with the editor during the context
move to confirm file saves, and I want to avoid that.

There are a few other options that may be useful to tweak, depending
on the other features of emacs you use. For example, I set
desktop-clear-preserve-buffers so clearing the desktop does not delete
the *Messages*, *Org Agenda*, or *scratch* buffers since
those are related to emacs operation and not limited to any one project.

virtualenvwrapper hooks

The next step is to set up the tool chain so emacs loads a new desktop
when you change virtualenvs from the command line.

In addition to making it simpler to manage multiple virtual
environments, virtualenvwrapper adds several hook points to
trigger changes outside of the virtual environment when various events
occur. For example, each time you run workon to change environments,
the predeactivate and postactivate hooks are run. The most
interesting of these for our purposes is the postactivate hook,
called right after the new environment is activated.

I usually add a cd command to the environment-specific postactivate
script (in $VIRTUAL_ENV/bin/postactivate) to move my shell session
to the working directory for that project and change the $PATH,
making it easier to run the tests for my project from the shell. For
example:

pymotw_root=/Users/dhellmann/Documents/PyMOTW
cd $pymotw_root/src
PATH=$pymotw_root/src/bin:$VIRTUAL_ENV/gettext/bin:$PATH

Changing Desktops

In addition to the virtualenv-specific hook, there is also a global
postactivate script, and that’s the one I use to switch contexts in
emacs. Edit $WORKON_HOME/postactivate to add these lines:

# Change emacs' desktop directory
emacsclient -e "(desktop-change-dir "$VIRTUAL_ENV")" >/dev/null

The function desktop-change-dir tells emacs where to save the
desktop session file. By changing the directory each time we change
environments, we can have a separate desktop file in each environment.
Changing the directory automatically saves the old desktop first, of
course, so the old project status is preserved until you come back to
it.

Now that the hook is configured, the next step is to initialize the
desktop for your projects. For each project, run workon to activate
it, then open several files from that project. As you workon the
next project, the session will be saved in
$VIRTUAL_ENV/emacs.desktop (assuming you set your
desktop-base-file-name to emacs.desktop). Once you have initialized a
few virtualenvs, switch back to the first. Emacs should load the desktop
file for that environment and restore the buffers you were editing.

Other Editors

The example above works for emacs, but other editors may need to use
the predeactivate hook to save a project file before loading the new
one from postactivate. There are global and local versions of both
hooks; refer to the virtualenvwrapper documentation for more details.

Shell history, jigs, & subversion

Everyone else is showing theirs, so here’s mine:

$ history|awk '{a[$2]++} END{for(i in a){printf 5dt%sna[i],i}}'|sort -rn|head
  162   svn
   99   ls
   80   rtop
   69   sudo
   63   cd
   55   dotest
   51   workon
   23   make
   21   close_branch
   21   cl2svn

Software Jigs:

Does it say anything in particular about me that half of those
commands are aliases or scripts I or my co-workers have created to wrap
up other tools?

rtop – is a bash alias to change directory to the top of sandbox. I
have an environment variable pointing there, too, but I guess I don’t
like typing $.

dotest – is an alias to run tests with our tracing module turned on,
preserving the output in the same log file each time. We have a very
verbose trace module that prints function inputs and outputs as our
program executes. It is superior to logging for low-level debugging, but
entirely unsuitable for production use (it’s easy to turn on and off).

workon – is a shell function that swaps out different sandboxes so
I can work on multiple branches on the same system. Our test framework
requires an installed version of the whole system, unfortunately, and
I don’t like to mix patches from multiple branches by copying files
into the install tree. Running workon rearranges symlinks so I can
replace the install tree with the build tree from my sandbox of
choice. Shell functions are an under-appreciated implementation
technique for something that has to operate on the current environment
(workon changes directory to the new sandbox) but is more
complicated than what would fit in an alias.

close_branch – is a bash script that takes a short branch name and
deletes the branch and any “rebase” branches based on it using the long
URL. We have a whole set of little scripts like this that we’ve written
in house.

cl2svn – finds changes in ChangeLog files in my svn sandbox,
extracts the new messages, and produces a single (sorted) output list
formatted nicely to show up in trac. We use ChangeLog files and trac
commit messages as part of the documentation for our code review
process, so having everything formatted nicely is important. I used to
do this by hand, but after one particularly large changeset I came up
with this Python app to do the work for me.

Wrapping Subversion:

I mentioned close_branch as a subversion wrapper. There’s a
make_branch script, too, to save from making typos in long URLs.

Another shell function, mksbox, finds a free sandbox in my pool and
switches it to use a particular branch. Our build tree is pretty large,
so it is way more efficient to just keep a bunch of sandboxes around and
switch them to point to different branches with svn switch instead of
checking out a full copy every time.

My favorite, though, is merge_branch, which figures out the start
point of an svn branch and merges all of the changes from that branch
into the current sandbox. I’m a little surprised that make_branch and
merge_branch didn’t show up higher in the list, but they’re in the top
20.

We wrote these wrapper scripts a couple of years ago, when we switched
from CVS to svn. We had similar tools for CVS, but branching worked
differently and we didn’t use branches as often then. Now every ticket
gets its own branch, so managing branches is a daily operation. A
typical development cycle for me looks something like this:

$ make_branch 6583 # that's a trac ticket number
$ mksbox 6583 # automatically does a workon for that sandbox
$ dcctl restart # restart our daemon services to pick up the sandbox change
# add feature or remove bug
# update ChangeLog files
$ cl2svn | tee changes.txt
$ svn commit -F changes.txt
# request code review for changeset
$ prepare4commit.sh # switch current sandbox to trunk & merge in the branch
$ docommit # commit, using the first line of changes.txt for log message
$ close_branch 6583 # clean up after myself

When we switched off of CVS, we had some particular needs that weren’t
met by svn directly (especially the way we do code reviews). There are a
whole host of tools for wrapping svn out there now. sv-subversion
looks interesting, but I haven’t tried it. If our code didn’t make
assumptions about the install path, we could probably just use
DivmodCombinator, which looks like it has a lot of the features
we’ve rolled ourselves, but the inertia for changing now is pretty high,
and the benefits aren’t great enough.

Unexpectedly broken, and fixed: svnbackup

Yesterday Pierre Lemay sent me one of the clearest bug reports I’ve
seen in quite a while, and a patch to fix the problem. He was having
trouble with svnbackup duplicating changesets in the dump files. It
turns out every changeset that appeared on a “boundary” (at the end of
one dump file and the beginning of the next) was included in both dumps.
Oops.

When I tested the script, I was able to recover the repository without
any trouble. I didn’t check 2 cases that Pierre encountered. First,
the changeset revision numbers did not stay consistent. When the
changeset was duplicated, that threw off all of the subsequent
changeset ids by 1. For each duplicate. That in itself is only
annoying. The more troubling problem is when a duplicate changeset
includes a delete operation. The second delete would fail while
restoring, which prevented Pierre from importing the rest of the
backup.

In his email describing all of that, he gave me great details about
how he had tested, the specific scenario that caused the problem, and
then provided the fix!

So, if you are using version 1.0, go on over and download version
1.1 with Pierre’s fixes.

PyMOTW: ConfigParser

The ConfigParser module is very useful for creating user-editable
configuration files for your applications. The configuration files are
broken up into sections, and each section can contain name-value pairs
for configuration data. Value interpolation using Python formatting
strings is also supported, to build values which depend on one another
(this is especially handy for paths or URLs).

Read more at pymotw.com: ConfigParser

Things to Do

In no particular order:

  1. Cull my Google Reader subscriptions. 364 is too many.
  2. Finish reading Dreaming in Code.
  3. Add tagging support to codehosting.
  4. Verify all of the domains under my control with Google Web Master
    tools.
  5. Create a Trac plugin for code reviews based on the process we use
    at work.
  6. Change the monitor feeds on CastSampler.com so they do not include
    items without enclosures.
  7. Enhance BlogBackup to save enclosures and images linked from blog
    posts.
  8. Write a tool to convert an m3u file to an RSS/Atom feed for
    Patrick so he will set up a podcast of his demo recordings.
  9. Improve AppleScript support in Adium.
  10. Add support to Adium for notifications when a screen name appears in
    a chat message.

Coder’s Block

Logan Koester posted some tips for overcoming Coder’s Block.

I get blocked, once in a while, too. In those situations, it almost
always comes with the feeling that the problem I am trying to solve is
too big. That, in turn, usually stems from not having thought about the
problem enough, rather than the other way around.

The development staff at my company is pretty small, so we are all
involved in each new feature from “front to back”, as it were. I like to
start by thinking about the user interaction aspect of the problem. It
doesn’t make sense to start with the back-end design until you know what
the front-end is supposed to do, right? So I think about what operations
the user needs to perform, then what inputs are needed to handle them.
From there I can work out how many of those inputs should be stored for
re-use.

I like to draw diagrams, since I find they are easier to re-assimilate
when I come back to a problem after some time. So I may sketch out a few
UI screens, or draw a few boxes and arrows to understand the
relationships between objects (I use a sort of pidgin UML for that). I
also make lists of attributes I might need for classes, since those map
to the database schema.

There are plenty of good tools for making such sketches on the
computer, but I guess I’m Old School. I find that sitting down with a
pen and paper, away from the computer, helps clarify my thoughts. Since
I don’t have my text editor, the temptation to write code is reduced and
I can concentrate on the big picture. And once I have the big picture
worked out, the way forward is usually clear.