The way i work now is that i have a bunch of terminal tabs open. Each tab has a shell which pretty much just sits in a single directory. If i need to switch to a different directory, i switch tabs. A nice effect of this is that each tab builds up a recent shell history specific to the directory it sits in; the shell in the source directory has a history full of build commands, the shell in the installation directory has a history full of start and stop commands, and so on.
This works because i generally use a fairly small (<10) set of different directories, and i don't move between directories much as part of a single task. Partly, this is because i use qualified paths rather than cd'ing around everywhere. I am happy writing (mostly, tab-completing):
vi lib/awesomeapp/dns/client.rb
Whereas a colleague of mine would always do: cd lib
cd awesomeapp
cd dns
vi client.rb
He might get a lot of mileage out of pushd/popd. But for me, it just optimises something i don't spend a lot of time doing.