Please join me at my new location bryankyle.com

Thursday, November 18, 2010

The Playbook

RIM recently released a video "previewing some of the cool stuff [they're] doing with the Blackberry Playbook browser." From the video, it certainly looks like the Playbook wipes the floor with the iPad. It loads pages faster. It supports "dynamic" content, by which they mean Adobe Flash. It passes the ACID3 test. Of course the video is incredible, they'd be fools to release a video that wasn't. But after thinking about it for a little while, I came to the realization that it wasn't really that amazing at all.

This video is showing a speed comparison between 2 devices. Yes, they're both tablets but it's not really a fair comparison. The iPad has been shipping to customers for about a year. Since Apple doesn't rev the hardware between releases that makes the hardware at least a year old, if not older. As for the Playbook, there's no official release date yet. All we've so far is early 2011, which means sometime between January and March. Assuming that the Playbook's hardware specs have been nailed down, the video is comparing a brand new device with one that's a year old. Of course the new one's going to be faster, no surprise there.

The sites that RIM picked for the demo were obviously not chosen at random. Clearly these were sites that they knew would show off the features of the Playbook. Almost any site would loaded faster and performed better on the Playbook given that it's newer. Similarly, the Playbook claims that it has better ACID compliance than the iPad. Both devices, as far as I know, use WebKit. Safari on the iPad is just using an older version of it. Maybe we'll see better ACID compliance out of Safari on iOS 4.2 which should be released in the next week or so.

While the video was certainly impressive at first glance, after some thought it's really not that amazing at all. In fact, it leaves a lot of open questions. What's the battery life like on the Playbook? Sure the device appears faster and supports flash, but if you can only use it for a few hours what's the point? How smooth is the UI? Where are the Apps? I'm sure RIM has a good answer for all of these questions, I just wish they'd stop releasing marketing material and just ship the damn thing and let it stand for itself.

Tuesday, October 26, 2010

Do Smart IDEs Cause Dumbening?

The other day I read an interesting blog post from Luke Palmer the other day titled IDEWTF. In the article Luke discusseshow IDEs appear to be falling behind in the state-of-the-art compared to creative tools like Photoshop, Premiere, AutoCAD, etc. Luke's main point is that as developers we should be able to create and use the best tools for our craft. IDEs should be much more advanced than they currently are. While I agree with his point in spirit, I'm not sure that making our IDEs do more is the best thing for developers.

In 2003, a study (pdf) was conducted by a psychologist named Christof van Nimwegen. In the study 2 groups of people were asked to play a logic game. The game involved transfering colours balls according to a set of rules. One group was given a piece of software that assisted them in playing the game. For example, the software would highlight moves the player could make at a given point in time. The other group was given software that was not helpful -- it would not highlight permitted moves.

In the beginning, the group that was given the helpful software was able to solve the problems faster than the group that had the non-helpful software. However as the study progressed the group that was given the non-helpful software became much more proficient. In the end, the group using the non-helpful software was able to solve the puzzles using fewer extra moves, and produced fewer dead-end states where no more moves were possible.

The two groups were brought back in 8 months later to re-run the tests and try a different, but similar, logic puzzle. The group that had initially used the non-helpful software hit the ground running, so to speak. Not only were they able to solve the puzzles faster than the group using the helpful software but they were able to adapt their knowledge to the second puzzle.

This study suggests that helpful software, or software that offloads complexity from the user onto the software, makes us reliant on it. This doesn't say that it's a zero-sum game in which by the IDEs getting smarter the developers must get dumber. Far from it. I believe that we need to strike a balance between HAL 9000 and Notepad.

If the IDEs become too smart, and coddle the developer too much the developer will learn to rely on it. Automatic correction of syntax, imports, exceptions, etc are not in and of themselves bad. They certainly improve productivity. But the developer then learns to rely on their presence, like a drug. If the developer ever tries to work with a language that doesn't have the kind of tooling their used to they will pay a huge cognitive price up front, something that might be enough to scare them away.

So where do we draw the line? Which features improve both long term and short term productivity, and which cause dependence? I think the line is right between those features that do something automatically for the developer and those that provide advice. A feature that does something for the developer effectively offloads the cognitive complexity from the developer to the software; the developer is freed from having to think about it -- at least that's how they see it. With features that simply provide advice to the developer the IDE is allowing them to be more productive without having to pay a long term price.

An IDE like Eclipse has many of types of features. The classic example of an automatic feature is "Quick Fix". When Eclipse notices that something is wrong with the code that it can fix, it allows the user to tell the IDE to fix the problem for them. Developers that are experienced without the IDE will probably understand what it's doing. They would have been able to make the correction themselves without the help of the IDE. To them, this automatic feature is simply a way of improving their productivity. For the less experienced developer however, its mode insidious. Because the user doesn't understand what the IDE is doing, or why it needs to the user becomes more dependent.

Eclipse also has a variety of features that are designed to assist the developer. Call Hierarchy, and Class Hierarchy are two great examples. The developer still needs to understand what these features are used for; the tool simply gives the user advice, quick information that helps them make a decision or explore a code base. These features still cause a sort of dependence, but since the developer understands what the tools are for, and why they need to use them the dependence is less insidious. Without these tools the developer can still do her job, but productivity might be affected. In contrast with automatic tools where the developer wouldn't be able to do his job.

So, do smarter IDEs cause dumbening? You be the judge.


Footnote: I know "dumbening" is not grammatically correct. The word comes from a Simpsons episode where Lisa worries that she's losing her intelligence and writes in her journal:

Dear log. Can it be true? Do all Simpsons go through a process of dumbening? Wait, that's not how you spell dumbening... waaait, dumbening isn't even a word!

Wednesday, October 20, 2010

Predictions Report Card

So Apple held their much anticipated Back to the Mac event today. Since I made some predictions, I thought I'd follow up to see how well I did on my first attempt and predicting what was going to be shown.

To recap, I made the following predictions. I'll address each of these in turn.

  • Sneak peek of OS X 10.7, to be called Lion
  • New OS will have more user facing features
  • New OS will have over-the-air syncing with portables
  • OS will be seeded to developers shortly
  • OS will be generally available around WWDC '11
  • New release of iWork
  • New release of iLife
  • New MacBook, MacBook Pro and MacBook Air
  • Minor speed improvements for new models
  • SSD becoming standard equipment
  • USB 3.0
  • No Blueray
  • No iPad

Sneak peek of OS X 10.7

Sure enough, Apple did announce a new version of OS X today. As expected the new release is called Lion. I got this one right. It was a gimme, but I'll take it.

New OS will have more user facing features

In the announcement today Apple talked about a few new things that they were adding to the OS X 10.7. These included Mission Control, Launchpad, and Full Screen apps. These are clearly user facing features but since I was extremely general with my prediction I'm only going to give myself a half a point.

New OS will have over-the-air syncing with portables

Apple didn't make any announcements about whether over-the-air syncing would be available. Even as I was writing that prediction it seemed a little far-fetched to me. That sort of announcement really only makes sense at an iOS/iTunes announcement, not a Mac event. I missed this one.

New OS will be seeded to developers shortly

Apple didn't make any announcements regarding when the OS would be going out to developers. Since it could be released any time I'm going to hold off on saying whether or not I got this one.

OS will be generally available around WWDC '11

According to Apple, OS X 10.7 is on track to be shipping during the summer of 2011. WWDC is typically in June which puts it in (the beginning) of summer. Since I was more specific than Apple, and these dates tend to slip I'll only give myself a half a point on this one.

New release of iWork

There was no announcement regarding a new release of iWork. I flat out missed this one.

New release of iLife

A new release of iLife was announced. I got it.

New MacBook, MacBook Pro and MacBook Air

This one's tricky. While a new MacBook Air was announced there was no mention of revving the MacBook and MacBook Pro line. I'm going to give myself 1/3 of a point for that one.

Minor speed improvements for new models

Sure enough, there were speed improvements for the MacBook Air line. +1 for me.

SSD becoming standard equipment

Again, SSDs are standard equipment on the MacBook Air. I got it.

USB 3.0

No USB 3.0. No points for me.

No Blueray

As expected, there was no Blueray announcement. But since the MacBook Air doesn't have an optical drive I'm not going to count this one for or against me.

No iPad

No new iPad was announced. +1 for me.

Conclusion

In total I made 13 predictions. Of those one is pending an outcome in the next few weeks and one I've rationalized away leaving me with a total of 11 predictions that I can grade myself on today. According to a completely impartial jury I got 6 and a 1/3 out of 11 right. That's better than half. Not bad for a first timer.

Monday, October 18, 2010

Predictions for Wednesday

Apple has a Mac press event coming up on the 20th of October. Usually, I don't do this but I thought I'd take a stab at some predictions for the event. So, without further ado, here's what I think we'll see.

Sneak Peek of Mac OS X 10.7

The invitation that was sent out to the press for the event includes a picture of a lion peeking out from behind an Apple logo. Given that all releases of Mac OS X are named after large cats it doesn't take a genius to put two and two together. Clearly a new version of the operating system will be previewed, and its name will be Lion.

The last release, Snow Leopard, was mostly about the plumbing. Lion will need to have more user facing features. I'm willing to bet we're going to see some better integration between the Mac and Apple's portable devices: iPad, iPhone and iPod. The new OS will probably include over-the-air syncing with mobile devices and some new APIs to support it. As for other features, I don't have a clue.

I don't think the new OS will be released at the event. Apple seeds a few releases to the developers before shipping it publicly. This will be a preview only, the developers will probably get their copies within a few weeks and the new OS will ship around WWDC '11 next year.

iWork and iLife

The last release of both iLife and iWork was in 2009. Usually Apple likes to release new versions of its productivity software at the beginning of the year, but seeing as the last release is almost 2 years old it could use an update. Plus, with Microsoft due to release Office 2010 soon it makes sense for Apple to release its competitive software around the same time, hopefully to knock the wind out of Microsoft's sails in the consumer market.

New MacBook, MacBook Pro and MacBook Air Portables

According to the MacRumors.com buyer's guide all of the portables have been out for about 6 months. In the case of the MacBook Air much longer than that. I'm guessing we'll see speed bumps across the board, SSDs becoming a standard component and USB 3.0. With Apple supporting high-def video through rentals and purchases in the iTunes Store I don't see Apple including a Blueray player.

No iPad

I don't think we're going to see an update to the iPad. iPad was first announced late January 2010 and didn't start shipping until March. That means the 1st generation iPad hasn't been shipping for a full calendar year yet. With the holiday season coming soon and a well oiled supply line on the device it doesn't make sense for Apple to announce a new one and canabalize its holiday sales.


This is the first time I've ever done a predictions entry, and usually I don't pay much attention to what's going on. So don't quote me!

Saturday, October 16, 2010

How To Deal With Customers

I was at a local computer store this afternoon and I overhead a conversation between who I believe to be the owner and a customer. I didn't hear the whole conversation since I walked in half way through, but the part that I did hear I found startling.

The customer was ranting and raving about how much he hated the computer that he had brought in. He was livid about how it constantly lost data, crashed and generally didn't do what he wanted. He kept saying that he was going to try a Mac because of all of the problems.

Instead of talking the man down gently and being generally agreeable the owner decided to get into a verbal fist-fight with the customer. For every knock the customer had against his computer the owner had something to say about it.

"It just turns itself off after an update!" "It doesn't just shut down, it give you 5 minutes to save what you're doing!"

"The screen doesn't work right." "These things work fine. If yours isn't working it's probably a faulty card or something."

The owner kept trying to give the customer reasons that he should stick with a Windows PC.

"The Mac has 1 trillionth the amount of software." "I don't care. It's not a toy, it's a tool. I don't need lots of software, I just need something that allows me to get my work done!"

The icing on the cake came towards the end of the conversation when the owner said, and I quote: "90% of the world can't be wrong."

In this case, I think the customer was angry when he walked in the door. He was looking for a fight. Clearly the owner doesn't have children. If he did he'd have realized what the customer was doing to him. Instead of fighting with the guy, he should have just agreed with all of his points and suggested that he do try a Mac. The customer had already made up his mind that he wanted to try one.
When the customer asked questions that he didn't know the answer to he should have picked up the phone and called one of the Mac stores in town. That would have diffused the situation and earned him some emotional currency. He could have even gone as far as to ask one of the stores if they do rentals or have a try-before-you-buy program. That customer didn't come in to buy anything, he came in for some help. So help him.

If the customer did ultimately decide to go with the Mac, he'd only have good things to say about the store. He'd refer business over to them if anyone asked and was in the PC market. In the age when brick and mortar stores are close to extinction any way that you can distinguish yourself from a faceless web site and earn some emotional currency is worth the price. Yes you might lose a sale, but you'll just have earned some in the future.

Monday, October 11, 2010

Nil Advice

Recently I wrote that one of the things I really like about Objective-C is how it handles nil-values when calling methods. It certainly makes for code that's easier to read however it does have a downside as mentioned by Daniel Jalkut of Red Sweater software. In Don't Coddle Your Code, Daniel writes:

It s also worth noting that LaMarche s defense of nil ing out instance variables hinges on the presumption that messaging nil is safe. True, messaging nil will not cause a crash. But is that safe? Not if it changes the behavior of your code in unpredictable ways.

He goes on to demonstrate his point with some contrived but applicable code:

if ([mDiplomat didReturnGestureOfPeace] == NO)
{
    [[NuclearWarehouse nuclearMissile] launch];
}

Daniel's point is this:

The biggest disservice you can do to your users is to allow them to run code that has unpredictable behavior. The whole point of programming is to make computers accomplish tasks in predictable ways.

I think he makes an excellent point. To paraphrase -- and I'm sure C++ developers will agree -- just because you can do something doesn't mean that you should. This language feature is a boon for those that understand how to use it effectively and design interfaces that work well with it.

Wednesday, October 6, 2010

Why FizzBuzz is a Great Interview Question

Interviewing can be really hard and stressful. You need to make a decision about how well someone will fit into your organization. That in and of itself is hard enough; combined with the fact that you aren't given anywhere near the amount of time you need to assess their skill level and personally makes it even more difficult.

The best way to assess skill level is to ask questions that give the candidate questions that allow them to demonstrate their knowledge. But what kind of questions should you ask? Given that 199 of out 200 applicants can barely code, it makes sense to ask a question to weed out the 199. FizzBuzz is just the type of question to do this.

FizzBuzz, if you aren't, is a question that asks the candidate to write a simple program. Typically it's proposed similar to the following:

Write a program that prints the numbers from 1 to 100. But for multiples of three print Fizz instead of the number and for the multiples of five print Buzz . For numbers which are multiples of both three and five print FizzBuzz .

This question is specifically targets problem solving skills; something that all good programmers need to have. It also has the advantaged of targeting the 3 most fundamental concepts in computation: sequence, selection, and iteration. That is, it has loops, conditionals and the sequence of them matters to the output.

The way in which the question is asked usually trips people up too. Implementing the program exactly as it's specified will end up working incorrectly. Why? Have a look at this JavaScript implementation:

for (var i=1; i<=100; i++) {
   if (i % 3 === 0 )
      print("Fizz");
   else if (i % 5 === 0)
      print("Buzz");
   else if (i % 3 === 0 && i % 5 === 0)
      print("FizzBuzz");
}

Anything strike you as odd? The last condition is in the wrong place. If the value is divisible by 3 or 5 the if/else construct would have been broken out of in the first 2 conditions.

Whether or not someone gets the correct answer doesn't really matter. What's really being tested is the candidate's ability to convert a problem description into the language of logic in a reasonable amount of time. What's reasonable? Accounting for nerves I'd say it shouldn't take longer than 10 minutes. A good programmer should be able to solve inside of 5.

Tuesday, September 21, 2010

Some Thoughts on Cocoa and Objective-C

I originally started writing this about a year and a half ago. It's been sitting on my desktop waiting to be published but for one reason or another I never got around to it. My thoughts now seem trite, but it's interesting to look back. One of these days I should write a post that covers the more interesting aspects of Objective-C's design; more than just what's covered here.


I've been dipping my toes in Cocoa again lately, and I'm really starting to enjoy it. I first played with Cocoa when I got my first Mac in 2004. I really thought there was something promising there but I couldn't wrap my head around how all the pieces fit together. After being abused by other OOP languages and their GUI frameworks Cocoa seemed really backwards. Delegation instead of subclassing. Freeze dried objects and connections that are brought back to life at runtime, etc. And the language. Why this bizarre language with it's odd syntax?

Each of the choices in isolation appear to be fairly arbitrary, or different for difference's sake. But as you learn more about the development model you can definitely see a method to their madness. The choice of language is a rather interesting one because it forms the foundation of how applications are written for the Mac. So why Objective-C? In order to understand why Cocoa, OS X's native framework is written in it it's important to know where OS X came from.

In the late 80s NeXT Computer was building high end computer workstations for education and businesses. The crown jewel of NeXT was its operating system: NextSTEP. NeXTStep was a performant, object-oriented, preemptively multitasking operating system with a graphical user interface. In order to quickly build the operating system and its application software a very performant, dynamic, reflective language was needed. At the time the best choice was probably a little-known superset of C called Objective-C.

In the early to mid 90s Apple was looking for a successor to its aging operating system. After several failed attempts to build one in-house Apple was approached by NeXT. NeXT convinced Apple that it had the technology that Apple needed. In the end NeXT Computer was bought by Apple, and NeXT Step was transformed into Mac OS X. If you've ever wondered why classes are prefixed with NS in Cocoa now you know why.

I've found Objective-C to be a really interesting and fairly elegant language. One of the more interesting things I found was that Objective-C uses a completely different calling metaphor from traditional OOP languages that I've learned. What most languages refer to as calling methods, Objective-C calls message sending. The distinction is more than skin deep, it's a fundamentally different paradigm. If you're experienced with the mainstream OOP languages you've spent a great deal of time thinking aboout class taxonomy and how classes relate to each other. You're trained to think that classes are types and methods are associated with the types. This makes a lot of sense if you look at the problem from a compiler's perspective. If you know the class and method at compile time then you can statically jump to the appropriate address. It's faster than a dynamic lookup but you pay for the boost in performance and the currency is developer time.

A message sending paradigm on the other hand is quite different. When you want an object to perform some operation you send a message to that object with some arguments. The object that receives the message will dispatch the appropriate method for the message. Typically there is a one-to-one mapping between messages and methods but in some cases you might want to respond to messages that don't correspond to a method.

You might boil the difference between method calls and message sending down to a difference in who is responsible for finding and invoking the appropriate code. In the method calling convention the caller is responsible (via the compiled code) for determining the address to jump to. Message sending on the other hand leaves the receiver of the messag to determine what method to invoke. Another interesting side effect of message sending is that sending a message to a non-existant object is perfectly legal whereas calling a method on a non-existant object is not. In Objective-C sending a message to nil returns nil. You can chain these together without any problems.

    return [[[a firstChild] nextSibling] nextSibling];

As I mentioned earlier, when an object receives a message that it doesn't understand it is allowed to perform any operation that it wants to.

Tuesday, July 20, 2010

Apple is not going to Open Source OS X

Last week I was listening to episode 203 the MacBreak Weekly Podcast. I agree with most everything that's talked about on the episodes I've listened to and for the most part this one was much the same, except for the one member of the panel insisting that Apple should open source OS X. Let me be one to say that there is absolutely no way that OS X will ever be open sourced. There are so many reasons that this will never happen it's ridiculous. Here's a few off the top of my head:

Traditional computing devices aren't dead yet

The notebook is far from dead. The desktop maybe, but not the notebook. iOS isn't feature rich enough to replace a traditional computer for the vast majority of people. There are lots of places where the OS shines, but for general purpose computing it's not there yet. You can tell that this sentiment is echoed by Apple in the fact that iDevices are treated as satellites that have to sync up with the mothership Mac.

OS X is required for iOS development, why lose out on a sale?

Right now the only platform that you can develop iOS applications on is OS X. The only hardware that you can (legally) run OS X on is a Mac. Apple makes a sizeable amount of revenue off of Mac sales. If they were to open source the platform they'd been losing Mac sales. Why would they want to cut off that revenue stream?

OS X is encumbered

Probably the main reason that Apple will not open source OS X is that it legally can't. Unlike full open source operating systems like Linux, OS X probably contains lots of code that's been licensed from third parties. What code might that be? It could be anything. For an example of this, have a look at OS/2.

Unlike OS X, OS/2 was actually discontinued. Some years later devoted users and businesses that had bought into the operating system wanted it to be open sourced. IBM refused citing licensing problems over some of the code that makes up the OS. This is coming from a company that does a lot of open source work. If they could, I'm sure they would open source it but legally they can't. It's not worth their time or the potential for law suits.

Apple is not going to open source OS X.

Tuesday, July 6, 2010

Design Matters

It's summer time again, and with summer comes a change in wardrobe. I have two pairs of shorts in my small wardrobe that are extraordinarily similar. They're just about the same color and cut, and fit very well. Where they differ is in the design of their velcro-shut pockets.

Now, I'm not talking about design in the sense of expensive clothing designers. No, no. I'm talking about their general design and the thought that went into it by whoever designed them. Let me explain, as best I can, the general design of the pockets on each of these. Lets call the first pair A and the second pair B.

Pair A was designed as a standard pocket is - a slit on the fabric with a pouch sewn in. The band of velcro is attached right at the top on the inside of the pocket. Pair B on the other hand has a flap that covers the opening of the pocket when it's closed. The soft side velcro strip is attached to the inside of the flap, while the rough side is attached to the outside of the pocket.

Both of these seem fairly straight forward and obvious. But do either of these strike you as bad designs? I can guarantee you that it isn't obvious until you've used this configuration for a little while. Think about it for a minute.

Did you figure it out? That's right! Design A is the bad design. Because the the velco is on the inside of the pocket whenever you try to pull anything out of the pocket your knuckles get scraped on the rough side of the velcro. It's not so bad the first few times but after a while it can wear your knuckles raw. With design B the only the soft side of the velcro will come in contact with your hand.

Now for the $64,000 Question: Which of these designs do you think was on the more expensive pair of shorts? Yeah, that's right. Design A, the scrape-your-knuckles-raw design was more expensive, but that's not what's important. What's important is that design matters. It matters a lot.

When you're designing something you need to really think hard and sweat the details. What you don't think is a problem could turn into real, actual, physical pain for your users.

Saturday, July 3, 2010

You're an Artist!

Do you know anyone that refuses to show you what they're working on until it's perfect? I know I do. What drives this person to polish and buff their creation before showing it to the world? I think they do it because they're scared of what people might think. They're scared that someone might ridicule their hard work. To this person I say: don't worry about what other people think. I know it sounds trite, but seriously. If you're too scared to show off your creation then why did you create it?

Putting something out in front of people isn't easy. Everything you create is a piece of art, it says something about you both personally and professionally. It's a very scary thing, but you have to get over that. If you never show people your half-finished project how will you ever know if you're on the right track? I heard an excellent analogy that sums this up very nicely: You can't steer your boat until it leaves the dock.

What's the worst thing that could happen if you show off your creation? If someone tells you what they think that's great! It doesn't matter if it's good feedback or bad. The fact that someone is taking the time to tell you what they think means they have some feelings about what you're doing. And isn't that what you're trying to do? As an artist you should be striving to make people feel something.

What, you don't think you're an artist? Do you know what the definition of artist is?

Artist
n. A person whose creative work shows sensitivity and imagination.

If you've created something from nothing that shows creativity. If it's something that's never existed before, that's imagination. And there's no doubt that a program shows sensitivity. Have you ever used a program or seen some code that you thought was beautiful? I'm sure we all have, that's sensitivity. So, believe it or not but you, a programmer, are an artist. So stop pretending to be something you're not. Create something that people will have feelings about and unleash it on the world.

Tuesday, May 18, 2010

An Elegant Design: Maildir

One of the most elegant software designs I've seen is that of Dan Bernstein's Maildir. Maildir is a way of storing email messages common to Unix platforms. It's the successor to an earlier format called MBox. These two formats differ in a very big way. To better understand the driving factors behind Maildir it's important to know the flaws that it's trying to address. The flaw in MBox, it turns out, is baked into its design and cannot be fixed without throwing out the design and starting fresh; which is exactly what Dan did with Maildir.

The MBox format keeps all messages in a single text file in the user's home directory, or anywhere for that matter. Each message is delimited by a From line, that is, a line that starts with from:. As you can imagine, this design makes is easy to count the number of messages in the file by counting the number of from lines. Another benefit of this format is that since messagse are appended on to the end of the file all of the messages are in chronological order. These benefits, are not without their drawbacks.

Since MBox stores everything in a single file that file needs to be locked anytime a process wants to write to it. That means that message delivery agents (MDAs) need to lock the file while accepting mail for a user limiting the total number of messages that can be accepted for a user at a given time to one. Locking isn't the only problem that occurs when you store lots of information in a single file. When a message user agent (MUA) wants to remove a message from the middle of the file it has to rewrite the entire file without the message that the user wants to delete. Along the same lines, in order to get a listing of the messages in the mailbox the MUA must scan the entire file from the first byte to the last -- apparently listing and deleting messages were not considered a common use case. Another problem, albeit one that only reveals itself in extreme cases, is that if a mailbox gets extremely large it could potentially run up against the operating system's file size limitations. Lastly, the file format is extremely fragile -- an errant From: line coult corrupt the mailbox and render the mailbox unreadable to MUAs. When designing systems it's important to balance speed, efficiency, robustness, and simplicity; MBox seems to be designed for simplicity at the expense of others.

Clearly the bar is set fairly low for other mailbox formats. Luckily, Maildir wasn't designed as an incremental improvement over MBox, it was designed to maximize speed, efficiency, and simplicity; and it did so in an amazingly elegant and robust way.

Enter Maildir

Maildir, as the name implies stores its data in a directory structure. This is a crutial difference between Maildir and MBox. Maildir, unlike MBox purports to be a lock-free system -- the mailbox can be read and written to at the same time. Under high load this is a really good feature to have. The most interesting piece is that Maildir maintains its lock-free design even when the mailbox is stored on a remote system and mounted using NFS (network file system).

Not only is the system lock-free it also doesn't fall victim to the other problems faced by MBox; receiving and deleting messages are O(1) operations -- meaning that they take a constant amount of time to complete, instead of an amount of time proportional to the amount of messages in the mailbox. Another advantage to storing the mailbox as a directory is that the number of messages can be found by counting the number of files in the mailbox directories -- the MUA doesn't need to open the files at all unless it wants to get information from them.

So how does it work? Maildir is a fairly simple system which has the nice side effect of making it robust. A Maildir mailbox is a directory that contains 3 subdirectories to store messages: tmp, new, and cur. Messages that are being delivered are placed into tmp while they are being received. Once messages have been received they are moved to new before being read. After a user reads a new message it's moved into cur.

So far this seems like a fairly simple system; but what are the files that contain the messages called? Each message is given a unique name. The unique name is made up of a combination of machine and process dependent information such as the host name, current time, PID of the MDA delivering the message, etc. By concatenating a few of these together a globally unique name can be created; in the event that a collision occurs Maildir specifies that the MDA wait at least one second before trying again. This timeout is meant only to ensure that enough time has elapsed that the data used to create another unique name will be different.

That's effectively all there is to the mailbox format. Certainly it's simple, but how is it elegant or robust? To get a handle on that it's important to have an understanding of the properties of the Unix file system.

Unix File Systems 101

When most people think of a file on their computer they percieve a one-to-one mapping between file names and data; that is, a file and its data are synonyms. Under Unix this isn't the case. Unix treats file names and data as two separate things. What you might think of as the data in the file is actually known to the operating system as a unique number called an inode. Files are simply references to an inode. When you create a new file the file system allocates a new inode and associates the data you're saving with it. The name you specified for the file references the inode. When you delete the file you're deleting the reference to the inode. When the file system sees that there are no longer any references to the inode it knows that the space being used by that inode can be reclaimed.

Since multiple names can reference the same inode you can save disk space and headaches by having multiple names for the same inode. The process for creating a new name for an inode is called linking and there are two APIs (application programming interfaces) exposed by POSIX (the portable operating system interface [for unix]) that manage links: link and unlink. As you can gather from the name link creates a new name while unlink removes a name.

Linking and unlinking inodes is an atomic operation -- an operation that occurs instantly without the possibility of being interupted part way through. When a new link for a file is created the file is completely accessible, there's no delay while the data is copied on the disk. Simply put linking amounts to adding some accounting information in the file system but doesn't need to shuffle data around on the disk. This property of atomicity can be used by any application that requires that readers have a consistent view of the world.

Another feature of the Unix file system, and file systems in general is that the metadata -- the data about the files -- is stored separately from the file data. The stat information includes, but is not limited to: creation, modification and access times as well as size and ownership information. Having this information at the file system level means that it's relatively inexpensive to load information about a file or directory. Loading information about a file is called stating a file based on the name of the POSIX function stat. Since this information is standard information stored by the file system and isn't buried within a data file access to this data doesn't require specialized APIs -- the ones exposed by the OS are sufficient.

How Maildir Exploits the Unix File System

The features of the Unix file system mentioned previously are exploited very well by the design of Maildir. In order to ensure currency Maildir stores mail that is being received in a temporary directory, tmp. This ensures that readers of the mailbox, who read messages from the new and cur directories will not see messages that have not been completely received. Once a message is completely received it is linked over to the new directory. At the moment that the file system is updated with the new link to the file in new, all readers of the mailbox can see the message -- and the message they see is the full message, not a partially written one. In a similar vein, the stat information makes is very easy to get the size and received date of each message without having to parse the message file.

These benefits are extremely tangible, especially when considered in concert with the notion that a user's mailbox is generally located on a remote machine mounted using a Networked File System (NFS). Accessing files over a network is an order of magnitude slower than accessing files that are local to a particular machine; however the networked file system is presented to the system as any other file system -- neatly abstracted away behind the standard POSIX calls. From a user's perspective an NFS doesn't look any different than any other file system, it's just slower. But since Maildir is optimized to use the POSIX calls for many common operations, the whole experience is greatly improved.

Consider the case where an MUA wants to get a listing of the number of messages and sort them by date. An MUA that uses MBox would need to first lock the mailbox file, then read and parse its entire contents before it could provide the listing. For large mailboxes this is an expensive operation -- and an order of magnitude more expensive when the mailbox is on a remote machine. The MUA using Maildir would need to simply stat the file system. The data returned doesn't need to be parsed since its already in a standard POSIX structure. To get email specific information from each message such as subject, sender, etc Maildir helps by reducing the amount of I/O that needs to be performed. An MUA can simply read the first few lines of any message it's interested in to parse the headers. Contract this with MBox where it must read the entire mailbox file since the only way to know that you've reached the last message is when you hit the end of the file.

An Example -- How MTAs Accept Mail for Maildir Mailboxes

As mentioned previously the Maildir directory consists of at least 3 subdirectories: tmp, new, and cur. When writing new mail to a Maildir mailbox the tmp and new directories are used.

When a new message arrives, the system constructs a (possibly) unique identifier for the message. The MTA then checks tmp directory for a file with the same name. If a file with that name exists the MTA waits for 1 second and constructs a new unique identifier and tries again until it finds a unique identifer that doesn't clash with an existing file. The 1 second delay allows enough time for any time-related information used in the unique identifier to change.

The MTA then writes the message data to the uniquely named file in the tmp diectory. When the file has been completely recieved a new link is created to the message file in the new directory. The file is then unlinked from the tmp directory leaving a single link to the file in new.

Conclusion

The design of Maildir leverages the facilities provided by POSIX to produce an elegant solution that is simple, efficient and robust. Its clever use of the Unix file system and associated POSIX APIs demonstrates that it's possible to design a robust and scalable inter-process communication (IPC) mechanism using nothing but these facilites. In general, Maildir is a great example of what can be accomplished by having an understanding of the pieces of technology that a system is built on.

Friday, April 16, 2010

The iPad, iPhone OS 4.0 and Dropbox

From the looks of the iPad it's designed to be used primarily as a content consumption device with support for content creation. It's a good position for a first release since consumption doesn't require Apple to work out all of the kinks around how to use this brand new computing device as a way to create content. However, Apple seems to be slightly schizophrenic about the device with the release of the iWork applications for the platform. From what I've been reading the problems with using the device as a content creation platform are numerous. Most of the complaints I've read fall into one of two buckets: the device is designed as a touch screen device and input is fraught with problems, and there's no built in support for syncing work between the iPad and another machine.

Obviously Apple is aware that people aren't going to get any serious work done with a touch screen keyboard, hence the iPad Keyboard Dock and support for Bluetooth keyboards. But allowing users to hook up a keyboard to the device is only a half solution; you still need to interact physically with the device to perform some operations. John Gruber of Daring Fireball sums this up nicely in his article about the iPad:

The iPad is fundamentally a touchscreen device. You absolutely do not need a hardware keyboard for it. But if you re hoping to do any amount of serious writing with it ... you re going to want one. There are a few places in the iPad UI where I really wish the keyboard was useful but it isn t. For example, Safari location field suggestions. ... On the iPad, you must use touch to select from the list. Since you re already typing if you re entering a URL, this is just begging for arrow key support. (Ditto for suggested results from the Google search field in Safari.) The Esc key does not dismiss popovers, but that s probably OK. It s only possible to invoke popovers via touch, so it seems OK that you must dismiss them via touch as well.

As an aside, it's nice that Apple's including the Bluetooth functionality for the iPhone as well. I'm not sure how much use it will be, but it's a nice little feature that other phones won't have.

The other issue that's been brought to light is that the sync story for apps on the iPad, as well as the iPhone and iPod Touch, is really weak. Apple hasn't provided an API to allow apps to sync their data with a Mac. In fact, given that the iWork apps don't sync with the Mac I'm not even convinced that the functionality exists. Sure, you could say that since the iWork apps are smaller, lighter versions of the iWork applications for the Mac they might not want to automatically sync since there isn't feature-set parity between the two suites.

The lack of any syncing support is really surprising to me given that Apple is trying to position the iPad as a light-weight computer. The fact that it wasn't available in the initial release is forgivable but when the iPhone OS 4.0 announcement came and went without any indication of it being in the pipeline I was annoyed.

The lack of a native sync story for 3rd party apps has really turned out to be a ghetto. Each application has its own way of synchronizing data between the sattelite - the iPad, iPhone, iPod Touch - and the mothership - the Mac. Developers are forced to come up with their own way of syncing data between the two devices. Obviously this isn't a good place to be in for developers or users.

From the developer's perspective they have to either write their own custom syncing protocol or use something like WebDAV, FTP or iDisk to transfer the data to location that's accessible to both the Mac and the device. Clearly this is a waste of time on the developer's behalf and it's not even that good of a solution since it has the fatal flaw that the app can only sync data if it's running on the mobile device.

As for users: it's a complete usability nightmare. Each app has to have its syncing configured separately. The app on the mobile device has to be running for the sync to work and potentially so does the sibling application on the Mac. If either isn't running the sync will fail and user's will have to figure out why. This shouldn't be. Syncing is one of those things that users just expect to work. Period.

Synchronizing data is a common enough problem that the platform really should address it in a standard way. The fact that sync support didn't make it into iPhone OS 4.0 but iAds, an advertising API did is just appalling.

So, if you read the title of this post I think you'll know where I'm headed: Dropbox. For the un-initiated, Dropbox is a service that automatically keeps a directory on multiple machines synchronized. Best of all, for small amounts of data - up to 2GB - it's free! Dropbox could provide the infrastructure needed for mobile and desktop devices to keep their data synchronized, a great place to be. The fact that Apple's dropped the ball on such an important piece of the puzzle leaves an opening for Dropbox to become a de-facto standard for synchronizing between mobile and desktop devices.

There's only one slight problem: as of this moment there is no public API available for Dropbox. This means that even if developers want to integrate with Dropbox they can't. From what I've heard an API is in the works, but it's not ready quite yet. All I have to say is that they had better get their act together and soon before Apple comes along and eats their lunch with an integrated solution.

Tuesday, April 6, 2010

What is Source Code?

Bryan
Hey, I've got a question for you. Can you define source code?
Kyle
Seriously? Source code is source code. What's wrong with you?
Bryan
No, seriously! I'm having a philosophical debate with myself about what source code is and so far I'm losing. I need an outside opinion.
Kyle
Let's see. Hmmmm. Well, I'd say that source code is some human readable form that tells a computer what to do.
Bryan
What do you mean by 'human readable?' Do you mean that it's made of letters and numbers and other things that humans write with?
Kyle
Yeah, human readable, like with words and numbers and stuff.
Bryan
Does it have to make sense to people in order for it to be human readable?'
Kyle
Well, I guess so. To a certain degree anyway. I mean you wouldn't expect just anybody to be able to read it and make sense of it.
Bryan
Ok, so source code is something that's human readable, in the sense that some people may be able to make sense of it, that tells a computer what to do.
Kyle
Yeah, how does that sound?
Bryan
Full of holes!
Kyle
Such as?
Bryan
Well, your definition seems to imply that the human readable form is run directly by a computer. So basically everything that most people think of as 'source code' falls outside of your definition.
Kyle
Like what?
Bryan
How about source code that's run through an interpreter, or a compiler, or a VM!?
Kyle
You know what I mean!
Bryan
Suppose I don't! That's the point of the debate!
Kyle
Alright. Source code is something that's human readable, in the sense that some people may be able to make sense of it, that is processed in some way to produce some output that then tells a computer what to do.
Bryan
That's better. But let's say hypothetically there is a computer that can understand and follow the instructions in the human readable form?
Kyle
I think you're splitting hairs here.
Bryan
Humor me.
Kyle
Fine. Source code is something that's human readable, in the sense that some people may be able to make sense of it, that may be processed in some way to produce some output that then tells a computer what to do, or is interpreted directly by the computer. Satisfied?
Bryan
Not even close. What's this computer you speak of?
Kyle
You're kidding me, right?
Bryan
Nope.
Kyle
A computer, ya know? A thing that runs the source code or the stuff output by the process that processes it.
Bryan
Interesting take on things. Ya know, I seem to recall the word 'computer' has many meanings. Before there were computing machines there were people whose job was to run computations. They were called computers. So far both the machine and the human definition of 'computer' fit your definition of 'source code'.
Kyle
Oh god, what's wrong with you?
Bryan
Pedantry. But I wouldn't say it's something that's wrong with me. Can you define computer for me?
Kyle
...
Kyle
A computer is an electronic device that performs computations.
Bryan
Humans use electrical impulses...
Kyle
ARGH! Fine, an electronic device that you plug in that performs computations.
Bryan
Well, that definition seems rather crude, but I'll accept it just to keep the ball rolling. So what about configuration files? They're human readable and tell a computer what to do. Take emacs for example, its configuration is a bunch of data structures that get interpreted by emacs, well the lisp interpreter part of emacs anyway and are run.
Kyle
What's with you and that stupid editor?
Bryan
What's with you and your stupid editor? What's it called again? 'six?'
Kyle
It's called 'vim' and if you're truely going to be pedantic, VIM in roman numerals is 6000.
Bryan
Whatever, both the fact and question remain.
Kyle
What fact?
Bryan
Your editor sucks.
Kyle
It does not suck, it's awesome. You just don't grok it.
Bryan
Look, why are you arguing with me about text editors? We're supposed to be talking about source code.
Kyle
Very well. I'm not sure that I agree with your assertion that configuration counts as source code. It doesn't tell the computer what to do, it tells a program what to do.
Bryan
That's true, it does tell the program what to do not the computer. But the configuration is still human readable, and processed, and tells the computer what to do. Maybe there's no intermediate form that's produced but I don't see that as being the sole determinant between source code and configuration. If that were the case then source code for an interpreted language would be considered configuration if the interpreter simply walked over the AST.
Kyle
Yeah but, it's configuration. I think you picked a bad example since most people think of lisp as a language, not configuration. What about simple configuration files that are just key-value pairs.
Bryan
I would argue that it could still be considered source code depending, of course, on what's reading and interpreting the configuration. I would say Turing-completeness shouldn't enter the picture at all. Simple configuration or extremely rich configuration doesn't matter. Some people consider HTML and CSS to be source code, but neither are Turing-complete. Conversely what about TeX and PostScript? Both are Turing-complete but nobody considers documents in either to be source code.
Kyle
Look, I'd love to debate with you about what is and isn't source code but I have some work to do that involves writing source code, not just thinking about it.

Tuesday, February 23, 2010

A Programmer's Toolbox

Every programmer needs to have a scripting language in their toolbox.  The more languages the better, but at least one is a necessity.  For the longest time I've been torn between a few different general purpose scripting languages.  Endlessly debating over the relative strengths and weaknesses of each:  "Python is a fairly ubiquitous, but the libraries aren't consistent."  "Ruby has consistent libraries but there seems to be a steep learning curve before I can be a ninja."  Forgetting, of course that in the end it doesn't matter which one I choose, just so long as it solves a particular problem.

Well, the other day I had just a problem that I needed a scripting language to solve.  I was re-re-reading one of Steve Yegge's terrific blog posts (yes, I've read them a few times).  Specifically it was the one about 10 challenging books every programmer should read.  One of the books he mentioned was Structure and Interpretation of Computer Programs by Harold Abelson and Gerald Sussman.  I'd heard of the book before, and being a fan of lisp I'd always wanted to read it but somehow never got around to it.  I'd even seen the free copy online and the lectures posted on the book's website.  Finally I decided that I'd done enough procrastinating and while I wasn't going to want to read through the book, the lectures might be a good thing to watch when I have some time.  The only problem was I didn't want to have to download each of the 20 torrents and start them up myself.  Clicking on links is for suckers, in case you didn't know.

I needed a way to automate the downloading of all of the torrent files.  I'd heard of a library for Python called Beautiful Soup, but I'd also heard good things about the late _why's Hpricot.  Since I'd already dipped my toes in the Ruby water for a small tool I started working on the other day (more on that another time) I figured I'd try Hpricot.  After about 10 minutes of playing around with the library I had a working script that would scan through the page and download all of the torrents of the .avi versions of the lectures.  Below is the code I wrote, with an explanation to follow.

require 'rubygems'
require 'hpricot'
require 'open-uri'

url = 'http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/'
document = open(url) { |f| Hpricot(f) }

document.search('a') do |a|
  if a[:href] =~ /.avi.torrent/ then
    open(File.basename(a[:href]), 'wb') do |f|
      f.write open(url + a[:href]) { |f| f.read }
    end
  end
end

The above code makes some fairly heavy use of blocks, one of my favourite features of Ruby.  The code is fairly straight forward if you understand that functions and blocks implicitly return the result of their last expression.  Here's a play-by-play of what's going on:

  • Lines 1-3: A few libraries are loaded.
  • Line 6: The web page containing the links I want to read is loaded and parsed.  Since the block being passed returns the result of its last expression the document is returned.
  • Line 8: The document is searched for all of its links.  For each of the elements found the passed block is executed.
  • Line 9: Weed out any links that don't target the files I'm looking for.
  • Line 10: Open a local file to write the contents of the file pointed to by the link.
  • Line 11: Read the target of the link.  The result of the block passed will be written to the local file.

That's it.  15 lines of code and I didn't have to click a single one of the links.  Yes, I probably could have done it faster manually, but by taking the time to write a script this little task is a great saw sharpening exercise and the amount of productivity gained from that is well worth the investment of time.

Saturday, February 6, 2010

Integrating Growl - A Quick Start Guide

As promised, here is a quick start guide to integrating Growl support into a Cocoa application. The documentation expects that you've worked with Xcode before and are familiar with creating new build phases and writing Objective-C code. For the impatient and those that just want to play around I've created a gist with the project. You'll probably want to clone the project instead of looking at it online because it contains some binaries..

git clone git://gist.github.com/297221.git gist-297221

The first thing you'll need to get started is a copy of Growl.framework. As of this writing the latest is version 1.2. Once you have a copy of the framework you'll need to link your application against it. To do so, simply drag and drop the framework onto the Linked Frameworks item in your Xcode project. Since the framework will need to be shipped along with your application you'll also need to ensure that it gets copied into your application's bundle. Create a new Copy Files build phase for your application's target, make sure that you set the Destination to Frameworks. Drag and drop Growl.framework from Linked Frameworks to the newly created build phase. At this point your application will compile against the framework and include it when building.

The next thing you'll need to do is create a plist file called Growl Registration Ticket.growlRegDict containing the registration information that will be required by the framework. Below is an example of such a file. You'll need to make sure that this file makes it into the application, this can be done by ensuring that its in the Copy Bundle Resources build phase.

In order for Growl to allow your application to send notifications you'll need to register the notifications that your application will be sending with the framework. To do this you'll need to create and implement a bare-bones delegate. All that's required is that you implement the (NSDictionary*) registrationDictionaryForGrowl method. The implementation of this method will simply need to return a dictionary whose contents come from the plist file created previously. The body of this method can be as simple as:

- (NSDictionary*) registrationDictionaryForGrowl {
   NSString* path = [[NSBundle mainBundle] pathForResource: @"Growl Registration Ticket" ofType: @"growlRegDict"];
   NSDictionary* dictionary = [NSDictionary dictionaryWithContentsOfFile: file];
  return dictionary;
}

Once this method is implemented, and an instance of the class is set as Growl's delegate by calling [GrowlApplicationBridge setGrowlDelegate: X] you'll be able to send messages to Growl using [GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky]

That's about all there is to it. It's a fairly simple framework to integrate with, but the documentation neglects the fact that you have to implement (NSDictionary*) registrationDictionaryForGrowl

An example project exists as a gist on github.

git clone git://gist.github.com/297221.git gist-297221

Thursday, February 4, 2010

Trials and Tribulations with Growl

A few nights ago I had just finished getting the core piece of a new application I started working on. It occurred to me that my little application and its users would benefit from having Growl support. It was pretty late, midnight or so and I didn't want to be up much later so I just downloaded the framework and had a quick skim of the developer documentation. It seemed pretty simple, but it was late and I knew that if I started that late I'd be up few a few more hours getting no where and end up going to bed feeling defeated. "Tomorrow, " I thought, "I'll do this tomorrow. If its as easy as the docs say then I'll have enough time to add at least 2 other features!".

I got up the next morning feeling great, I knew that come that evening I'd have integrated Growl support. Evening rolled around and I sat down and got to work. I re-read the documentation...well, skimmed is more acurate, and started following the instructions. I created the plist file containing the information that the documentation said I needed. I added a build step to copy the plist to my application's Resources directory. I double checked the name of the file -- the documentation says it's case-sensitive. I linked Growl.framework to my application. I added a build step to copy the framework to my application's Frameworks directory. And lastly I added the code from the documentation to send a notification to Growl ensuring, of course, I was sending one of the notification names that was in my plist file.

I clicked the Build and Run button, and my application compiled and my application's Dock icon started to bounce. By this point I felt like a kid at Christmas. I'd written my letter to Santa, stuffed it in an envelope, and very carefully, in my tidiest printing I wrote the address: "North Pole." I placed my stamp and tossed it in the mailbox. My letter must have gotten there, it hadn't been returned to sender so I knew that good stuff was heading my way.

The Dock icon stopped bouncing and my application's window opened up. "This is it, " I thought to myself "the moment of truth!" I clicked the button to fire off the notification aannnddd...nothing.

Silence.

"That's ok," I thought "it's probably some silly little thing I did wrong."

I looked at my run logs and they were eerily quiet. No messages at all. Surely if I'd done something wrong the framework would tell me. That must mean that the framework didn't get copied to my application's bundle. But if that's the case, then shouldn't there have been an error in the log about my code trying to perform a selector on a class that didn't exist? So that must mean that my code that posts the notification was never called. This sounds like a job for Captain Breakpoint!

I placed a breakpoint on the first line of my method and started the application again. Application startup under the debugger always takes longer so I was caught off guard when my application's window opened up. I moved my mouse cursor over the button, knowing that I was one mouse click away from finding out that my code wasn't being called thereby giving me all the information I'd need to fix the problem. My eyes narrowed as I pressed the button.

Half a second later I was staring at the Xcode debugger, my line with the breakpoint highlighted and a stack trace showing me that execution was indeed stopped in my method. I felt totally disarmed like I'd just gathered up my courage to tell that guy what I really thought of him only to be knocked off my feet by an overpowering wall of cheap cologne.

"What...the...what?"

I gingerly stepped through the method stopping just shy of executing the line to post the notification. Pausing for a second to think about what could possibly happen next. If the debugger tosses me out of my method, I know that either the framework doesn't exist or my parameters are causing it to barf. If the debugger stops and the next statement in this method...well that doesn't sound easy to debug, so lets hope that doesn't happen. I stepped over the line and found myself looking back that beautiful line of code just after the call into the framework.

This doesn't make sense. The framework accepted my parameters without problem, ostensibly did something with them and succeeded. So what could it possibly be? The framework didn't log anything, so it must not be a problem with my code. But no notification showed up, so the problem must be that Growl just isn't running. At that moment notification showed up in Growl -- but not from my application.

"Well, if other apps can send notifications then it's gotta be something I'm doing wrong." Since the documentation told me that all I needed to do was create a plist file and make sure it was in my application's Resources folder I figured I'd double check, and sure enough it was there. I'd just been banished to developer's purgatory where I have to debug configuration..

I thought to myself, "If my application has to have one of these plists, then other apps must have to have them too!" The first few applications I found didn't have one of those plists and they were working just fine. Finally I found an application that had a plist. So I compared them to make sure I'd done it right and sure enough I found a problem with my configuration. I updated my file, saved, built and ran the app again. My application's window popped up and I clicked the button and this time...nothing happened...again.

Silence.

Not believeing that it was something that I'd done I cleaned, rebuilt, and ran the application a few times knowing that it shouldn't make any difference in the world but hoping that it would just magically start working. After several runs in vain I figured that maybe The Google would have an answer for me. Sure enough, after trying a few google-y incantations I found some source code buried on a page that showed how to initialize Growl implementing a delegate method. I modified my code in a similar way, saved and ran again. I clicked the button and was surprised to see my little notification appear on the screen - only an hour after I started.


Truth be told, the Growl documentation did mention that one could would have to implement a delegate if you were attempting to talk to Growl 0.7, but since my code was running against 1.2 I didn't think I'd need to. In any case I managed to get it to work, but not without some frustrations that could have very easily been avoided had the Growl team produced some other artifacts that were as easy to find as the developer's documentation.

The first of these is some sort of a quick-start guide that just provides the bare minimum steps that are needed to use the framework. The developer's guide was littered with documentation about old versions. I don't need to know that stuff. Just assume that I have the latest and tell me exactly what I need to do.

Another thing that would have really helped, especially for developers that like to get dirty is a downloadable example. I'm sure they have one somewhere, but I wasn't linked to from their documentation so it effectively didn't exist.

Last lastly, but certainly not least is some level of logging in the framework itself. This would have been immensely helpful since I'd be able to tell if the framework was finding my plist or not, or whether there was a problem with my parameters. Don't just leave me to figure it out on my own, give me some help!

I hope what I'm saying doesn't label me an Open Source Douchebag. Honestly, I'm really just trying to improve the project by making it easier to get people up to speed. And in the next few days (hopefully) I'm planning on uploading some sample code along with a quick-start blog post.

Thursday, January 28, 2010

On Subclassing

And now for another excursion into the depths of my experience and thinking about object oriented design and philosophy. This time I'm going to talk about some pitfalls I've seen with one of the most commonly used, and abused tools in the object oriented developer's toolbox: subclassing and access modifiers.

Subclassing has been around since the dawn of objected oriented programming. It's just one of many ways to enhance code reuse, but I've seen enough blood shed due to the misuse of this feature that I've stopped using it in cases where I can get away with another approach. The core of the problem with subclassing tends to be an eagerness to reuse as much code as possible without any consideration of how code reuse decisions will effect the overall design. Yes, reusing code means that there are fewer places to change when a change must be made, but subclassing is a merely a means to an end. There are other, better approaches that give the same benefits without the problems.

So what are some of the problems with subclassing? I think the central failing is that subclassing is the most tight form of coupling there is. When you decide to subclass an implementation, you've solidified part of your implementation. A common word of wisdom is that you should always code to interfaces so that implementations can be changed at a later date with a minimal of fuss. By subclassing an implementation you are publically declaring that you are and always will be a subclass of X.

Another problem with subclassing is that you cannot narrow the interface of the class to anything smaller than the subclasses interface, even if it doesn't make sense. A textbook example of this in Java is the java.util.Stack class. java.util.Stack extends java.util.Vector which in turn extends java.util.AbstractList which is an abstract implementation of java.util.List. The java.util.List interface contains methods such as add, get, indexOf, etc. If you've followed along that means that java.util.Stack, in addition to its own interface also has these methods. A stack should really only have two methods for mutating the stack (push and pop) and perhaps some methods to determine how many items are on the stack. By subclassing, java.util.Stack has guaranteed that it implements the java.util.List interface and therefore has methods that allow a developer to work around the stack encapsulation. Ah, but you can override those methods in the subclass with ones that do nothing or throw a java.lang.MethodNotImplemented exception. Certainly you could, but then if an instance of java.lang.Stack was passed to a method that accepted java.util.List it would not produce the desired result -- either by throwing an exception or not performing the operation.

No discussion of subclassing would be complete without mentioning the Liskov Substitution Principle. I think it's great advice it theory, but as we've all seen it's not exactly easy to follow. If the JDK developers can make such an error with all of their review process, how does a lowly developer stand a chance?

Aside from these problems there's always the minefield of access modifiers. In my opinion there should really only be 2 at the class level: public and private. Protected variables are a major cause of headaches since subclasses can easily muck around with the internals of a superclass, violating encapsulation. Protected methods provide a second interface to the class which has to be maintained and documented -- as if a single interface wasn't enough problems. So, private and public is really all that's needed - stuff that's internal and stuff that's public.

So if not subclassing then what? In a word delegates, specifically the delegation pattern. With the delegation pattern you simply implement interfaces, if applicable, and delegate parts of the implementation to a concrete class. By doing so you don't have to expose any information about how your class works internally. And since you're not subclassing you don't inherit interface that doesn't make sense for your class. As an added bonus, since you're using the public interface to the concrete class you don't have to worry about methods internal to the implementation changing or becoming deprecated.

Delegates are also an effective strategy for reusing code. You can encapsulate logic into a single class and use it from anywhere in your application. This is a great benefit when you have an irregular class heirarchy, it effectively gives you mixins without the headaches of trying to figure out which pieces of implementation are coming from which mixin.

Obviously there are times when subclassing is the right thing to do. But in my experience I see it used much more often than it should be and usually for the wrong reasons. I hope my thoughts have given you something to think about next time you reach for that subclassing hammer.

Saturday, January 16, 2010

First Impressions of Cocoa

Over the past few months I've been doing a lot of playing around with development on the Mac using Cocoa. Although I do disagree with some of the design decisions that have been made, but for the most part I really like both Objective-C and Cocoa. The developer community is extremely vibrant and very helpful, a feeling I haven't had elsewhere.

One of the things I really like about Cocoa is that it handles a lot of the mundane tasks for you. There's a technology called CoreData that handles object graph persistence. You simply setup your data model and the framework takes care of the rest. This is really great since one initial hurdle I always run into when coding, and where I usually lose steam is in persisting and reading data that my application is working with, CoreData takes care of this beautifully.

Another great technology is Bindings which is built on top of Key-Value-Coding and Key-Value-Observing. In essence, Bindings allows you to visually tie the value of a control to a piece of data in your data model. This removes the need for reams of "glue" code that you'd otherwise have to write to keep your View and Model consistent. With these two technologies all you really have to do is write your Controllers.

Granted, the Controller is generally where the rubber meets the road, but since the frameworks take care of the Model and View you're free to think almost exclusively on the problems and structure of the Controller.

So far I've been really happy with the results that I've been able to achieve with only a small time investment. Between the results and how supportive the developer community is I think the Mac is a great platform to develop for and look forward to doing so in the future.