Mac OS X Developer Mailing Lists
[info]chanson

I just figured I would take some time out for a public-service announcement.

If you're developing Mac OS X software, you should really be on the appropriate developer mailing lists. Apple hosts a number of mailing lists at lists.apple.com and hosts archives there too. The lists are managed with GNU Mailman and have its convenient subscription and administration interface.

In my opinion, the principal lists for application developers are:

carbon-dev Developing software with the Carbon framework.
cocoa-dev Developing software with the Cocoa framework.
java-dev Developing software for Mac OS X in Java.
webobjects-dev Developing web applications with WebObjects and EOF.
xcode-users Using the Xcode Tools suite for Mac OS X development.

There are also a whole lot of task- and technology-specific lists, including lists for developers implementing AppleScript support in applications, developers working with networking, developers creating device drivers, developers writing multithreaded applications, developers working with Xgrid...

Be sure to look through the list of lists to see what else you can take part in.


DBKit .NET
[info]chanson
Evidently Microsoft has a partial clone of the Enterprise Objects Framework for .NET, called ObjectSpaces. Or perhaps it's more of a clone of the old NeXT DBKit, or EOF 1.1.

It looks pretty simple to use at first glance, but also seems pretty unsophisticated. For instance, it doesn't seem to have the concept of an editing context, only data stores. Editing contexts are very powerful; they provide sandboxing, interaction with a data store, undo support, and generally manage your enterprise object graph. Also, it looks like queries are just strings in a special query language; there didn't seem to be a use of anything like qualifiers or fetch specifications.

Granted, I was looking at a very simplistic demo of an earlier release. ObjectSpaces is still under development and is supposed to be shipped with a later release of .NET; it's something else that's going to be talked about at the Microsoft PDC.

I wonder how hard it would be to knock out something similar in Objective-C.

I wonder if Apple's going to have an object-relational mapping framework for Cocoa before Microsoft ships ObjectSpaces.

Microsoft PDC Prediction: Avalon
[info]chanson
Lots of people in the weblog universe are talking about the upcoming Microsoft Professional Developers Conference in Los Angeles. The PDC is where Microsoft is going to be shipping their first development release of Longhorn, their successor to Windows XP.

There are a whole lot of code names being used for various different parts of Longhorn. Aero, Avalon, etc. Just keeping track of the code names is a full-time job.

One of these, Avalon, corresponds to some new application framework that people like Scoble keep hinting will make the browser obsolete. They say it'll do this by turning the operating system into some sort of fancy information environment. Here's my prediction for what Avalon really is...

I think Avalon will do the following: First, it will let developers specify their application's interface via XML, probably through a graphical interface editing utility. Second, it will let developers bind model objects directly to interface elements. Third, it will let these model objects reside — somewhat transparently — on a server, rather than on the client side. Fourth, it will exist as a runtime that is included in Longhorn, so an actual Avalon application will consist of an assembly containing only the XML interface files and the code for the model objects or model object proxies.

In short, Avalon will be an implementation of something Apple has had for several years now: WebObjects Java Client. With Java Client, you build your interface in Interface Builder, which generates an XML file. You use the EOInterface framework to bind interface elements directly to model objects and operations on them (queries etc.). The model objects live on a WebObjects application server, but they can have custom client-side proxies that you can add your own logic to. The Java Client runtime is a jar file that can either be downloaded to the user's machine as necessary via Java Web Start or as a Java applet, or it can be installed directly on a client machine.

There are two twists to this: Java Client works pretty much anywhere you have a Java 2 Standard Edition 1.3.1 or later virtual machine. That means you can deploy Java Client applications to Mac OS X, to Windows, and probably even to Linux and Solaris and all sorts of other platforms. More importantly, though, Java Client is itself just a foundation for Direct to Java Client.

Direct to Java Client automatically generates Java Client applications on the fly from a data model and a collection of business rules. You can customize the objects used in the data model and you can customize the business rule set to customize your application; you don't need to spend your days in Interface Builder laying out interfaces for CRUD (create, read, update, delete) applications.

Avalon sounds like great news for Windows desktop application developers. After all, in 2006 they'll be able to get benefits that have been available since the late 1990s with WebObjects!

New BDControl, BDRuleEngine, and BDRuleEditor
[info]chanson
Jon reminded me tonight that I needed to post about this somewhere.

I shipped new versions of the Open Source BDControl and BDRuleEngine frameworks and the BDRuleEditor application. They're all targeted developers writing Cocoa applications in Objective-C on Mac OS X 10.2 or later. They'll probably build just fine and be usable on Mac OS X 10.1 as well, but they're built for 10.2 now. They're on the bDistributed.com web site as separate source and binary tar archives, except for the actual BDRuleEditor binary.

There's a major API change in BDRuleEngine 1.1 that isn't backwards-compatible with BDRuleEngine 1.0. It corresponds to a change in the ruleset format. There's a couple new methods that can load old-format rulesets, but all writing uses the new format. The new version of BDRuleEditor understands both formats and will automatically convert a ruleset if you open it and save it.

There's another major change to both frameworks: They're built solely to be embedded in applications. That is, they're built with their internal install path set to @executable_path/../Frameworks rather than /Library/Frameworks. You can put them in /Library/Frameworks or in ~/Library/Frameworks or pretty much wherever you want, and they should work just fine so long as you add a "Copy Files" build phase to any project that uses them to embed them in the resulting package.

Oh, and finally, the new release of BDRuleEngine adds an additional BDAssignment subclass: BDPropertyListAssignment. If you create a BDPropertyListAssignment and specify its value as the string (either old-style or XML) representation of a property list, it will automatically convert the property list to an actual property list object of the appropriate type. This is very handy when you need to return collections of values from fired rules, for instance, the property keys to display for a particular type of object:
R1. inspectedObject.class.name = 'ClassA'
    => displayedPropertyKeys = "(foo, bar, baz)" [100]

R2. (inspectedObject.class.name = 'ClassA') and (inspectorType = 'overview')
    => displayedPropertyKeys = "(foo)" [100]

If the right-hand side of the above rules was a regular BDAssignment then the result of asking for displayedPropertyKeys would just be a string. But with a BDPropertyListAssignment it's an array containing some strings. Keen, huh?

I think that's it for the major changes. For more detail, see the release notes in the documentation.

Life without EOF sucks
[info]chanson
How does anyone have the patience to write a database-backed application without the Enterprise Objects Framework?

I mean, really. It's so damn convenient, and you wind up reinventing a good chunk of it anyway, why not just use it in the first place? Or at least use a framework that's somewhat equivalent like Hibernate or Cayenne. Or even TopLink...

(If you can't tell, I'm being frustrated by the lack of EOEditingContext right now. Quite frustrated. Also the lack of faults, and transparent relationships.)

Enterprise Objects
[info]chanson
The Enterprise Object technology provides a set of flexible, modular, and mature object-oriented frameworks that allow you to build data-driven applications without needing to worry about an application’s data sources. It allows you to work with objects rather than directly with the data source, which reduces development time, reduces the amount of code you need to write, and allows you to build reusable, portable business objects that can be shared between many different applications.

That's an excerpt from Enterprise Objects, a new bit of WebObjects developer documentation that's been sorely needed for quite a while. Lots of us OpenStep and WebObjects developers rave about how cool the Enterprise Objects Framework was; now there's a good place we can point people to and say "See?"

One thing that's jarring in the document is that Apple is apparently changing the name of EOF: It's now just "Enterprise Objects" and is used as a modifier, as in "Enterprise Objects frameworks." (Yes, they say "frameworks" rather than "framework" — I suppose because EOF is really made up of EOAccess, EOControl, and EOInterface.) This is probably for trademark reasons; trademarks can't be nouns, only adjectives or adverbs. (So that's not a Kleenex® you're using, it's a Kleenex® facial tissue.)

(Thanks to Jim Roepcke for the pointer! I hope we can both make it to WWDC this year, Jim...)

BDControl 1.0.4, BDRuleEngine 1.0.1, and BDRuleEditor 1.0.1 released
[info]chanson
I've released BDControl 1.0.4, BDRuleEngine 1.0.1, and BDRuleEditor 1.0.1. The big difference is that the frameworks are built with an "install path" of /Library/Frameworks, and that BDRuleEditor references the frameworks in /Library/Frameworks instead of the frameworks in the build products folder. This means it doesn't expect its frameworks to be in /Users/cmh/Documents/Projects/BDModel/BuildProducts, which 99.999% of users won't have on their systems...

It turns out that even with the Jaguar developer tools Mach-O binaries still store full paths to frameworks they reference. This is because Mach-O is shit. The Preferred Executable Format developed by Apple in the early 1990s for the PowerPC doesn't have this problem; it stores the internal name of any library a code fragment is linked against, instead of a full path to the file containing that library or even the name of the file containing that library. This makes it robust in the face of name changes to the library file, the location of the library file (so long as it's in the library search path), etc.

Then again, PEF and CFM are just generally superior to Mach-O and dyld. Unfortunately, people who I would think would know better - the people that brought the world WebObjects and Cocoa - still just don't get it. (Of course, these same people still haven't brought back EOF for Objective-C despite massive amounts of want from the developer community and a willingness to pay money for it so...)

BDRuleEngine 1.0.0 & BDRuleEditor 1.0 Released
[info]chanson
I just shipped BDRuleEngine 1.0.0, an Open Source framework that provides Cocoa developers with the ability to develop business rule-driven applications. BDRuleEngine requires BDControl 1.0.3 or later, another Open Source framework I released a couple weeks ago.

I also shipped a simple application for editing rule sets, BDRuleEditor. BDRuleEditor requires BDRuleEngine 1.0.0 or later and BDControl 1.0.3 or later.

The rule system works by letting you specify rules, supply some initial data in a context connected to those rules, and then ask that context various questions about that data.

Rules have the form
(condition) => keyPath = value [priority]
where condition is a qualifier object. (See the description of BDQualifier in the BDControl documentation for details; in short, qualifiers are object-oriented predicates.)

For instance, a couple rules for an adventure game might include:
  (torch.burning = false)
    => exitsVisible = () [100]

  (torch.burning = false)
    => description = "Your torch is out.  You can't see a thing." [100]

  ((room.name = 'mainHall') and (torch.burning = true))
    => exitsVisible = ("north", "south", "west") [100]

  ((room.name = 'mainHall') and (exit = 'north'))
    => description = "There is a door to the north." [100]

  ((room.name = 'mainHall') and (exit = 'north') and (exit.open = true))
    => description = "There is an open door to the north." [100]

To start with, you'd create a context linked to the above rules and set whatever data you needed. For instance, you'd set the context's "torch" key to your torch object. Then you ask the context for a value, such as "description". When you ask for that key, the rule system finds the most applicable rule given all of the data in your context that has that key on the right hand side of the =>, and returns the value for that key.

Thus if your torch is initially not burning, asking the context for the value of the exitsVisible key would return an empty array, and asking for the value of the "description" key would return "Your torch is out. You can't see a thing." regardless of what room you're in. When you turn your torch on, asking the context for the value of either key will instead return the appropriate value depending on the name of the room you're currently in.

Priorities are used to differentiate among equally-applicable rules; the rule with the higher priority is the one that's fired.

BDRuleEngine uses Objective-C's introspection features via the key-value coding mechanism to work its magic, so you don't need to do anything special in your own classes to be able to use them with the rule system.

BDControl 1.0.2 update
[info]chanson
Very early this morning, I shipped version 1.0.2 of the BDControl Framework. Version 1.0.1 had a couple bug fixes and a couple new APIs, while version 1.0.2 has three bugfixes. Thanks to James Corrigan for pointing out the leak that I fixed in version 1.0.1.

I'm working on a new and even cooler framework for Cocoa developers right now, and I just got the first test case up and running. (Part of doing that was fixing the bugs in version 1.0.1 and producing the version 1.0.2 release.) I'm confident that I'll be able to release my new framework soon, though I may need to hold off on its release a little so I can create a desktop application to go with it. My new framework lets you do some useful things in a very data-driven manner, and having a nice editor for the data that drives it will make it significantly more useful.

Here are the updates that were in BDControl 1.0.1:
  • A memory leak in -[NSArray (BDQualifierAdditions) filteredArrayUsingQualifier:] was fixed.

  • Documentation is now placed in a Documentation folder within the Resources folder, in the proper hierarchy. Previously, it was all copied into the Resources folder, which broke some internal links.

  • A new method, -[BDQualifier count] has been added. Sending -count to a qualifier tells how many qualifiers are part of the entire qualifier expression. (In other words, it counts that qualifier and any sub-qualifiers.) Any BDQualifier subclass that supports sub-qualifiers should override this method; see the implementation of -[BDAndQualifier count] for an example.

  • A new method, -[BDQualifier subqualifiers] has been added. Sending -subqualifiers to a qualifier gets an array containing the qualifier's sub-qualifiers, if any. If the qualifier can't have sub-qualifiers, this method returns nil; if the qualifier can have sub-qualifiers but doesn't, this method returns an empty array. Any BDQualifier subclass that supports sub-qualifiers should override this method; see the implementation of -[BDAndQualifier count] for an example.

And here are the updates in BDControl 1.0.2:
  • The lexer used by the qualifier parser wasn't quite correct in its parsing of numebrs. It would have allowed bogus numbers like "1.2.3" and didn't handle a preceding plus or minus.

  • EOSortOrdering was using -valueForKey: rather than -valueForKeyPath: to get values to compare during sorting. This made it impossible to sort on an attribute of an attribute (i.e. a sort key of "foo.bar").

  • The library was being prebound to the default address of 0x00000000. This overlaps with applications' default start location. The prebinding default address was set to 0x30000000 instead.

BDControl 1.0 released
[info]chanson
Early this morning, I released BDControl version 1.0.0 to the world through my company, bDistributed.com. You can download it directly as BDControl-1.0.0.dmg.gz. The disk image contains both the release version of the framework and the complete source code for release 1.0.0.

I sent out a press release to a bunch of Macintosh-related news outlets this morning, and many of them ran it or an article based on it. At the time I post this, 180 unique IPs have downloaded it. I think that's a pretty significant number for the first day of release of a developer framework

BDControl contains the implementation of the BDQualifier class hierarchy and the BDSortOrdering class that I've been going on about the past couple of weeks. Anyone doing Cocoa development for Mac OS X in Objective-C should check it out; chances are, there are ways you'll be able to use it to make your applications' code simpler and more flexible. It's released as Open Source under a BSD-style license, so nobody should have any issues using it in commercial applications.

Of course I'm not just sitting on my heels now that I've released 1.0. I already have a couple of enhancements up my sleeve and a fix for a documentation issue to verify and push out. I'm also working on a new framework for Cocoa developers that uses the functionality in BDControl to provide some very cool capabilities that haven't been available to Cocoa developers before...

Test-Driven Development
[info]chanson
Every now and then for the past couple weeks, I've been working on a Cocoa replacement for the EOQualifier class in the Enterprise Objects Framework. A qualifier in EOF lets you specify some criteria, and then check an object against the criteria to see if it matches.

You create a qualifier by specifying a string like (foo = bar) and (baz like 'qu?x'). This qualifier is actually three qualifiers: a key comparison qualifier checking whether the object's "foo" property matches its "bar" property, a key-value qualifier checking whether the object's "baz" property matches the string "qu?x" (with a filename-style ? wildcard), and an and qualifier matching those two.

Because Objective-C is a truly dynamic language with real support for object introspection, qualifiers can use key-value coding to apply a qualifier to any object descended from NSObject. Objects don't have to be instances of a particular class, or implement a particular interface to be qualifiable.

To create and evaluate a qualifier, you do something like this:
- (BOOL)fooIsReallyFoo:(id)object
{
    BDQualifier *q;

    q = [BDQualifier qualifierWithQualifierFormat:@"foo = 'foo'"];

    // This qualifier sees if an arbitrary object has a property
    // named "foo" and checks to see if its value is a string
    // containing "foo".

    return [q evaluateWithObject:object];
}

(Obviously the "BDQualifier" above is my replacement for EOQualifier. The "BD" comes from the name of my company, bDistributed.com.)

You can do other cool things too, like filter an array based on a qualifier and get a new array of only objects matching the qualifier. You can have variables in qualifiers that are replaced by values in a dictionary; this is useful for creating database query templates, like "(parentMessageID = $parentMessageID) and (score > $articleScoreThreshold)". Since qualifiers are broken down into objects that can themselves be interrogated, it's possible to do things like create a qualifier and then generate SQL from it to query a database. (This is how they're used in EOF.)

So, why did I title this post "Test-Driven Development" when I'm raving about the coolness of qualifiers and my mad skillz? Because I've started using test-driven development to get this up and running. I wrote the bulk of it a few weeks ago, just off the cuff. Then a couple weeks ago I started trying to make it actually build. Recently I wrote a parser for qualifier format strings using lex & yacc. Getting that working properly was entertaining. So a couple days ago I finally started integrating everything together, and trying to get qualifier evaluation working. I had set up this project to use the Open Source OCUnit unit testing framework for Cocoa from Sen:te, but hadn't written any test cases yet. While waiting for Gnomedex events to start, I actually wrote a few test cases.

I was able to get a whole lot done once I had a half dozen test cases. I'm starting to get pretty close to declaring this working and putting it out there for the rest of the world to use. I didn't think I was nearly this close before I started using the Test-Driven Development "write a test case, make the test case work, repeat until new test cases tend to pass immediately." I'd recommend everyone take a look at it.

DirectToWeb fun
[info]chanson
I've been looking at DirectToWeb a bunch more. DirectToWeb is a system in WebObjects that dynamically generates web applications on the fly based on rules that are evaluated and fired in a context. It's leveraged by DirectToJavaClient to generate Java applications on the fly in exactly the same way it generates web applications on the fly. Trust me, it's really, really impressive. Everyone I've demoed it for has been blown away.

For instance, when you invoke an "edit" action for a particular entity (by clicking an "edit" hyperlink, for example) it sets the "task" key in its context to "edit" and the "entity" key to the name of the entity being edited. Then it determines what type of page to render, and while it's rendering the page it will resolve any number of other requirements by going through the rule system and firing rules that are specific to what it's looking for and its current context.

Another, more detailed example: To determine what property keys a particular entity has, DirectToWeb asks the rule system for the "propertyKeys" value with the entity, task, etc. set appropriately. You can create a rule like
(entity = 'MyEntity') => propertyKeys = "(name, creator)"

to return an array indicating that "name" and "creator" are the properties in the MyEntity entity. Say, though, that MyEntity objects should only show their name property in lists. You can add a rule like
((task = list) and (entity = 'MyEntity')) => propertyKeys = "(name)"

and the most specific rule will be fired. And the best part is that all this is extremely flexible: Rules don't have to be created in your Java code; you can specify rules in a data file as well. Rules don't have to perform simple assignments; they can perform more complex assignments using Key-Value Coding, or even use custom Assignment subclasses. And so on. The rule system itself can even be subclassed and extended, though the WebObjects team hasn't yet added delegate support to it.

There's even a nice graphical rule editor that uses the standard qualifier editor control for building the left hand side of a rule and lets you set Assignment subclasses, keys, and values for the right hand side.

It'd be nice if the WebObjects team would do just a little more refactoring, and make the rule system slightly less coupled to DirectToWeb than it is now. There is some indication they're going to be doing this; they have "this implementation is subject to change" stamped all over the documentation. And there's no delegate support yet, unlike everywhere else in EOF and WebObjects.But it's not like Apple would license it separately from WebObjects anyway...

That's some crack!
[info]chanson
Dave Winer is now saying that hierarchical databases are "better for the web" than relational databases, and that by planning to include a relational database engine in a future version of Windows, Microsoft is "barking up the wrong tree." It must be nice to have such a simple view of the world.

The fact of the matter is that relational databases, with their data integrity, flexibility, and power are far, far more suited to web development than simple hierarchical databases like that in Frontier. What's more, with good data-access technology it's easy to map transparently between records in relational databases and real business objects that model both state and behavior.

Something like Frontier might be a fine toy, and might even work well for some low-volume content sites, but for developing real web applications there's just no contest.