2008-04-10 20:00:00 -0400
We’ve seen mention on a few sites about the potential for Twitter to monetizing their service by charging businesses for mobile interfaces. The case study they quote is a mobile interface for
Harvest.
We think that it’s great that more companies are exploring mobile interfaces like this. Our own small business time tracking system Tempo also
excels at
mobile entry, letting our users record time through Twitter, iPhone, SMS, mobile web, and even desktop mail (much of this functionality is borrowed from
PingMe, a mobile app from birth). While the idea of Twitter as a mobile command line is not new, its always great to see more tools embrace the idea.
So, with a constantly expanding list of services like
Twittercal,
Jott,
Harvest ,
Timer,
RTM,
PingMe,
and
Tempo
all using Twitter, it would seem reasonable for them to monetize these relationships.
That said, even as a company that loves Twitter and already uses it in our apps, the big concern is reliability. Tweets get dropped or delayed more often than we’d like to admit, default rate limits can cause issues, web service calls can cause delays, and the APIs don’t provide scalability to really large numbers of messages. When the service is free these aren’t show stoppers. If charges are involved it’s a different ball-game.
If Twitter were to pursue the monetization strategy the right move would be to provide a dedicated business service. Include guaranteed delivery, improved message processing integrations, dedicated API servers, and quicker processing. This would make the offering very competitive with all of the existing SMS and Text-to-email gateways on the market.
Now that would be worth paying for.
2008-04-10 20:00:00 -0400
Trying to explain a new technological concept to the uninitiatied, especially something involving social networking, can sometimes be an up-hill task, but it’s a challenge I generally relish.
I came across Melissa Chang’s article on Twitter via the excellent Y Combinator Hacker News. In broad broad summary, Melissa feels Twitter will remain an obscure service in the cultural mainstream (for the time being) due to difficulties in explaining the concept and use-cases.
So I’d just like to address a couple of points Melissa made:
1. It’s hard to explain.
I find it’s very easy to explain, especially to non-nerds, if you tell them “it’s like a slow chat or IM with all your friends.” Elaborating, “your friends’ messages come and go as presence or conversations, and you can reply, start your own, or let them pass by and keep working.” Recent explanations like that have worked for me. Or you tell your neophyte buddy, “it lets you send an IM or text to all your friends at once and they can reply and send you messages, on the internet or on your phone.”
There are lots of neat things you can do with Twitter, so just pick your favorite and say it out loud.
I’m not trying to be a total Twitter advocate here, but I don’t think it’s that hard for people to get, especially for anybody under 25 right now.
2. There is no “key selling proposition.”
See above. There are lots of neat things you can do with Twitter. Just tell your friend what you use it for, in simple terms. “I use it to tell everyone about my cat,” or “I use it to stay in touch with friends during the workday.”
3. People sign up and then leave.
Well, welcome to the internet. But the crux of Melissa’s problem here was not really understanding what to post about. Which I can’t entirely blame her when she first signed up. I think everyone gets that moment at first of, “so… now what? do I put that I’m hungry? I have no friends yet, this is interesting.”
It’s the same with any social network, actually. And I think there’s a huge population of people right now who get that and have no problem sticking around and making use of such tools, linking up with their meat-space friends.
4. The people who don’t use Twitter don’t understand the language of it.
Maybe it’s because I had some experience with IRC back when the crust of the Internet started to cool at the end of the 90’s, but I totally got what the ‘@’ symbol meant and I think most of the young’ins out there get it, too. It’s pretty obvious that those are screen names when you are looking at someone’s timeline (twitter page); people are having conversations.
2008-04-09 20:00:00 -0400
Update 06-JUN-2008: This plugin now includes acts_as_union, and we moved the repository to GitHub.
A better-late-than-never announcement: we released a Rails plugin a while ago that implements a better, DRYer way to roll network relationships using ActiveRecord. It's called, acts_as_network and it now updated to support Rails 2.0.
So why is this such a problem? It may not be immediately apparent, but the short answer is that these types of relationships usually require 2 redundant rows of storage in your database. Take a social network relationship: one record might say that Jack is Jill's friend, but a separate row must be present to say Jill is Jack's friend.
acts_as_network does away with this nonsense, and lets you say implicitly that If Jack is Jill's friend then Jill is Jack's friend. Or, in Ruby
# Jane invites Jack to be friends
invite = Invite.create(:person => jane, :person_target => jack, :message => "let's be friends!")
jane.friends.include?(jack) => false # Jack is not yet Jane's friend
jack.friends.include?(jane) => false # Jane is not yet Jack's friend either
invite.is_accepted = true # Now Jack accepts the invite
invite.save and jane.reload and jack.reload
jane.friends.include?(jack) => true # Jack is Janes friend now
jack.friends.include?(jane) => true # Jane is also Jacks friend
The syntax is clean, and it stores only one row in your HABTM table. Online Documentation available or install/upgrade the plugin:
% script/plugin install git://github.com/sjlombardo/acts_as_network.git
% rake doc:plugins
Much thanks to Maurycy for submitting patches to AAN!
Note: for a more in depth look at the acts_as_network syntax and usage please check out the original release page.
2008-03-19 20:00:00 -0400
Throughout the course of building Tempo, we’ve relied heavily on software written by other people and made freely available. It’s worth doing a quick run-down to give credit where credit is due.
Ruby On Rails web application framework
No surprise there, right?
PostgreSQL relational database
Our favorite relational database system, Postgres is the most mature of the free systems out there, has the best feature set, and has quite a bit in common with Oracle. Highly recommended.
FamFamFam icons
Everybody needs icons, we’re big fans of the Silk set.
Acts As State Machine Rails plugin
This plugin by Scott Barron allows an ActiveRecord model to act as a finite state machine rather elegantly.
HAML & SASS HTML & CSS templating
Gone are the days when we painfully labor over HTML templates thanks to this great Rails plugin by Hampton Catlin. We can’t live without it now.
gchartrb Google Charts for Ruby
Those charts in Tempo look really good, but they’re largely the work of Google’s Chart API and this wrapper library for Ruby written by deepak.jois and aseemtandon. All we had to do was write some clever SQL and voila!
Active Merchant Rails plugin
Definitely the easiest way to integrate with a payment gateway in Rails. Also provides an awesome layer of abstraction in the event that we decide to switch gateways – we won’t have to do a major rewrite of the code in our site that handles payment processing.
Ruport Ruby Reports
Ruport made it incredibly easy for us to provide Excel/CSV and PDF exports from within Tempo’s WYSIWYG reporting interface.
RESTful Authentication Rails plugin
Very handy plugin by Rick Olson for quickly setting up an authentication system for your users that includes an activation step.
Thanks everyone for making these valuable open source contributions to make software like Tempo possible.
2008-03-10 20:00:00 -0400

This took enough of my time that I think it’s worth a blog post. In Tempo you’ll see a familiar paradigm in the time reporting interface (the main screen): a list of editable items in a row, each with the same set of controls. They are editable via AJAX calls, so you can open a number of them for editing at once.
Now, when you’re looking to add javascript observers to these elements (to do automated things like type ahead, etc), you have to assign them unique id attributes, usually based on the object id. While it’s easy to add an :id attribute to any of the usual tag helpers in Rails, it doesn’t work like this with date_select:
%table
%tr.s1
%td{:colspan => '2'}= project_select(f, @current_user.projects, entry)
%td{}
= f.date_select :occurred_on, :order => [:month, :day, :year], :start_year => 2007, :use_short_month => true, :use_short_year => true, :id => "#{entry.id}"
= popup_calendar("entry_#{entry.id}_occurred_on", entry.occurred_on)
Our javascript calendar is expecting a unique ID on the date select drop downs so that it can set their values. But, that’s not the case, the id of each drop down is generated automatically from the name attribute, thus:
<select id="entry_occurred_on_2i" name="entry[occurred_on(2i)]">
<option value="1">Jan</option>
<option value="2">Feb</option>
<option value="3" selected="selected">Mar</option>
...
</select>
Makes sense, really, since the separate drop downs are being generated to be re-assembled when posted, and what else to id them?
The trick to getting unique id’s into these elements was a monkey patch I put in config/initializers/date_helper.rb:
module ActionView
module Helpers
module DateHelper
def name_and_id_from_options(options, type)
options[:name] = (options[:prefix] || DEFAULT_PREFIX) + (options[:discard_type] ? '' : "[#{type}]")
name = options[:name].gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
unless options[:id].nil?
options[:id] = name.sub(/_/, "_#{options[:id]}_")
else
options[:id] = name
end
end
end
end
end
Pretty close to the original, it preserves the original behavior, but respects your inclusion of the :id attribute in the options you pass to date_select. Now our id’s look like:
<select id="entry_2013_occurred_on_3i" name="entry[occurred_on(3i)]">
We found a similar problem with the auto_complete plugin – doesn’t work when there are more than one active on the screen at once, due to non-unique id’s. That required a bit more work. First a monkey-patch in config/initializers/auto_complete_macros_helper.rb:
module AutoCompleteMacrosHelper
def text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {}, object_id = nil)
if object_id.nil?
field_id = "#{object}_#{method}"
else
field_id = "#{object}_#{object_id}_#{method}"
tag_options[:id] = field_id
end
(completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
text_field(object, method, tag_options) +
content_tag("div", "", :id => "#{field_id}_auto_complete", :class => "auto_complete") +
auto_complete_field(field_id, { :url => { :action => "auto_complete_for_#{object}_#{method}" } }.update(completion_options))
end
end
Adding an optional parameter on there seemed like the easiest thing to do for the moment, creates for only a slight change in our form:
= text_field_with_auto_complete :entry, :tag_s, {:size => 40}, { :indicator => "entry_#{entry.id}_tag_s_form_loader", :frequency => 0.4, :tokens => ' ' }, entry.id
I’m tempted to make it work off of whatever shows up in tag_options[:id] but this will do for now.