bDistributed.com Open Source back on line
[info]chanson
Tonight I uploaded a new page to my web site that describes and has links to all of the bDistributed.com Open Source projects that I released several years ago, before I started at Apple.

A lot of people are still interested in it and still use parts of it — especially BDAlias — and with the bDistributed.com web site down now, I figured (with some friendly prodding from the #macsb crowd on irc.freenode.net) that it would be a good idea to put it back online on my own site.

Share and enjoy! It's all under a BSD license, but it also hasn't been touched for years. Portions are obsoleted by thing that came out in, uh, Panther, so take that for what it's worth...

Update: Wolf Rentzsch has generously put BDAlias in his public Subversion repository, including his own updates to it. Thanks a ton!

PSIG tonight
[info]chanson
I'm going to be presenting at the Northwest of Us Programming SIG (PSIG) tonight about the bDistributed.com BDControl and BDRuleEngine frameworks, and demonstrating a rule-based application. I wrote the frameworks and they're Open Source under a BSD license; I encourage every Cocoa developer to check them out, since they can make your life easier.

I'll also give a quick overview of how Interface Builder palettes work, and a palette I've created that acts as a table data source and lets you wire up an object to a table without writing any code.

The full meeting announcement is here on Jon's weblog: PSIG 68: Thursday, September 4th, 2003

For those who don't know, the Northwest of Us is a Macintosh User Group in the northwest suburbs of Chicago, IL. The PSIG meets at the NWoU office in Palatine, Illinois a couple blocks northwest of the intersection of route 53 and route 14.

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.

Presentation at CAWUG, Tuesday, 11/05/2002
[info]chanson
I'm giving a short presentation at the next Chicago Cocoa and WebObjects User Group (CAWUG) meeting this coming Tuesday.

Jon Rentzsch is going to give an overview of Direct to Web, the rule-based system for generating web applications automatically from your data model in WebObjects. Following Jon, I'll be discussing BDRuleEngine, my Open Source framework for building rule-based Cocoa appliations.

More details, including the location, time, and where you need to RSVP if you're thinking about attending are in the meeting announcement at StepWise.

(The RSVP thing is important because the meetings are at Apple's office in the Mercantile Exchange Building in the Chicago Loop, which became access-controlled after September 11, 2001.)

Mac OS X developer frameworks
[info]chanson
Anyone doing Mac OS X development should check out OCUnit from Sen:te and Log4Cocoa by Bob Frank.

OCUnit is a unit testing framework modeled on the Smalltalk unit testing framework written by Kent Beck, father of eXtreme Programming. I've raved about unit testing here before. OCUnit makes it extremely easy to integrate unit testing into the build cycle for your Cocoa applications.

Log4Cocoa is a straight port of Log4J to Objective-C and the Cocoa frameworks. Bob did a lot of good, hard work and now more developers need to pick up the ball and run with it. For the uninitiated, you use Log4Cocoa to add logging to all the various interesting parts of your code. And that logging can be controlled at run time. It can be useful for debugging hard-to-find bugs, like timing-dependent bugs and multithreading bugs.

(Oh, and if you haven't checked them out yet, be sure to look at BDControl and BDRuleEngine.)

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...

What's this stuff good for, anyway?
[info]chanson
What's all this code I've been hammering on the past week good for anyway?

Say a client hires you to write a trading tool for financial instruments. They want to be able to set alarms when certain criteria are met, so they know when to cash out and buy a yacht, and when to jump out their window because they're hopelessly underwater.

One way to do this would be to have a few specific ways to match criteria: The current price is less than, greater than, or equal to a threshold value; the trading volume has reached a certain point; and so on. This might be sufficient for your client's current needs, but if they ever need to do anything more complicated, or anything that you didn't think of (like compare the day's percent change of a particular security to the day's percent change of an index it's a part of) they'll be SOL. You'll have to change the software, test it, and send your client a new version.

Qualifiers are really just predicates that are easy to manipulate programmatically. This means it's easy to build a human interface that lets sophisticated users specify arbitrary criteria to match against. And as long as the model objects in the application are sufficiently rich (i.e. they expose a large number of interesting attributes), that means you can create a very deep application without a huge amount of work.

Sort orderings are a little more mundane, but they're still pretty useful. If you have an application that needs to sort a list of people by last name, then by first name, then by age, you don't have to do much of any work to actually code it if you have sort orderings. The user clicks a different column heading to sort on? Just change which sort ordering you're filtering your data through and tell the table to reload.

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.