Up and running with PmpknPi
about 1 month ago / 0 Comments
Time for a change -- I've been needing to move my blog to a different server for awhile now, so I'm using this opportunity to change from Typo (a Rails-based blog platform) to PmpknPi, which advertises itself as "A RESTful Blog API written in Merb."
If you've a techie who's been hiding under a rock, and don't know what Merb is, it's an MVC Web-app development framework written in Ruby. It's basically a competing/complementary framework to Rails -- much more minimalist and performance-oriented.
I'm running this blog on Merb with the Thin Ruby Web server, a small, fast, event-driven HTTP server written in Ruby.
Merb is what we're using to build a lot of the Seesmic Web app, including the Ajax Web UI that's my primary focus.
We've been hard at work at Seesmic building out our REST API, which at least in part explains the dead air on this blog. (Twitter is probably another good target for finger-pointing on that count.)
Anyhow, with the switch of this blog to PmpknPi, I lose a lot of the bloat of both Rails and Typo, and should have something a bit more hackable. I'll also get something I should have put a premium on long, long ago -- code syntax highlighting from the excellent CodeRay library. 'Bout frigging time.
OSAF 2.0 to Seesmic pre-alpha
4 months ago / 1 Comment
On Tuesday of this week, OSAF announced a significant restructuring of the organization. OSAF is now moving forward into a new phase of its existence with a smaller team -- a team that I will not be a part of.
I'm extremely proud of my work at OSAF, and what our small team was able to accomplish on Chandler Server in such a short time. However, I had been thinking lately that it might be time to consider other possibilities -- so when the reorg began, I decided OSAF would be better served by letting me go, and keeping people who are tightly focused on the goals of the project.
My life has been incredibly enriched by all of the people I've worked with at OSAF, and I'm proud of the work I've done -- both on Chandler Server, and on the Windmill Web-app testing framework. I will of course be following the progress of Chandler with great interest, and will be offering whatever help or assistance I can to the Chandler developers and community.
I'm sure it won't take long for my fellow former OSAFers to get snapped up by various cool ventures. Bay Area tech companies are likely all salivating at the prospect of these brilliant people now out looking for jobs.
As for me, thanks to a kind introduction from one of those ex-OSAFers, Mike "Bear" Taylor, I am pleasantly surprised to find myself already employed, working on something new and pretty damned exciting. Starting January 16th, I will be working at Seesmic, a startup company doing some very interesting stuff with Web video.
The service is still pre-alpha. (no, I don't have any invitation codes yet :)), and I'll be working on an Ajaxy Web UI for the service. I'll be blogging about the new job as things develop -- it's a startup, I'm hoping and expecting that things will be moving quickly.
Updated: here are some links to the various news items regarding OSAF's reorg:
Fleegix.js JavaScript Toolkit 0.4.1 release
4 months ago / 0 Comments
Somehow amidst all the chaos that is currently my life, I've packaged up version 0.4.1 of Fleegix.js for release. You can download the new release at the usual location.
This is primarily a bugfix release. Here are some of the fixes and improvements:
- Fixes in the hash plugin for Safari 2's ridiculous Math.random bug
- Updates to the xml parser plugin to handle CDATA and comment nodes properly
- Fixes for multi-selector class attributes with
css.addClass - Improved caching in timezone-enabled Date plugin, new
getTimezoneAbbreviationmethod - Fixes for previous-year inclusion in rule-hits in the timezone-enabled Date plugin
- New option to squelch errors from execution of handlers in
event.listen - A bunch of new unit tests that work with Windmill's JavaScript test framework
PHP is the McDonald's of programming languages
4 months ago / 0 Comments
Tim Bray has a nice post that succinctly describes the situation with PHP in 2008 -- why it's still popular, but its growth continues to slow.
I think that the various pluses and minuses could be reduced even more by simply thinking of PHP as the McDonald's of programming languages.
PHP, like McDonald's, is really, really convenient, -- it's pretty much already installed everywhere you go. Deployment, like eating at Mickey Dee's, is a breeze.
And maybe I'll be totally ostracized for saying it, but I don't particularly mind using PHP to set up a quickie Web site with some simple templating. It's dead simple, and I know stuff will just work.
Like the food at McDonald's, using PHP isn't that bad every once in a while -- but I wouldn't want to eat it every day. And I'm pretty sure a steady diet of it will kill you.
Rails polymorphic associations and migrations
4 months ago / 0 Comments
In a Rails app I was recently working on, the data model called for associating sets of related business objects. Initially it looked like I was going to have to handle it with sub-classing.
Sub-classing and prog-rock keyboardists
I was kind of reluctant to do this in a Rails app, because the traditional Rails approach to representing an object hierarchy uses single-table inheritance -- dumping a column for every possible attribute for every possible sub-class into one table.
This kind of ugliness is an example of the Rick Wakeman Brute Force Approach: no worries about those primitive synths that can only provide one patch at a time, just drag an ass-load of them with you whenever you go on the road. It gets the job done, but it's not particularly elegant.
In my particular case, sub-classing might have actually worked, if I could have endured the single-table-inheritance stink. But what about cases you may want to group types of things in your app that have a less obvious relationship than can be represented with a hierarchy chain?
Promiscuity is so much nicer
Thankfully, a very nice way to do this sort of thing exists in the form of polymorphic associations (also called "promiscuous associations," yay!), which allow you a lot of the same capabilities as an inheritance hierarchy, but gives you more flexibility in creating relationships between objects.
With polymorphic associations, you can literally connect any type of thing in your data model to any other type. A common example used to describe this is tagging, where a given tag could potentially be associated with any type of thing in your data model.
It almost makes you a little drunk with power, this newfound ability to link this to that and that to the other thing over there. You can almost imagine, with all due apologies to the Pythons, a Royal Society for Associating Things With Other Things.
The has_many_polymorphs plugin
Using polymorphic associations without any special help is possible in Rails, but it is somewhat limited. I found that what I needed to do required the use of the excellent has_many_polymorphs plugin developed by Evan Weaver.
If you find yourself reading the docs and getting utterly confused the first time through, as I did, you can check out Pratik Naik's helpful tutorial that does a really nice job of laying it all out.
Dude, where's my DB?
The one piece I found missing in all the docs and tutorials for the has_many_polymorphs plugin was anything that showed what the corresponding database tables should look like, or how to use Rails migrations to set them up.
(There is a helpful, albeit minimal, example in the plugin source code examples/ directory for a simple single-sided association that pointed me in the right direction.)
I figured it might be helpful for other people using the plugin to see some migration examples. It might save them some of the time I spent futzing with things to get it all working.
Single-sided associations
Single-sided polymorphic associations are the simpler of the two kinds, where many types of things are associated with a single other type.
Say I'm writing an e-learning app, and I have courses, exams, and seminars, all of which might be assigned to a person to take. My model would look like this:
class Course < ActiveRecord::Base
end
class Exam < ActiveRecord::Base
end
class Seminar < ActiveRecord::Base
end
class TasksPerson < ActiveRecord::Base
belongs_to :person
belongs_to :assignment,
:polymorphic => true
end
class Person < ActiveRecord::Base
has_many_polymorphs :assignments,
:from => [:courses, :exams, :seminars],
:through => :tasks_people
end
And the migration would look like this:
class TasksPeople < ActiveRecord::Migration
def self.up
create_table :tasks_people do |t|
t.column :person_id, :integer
t.column :assignment_id, :integer
t.column :assignment_type, :string
end
create_table :people do |t|
t.column :name, :string
end
create_table :courses do |t|
t.column :name, :string
end
create_table :exams do |t|
t.column :name, :string
end
create_table :seminars do |t|
t.column :name, :string
end
end
def self.down
drop_table :tasks_people
drop_table :people
drop_table :courses
drop_table :exams
drop_table :seminars
end
end
Once you've got that set up, you can try it out in the console to see if stuff is working:
>> c = Course.create(:name =>
"How Not To Get Eaten By An Alligator")
>> e = Exam.create(:name =>
"Zombie Army Attack Preparedness")
>> p = Person.create(:name => "Ravi Shankar")
>> p.assignments.push(c)
>> p.assignments.push(e)
>> p.assignments.length => 2
Woohoo, Ravi has two assignments, just like you'd expect.
The beauty of this is that now I can assign courses, exams, seminars -- or anything else I deem "tasky" -- to people in my app, without having to wrangle the unwieldiness of shoving all that taskiness into a single table.
Double-sided associations
This is where it gets all wacky -- where multiple different types of things can be associated with other, multiple different types of things. Mass chaos ensues -- but in a good way.
Imagine now that e-learning app has grown and I need to make more complicated kinds of assignments. I need to be able to assign those different types of tasks (courses, exams, seminars) to individuals, or to groups -- say, for example, to people, jobs, and organizations.
(For anyone who worked with me back in the KnowledgeWire days, this is a nice trip down memory lane.)
This is a good example of a case where simple sub-classing would be conceptually awkward and weird -- people, jobs, and entire organizations aren't particularly similar things. The only thing they really have in common in this data model is their ability to have things assigned to them.
The model code would look like this:
class Course < ActiveRecord::Base
end
class Exam < ActiveRecord::Base
end
class Seminar < ActiveRecord::Base
end
class Person < ActiveRecord::Base
end
class Job < ActiveRecord::Base
end
class Organization < ActiveRecord::Base
end
class AssignmentsAssignee < ActiveRecord::Base
belongs_to :assignment, :polymorphic => true
belongs_to :assignee, :polymorphic => true
acts_as_double_polymorphic_join(
:assignments =>[:courses, :exams, :seminars],
:assignees =>[:people, :jobs, :organizations]
)
end
And the migration would be like this:
class AssignmentsAssignees < ActiveRecord::Migration
def self.up
create_table :assignments_assignees do |t|
t.column :assignment_id, :integer
t.column :assignment_type, :string
t.column :assignee_id, :integer
t.column :assignee_type, :string
end
create_table :people do |t|
t.column :name, :string
end
create_table :jobs do |t|
t.column :name, :string
end
create_table :organizations do |t|
t.column :name, :string
end
create_table :courses do |t|
t.column :name, :string
end
create_table :exams do |t|
t.column :name, :string
end
create_table :seminars do |t|
t.column :name, :string
end
end
def self.down
drop_table :assignments_assignees
drop_table :people
drop_table :jobs
drop_table :organizations
drop_table :courses
drop_table :exams
drop_table :seminars
end
end
Now let's hop back into the console and see if this stuff all works:
>> c = Course.create(:name =>
"Life and Times of the Three Stooges")
>> s = Seminar.create(:name =>
"LARPing for Fun and Profit")
>> p = Person.create(:name =>
"Henry Kissinger")
>> o = Organization.create(:name =>
"Australopithecus Unlimited")
>> p.assignments.push(c)
>> p.assignments.push(s)
>> p.assignments.length => 2
>> o.assignments.push(c)
>> o.assignments.push(s)
>> o.assignments.length => 2
Very nice. I can give the same assignments to both Henry Kissinger and to the entire Australopithecus Unlimited organization.
I can assign any of these tasky things to a person, job, or organization in the app. And also interestingly, I can do the reverse:
>> e = Exam.create(:name =>
"Apple Fanboy Test")
>> e.assignees.push(p)
>> e.assignees.push(o)
>> e.assignees.length => 2
Gotchas
One gotcha I noticed was that migrations wouldn't run to set up the database properly with the has_many_polymorphs plugin loaded. Looks like it's some kind of circular dependency issue. In any case, leaving the plugin require statement out of environment.rb until after setting up the DB is a workaround for this problem.
Wrapping up
There you have it. A nice, flexible way to create associations between loosely related types in your model. No ugly sub-classing stuff by trying to shoehorn every related type into one table.
There are some other nice tutorials and docs online to help you, but I couldn't find any that include the migration scripts above. I hope this helps save somebody some time.
FLOSS Usability Sprint V
6 months ago / 133 Comments
I recently participated in FLOSS Usability Sprint V, an event run by the FLOSS Usability organization to foster better usability in open-source software, and to encourage collaboration between usability/design/UX practitioners and the free/libre/open-source community.
Open-source software in general is sadly not known for its stellar usability, so this sort of event is really important -- both for the short-term aim of improving our UIs, and the long-term aim of developing some awareness of basic usability tenets in the open-source community.
Developers need to know that design and usability are not simply window-dressing, and they're not something you glue on after the fact. Attention to usability needs to be built right into the development process from the get-go -- including filing bugs about usability, and educating developers about basic usability principles.
The event was hosted by Google, and this was my first trip to the Google campus. I can see why so many people love working there. Google really made sure things went smoothly for us, and it was a great environment for collaboration and discussion.
The Mozilla Corporation hosted some beer-and-food happy hours that gave us a chance to continue discussions in a bit more informal atmosphere. It's always amazing to me how much of a difference that kind of face-to-face contact makes when so much of your communication happens with people over the phone or in text.
We were paired up with some really nice folks from the Oracle Usability Group, who were actually kind enough to let us have some use of their Usability Lab for testing Chandler Server's Web UI.
The Oracle guys were super-nice, and we had a ton of fruitful interaction with them. We got some good hard data about which parts of the UI work, and which parts don't -- and some ideas for improvement in a lot of different areas.
We focused on a particularly problematic piece of the Web UI -- calendar overlays, which are really a complicated design problem to solve. We whiteboarded a bunch of different approaches with the aim of trying to make things clearer than the design we currently have. You can see graphics of all the whiteboard designs here.
I ended up coding some prototypes that demonstrate the design concepts we came up with:
- The existing design, for contrast.
- A treatment using only standard formelements,
- A treatment using a custom icon to indicate visiblity of the calendar layers
Jeffrey Harris (who is essentially my equivalent on the Chandler Desktop application) and I put the feedback from the Sprint up on a wiki page on the Chandler wiki. The design ideas and input were really great, and I'm looking forward to incorporating them into our design for the Web UI.
Test for broken images -- works in Safari
7 months ago / 4 Comments
I've been doing a bit of work recently on the Windmill project for OSAF -- it's pretty usable already, and we're just now approaching the 0.2 release.
One of the pieces I added awhile back was an assert to check for broken images. After doing a bunch of poking around online, the one piece that seemed to elude everyone doing this kind of check was something that works in Safari 2. We plan to support Safari in Windmill, so I did a bit more research and hammered out something that seems to work reliably.
The crux of the problem with Safari is that it doesn't support the complete attribute -- at least not for images loaded normally in markup. Interestingly though, it does support it for script-created images -- which opens to the door to this hack.
Here's the code:
function assertImageLoaded(img) {
var complete = img.complete;
var ret = null; // Return value
// Workaround for Safari -- it only supports the
// complete attrib on script-created images
if (typeof complete == 'undefined') {
var test = new Image();
// If the original image was successfully loaded,
// src for new one should be pulled from cache
test.src = img.src;
complete = test.complete;
}
// Check the complete attrib. Use strict equality
// check -- don't want undefined, null, etc.
// --------------------------
// False -- Img failed to load in IE/Safari, or is
// still trying to load in FF
if (complete === false) {
ret = false;
}
// True, but image has no size -- image failed to
// load in FF
else if (complete === true &&
img.naturalWidth == 0) {
ret = false;
}
// Otherwise all we can do is assume image loaded
else {
ret = true;
}
return ret;
}
The hack for Safari depends on the normal caching behavior of the browser.
When you do the check, the complete attribute for the original image will be undefined -- but when you create a new Image with JavaScript, and set its src to the src of the original, it grabs the image from cache, and the complete attribute for the script-created image is immediately set to true.
This assumes of course that Safari is pulling images from cache after the first hit, but that should be the default behavior, and in the vast majority of cases that's what you want. If you're using this code, and you get a bunch of false hits for broken images in Safari, you'll want to take a look at how both your browser and server are configured for caching.
MS to deliver Silverlight for Linux
8 months ago / 0 Comments
Okay, now I'm a bit more inclined to believe the guys at Microsoft are serious about this stuff. An MS press release has announced they're working with the Mono guys to deliver Silverlight for Linux:
In addition, Microsoft will work with Novell Inc. to deliver Silverlight support for Linux, called Moonlight, and based on the project started on mono-project.com.
Sure, like Chris Koenig pointed out to me when I asked about Linux support, Linux's desktop share is tiny. But there is a disproportionately high number of developers in that tiny share, and we're pretty vocal. :)
Working with Novell is an easy way to get going on this -- and the Linux support shows they're serious about competing with Adobe in this space.
BarCamp Houston 2007
8 months ago / 0 Comments
BarCamp Houston 2 was great. The Houston Technology Center was a really nice venue, and it was cool to hook up with so many locals who are into bleeding-edge tech. Nice too, to get some faces to go with Twitter avatar pics.
I was also pretty happy to see three other KnowledgeWire alums representing -- Marshall, Uncle Gerry, and Jonti.
Check out the Twitter update archive from Dwight Silverman (Houston Chronicle).
State of the Startup
(Kurt Stoll, StartupHouston.com)
- Lots of startups in Houston, but little communication/coordination.
- Not enough interested talent and not enough local capital. Houston startups have to go outside of town for their cash.
- Brain drain -- not enough connection between the startup community and the universities, easy opportunities with big business in Houston.
- Open-source participation can propel entrepreneurship
The Up Experience
(Ernie Rapp, The Up Experience)
A conference modeled after TED (www.ted.com), coming in to Houston in February. One announced speaker is Steve Wozniak.
Seems a bit pricey at $1000, but they are trying to make it something pretty extraordinary.
Spresent
(Alexander Kouznetsov, Spresent)
Software-as-a-service, Web-based presentation application. Written in Flash. Looks pretty decent, if you need to do Powerpoint-style presentations.
If it were me, I probably wouldn't be able to get past my visceral distaste for Flash -- I'd use S5 or something. But I can see how it would really appeal to people who do presentations with a lot of media in them.
OpenTeams
(Tory Gattis, OpenTeams)
"Takes the icky out of wiki." These guys are a Houston-based startup.
A friendly, more usable wiki-style collaboration Web-app for business. ZDNet blogs has a good writeup with video of the actual app.
Really nicely done Ajax frontend -- easy on the eyes, especially considering the amount of data that's getting packed in there. Their JavaScript toolkit weapon-of-choice is Dojo, and they use PHP/MySQL on the server. (I'm interested in talking to their font-end guy (he's in Austin) about their plans for transitioning to Dojo 1.0.)
I talked with Tory a little bit about open-source -- it's apparently a question they get asked a lot. He said they had tried to contribute some code to Dojo, but didn't have much luck coordinating with the Dojo guys to get it included.
They're an ASP, so they don't want to open-source the entire app. But I mentioned the idea that they could consider open-sourcing something smaller like a component -- something generally useful, but unique to their app. It's a nice way of contributing back without killing your whole business. Tory seemed interested in the idea, since people seem to be badgering them a lot about their open-source story.
I was also pretty impressed with the open way they've set up their business -- it's very community driven, and they're deliberately blurring the lines between employees and community. Check out their FAQ on the Open Model Entrepreneurial Organization.
I need to throw this out to the OSAF crowd, since it's completely free for non-profits.
Text and Readability, E-Books
Robert Nagle, IdiotProgrammer Weblog
Gerry Manacsa, Wowio.com
(Disclaimer: I have a bunch of good friends at Wowio.)
Lots of talk about various types of new media, the importance of graphics versus text, and the influence on reading of technology.
I won a book for my answer to one of the poll questions. (The question: Where are some places people read? My answer: On the can.)
Robert has his slides available online here.
Silverlight
Chris Koenig, Microsoft
A really impressive demo that showed how serious Microsoft finally has gotten about making RIA programming a first-class citizen in its tools-oriented programming ecosystem.
Silverlight is going to be an interesting technology to watch as it matures, and things like Ruby/Python support fall into place.
They tout it as cross-platform, but sadly, to the guys at MS that still just means "Wow, it works on Mac." I'll be impressed when there's a Linux player. No one expect development tools, but hey, Adobe has a Linux player for Flash. This is kind of minimum effort here, guys.
If Microsoft can lose billions of dollars on XBox, they can spend some resources on a Linux player for Silverlight. (And no, I don't want to hear what the Mono guys are doing.)
JavaScript lazy function definition
9 months ago / 0 Comments
I've been off for most of the past week as my mom had our boys (keeping all the grandkids together for the week, frighteningly enough), and my wife and I took the opportunity to do some house-hunting. We're looking for something with a bit more yard space for the boys to play in.
I've been offline a lot this week, but I did see an interesting post by Peter Michaux (creator of the Fork JavaScript library), about lazy function definition in JavaScript.
This is a flavor of self-modifying code where on initial invocation a function actually redefines itself before executing and returning a value. On subsequent calls, it simply executes according to the updated definition. Peter's very simple first example looks like this:
var foo = function() {
var t = new Date();
foo = function() {
return t;
};
return foo();
};
Peter writes:
Another way of thinking about this this pattern is that the outer function that is first assigned to foo is a promise. It promises that the first time it is run it will redefine foo to a more useful function.
The term 'promise' he uses is a reference to lazy evaluation in languages like Scheme.
An obvious use for this pattern would be library code that paves over differences between browsers. (Peter's final example is a cross-browser function that gets the page scroll.) Having the function tailor itself for the specific browser allows you to avoid a conditional check for what browser every time the function is invoked.
This pattern might be a bit acrobatic for some people's taste -- it's arguably better to be clear than to be clever, particularly in code that lots of people will be touching. But it never hurts to have another powerful tool like this in the toolbox.