WWDC 2005 Wrap-Up

WWDC 2005 is over, and *damn* was it a great week! Apple made some incredible announcements and shipped some incredible software, I got to see lots of old friends and make a lot of new ones, and I got to talk to lots of developers about things that I’m passionate about: Core Data, unit testing, setting up and streamlining your build process, and creating insanely great software to make users’ lives better.

It was a wonderful, wonderful time. Thanks to everyone!

Unit testing and Core Data

Mike Zornek asks about unit testing and Core Data. I’ve been meaning to write about this, so this is the perfect opportunity to do so.

Writing unit tests against your model and code that uses Core Data is easy. For example, it’s trivial to load your compiled model in a unit test:

NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];

Not only that, but you can introspect it:

NSArray *entities = [model entities];

And you can do this all the way down to the property level. This means that it’s possible to assert that your entire model is set up the way you expect it to be. For example, you can make sure that your Employee entity has a mandatory salary attribute with a minimum value of 1 and a type of NSDecimalAttributeType, and descends from a Person entity that has a mandatory name attribute with a minimum length of 1 and a default value of “name.”

But how do you test your use of Core Data? You just use Core Data in your tests as you would in your project. For example, to instantiate a complete Core Data “stack” (as it’s sometimes referred to):

NSManagedObjectModel *model;
NSPersistentStoreCoordinator *coordinator;
NSManagedObjectContext *context;

model = [[NSManagedObjectModel alloc] initWithContentsOfURL:urlToModel];
coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];

To instantiate managed objects associated with that context from entities in your model:

NSManagedObject *employee;

employee = [NSEntityDescription insertNewObjectForEntityForName:@”Employee”
inManagedObjectContext:context];

This gives you an autoreleased Employee (assuming your context’s coordinator’s model has an Employee entity, of course). It’s that easy.

You can then do things like check that this object was created with the correct defaults (e.g. the ones specified in your model), that it posts KVO notifications properly for properties where you care about such things, and so on. You can even add a persistent store to the coordinator and test that saving and loading work (and don’t work when they’re supposed to fail, of course) just by using normal Core Data and Foundation APIs.

You can multiply the full power of data modeling with the full power of unit testing and test driven development. It kicks ass.

Core Data: Generating an interface for an entity

The new Core Data framework and Xcode 2 modeling tools in Tiger are an extremely powerful way to develop great end-user applications quickly. You can even easily generate a human interface for your application that will let you work with its data model with little to no code.

To generate an interface, create an empty window in Interface Builder and make sure you’ll be able to see it with Xcode in front. Switch to your model in Xcode. Then just option-drag the entity you want an interface for into your window. Interface Builder will ask you whether you want an interface for one or many instances of that entity, and then generate a basic form-style human interface for all of the attributes and to-one relationships in that entity.

This generated interface isn’t a special monolithic “NSCoreDataControl” or anything of the sort. it’s composed of standard Cocoa controls that wired to standard Cocoa controllers via bindings. If your nib file’s owner is set to be an instance of NSPersistentDocument or a subclass, Interface Builder will even bind the controllers’ managed object contexts to the document’s.

If you just want to create controllers rather than full interfaces, or if you want to update the controllers in your nib file with the latest definition of your entity, drag the entity from your model straight to your nib’s document window. (That’s the one with the tabs for classes and instances etc.)

Note that none of this, none of this requires generating or writing code. You can create a new Core Data Document-based Application from the project template, create a data model for it in Xcode, create an interface for it in Interface Builder, and then build and run it. You can create, save, load, and manipulate documents and even undo and redo changes and avoid saving invalid data with no code.

Code Width

There’s a question on wrapping code at 80 columns in the Joel on Software Forum. Most of the time, when I see 80 columns as a standard it’s to enable easy printing of the code. However, in this day and age, why are you printing code? I print code occasionally when I need to read it in-depth, but other than that I do most of my reading on-screen. It’s certainly not a regular occurrence.

I also use mostly large or widescreen displays for coding. The smallest display I use regularly is my laptop, which is 1152 by 768. Most of the time I use my 19-inch monitor, which I run at 1600 by 1200. As a result, if I want to write really long lines, I can. But I don’t.

I generally limit the length of lines I write to 80 to 120 characters. Most of the time this is easy, because Objective-C’s syntax lends itself to very readable multi-line expressions:

NSDictionary *d = [NSDictionary dictionaryWithObject:@"Chris"
                                              forKey:@"name"];

The main reason I do it, though, is that I use multiple windows while I code. I usually have at least 6 windows open in Xcode while I’m coding: The Xcode project itself, the source and header file for the class I’m working on, the source and header file for the unit test I’m working on, and the build results window (which also shows my unit test results). Often it’s much more, with more class and unit test sources & headers open. And it’s much easier to fit these windows all on a screen when they don’t need to be as wide as the screen to see their contents…

Joel Spolsky’s Bionic Office

In the latest installment of Joel on Software, Joel talks about his new office.

I like a lot of what he’s done with it. It’s largely the kind of space I’d design. I might or might not have private offices, now that I’m starting to buy into XP more, but I definitely like a lot of what I see.

This amused me, though:

> The monthly rent for our offices, when fully occupied, will run
> about $700 per employee. The build-out was done on budget and paid
> for almost entirely by the landlord. I suspect that $700 per person
> is on the high side for software developers throughout the world,
> but if it means we can hire from the 99.9 percentile instead of the
> 99 percentile, it’ll be worth it.

I strongly expect it’s actually on the low side, at least in large corporations.

Joel says each employee is getting about 425 rentable square feet, at a cost of $700 per month. That’s about $20 per square foot per year. That’s low for Class A office space, at least in some markets. Like, say, Schaumburg.

(Though with 53,255 square feet available in Zurich II, and a couple of newly-built office towers standing vacant, and a bunch of other Class A space vacant, perhaps Schaumburg rents have come down since I last looked in 2001…)

I knew it wasn’t all puppies and rainbows!

[Joel on Software][1], “[Local Optimization, or, The Trouble with Dell][2]”

> Unfortunately, the dirty little secret about Dell is that all they have
> really done is push the pain of inventory up to their suppliers and down
> to their customers. Their suppliers end up building big warehouses right
> next to the Dell plants where they keep the inventory, which gets
> reflected in the cost of the goods that Dell consumes. And every time
> there’s a little hiccup in supplies, Dell customers just don’t get their
> products.

This isn’t the only problem with Dell. Their other big problem is that they’re constantly starting price wars, which keep driving down their margins further and further, which makes not only their products but all of their competitors’ products crappier and crappier. It also fuels the delusion that price is the only factor that customers use when selecting a supplier. It’s a race to the bottom that nobody wins.

[1]: http://www.joelonsoftware.com/
[2]: http://www.joelonsoftware.com/news/20030115.html

Platform Futures

On Windows, many developers seem to want to run as fast as possible away from Microsoft Visual C++ and embrace Microsoft’s C# and .NET platform for new development. Most Windows developers that I’ve seen seem downright enthusiastic about these technologies. It’s disconcerting; I’m not used to seeing Windows developers (or users) be enthusiastic about their platform.

On the Mac, many developers are trying to hold onto C++ and Carbon for as long as they can, even for new development. A new Mac developer on the Carbon list actually said he wished Apple had a C++ framework that used MFC-like “message maps” for Mac OS X-only Carbon development “to make it easier to build software fast!” (Paraphrased.) And Metrowerks is spending money & time building a next-generation C++ PowerPlant framework for Mac OS X-only Carbon development! And some developers keep on Apple’s case to try and maintain feature parity between Carbon and Cocoa.

Fortunately, Apple isn’t giving in to them as much as they might think. For instance, WebKit has a Carbon wrapper, but it’s just a wrapper; WebView is really a Cocoa framework and if you want to extend it you’re going to have to use Cocoa. The Cocoa Controller layer is only really possible to do with a rich dynamic runtime; it’ll never make it to Carbon. You can only build screen savers using Cocoa and Objective-C. You can only build preference panes using Cocoa and Objective-C. Virtually all new applications coming out of Apple are built using Cocoa and Objective-C.

(Keynote, SoundTrack, LiveType, iCal, iPhoto, iSync, iChat AV, Safari… Final Cut and Logic don’t count, since they ware originally developed for the traditional Mac OS and thus aren’t new. Neither does Shake, since it was originally developed for Irix and X11 — though it wouldn’t surprise me at all to see it rearchitected as a Cocoa application in the next couple of years.)

The future of development on Windows is C# and .NET. This has been clear since Microsoft first released .NET, and it’s especially clear in light of the latest PDC and Longhorn.

The future of development on the Mac is Objective-C and Cocoa. This has been clear ever since Apple bought NeXT, and it’s especially clear in light of the latest WWDC and Panther.

Deal with it.

Joel still doesn’t get it

A couple days ago in [Joel on Software][1], Joel claimed that in order for it to make economic sense to develop a Macintosh product, you had to be able to sell *25 times as many* copies as you would a Windows product.

**Bullshit.**

First of all, you can’t just assume that the relative market sizes between the Macintosh and Windows are accurately represented by their market shares. This is partly because market share is a measurement of new computer sales rather than installed base, and partly because there are broad swaths of each market that *aren’t* in the market for your application.

Secondly, it presumes that it costs the same to develop and bring to market a Macintosh product as it does to develop a Windows product. It doesn’t. It costs substantially less. The development tools on Mac OS X are the best on any platform, and speed development significantly; very small teams can create high-end applications in very short timeframes. There is a far smaller test matrix when you’re dealing with Macintosh software, and within that matrix there are far fewer bizarre interactions. There is significantly less competition in the Macintosh market, so you don’t have to spend as much on marketing and promotion of your product. Consumers also don’t have to wade through nearly as much complete garbage to discover the good applications.

Finally, you have to consider post-sales support. The support load presented by Macintosh software is also far lower than for the typical Windows product. This means lower post-sales costs, which means you get to keep more of the revenue generated by the product.

All this adds up to an excellent ROI story for Mac OS X development. You may still have the potential for a higher return on a Windows product, but you’ll also have substantially higher costs, a longer development timeline, and correspondingly greater project risk. All sides need to be weighed before deciding whether it’s worth pursuing one platform or another – you can’t just do a couple bogus back-of-the envelope calculations and decide you need to sell 25 times as many units to make Macintosh development worthwhile.

[1]: http://www.joelonsoftware.com/news/20020910.html

Open Source Human Interface Design

Peter Trudelle, Shall We Dance? Ten Lessons Learned from Netscape’s Flirtation with Open Source UI Development (CHI 2002 – Getting to Know You) We wound up spending longer getting requirements in the form of bug reports, and doing design by accretion, backout and rework. Don’t let rushed coders drive things, design the product. [via Joel on Software]

I don’t agree with Joel that it’s impossible to do good design with a geographically distributed team. I think it’s entirely possible for distributed collaboration to work. The big problem with Mozilla was too many cooks spoiling the broth; everyone thought they were a human interface expert, and everyone had different goals, and everyone pushed as hard as they possibly could to achieve their goals. A small, tightly focused team would have done just fine, even if they were distributed.

I really, honestly believe in the effectiveness of distributed collaboration, when it’s done properly. But trying to do human interface design with in an open and ever-changing and questionably-qualified group doesn’t sound like a recipe for success.

Joel Climbs Into the Trunk

Joel is smoking the good stuff! Or is he drinking the purple stuff?

Joel Spolsky of Joel on Software is actually claiming “.NET appears so far to be one of the most brilliant and productive development environments ever created.” He goes on to say “ASP.NET is as big a jump in productivity over ASP as Java is to C. Wow.”

Living inside Microsoft’s locked trunk for too long obviously ruins your sense of perspective. They’ve been steadily improving their tools over the years, but they started in such a truly awful state that what they have now seems like absolute luxury to Windows developers. If these people would bother to look outside their cramped quarters occasionally, they’d see that they really, honestly don’t have it very well off at all.

Here’s a choice quote:

I love the fact that you can use an ASP.NET calendar widget, which generates HTML that selects a date on a monthly calendar, and be confident that the “date” class you get back from that thing (System.DateTime, I believe) will be the exact same date class that the SQL Server classes expect. In the past you would not believe how much time we wasted doing things like reformatting dates for SQL statements, or converting COleDateTimes to someOtherKindOfDateTime.

I’d believe it because I’ve seen the kind of crap you have to go through to get anything done with Microsoft’s development tools and programming interfaces. In fact, I’ve written ported Macintosh software to Windows with them, and even tried to build Macintosh software with them (using their terrible Macintosh MFC SDK). It’s amazing Windows developers are ever able to get anything done.

Contrast that to OpenStep, WebObjects, and the Enterprise Objects Framework circa late 1995. There is one date class, NSGregorianDate. You didn’t have to write low-level code to access databases, so you didn’t have to worry about turning dates into strings you could embed in SQL statements. Instead, your Enterprise Objects – objects transparently backed by your database could just have attributes containing NSGregorianDate objects and The Right Thing would happen automatically.

As I read through this, I find more and more absolutely laughable comments. For instance:

First, they had the world’s best language designer, the man who was responsible for 90% of the productivity gains in software development in the last 20 years: Anders Hejlsberg, who gave us Turbo Pascal (thank you!), Delphi (thank you!), WFC (nice try!) and now .NET (smacked the ball outta the park).

Yes, the creator of Turbo Pascal is responsible for all of our productivity gains in software development. Especially since, even though Joel credits him as a “language designer” he didn’t really “design” Pascal or Object Pascal. Not, say, Alan Kay, leader of the team that invented true Object-Oriented Programming in the 1970s at Xerox and popularized it in 1980 with Smalltalk-80. Then again, that’s 22 years ago – maybe it doesn’t count (since Joel said “20 years”), even though industrywide movement to OOP didn’t really have critical mass until the 1990s…

Perhaps with .NET, Microsoft is only 5 years behind where NeXT was in 1995 with OpenStep, WebObjects, and the Enterprise Objects Framework. But they’re still 5 years behind where NeXT was, and now that NeXT has funding – in the form of millions of Apple Macintosh users running Mac OS X – they’re starting to move ahead quickly. If they can bring back the Objective-C version of EOF for Cocoa, they’ll be way ahead of the game.