April 2006 Archives

Here Be Monsters

April 29, 2006 8:39 PM

Apple had the "Switch" campaign. Maybe you remember -- some famous, not so famous, and soon-to-be-famous[1] people talking about how their Macs are so much better than their PCs.

And a Mac is much better than your PC[2]. Yes, this sounds like religious fanboy zealotry -- and to be fair, it is -- but that doesn't mean I'm necessarily wrong. At home, I use Windows approximately never[3], and I've relegated Linux solely to my servers. Macs "just work" so often, and so well, that I'd rather just use my computer than spend all my time maintaining it.

There are already scores of religious fanboy zealots who are going to tell you - in great detail - how great the Mac is, and why you should switch. I'm not going to. I'll let them convince you. But beware. Just because the Mac is an excellent computer, that doesn't mean it's panacea. Here are some things you're going to want to pay attention to as you switch:

  • Get a new keyboard. Somehow, the Apple USB keyboard gets worse with each new revision. It's mushy, click-negative, the key travel feels really short and they break easily[4]. I particularly like the old IBM keyboards which "make it sound like the world's ending" when you type in your passphrase. Unicomp owns the IBM/Lexmark keyboard patents now, and recently delivered a Mac-friendly USB model of their 104 key stiff buckling-spring keyboard.

    Caveats: you lose the keys that control volume, brightness, and eject, so you'll want to add them to the menu bar. You'll also want to go into the Keyboard Preferences and swap Option and Command because the default keymapping for non-Apple keyboards is backward.

  • Get an old mouse.
    Two years ago, that annoying one button mouse would have been at the top of my "replace this immediately" list. One button!? That's two less than there should be! It might have been cute in System 7, where you only needed one button but it's impossible in OS X.

    The mighty mouse is better -- in fact, I like the scroll "ball" a lot - it's a great feature. But the one-piece top makes it hard to get a positive click ("was that the left or right button, dammit!?") and if you're trying to go cord-free, their wireless mouse is still just one button. One day Apple will realize that most computer users have more than one usable digit on their dominant hand, and finally make a mouse that is both usable and meets their exacting aesthetic criteria for releasing a pointing rodent. Until then, just keep your existing mouse.

  • Ditch Safari. Quickly.
    All the Mac users are going to tell you how great Safari is. What they actually mean is "it's really great compared to Internet Explorer." What they neglect to mention is that next to Firefox, it's sort of a pile of poo. On paper, it looks great - it's got all the modernities like tabs, RSS, popup blocking. And I could forgive the schizoid Apple UI. But I can't forgive The Beachball. When you've got a lot of pages open, it drags. Even on a dual G5 with 4GB of RAM. Open up a bunch of pages. Open another -- while that page is loading, raise a different Safari window. Beachball. Open a few links off a page in new tabs, then try to raise one of those tabs. Beachball. The whole app is blocking for seconds at a time. And God help you if you try to go to a poorly designed page. The dreaded foodtv.com's Flash search box kills Safari for a full minute, even with nothing else going on.

    The best thing going for Safari is its ability to download Camino which is Mozilla's rendering engine wrapped up in a more Mac-like UI, and the add-on CamiTools, which lets you tweak Camino quite a bit.

  • Ditch iChat, too.
    If you ever use any sort of Instant Messaging, iChat will seem great. Rather, if you use AIM, iChat will seem great. Eventually, you'll want to talk over some other protocol, and you'll start looking for the multiprotocol plugins. Don't bother, by this point you've already outgrown it. Just download Adium instead. It's a free, multi-protocol instant messaging client built on GAIM.

  • And Apple Mail?
    You're on your own with this one. Apple Mail in 10.4 works pretty well, but still has some big annoyances. (You will submit to the Global Inbox. You will restructure your IMAP folders to suit its needs. You will wait for its pokey IMAP implementation.) But it integrates well with the other Apple apps (notably Address Book.) I used to hate it, and used Thunderbird instead. Lately it's been growing on me. You'll have to make up your own mind.

  • Don't expect to be able to compile anything yourself.
    So you like that pretty little shell, huh? This really is one of the big advantages to OS X - it's BSD under the hood. You're going to love that, right up until the time you want to run some little utility that was disappointingly not included with the OS X core. (Which is most.) At that point you're going to try to compile it yourself. I pity the fool.

    Despite the fact that you're back in 1990 with regard to tracking down and building dependencies yourself, and managing conflicting system libraries, you're going to be lucky if the software compiles out of the box. For example, I was trying to build an app that included a file called String.h. It also did #include <string> to include the system string library. It took about an hour for my sluggish brain to realize that HFS+ is case insensitive, and those would be the same file.

    Fortunately, there are several package management tools for OS X, meaning someone's taken care of making sure that libfreetype (and its dependencies) build cleanly and easily. Unfortunately, there are several package management tools... that is, the effort is split and lots of work is duplicated. There's DarwinPorts, which is based on FreeBSD's port system, Fink, which is based on Debian's apt system, and Portage, which is based on Gentoo's package management of the same name. I've tried them all, and I believe DarwinPorts sucks the least[5]. But then, that's not saying much.

  • Install Xcode and X11.
    If you're a developer or coming from a Unix background, you'll need them or want them eventually. Downloading Xcode takes hours, and Apple doesn't distribute X11 on anything but your install CD[6]. Just install them when you get your machine, otherwise you'll be cursing up a storm when you actually need them.

  • Your computer has amnesia.
    It will forget its name. Rather, it will trust some random DHCP server to set its hostname for it. So, next time you're in a coffee shop, suddenly your computer went from whatever cute name you have for it[7] to shop-dhcp-4224 and that's no good. Edit /etc/hostconfig and add the line:

    HOSTNAME=yourcutehostname.domain.com

    After that, it will ignore that DHCP server that thinks it knows better.

  • If you're a graphic designer, wait.
    Don't make the switch (at least to an Intel Mac) if you rely heavily on Adobe Creative Suite. Yes, they work in Rosetta, and yes, those Core Duos are fast. But CS2 runs slow as hell on an Intel Mac thanks to Adobe's stubborn insistence that they don't need to pay attention to Apple's roadmap.

    It still runs great on a G4 desktop, but do you really want to invest in a technology that's about to be replaced by the Bigger Better Deal?

  • Get a wireless card
    If you get a PowerBook or a MacBook Pro, your wireless signal is going to suck. The antenna is housed in Aluminum. You might as well build a faraday cage around your laptop for all the signal you're going to get. That's not to say that it won't work -- it will. Just not well. I carry around a 802.11 PC Card in my bag and use OrangeWare's Wireless Drivers for Mac to get some extra signal in a pinch, like when I'm in an airport, a hotel room, or the room across the hall from my access point at home.

Of course, there are going to be some things that are going to piss you off that you have no control over:

  • Apple's schizoid UI Is it a normal window? Is it polished metal? Who knows! Some programs in iLife (but not iWork) use the polished metal theme, some use the normal Mac theme. There's no distinction as to which one is used, and third-party developers are free to use either (or worse, both.) Personally, I'm not a big fan of the polished metal theme, but either way: Apple should pick a theme and run with it. To my knowledge, there's no simple way to get around this one.

  • You will not play games.
    At least not any fancy games written in the last few years, like Quake I or Wolfenstein 3D. There might be a Minesweeper somewhere. No, seriously, it's not that bad, the studios do eventually release a Mac version of their games. And it sometimes works, mostly. I got into SimCity 4 for a little while (when it was released for OS X -- long after the Windows users were already tired of it) and it had big problems with my PowerBook's graphics card. Tearing everywhere. They released a patch which improved the situation, but didn't fix it entirely. Meh. I guess that's why I've got a Super Nintendo.

  • The other Mac users.
    You'll have to adjust to the idea that you're joining a userbase of raving zealots[8], who believe that Steve Jobs is the Second Coming. It will annoy the hell out of you at first, and you'll say things like "yeah, but I'm not like the other Mac users." I used to say those things. Eventually, you'll become an Apple apologist, too.

Hopefully you're not scared away by now. Sure, it's got its issues, but what OS doesn't? I could write a book about the annoyances of using Windows XP[9] or Linux on a desktop. But with a few little tweaks, my Macs just work.

  1. Yes, that's an Ellen Feiss reference. Beep beep beep.
  2. I'm talking about for your home, not for work. But don't get too sure -- the religious fanboy zealots are coming for your office computer next.
  3. The computer in my bedroom doubles as a TV. If Apple puts a tuner in a Mac Mini and makes Front Row talk to it, I'm ditching that PC too.
  4. The last keyboard Apple shipped me worked for two days before the USB stopped working.
  5. This coming from a guy who is still in love with Debian's apt system. I really wanted to like fink, but it's immature and incomplete. You'll really be happier with DarwinPorts, especially if you're going to develop software that links against these libraries. It's not at all painful to develop a build script that uses DarwinPorts to build redistributable packages. But that's another article.
  6. I did see an unofficial download page for X11.app, but I tend not to trust third parties unless I knew the MD5 signature of the original. And then we're back to needing the install CD again...
  7. I suggest comic characters. In fact, I'm writing this on tankgirl right now, and saving it to thetick. Spoon!
  8. Unless you're switching from Linux, in which case you're already used to it.
  9. I was going to suggest that Windows might be better now than when I used it day-to-day, but then I remembered that it's still the same version![10] Hah! In the time Windows XP has been out, OS X has gone from 10.0 to 10.5.
  10. I know, some day Vista will ship, and it'll finally start to look like OS 10.2. Some day...

I've been playing with Ruby on Rails for a few days now, slowly grokking Ruby's unique syntax, sparsely documented stdlib[1] and lack of semicolons. The first stumbling block, albeit simple, was Rails' seemingly simple error_messages_for.

In a view, <%= error_messages_for 'MODEL' %> will show you any errors from MODEL's validate method. It's straightforward enough... unless you're trying to validate against a second model as well, from a validate_associated. Then MODEL's only error message is "othermodel is invalid". Not terribly helpful. You could draw a second box explaning why, but that's only slightly more enlightening (if at all.)

It would be ideal if we could just put all the error messages in a single error block. So what we need to do is get rid of the "othermodel is invalid" error, and add the other model's errors. For example:

errors = ActiveRecord::Errors.new(nil) @model.errors.each { |key, message| errors.add(key, message) unless key == "othermodel" } @othermodel.errors.each { |key, message| errors.add(key, message) } @model.errors.clear errors.each { |key, message| @model.errors.add(key, message) }

Sort of a hack, I'll admit. But hey, it works, and we can do this at any point after valid?[2] has been called on your models. (valid? actually populates @model.errors.)

Here's a detailed example -- let's say you have two objects, a Transaction and an Account, and you want a view that simply asks for an amount for a transaction and an account number, and you want to show the user if they enter an invalid amount or an invalid account number. Your models and views are going to look something like this:

views/transaction/create.rhtml:

<%= error_messages_for 'transaction' %>
<%= start_form_tag :action => 'create' %>
<label for="transaction_amount">Amount:</label> <%= text_field :transaction, :amount %>
<label for="account_number">Account:</label> <%= text_field :account, :number %>
<%= end_form_tag %>

models/transaction.rb:

class Transaction < ActiveRecord::Base
  belongs_to :account
  validates_presence_of :amount, :message =< "is a required field"
  validates_associated :account
end

models/account.rb:

class Account < ActiveRecord::Base
  has_many :transactions
  validates_presence_of :number
end

controllers/transaction_controller.rb:

class TransactionsController < ApplicationController
  def create
    if request.post?
      @account = Account.find(:first, :conditions => [ "number = ?", @params[:account][:number]])
      @transaction = Transaction.new()
      @transaction.account = @account
      @transaction.amount = @params[:transaction][:amount]
      if @transaction.save
        redirect_to :action => 'show', :id => @transaction
      else
        # here's where we get the good errors
        errors = ActiveRecord::Errors.new(nil)
        @transaction.errors.each { |k,m| errors.add(k,m) unless k == "account" }
        @account.errors.each { |k,m| errors.add(k,m) }
        @transaction.errors.clear
        errors.each { |k,m| @transaction.errors.add(k, m) }
      end
    end
  end
end

Now, if you were to leave both fields blank, you'd get an error message like:

  • Amount is a required field
  • Number can't be blank

Which is the error message that one would expect out of this view.[3]

  1. Really, the stdlib documentation is almost nonexistant! Digest? OpenSSL? Hah! Your best bet is to look at code samples and guess!
  2. valid? is called by save, for the record
  3. Far superior to the default:
    • Amount is a required field
    • Account is invalid

Boot Camp

April 19, 2006 1:37 PM

Boot Camp Since Teamprise is a front-end to Microsoft software, and it's cross-platform, it stands to reason that I'd need a Windows box to poke around with from time to time. And since VirtualPC is so painfully slow on my G5, I decided to make Boot Camp run on the iMac.

I've got to say: installation of Windows with Boot Camp was painless. Really, aside from the 39 minute[1] installation of XP, the whole process took just a few minutes. Dynamically resizing HFS+ partitions while they're mounted? Absolutely awesome!

XP hums on this baby. So much nicer than VirtualPC.

Update: After my initial success, I got cocky. I resized my HFS+ partition again, to make room for Linux. I wanted it to triple-boot OS X, XP and Ubuntu. The Ubuntu will only run in text mode (the assumption about the refresh rate for the LCD is wrong), but it does run. Everything installs fine - seemingly - until it tries to run elilo to update the bootloader. Then things were very unhappy. Strangely, Windows crapped out at the same time[2], so now I have neither Windows nor Ubuntu working. OS X, of course, still rocks. So I'm off to reinstall Windows[3] again.

  1. Why do all Windows installations take 39 minutes? Rather, why do all Windows installations claim they're going to take 39 minutes? Why 39? They might as well have just said 42, at least that would have been funny.
  2. Unknown if elilo twiddled something with Windows, or if the two are unrelated.
  3. That's right, another "39" minutes...

Teamprise on Intel OS X

April 8, 2006 5:51 PM

While Teamprise officially supports Mac OS X (PPC), it will come as a disappointment to the rest of the mac zealots out there that the Teamprise Client Suite is not officially supported in OS X for x86. If I were reading about a product release in April 2006, and it included OS X PPC support but no OS X Intel support, I'd start wondering. After all, it's April 2006! Apple's shipping three machines with Intel chips, and the developer box has been available for nearly a year! Apple says making Universal applications is trivial, you just check another box in XCode! So why no Intel support?

Well, it's not always as trivial as checking another box - and leaving Intel support out of 1.0 was actually a trivial decision.

Remember that the Teamprise Client Suite is composed of three applications:

  • Teamprise Plugin for Eclipse
    A plugin for Eclipse and Eclipse-based IDEs which provides access to Microsoft Team Foundation Server version control and work item tracking. Being an Eclipse plugin, this code is written in Java using SWT for its UI.
  • Teamprise Explorer
    A standalone application for cross-platform access to Microsoft Team Foundation Server. Explorer is an Rich Client Platform application - since all the code necessary to access TFS exists in the plugin, along with a whole bunch of dialogs and UI code, it would be silly to rewrite that. Thus, Explorer is a Java app using SWT for its UI.
  • Teamprise Command Line Client
    An emulation of Microsoft's TFS Command Line Client. Again, it uses the base of Teamprise, and so is written in Java.

But wait, you say - Java should be even more portable! The Intel Macs have Java 1.5 already installed. They should just be able to run that bytecode!

Ah, again, it's not that easy. See, we're not exactly 100% pure Java. We have some native functions to do some various things we can't do in Java. We'd also need to port these native functions to Intel. But this should take just a few minutes, right? Pass the -arch flags to gcc and you'll get a Universal library, right?

Yep, but there's still more. As I mentioned, we use SWT for our UI. It's basically a wrapper for native system calls. Where once Java apps were strange looking and slow, SWT writes directly to Carbon on OS X. The result is a real native-feeling[1] application, and you should never know it was written in Java. SWT is great if you want to target a lot of platforms without having to think too much about it. Unless, of course, one of those platforms is OS X on Intel.

See, when Eclipse 3.1 was released, there were no Intel Macs. Eclipse 3.2 will support them when it's released this year. Until then, there is no official version of SWT and RCP for Intel Macs. We could have, a few months ago, made a big plunge and dumped Eclipse 3.1 in favor of one of the milestones of Eclipse 3.2 and gotten support for Intel Macs, but we'd be building against a prerelease for the platform we rely upon. It was clearly too big a risk to make a jump that big, that late in the development cycle.

So what's to be done? What if you've got a shiny new MacBook Pro, you're running Eclipse 3.2M6, and you want to access a Team Foundation Server?

Well, it's not as dire as it may have sounded -- first, all our native code is already Universal, so if you happen to have an Intel Mac, both the Command Line Client and the Plugin will run. (The Command Line Client has no dependencies on SWT or RCP, and the Plugin will use your version of Eclipse's SWT.) I've done simple testing on my iMac and I can verify that both the Command Line Client and Plugin run and pass simple tests. Please note, however, that this was a stopgap solution for Intel Mac users, and has not been thoroughly tested. It is not officially supported by Teamprise.

That just leaves Teamprise Explorer. And I'll tell you what - if you need Explorer for Intel Macs, send an email to feedback@teamprise.com, and we'll build a copy just for you. (Again, not officially supported.)

Hey, it's still better than what you'll get out of Adobe.

  1. To be fair, SWT feels very native, but still has a few UI quirks, particularly for the Mac. But that's another article.

Sun sells cshells...

April 5, 2006 11:27 AM

well, actually Sun doesn't sell much of anything notable anymore. But back when I started playing with Unix, Sun workstations were golden, and SunOS was the standard by which all other Unixes were judged. 4.1.3U1 was rock solid, fast and ran on neat Sparc hardware.

And with it came the cshell. Well, of course it came with the original Bourne shell, but that was just for scripting, right? Surely nobody used that dinosaur interactively, right? Did it even have command history?[1] And ksh - that was like the Scientology of shells[2] - it was always around, but only the kooks used it. Everybody used /bin/csh, because that was just The Right Thing, and there was little argument.

Except, of course, from the ubernerds using tcsh[3]. The arrow keys were useful! It had filename completion! It understood terminfo! It was badass timesaver for anybody who sat in front of a shell all day.

That was over a decade ago, and my login shell is still tcsh. I haven't even thought about it in the last ten years -- meaning I've probably used it more than any other single piece of software in my lifetime[4]. And then, the Linux guy - my former tcsh-using colleague - questioned my choice of interactive shells. He was creating an account for me on some server and realized, "oh, I have to install tcsh so you can login."

What!? It's tcsh, it's the standard... well, maybe that should be was the standard...

% echo $version
tcsh 6.12.00 (Astron) 2002-07-23 (powerpc-apple-darwin) options 8b,nls,dl,al,kan,sm,rh,color,dspm,filec

There hasn't even been a point release in almost four years. Yeah, maybe that's a positive on me being behind the times. So I dusted off my scruffy Unix-guy beard and ran that scary chsh command. After a little playing, here's why I'd recommend you make the plunge and dig into zsh over tcsh:

  • Extended aliases
    tcsh lets you alias a command, but zsh lets you alias arguments, too. Global aliases (alias -g) match any position. So you could, for example, work around annoyances with system utilities. On a Mac, /tmp is a symlink, and you rarely want to operate on the symlink, but almost always want to operate on the directory. tar -cf tmp.tar /tmp? Not very useful. Thus:
    alias -g '/tmp'='/tmp/.'

    You can also alias file extensions to map to programs to execute. Let's say you have some .NET programs (for example: Vault[5]) as .exe files:

    alias -s exe=mono

    will let you type vault.exe, and will execute mono vault.exe. Beautiful!

  • Directory history
    Sure, tcsh has pushd and popd, and they're surpremely handy if you're disciplined enough to actually use them. I've never been that disciplined, and I always end up shooting myself in the foot when I leave the insane depths of a source tree to go into my home directory or /tmp for a second. Solution?

    setopt AUTO_PUSHD

    Now instead of kicking myself for not running pushd, I just popd back to where I was before. Handy.

  • Multi-line history editing
    This one's a no-brainer. tcsh's history editing stinks. Do a foreach, make a mistake inside the block, and then try to go back and change it. Nope. zsh pops up the entire block. (Heck, even bash does this right.)

  • Better single line history
    Let's say you edit a file in a faraway directory, do a few dozen things and forget where that file was. In tcsh, if you know the line number, you may able to get that faraway path back. In zsh, if you remember part of it, you're better off:

    vi /Users/ethomson/tmp/project-1.0/src/libproject/Makefile
    ...
    ...
    !?Makefile

    will search your history for Makefile and bring up the most recent. Want to do something else with that file, instead of running vi? Try:

    cat !?Makefile?:1

    (the first parameter from the matching line.) Or, try:

    !?Makefile<TAB>

    to bring up the whole command from history on your prompt, for editing.

  • Smarter shell builtins
    It surprises me how often I use foreach to do renames. Backing up a group of files -- or worse, restoring them. Previously I might have done:

    foreach a ( *.log.bak ) set b=`echo $a | sed -e "s/\.bak$//"`
    mv $a $b
    done

    zsh's builtin zmv makes this easy:

    zmv -W '*.log.bak' '*.log'

  • Math!
    Despite majoring in math, I never was very good at arithmetic. But neither is tcsh. On the other hand, zsh has math builtin. Let's say I want to add track numbers to some music files[6] in tcsh:

    set cnt=0
    foreach a (*)
    set cnt=`expr $cnt + 1`
    mv $a $cnt-$a
    end

    But in zsh:

    cnt = 0;
    for a in *; do
    mv $a $((cnt=cnt+1))-$a
    done

    (Okay, so you only save one line, but you also don't have to remember that expr has such a broken tokennizer that it can't understand the difference between "0+1" and "0  +  1"

I'm very pleased with zsh. Even if its improved history, better aliasing and better directory traversal only shave a little bit of time off my shell usage, that adds up over the course of a week - and maybe it makes me a little less grouchy[7]. In the little bit of time I set aside for learning new zsh features, I found the the zsh wiki to be super-helpful.

  1. No
  2. Sorry Jeremy... ;)
  3. Nobody I knew had ever heard of bash until those crazy first Linux distributions came out, at which point its familial heritage was called into question on several occasions.
  4. vi would be first if it weren't for the transition to nvi in 4.4BSD and the widespread adoption of vim by linux distributions (despite its incorrect undo syntax.)
  5. You'd be correct if you recognized this as shameless corporate promotion.
  6. Globbing the filenames with * will obviously only work if the filenames are track-ordered. For the purposes of this example, let's assume filenames are song names and the album's tracks are in alphabetical order. This isn't completely contrived: see the excellent (and alphabetical) The Magnetic Fields: i.
  7. My co-workers may, of course, disagree...
Edward Thomson is a Software Engineer at Teamprise, where he develops cross-platform client solutions for Microsoft Team Foundation Server, with an emphasis on Macintosh compatibility and IDE integration.