Thursday, May 15, 2008

my brief affair with a mac book pro

It finally happened. Last week, I got a MacBook Pro for work.

I’ve been a proponent of Apple products for a while now. Years ago, my wife and I bought a PowerBook, and when it needed to be replaced, we didn’t hesitate to get a MacBook. I’ve been very happy with both machines: no fighting viruses/trojans, great bundled software, simple, usable, and no-hassles.

When people ask for my recommendation on a new computer (as if using computers at my job makes me somehow qualified), I ask if it is for personal use: email, internet, and such. If so, I say: get a Mac, because a Mac makes for a great personal computer.

So, it may be a little surprising to hear that I am trading in my new MacBook Pro for a run-of-the-mill MPC laptop. Why? Three reasons…

#1: Apple Store

I was eager to get my new laptop, so I ran over to the Apple store. As it turns out, if you are looking to make a quick purchase of an Apple product, the Apple store is the wrong place to go. It’s an interesting idea to remove the cash registers while hiding all the stock in the back room, but it is not practical for two very important reasons:

  1. First-time customers don’t know where to pay
  2. You have to wait for (or go find) an employee for any purchase

After waiting about 10 minutes, I finally had to interrupt two employees to ask for help. They were too busy chatting (probably about how cool their iPod-ish name tags were) to ask me why I was patiently standing there looking helpless. Then, I had to endure several minutes of smarmy Q&A before he understood that all I wanted him to do was go in the back and get a MacBook Pro.

#2: Walled Gardens

The robust and seamless nature of the Mac (and iPhone) is largely due to the control that Apple has over the entire process: hardware, software, distribution, etc. It’s hard to imagine that equally compelling products could come from a more open ecosystem, and if they did, it would take much longer.

To me, it’s a design vs evolution (or craftsman vs committee) debate. The OSX vs Linux comparison makes for a great example…

With OSX, there is a small group in charge, and they exert their control to create a very consistent and stable platform. The focus is narrow, so the details get taken care of. Also, with lots of control, it is easier to have a high level of integration between the parts (a.k.a. seamlessness). The downside is that potential good ideas from the outside are often locked-out.

Linux, on the other hand, is more open and has less filtering from the top. This means that you get an amazing diversity of ideas, which allows innovation that can’t happen in a closed environment, but it also creates a ton of mediocre and crappy ideas too. So it becomes a survival of the fittest for Linux features/apps. The downside to the open system, is the dilution of effort. There is so much diversity that it takes longer to get enough people focused in the same direction to make significant progress.

In the long run, bet on the open system, because walled gardens don’t last.

#3: Old Habits

When I’m working, I want efficiency, and if I have to hesitate because the keyboard shortcut is different or because I need to reach for my mouse, time is lost. Not only do I lose time because it physically takes longer, I lose time because I have to focus on the keyboard/mouse and then return my focus back to the actual work. A good tool should become “invisible” so I can focus on the work, not on the tool.

My old laptop was a dual-boot machine with Ubuntu Linux v7.10 and Windows XP, and I spent 95% of my time in Ubuntu. I’m a keyboard maniac, so when I originally transitioned from Windows to Ubuntu, it was a very easy transition because the keyboard shortcuts in Ubuntu are so similar to Windows.

True, if I had been using a Mac all along, then I would be used to its keyboard shortcuts, but that is just a “walled garden” argument design. The Mac has a small percentage of large market, and when they don’t conform to the defacto standards, they get punished by the fact that consistency is one of the strongest contributors to usability.

The Break Up

Mac, I’m afraid that this is goodbye. You are sexy, and we had some good times. Playing with photos and movies was fun, but I want to get serious, and you just weren’t as open as I had hoped. I know you’ll do fine without me; there are lots of designers and trendy people out there to make you happy.

I wish you the best, and remember: It’s not you. It’s me.

Thursday, May 8, 2008

e4x to the rescue (sort of)

Note: This is the follow up to a old, poorly-written, rant on e4x where I used the wrong terms and left huge holes in my arguments. I can only hope to do so poorly this time.

A simpler DOM

Many developers (myself included) tried to scab together our own object-ish XML processing. Usually this meant converting the XML into a big "object tree" where the names of the object properties were the same as the XML nodes. This would allow us to turn:

<root><foo>hello</foo></root>

into:

root.foo // returns "hello"

And when we did this, we quickly ran into problems:

  • Attributes: What if an attribute had the same name as a child node?
  • Collections: It would be nice to skip array-like access for nodes that only have a single child, right?
  • Naming collisions: How do we make sure that the properties and methods that we need to have on a node don't conflict with the names of the child nodes? For example, what if a node is named "children?"

e4x bring object traversal to the masses

So e4x comes along, and it looks a lot like that stuff that developers had been scabbing together. It added some nice syntax for "querying," and they prefixed the attributes with an @ symbol -- so we don't have to worry about attribute names and node names colliding -- but otherwise it's mostly the same.

The two places where they dropped the ball were on collections and the naming collisions. Let's ignore the collection problem for now and talk about their "solution" to the naming collisions that can occur between methods/properties and node names. They decided that all methods/properties of a node (children, length, toString, etc.) would be accessed as methods, requiring parentheses, and all the child nodes would be accessed as properties; no parentheses.

It's too bad that they didn't just use a prefix to distinguish between traversing xml nodes and methods/properties. Much like the attributes are prefixed with the @ symbol, I wonder why they didn't use some prefix (a # sign, perhaps) for xml nodes.

This is a big problem because it creates an inconsistency with most languages, because they follow a rarely discussed rule-of-thumb (see the When to Use Properties vs. Methods section)...

* methods/functions are verbs: perform an action
* properties are nouns/adjectives: read/write values

Let's look at some Javascript for example:

* String.length
* Document.links
* Window.parent
* String.toUpperCase()
* Document.write()
* Window.close()

Now let's see if e4x follows that same rule:

* XML.name()
* XML.length()
* XML.parent()
* XML.replace()
* XML.insertChildAfter()
* XML.contains()

Nope.

And what happens when you try to implement e4x in a language like Ruby? Ruby has no properties and parenthesis on method calls are optional.

In case you missed it, I had a bug where I called node.children, instead of node.children() because I relied on that rule-of-thumb. It served as another fine example of why consistency is so critical to usability.

Random light switch trivia:
In the United States it is universal for the "on" position of a toggle switch to be "up", whereas in the UK, Australia, and New Zealand it is "down." -wikipedia



Tom - May 9th, 2008 9:51 am

Good points. As you pointed out, the issue comes down to XML element name mapping in the object graph. Since they went down the road of using the exact names from the XML, they needed to make the built-in properties be methods to avoid name collisions with elements that might be named "parent" or "name", etc. (which are probably commonly found in XML).

e.g. given <foo><name>bar</name></foo>, x.name is different than x.name().

But you could also make the argument that constantly writing x.#foo.#bar is less convenient (and hence less usable) than x.foo.bar. It's really more of a trade-off for consistency in attribute/method conventions vs. the readability of the code/API.