Productivity and my Increasingly Poor Short-Term Memory

Posted on Aug 06

Here's a little shortcut I use courtesy of Mac OSX; I'm sure others do something like this, but I think it's worth sharing.

When I first started doing development for work I needed to keep track of what I did everyday and all my hours (ahhh, contracting). So I kept a steno notepad for the first couple years and had an embarrassingly epic record of everything I'd done. 

Nowadays I don't have to deal with invoicing very often anymore, but it's still nice to know what I did yesterday or the last couple of days. There are a bunch of great ticketing systems out there that can help you keep track of your long-term goals and what you've been working on day-to-day. But sometimes I just need a quick reference of what I'm doing this week to use for stand-up meetings, to remind me of what I was working on when I left work yesteraday, etc. After scrapping the clutter of hand-written notes, I have fully migrated to... STICKIES. 

 Yes, those little notes that you use and then forget about have finally proved useful. I keep one Stickie for every day of the week and write shorthand for what I'm doing. The best part is that it's about 1 second and a mouseclick away. I definitely recommend this system for reference and staying on task with it. 

dashboard_notes.png

(and the bright colors are pretty to look at)

Rails' named_scope: Picking Up Where Associations Leave Off

Posted on Jul 22

With the addition of named_scope to Edge Rails a while ago (merged from the has_finder plugin), many doors were opened and many codes were DRY'd up (presumably). Fast-forward to today when I was faced with an interesting situation… 

 In my scenario I have Account, Document, and DocumentFilter classes:
class Account < ActiveRecord::Base
  has_many :documents
  has_many :document_filters
end
class Document < ActiveRecord::Base
  belongs_to :account
end
class DocumentFilter < ActiveRecord::Base
  belongs_to :account 
  has_many :rules 
  def to_sql()
    ... produces a string for the WHERE clause based on its rules ...
  end
end 

The DocumentFilter can easily be changed to add/remove rules like "document type is Spreadsheet" (SQL: "type = 'Spreadsheet').  Given that, I needed to create a method called DocumentFilter#documents that would:

  a) return all its account's documents

  b) filter the documents based on its rules

One might consider creating a join table called DocumentFiltersDocuments, which would create a "has_many :documents, :through => :document_filters_documents" on the DocumentFilter class. But we really don't want to keep an extra table row for each match between a Document and a DocumentFilter. 

Both Document and DocumentFilter share no foreign_key relationship in the database besides that they might both belong to the same Account, so my first idea was that I could do a has_many :documents, :through => :account (based on the "DocumentFilter#belongs_to :account" relationship). This would not work though, since has_many :through doesn't work with a belongs_to in the middle (and was really meant to work with join tables, afaik). 

 There are traces of attempts to change this, but I didn't want to rely on a hack or try to rewrite a new AssociationCollection class for ActiveRecord. So here's my solution (which required just a few more lines of code than a has_many):

class Document < ActiveRecord::Base
  belongs_to :account
  named_scope :for_document_filter, lambda { {|df| :conditions => df.to_sql]} }
end 
class DocumentFilter < ActiveRecord::Base
  belongs_to :account
  def documents(force_reload=false)
    @documents = account.documents.for_document_filter(self) if @documents.nil? || force_reload
  end
end 

And if you're on the latest Edge Rails, you can also shorten it further with memoize():

def documents
  account.documents.for_document_filter(self)
end
memoize :documents 

 

Now you can almost treat DocumentFilter#documents as you would a has_many.

df = DocumentFilter.first # account_id is 1 and df.to_sql() returns "type = 'Spreadsheet'"
df.documents
#=> SELECT * FROM `documents` WHERE (`documents`.account_id = 1 AND (type = 'Spreadsheet') 
df.documents
#=> same results, but cached in @documents, so there is no SQL 
df.documents(true)
#=> SELECT * FROM `documents` WHERE (`documents`.account_id = 1 AND (type = 'Spreadsheet') 
df.documents.find(:all, :conditions => "true", :limit => 5)
#=> SELECT * FROM `documents` WHERE (`documents`.account_id = 1 AND (true)) AND (type = 'Spreadsheet') LIMIT 5 

 

 

Conclusion: named_scope is rule. 

Summer reading

Posted on Jul 18

Like any tech shop, we send around interesting links and reading material.  From the past week:

Threads Suck

Intel's declared the hyper-core future, throwing the gauntlet firmly in the direction of programmers everywhere.  It's natural to start thinking about multithreading, lock-related pain and synchronized blocks, but Eich of JavaScript fame lays out some ground rules for the future of that language.  Seems that even web developers will need to deal with parallel processing in some form.

jQuery Sparklines

Nifty.  We're currently writing with Prototype/Scriptaculous, but the entire team's pretty impressed with jQuery.  There was an aborted mootools conversion attempt in the past, but perhaps that won't stop us from trying again.  In any case, supplementing activity logs with some sparkline graphs may be a nice touch in LimeSpot.

Sexy Forms in Rails

It's arguable that Rails's greatest benefit is simplifying form building.  Here's a step further.

Wordpress 2.6

The best keeps getting better.

 

Well Into a Lot of Changes

Posted on May 07

New 9th Floor Digs

This has been a fairly eventful release cycle for LimeSpot, though in ways you probably won't see in the release notes.

The photo is from the first day in our new digs within the 9th floor of Lime offices, which we moved into a few weeks ago. Pretty nice space, but what's nicer is the fact that we'll be in the same general area as the rest of the Lime Wire teams for the first time in the history of our project. All that creative energy and light has seemed to do us well already.

We've also added three new team members -- Ari, Derek, and Tieg -- which has almost doubled the size of the LimeSpot team overnight. They've already been contributing a lot or hard work and new ideas, and I'm excited to see what the future holds for with all this new muscle to flex.

Finally, on the interface side of things, we're just about to conduct our second round of usability testing. You can see some of the results of the first round of testing in the interface tweaks debuting in today's update to LimeSpot. We already know that we have a good looking web app here, but we want it to be as easy to use as it is easy on the eyes.

By the way, this usability testing is slated to be an ongoing thing, so if anyone out there in the New York City area would be interested in helping us, then by all means drop us a line.

Not Too Lazy

Posted on Apr 16

The blog has been quiet, but LimeSpot's been busy, picking up steam and returning to form after a raucous SXSW.  There's been a lot of work done over the past few weeks, and I'd like to highlight a few changes.

First, the covers have finally come off and LimeSpot Beta is now fully open to the public.  After a brief private beta period, we're ready to allow anybody to register and begin publishing using sites and apps.  Have at it.

One of our short term goals is to improve LimeSpot's interface, making its functionality intuitive.  In that regards, feedback is always welcome.

notification.png Some visual changes have also been added recently.  For example, notifications now appear in a pop-over on the lower left of the page, and we're using the same widget for both AJAX and non-AJAX messages.  We think this is a big improvement over our previous notifications, which were anchored to the top of the page and moved content when they appeared or disappeared.

mutual_friends.png Finally, we also added mutual friend badges to the user cards on the Friends page.  Now it's easy to tell if a friend has been kind enough to return the favor.

What's in store for the future?  Continue to expect UI improvements that will make LimeSpot even simpler to use.  We also want to highlight the social side by adding a Followers page (users who have friended you) and a user search tool. 

A bit further out... well, we have some big plans.  LimeSpot is marked for some serious growth and change, so stay tuned.

Javascript, the minefield

Posted on Mar 31

When a few of us from the LimeSpot team began using LimeSpot for our own blogs, we quickly realized that content scrubbing is a real pain.  We had been whitelisting tags, which meant that any time we discovered we needed a new tag we'd have to add it to the LimeSpot codebase.  Furthermore, there are some tags that we can't add because malicious users can do bad things with them.

User-generated javascript is one of those things that presents so many opportunities but is so dangerous that most sites remove it completely. One of the main dangers of user-generated javascript is cookie theft—malicious users can embed javascript that steals other users' cookies and thus gain access to the users' accounts.  Another danger is the possibility of user-generated javascript executing an AJAX post request to do something malicious such as deleting the user's own account.

Because of these vulnerabilities, users usually have to have their own hosting in order to use Javascript.  For LimeSpot we wanted something a bit more.

Our first approach was to try and protect the cookies.  Several browsers now have support for HTTP-only cookies, but there are still too many browsers that do not.   Also, javascript allows too many methods for evaluating code for us to simply remove the methods for retrieving cookies.  What we ended up doing was moving all user-generated content into separate subdomains, leaving limespot.com for administrative tasks.  By putting users' sites on separate domains, javascript that is executed there cannot access the cookies on limespot.com.  We split our cookies into trusted cookies and untrusted cookies.  Trusted cookies are set for limespot.com and allow users to do anything they please, whereas untrusted cookies are set for (your site).limespot.com and only allow a few actions, such as leaving comments for that particular site.

Each untrusted site cookie needs to be linked with a trusted limespot cookie, so we used <script> tags register the untrusted cookie: (it conveniently renders our lime bar as well)

<script src="http://limespot.com/sessions/lime_bar?app_id=3 
&app_session_id=123456789abcde&site_id=1"
type="text/javascript"></script>

When we receive this on limespot.com, we go ahead and set up an app_session that is linked with the user's real (trusted) session. This way we can always tell who a user is, but we know to limit their privileges when they are on user-generated sites.

There are still a few kinks to be worked out, but we think this is a pretty good way to mix trusted and untrusted markup in the same web application.

Winding down to wind up

Posted on Mar 05

Its been a long, strange trip for us to get to this point, but after weeks and weeks of frantic work and feverish discussion, things have finally begun to draw down into a relative, quiet calm.  And yes, this is the proverbial calm before the storm.

Austin, TX is the place this storm will be centered, because that's where we finally get to open our fledgling site to the public at large as part of Lime Wire's attack on SXSW.  But we sure hope its effects will be felt far and wide shortly thereafter.

While this is a big moment in our short and stormy existence, it's also very exciting for one huge reason: this is only the beginning.  It might sound cliched, but its true.  Up until now, it's been a monumental task just getting the gates opened.  But now we can start actually building on the platform we've worked so hard to create -- adding new apps and tweaking the ones we have as the feedback starts rolling in.

Welcome to the starting line.  ^_^ 

Update and Apology

Posted on Feb 15

LimeSpot was updated again yesterday evening, with only a minor outage.  Another week, another spate of backend fixes that aren't readily apparent -- we've overhauled much of the admin UI and begun to split off asset serving and thumbnailing to dedicated processes.  Exciting work!

Unfortunately, the update introduced a slight misconfiguration and emails weren't being sent out starting at 6:00PM EST yesterday.  My apologies for the error.  To users who registered after that time: confirmation messages have been resent, so please check your inbox.

Friday Update

Posted on Feb 09

This was supposed to be a Thursday Update, since we've moved our weekly deployment back in order to give ourselves a working day to fix any immediate issues.  A series of mishaps, however, delayed the actual release until today.  It was also another "disruptive" update, so I apologize for the outage, but these sorts of things should become far more infrequent.

The big change this week: we've moved LimeSpot onto Engine Yard, and we're thrilled to be backed by such a responsive, savvy crew.  Scaling up should be a lot easier with a dedicated Rails host supporting us, and it's nice to leave the anxiety of managing your own servers behind.

Otherwise, we're continuing towards the public unveiling of LimeSpot's publishing features, and in fact, I'd like to announce that we'll be lifting the curtain prior to SXSW in early March.  Stay tuned for more news about that as we approach the date.

The Joys of Beta Software

Posted on Jan 28

So we came in on this lovely Monday morning to find 14,000 emails in our inbox notifying us of failures in the latest build.

On one hand this means that our exception notification system works, which is a good thing as it allows us to be notified of problems in the field without you having to send us feedback. On the other hand each of these emails represents a user who didn't get the content which they were searching for meaning that the latest build has a few problems to say the least.

Oh the joys of beta software....

To everyone who experienced the random and unexpected "500 Error" page over the weekend we apologize. We have identified the problem and will be pushing out a bug-fix release this afternoon.

Thank you for your patience and support through this roller coaster of a beta!

Friday Update from the UI point of view

Posted on Jan 26

For those of you who have been captivated by our posts of progress here, bless your hearts.  But honestly, there hasn't been a whole lot of visible changes at LimeSpot unless you've been lucky enough to have a site here.  With this past Friday's release, that has started to change.

There's been a long ongoing dialog inside our offices about updating and refining the user interface, and the first bits of that can be seen in the new navigation menu.  Of course, this is just the tip of the iceberg, but Jorge did a nice job of making it the prettiest looking iceberg he could.

This is along with all our normal bug fixes, code revisions, etc.  But hip-hip-hooray!  UI is in the house! 

Yet Another Friday Update

Posted on Jan 21

Nothing major to report this week. We tweaked the UI a bit in preparation for a major face lift that Jorge and Andrew have been working on. In addition we enabled user confirmations, which were mistakenly broken.

As always if you run into any problems, or have any suggestions, please let us know. Contact details are over on the feedback page.

Friday Update

Posted on Jan 11

As I mentioned in the last post, LimeSpot's moving to a weekly update cycle, which we've scheduled for Friday evenings.  It's nice to start with a clean slate every Monday, and we also happen to have the kind of hubris that lets us introduce potential show-stoppers when absolutely nobody will be at the office.

For this release, we've fixed a few bugs, primarily within the admin section, but we've also introduced a very important public feature -- feedback.  In the footer of LimeSpot pages and in the bar at the top of the blogs you should now see links to the feedback page.

We hope you'll share your comments, questions, well-wishes, bugs and annoyances with us as LimeSpot grows.  So speak up, we'll do our utmost to keep our ears open, and help us make LimeSpot truly yours.

21 times more powerful!

Posted on Jan 09

Last night, we completed a massive upgrade of Limespot, one that was a long time coming. Many of the changes, however, are under the scenes -- architecture shifts that should help us grow out and become the community of communities we so desire.

Nevertheless, you may notice some small changes. In-place editing on the profile page has been temporarily abandoned in favor of a traditional form under the Settings tab. This was done largely as a convenience, and since we still prefer the old way of doing things, we'll probably re-implement the "cooler" way soon.

There's also this mysterious "Sites" tab that may beckon to you and present an empty vista. It's a stub but also a promise -- soon enough, the full features of Limespot shall be unleashed, and the power that's been granted to the LimeWire music team shall be available to all. We hope you'll stick around for that.

Future updates should come at a faster pace from here on out, as we experiment with a weekly release cycle. Keep your eyes peeled, and we'll be sure to inform you of the changes, big or small, right here.

Humanized Messages

Posted on Oct 24

humanized_messages.jpg Michael Heilemann of K2 fame recently released a jQuery script called Humanized Messages that implements an idea by Humanized Software. It is a notification system that displays notices in the middle of the screen for a short time until the mouse is moved, at which point they fade away. Demo here.

Upon seeing it, my first thought was "I don't see how this is any less obtrusive than any notification other than a javascript alert box", and my second thought was "this would make a really cool visualization!" Set up a machine just to show off to visitors and every time a new user registers or a member creates a new post, flash a message up on the screen for a few seconds before fading away. If we're going to be a Web 2.0 startup, we at least need some bling, right?

Update: Here's a Script.aculo.us version.

Naughty or Nice?

Posted on Oct 15

Christmas is just around the corner (no, really), and LimeSpot has a pretty ambitious wish-list. We've been nice, however, so we expect Santa to drop off a pretty hefty sack of goodies, including:

More Content: Besides user profiles, there's currently two things to look at on LimeSpot -- the LimeWire Music Blog and the LimeSpot Team Blog, which you are reading at this very second. Not enough, I say. By the year's end, we hope to grow the content by allowing a small number of users to begin kicking the tires on this thing. Hopefully, we'll see some diverse and interesting stuff beginning to emerge.

More Visitors: The LimeWire Music Blog has been a boon to us, driving traffic our way and acting as our flagship site. But we're hungry for more. We want to see traffic steadily rising as we add more content and more features, keeping us busy on the back-end to make sure it all goes smoothly. In short, we want to be the biggest Rails app in the world.

More Interactivity: Leaving comments, fleshing out a profile... it's all well and good, but the real power of LimeSpot lies in its group collaborative and web publishing abilities. To date, however, such power has been reserved for a select few. But the day draws ever nearer, when we shall unleash this unto the world, allowing anyone and everyone to create their own web presence.

More Feedback: We think it's important to listen to our users, adapt and flow with their needs as much as our own internal vision. Unfortunately, the feedback loop is currently non-existent, and this is something we need to fix. A forum? Custom feedback forms? Open ticketing system? They're all up for debate, but we hope to roll out something soon.

There's so much more, but Santa, if you start with this we'll be mighty pleased.

Smash

Posted on Oct 06

Here at Lime Spot, we have a culture of Smash. In the projector room (we once had videographers... don't ask) sits Michael's Wii, and for as long as I remember, only a single game has graced its presence -- Super Smash Bros. Melee.

Penny Arcade has its ping-pong, Googlers probably play Segway polo or some nonsense, and we simply Smash the hell out of each other. And laugh all the while.

Over time, team members have naturally gravitated towards a preferred character, and since I think our on-screen doppelgangers have something to say about us, I'm going to dive into an impromptu team biography. Here's hoping wily traps do not await my return...

Dave as Link: Full disclaimer, this is actually me. Link can't really hit you with any really powerful moves, and he's out-sworded by Marth and Roy, but that spinny thing is damn effective. Likewise, I can't characterize myself as an uber-developer, but with my head down and with a lot of nail-biting, I can usually get the job done. And I can pull bombs out of my ass. Really.

Jorge as Kirby: Kirby seems like a nice guy, someone you'd want to have lunch with, talk about last night's Heroes episode with... like Jorge. Except when he decides to swallow you up into his gaping, sucking jaw and then walks off the stage, taking the suicide just to watch you die. Jorge has that dark side, I just know it.

Michael as Marth: Michael is effective. Marth is effective. Not much more really needs to be said. On a small confined stage, Marth's ability to sweep the air around makes him truly deadly. That doesn't really apply to Michael, but he kind of looks like him.

Josh as ???: I haven't played with Josh yet, so he'll stand in as the random character feature that Nintendo left out by accident. And then you randomly get Mewtwo and curse out loud.

Andrew as Fox: Last but not least, my nemesis, the Fox. For a long time I was completely owned by Andrew's deft control of Fox. But a slight miscalculation or a tremor, and Fox is out-of-control, plunging himself to his own death. So I learned to wait for those opportunities and take advantage of them. I guess trying to compare laid-back, easy-going Andrew as a twitchy, fashion-impaired, cartoon fox doesn't really work.

In the coming weeks and months, we'll talk a lot about LimeSpot here -- more features, fixes and improvements that will transform your life. But expect a bit of a respite... around December 3rd.

LimeSpot.

Posted on Oct 03

Provide people with the tools, and they will build something better than you can ever imagine. On the web nothing ever goes quite according to plans and at Lime Spot we hope to harness that randomness into something people will enjoy using. The product of many months of blood, sweat and tears, LimeSpot aims to provide a platform on which anybody can build anything.

Over the coming months we plan to roll out many new applications and features. Collaborative content creation will allow both regular users and groups to create awesome community-centered websites. Our "apps" will enable users to quickly deploy many themed applications, such as blogs, wikis, and events calendars. Once people have chosen apps they can deploy them to their own domain name.

We'll be blogging regularly about feature updates and other issues surrounding LimeSpot. Check back soon.