MinneBar 2008

Posted by Luke
on Thursday, May 08

MinneBar Logo

MinneBar – one of the largest BarCamps in the world – is being held this Saturday at the University of Minnesota.

Several folks from the Rail Spikes/Slantwise/Tumblon orbit will be presenting.

  • Jon will be speaking about Consulting for fun and profit based on his experience with Slantwise as well as demoing Tumblon.
  • Norm will be sitting on the Design Coding Panel as well as leading a session on CSS frameworks
  • Dan Grigsby (Rail Spikes alum) will be sitting on the State of the State: Technology in Minnesota panel and giving a talk called Screw You LAMP. Plus Virtualization.

Me? I’ll be helping run the thing and maybe giving a demo.

There’s 360+ people signed up already. If you’re in the area, you should definitely come. It’s going to be awesome.

Rails gets more mature

Posted by Luke
on Friday, May 02

Rails 2.1 is right around the corner. I’ve been following the new features in Edge Rails and eagerly looking forward to this release. Rails 2.1 includes a number of features that will make developers’ lives easier. Here’s a few of my favorites.

Necessary directories created if they don’t exist

Neither Mercurial nor Git track empty directories. This is a pain with Rails, because you have to create a file in the log directory to make sure it gets created when you check out code, otherwise Rails won’t start. This is no longer needed, because Rails will create necessary directories if they don’t exist.

Time zone support

Time zones are a huge pain in any application, in any language because they are just plain confusing. But ya gotta do it. In Rails, the solution used to be using the TzTime and TzInfoTimeZone plugins. Rails 2.1 adds support for tracking Time objects with their time zone. This is going to make everyones’ lives a lot easier. Check out Geoff Buesing’s in-depth tutorial.

Partial updates and “dirty” tracking

Two features that I knew and loved in our home-brew ORM from my former life as a Java developer have made it into Rails.

With dirty objects you can know if you need to persist an object, and which attributes have changed, and what an attribute’s previous value was. This will be great for user messages and validations!

In Rails 2.1, ActiveRecord can update only the attributes which have changed. This can (sometimes) put your objects into an inconsistent state, but partial updates improve performance, especially when you have big TEXT or BLOB attributes that haven’t changed. Use optimistic locking to prevent users from stomping on each others’ changes.

Timestamped migrations

With all this distributed SCM going on, the classic problem of messed up migrations gets way worse. I talked about solutions to this in my talk at acts_as_conference, one of which was timestamped migrations. Timestamped migrations allow interleaved migrations. As long as those migrations don’t conflict with each other, they can be applied in any order. This has been added to Rails. Nice!

Better gem dependency and unpacking

I am a big fan of the vendor everything approach to gems because I got burned way too many times by missing gems.

But it doesn’t always work (for example, gems which must be natively compiled are a problem), and you have to install one of the various vendor everything plugins—and everyone seems to use a different one. In Rails 2.1, gem unpacking is built in with rake gems:unpack GEM=gemname. (more info)

And for those gems that don’t work, you can list them as a dependency. Your app will fail to start if the gem is not installed. Fail early, fail often!

Text helpers usable outside the view

You can now use helpers without including them into your class. Hurray!

RubyFringe keeps rolling

Posted by Luke
on Thursday, May 01

RubyFringe is shaping up to be a pretty kick-ass event. Besides tons of great speakers (present company excluded), they are having all-inclusive parties every night, and no lame sponsors to dilute the signal to noise ratio. Keeping attendance capped at 150 also ensures awesomeness, because everyone will get a chance to meet everyone else.

It’s also the only conference out there that I know of that has activities for your non-technical girlfriend/boyfriend/wife/husband/whatever. That is such a great idea.

July 18-20 in Toronto, Ontario (aka Accordion City). Registration ends June 11. Get on it.

Quick tip: store_location with subdomains

Posted by Jon
on Thursday, May 01

Both restful_authentication and the older acts_as_authenticated have a handy method called store_location. This method stores a URL in a session variable for future reference. The obvious use case involves login. For example, if you’re browsing a product anonymously and want to write a review, you’ll need to sign in first. So if you click a link on that product page that requires you to be logged in, and this sends you through the login process, you’ll ideally want to be returned right back to where you were before you logged in. store_location enables this, along with the redirect_back_or_default(), also provided by Rick Olson’s authentication plugins.

You store a location like this:

1
2
3
4
5
6
7

  def private_action
    unless logged_in?
      store_location
      redirect_to login_path
    end
  end

After authenticating the user, you send them back to the stored location with this:

1
2
3
4
5
6

  def login
    if login_successful? # pseudocode, obviously
      redirect_back_or_default(home_path)
    end
  end

If a location is stored in session, redirect_back_or_default will send the user that location. Otherwise, it redirects to the default path.

This is pretty handy. But unfortunately, it doesn’t jump across domains, including subdomains. Tumblon lets parents set up blogs for their families, and these blogs are either identified by a subdomain (e.g. myfamily.tumblon.com) or by a top-level domain (coming soon). Tumblon also has privacy controls, so I can set a story to be viewable only by my family and friends. So if an anonymous user hits the URL of a private photo/story/video, they should be redirected to the login screen and then right back to the item they were trying to view. But out of the box, store_location can’t handle this.

Let’s look at the store_location method to see why. This method is in lib/authenticated_system.rb.

1
2
3
4

    def store_location
      session[:return_to] = request.request_uri
    end

store_location uses the request.request_uri method, which only provides the relative path (e.g. /photos/932783). So if you login at tumblon.com, store_location won’t return you to myfamily.tumblon.com/photos/932783 – it will send you to tumblon.com/photos/932783. Your app could have logic to redirect from this page to the subdomain, but an easier solution is just to create a new store_location method, like store_location_with_domain. Or you could always override the store_location method to always use request.url instead of request.request_uri if you don’t want a separate method.

1
2
3
4

    def store_location_with_domain
      session[:return_to] = request.url
    end

Put this method in application.rb, and you can now use redirect_back_or_default to hit an exact URL – complete with subdomain, top-level domain, and port.

Quick links

Posted by Luke
on Wednesday, April 30

MySQL’s Over-looked and Under-worked Slow Query Log.

Dynamite is a JRuby interface to Processing.

How to send multipart/alternative e-mail with inline attachments.

Prototip and Starbox are awesome.

Note to self: alias_method_chain doesn’t work with ActiveRecord attributes.

Rails Search Benchmarks comparing Ferret, Solr, and Ultrasphinx.

Extend String to use ActionView’s Text Helpers. I may have to add this to my standard bag of tricks. Wish it was in core. Fortunately, in Edge Rails, the helpers are now accessible by module. Nice!

ar_mailer: how to avoid memory related issues and Running ar_sendmail with monit.

Timeframe is a totally awesome looking Javascript date picker.

Datejs parses human dates in JavaScript. Very cool.

Promise and Peril for Alternative Ruby Impls. JRuby’s Charles Nutter takes a look at the state of the alternative Ruby implementations and the challenges they face. I hadn’t heard of MacRuby before—sounds like it will be a great way to write Mac OS X apps. MagLev (Ruby with Smalltalk VM technology) also sounds interesting (interview) but I imagine it will cost booku bucks.

Seed Fu is a new library for loading seed data.

Duplicate posts in some feedreaders

Posted by Luke
on Monday, April 28

We’ve been getting complaints about seeing duplicate posts in some feedreaders (and I’ve seen this myself several times at Planet Ruby on Rails). We like our subscribers and don’t want to piss you off!

Does anyone know what causes this? We are using FeedBurner with Mephisto (approximately version 0.8) and producing Atom. The feed validates.

Our guess is that it has something to do with updating the posts, but we’re not sure. It may also happen when updating the permalink (which I encourage my co-authors not to do after publishing. Naughty naughty!) On Planet Ruby on Rails, there is sometimes a problem where one copy of the post goes to “www.railspikes.com” and one to “railspikes.com” and one to the FeedBurner post link (example).

We have id, published, updated and link tags to identify each entry:

1
2
3
4
5

<id>tag:railspikes.com,2008-04-25:1351</id>
<published>2008-04-25T18:57:00Z</published>
<updated>2008-04-25T18:57:12Z</updated>
<link href="http://feeds.feedburner.com/~r/RailSpikes/~3/277795704/startup-school-2008-misc" rel="alternate" type="text/html" />

Any ideas? We’d like to fix this problem.

Startup School 2008: ...and many more!

Posted by Jon
on Friday, April 25

This is the third of three articles discussing Startup School 2008, a free conference that happened at Stanford on April 19. The first article covered Paul Graham and David Heinemeier Hansson, who talked about building the right product and how to make money from it. The second article talked about VC funding. This one covers five remaining presenters.

Listen to your users – but not too much

Paul Buchheit, creator of Gmail and FriendFeed, talked about the process of listening to users. User feedback is important, of course, but when it comes to this feedback, listen != obey. Often, users’ feedback needs to be decoded and interpreted; a user may ask for one thing but really need/want something else. At Gmail, for example, a lot of users asked for the ability to reply to a message right from the inbox. After listening to users, though, Paul learned that what they meant was that it took too long to view a message and reply from there, which means that the real problem was that Gmail was too slow. So they sped up the system, and users stopped asking for this feature.

Similarly, users sometimes ask for conflicting things. 5% of your users may ask for Feature X, but what if Feature X makes the system less useful or more cumbersome for the other 95%?

The long and short is to care about user feedback, but don’t be a slave to it. Users don’t always know what’s good for them, and what’s good for one user may not be good for another.

EC2 is interesting

Jeff Bezos of Amazon pushed AWS. Hosting is basically “undifferentiated heavy lifting” – it needs to be done, but it doesn’t matter who does it. In other words, your site will be worse if it is hosted poorly, but once you reach a baseline of quality, your site won’t be any better or worse based on who does your hosting. Jeff compared this to electricity: 100 years ago, a factory may have its own generator for creating electricity. But with modern electrical grids, most businesses would be crazy to create their own electricity.

I’m not sure if EC2 is quite ready (though persistent storage and elastic IPs help), but it definitely has promise. Indefinite auto-scaling of the application layer sounds great. Unfortunately, EC2 doesn’t offer much to help database scaling, which is a harder problem anyway; so capacity for thousands of web/application servers might not mean anything if your database is the bottleneck. And you almost certainly want your database and your application servers in the same network.

There is one thing that EC2 is perfect for, though: asynchronous processing. If you need to do a lot of processing in the background (see Zencoder, NY Times, Animoto), then you have an easy choice between EC2 and purchasing thousands of servers to meet a short term need.

Tell TechCrunch a Story

If you want to get on Techcrunch, you’re in good company – just about every startup would like a positive writeup from Michael Arrington, and the traffic that follows. But TechCrunch has grown to the point where it can’t write about every startup, so it is picky. Michael talked about how to stand out from the crowd. The solution is what any good PR firm knows: tell a story. “Please write about GoodReads” is not a story. “GoodReads Launches” is a story, but not a very interesting one. “GoodReads gets 1,000,000 users” is a bit more interesting. “GoodReads to publish Harry Potter 8 online” will be picked up by TechCrunch, Mashable, CNN, NY Times, and everything else.

Michael also cautioned that sometimes the stories that are most interesting to the media (TechCrunch included) are the ones that you don’t want written. Leaks, rumors, and scandals play well in the press. So you might want to think about how you can make the most out of gossip and “negative” stories if they arise. And if TechCrunch bashes you, says Michael, engage them – don’t ignore or throw stones.

Finally, Michael recommends that startups not pay for PR, but rather engage the community through blogs, Twitter, discussions, etc. Personally, I don’t see what’s wrong with combining traditional PR help with social/community relations, but talk to me in another year or two and I’ll have a better perspective on the matter.

Be so good that they can’t ignore you

Marc Andressen has several big successes under his belt and is currently working on Ning. He did a Q&A session with Jessica Livingston, asking questions voted on by Startup School attendees. The discussion was good, though as Q&A it didn’t really have a single theme. One thing that stood out was Steve Martin’s advice to young comedians wondering how to break out: “Be so good that they can’t ignore you.” This is great advice to startups, who sometimes get caught up in issues of funding, pricing, staffing, marketing, networking, etc. All of these things are important, but if your product is good enough, the others will fall into place.

Data provides the best feedback

Peter Norvig closed the day and talked about learning algorithms, not surprisingly. But of course, he connected them to startups. A good formula for a startup goes something like this:

  1. Start small
  2. Go fast
  3. Gather feedback *
  4. Iterate

Learning algorithms can help with #3. The right dataset plus 20 lines of code can tell you important things about your users, your market, etc.

Conclusions

  • Build something worthwhile, and build it really well.
  • Build something you care about.
  • If you need funding, go in with your eyes open and with the right advisors. And don’t let the quest for funding kill you before you even get out the door.
  • Build something that people want and need.
  • Iterate quickly and frequently, based on user feedback; but dig into the feedback rather than following it blindly.
  • Engage the community.

Startup School 2008: how and when to work with investors

Posted by Jon
on Thursday, April 24

A few days ago, I wrote about Paul Graham and David Heinemeier Hansson at Startup School 2008. This article discusses three more talks, all of which deal with funding and legal issues. I’ll write more tomorrow about five remaining talks, which talk about building and marketing the right product.

I’m not going to spend as much time on the these 8 presenters. If you want to read more about the event, check out the videos themselves online, or other summaries of the event (Phil Crissman, Matt Maroon, Foodliker, etc.).

Raising money is an evil – make sure it’s necessary

Sam Altmann of Loopt discussed his experience raising venture money from Sequoia. VCs, in his experience, look for three things: the right market, the right team, and the right product. Each firm has a different emphasis, but all three really need to be in place. Sam introduced a great concept: demand by proxy. For example, if the most common text message is “where are you?” – which it is, apparently – then there may be demand for a mobile solution for locating people.

He also talked a bit about the process of raising money. Raising money is no fun, and it ultimately isn’t productive. Every week spent courting investors is a week that you aren’t working on your product, your marketing, etc. Of course, it is sometimes necessary. But if your company is going to raise funds, this should be the responsibility of only one of the founders, and (ideally) this should not be his or her only responsibility. This sounds obvious, but Sam has seen startups where multiple founders focus all of their energy on raising money for several months, which is tough on a company.

I can say from experience that raising money is a hard process, and that it really needs to be kept in check. If you need investment, you’re better off spending some time on your product as well; after all, if you can build a good product and get early signs of traction in the market, investors are going to be much more interested than if you just have an idea. And if you don’t get the funding you need and need to bootstrap, then you’re better off spending more time on the product as well.

Actually, there is one sense in which pitching to investors is productive (apart from the potential investment). Pitching helps you to nail your plan. Most angel and venture investors are careful with their money; they don’t want to throw it away. And most get pitched frequently – several times a week even. So they will typically be happy to point out what’s wrong with your business and why it won’t work. As an entrepreneur (who can easily get buried in a project and lose perspective), it is great to be challenged. Even if you get rejected, talking to a few smart investors will help your vision.

Hire good attorneys

Jack Sheridan, an attorney with Wilson Sonsini etc. (the law firm for Silicon Valley startups, according to Jessica Livingston), talked about legal issues for startups as they are founded, raise money, etc. The biggest take away was to have good lawyers. More specifically, Jack warned founders against participating preferred stock, where on liquidation an investor first gets paid back their original investment (the “preferred”) part, and then receives a full share of the remaining funds (“participating”; and cumulative dividends, where the company is obligated to pay a continual dividend to preferred shareholders, and where the obligation accumulates over time if it can’t be paid. In other words, if you take VC money under the wrong terms, your company could be a moderate success (e.g. sell for $20M), and the investors could walk away with just about everything.

The second main point was to be careful with vesting. Even founders’ stock should be vested, according to Jack. Let’s say three people start a company and divide ownership evenly. One quits after two months, while the other two work hard for years for low pay. The company is then acquired after 5 years. With no vesting, the founder who left still owns a significant portion of the company. Vesting takes care of this by issuing shares progressively over time. Brad Feld has a good article on vesting with details of typical terms, etc.

Find and ride the right wave

Greg McAdoo is a partner at Sequoia Capital, one of the top VC firms in the world. Greg gave a good overview of what VCs look for. Some of this was redundant with Sam’s earlier talk, though it was interesting to hear about VC funding from both sides (the investor and the entrepreneur). Greg emphasized the importance of finding the right market, using a surfer analogy. A surfer (entrepreneur) needs to wait for the right wave (market), and needs to hit it at the right time. The surfer can’t change the wave and can’t create the wave – they can just ride it, successfully or unsuccessfully. Similarly, a great product isn’t worth much if it hits too early or too late, or if there is no market for it.

Greg also suggested that startups build products for people whose hair is on fire. If you come across someone who is on fire, and offer them a solution, they’re likely to take it and unlikely to haggle with you on price.

Finally, try to find an unfair advantage – something that keeps other people from competing successfully with you. And try to increase this advantage over time, rather than just worrying about it early on.

Watch for the final post tomorrow, which will cover Paul Buchheit, Jeff Bezos, Michael Arrington, Marc Andressen, and Peter Norvig, along with a conclusion.

5 little-known Rails methods

Posted by Eric
on Wednesday, April 23

While the next release of Rails appears to be coming up, there’s still plenty of small, useful features from previous releases that aren’t widely used.

A few of my favorites:
  1. query_attribute
  2. polymorphic_path
  3. debug
  4. rake -T `query` ( Not Rails specific, but still handy! )
  5. extract_options!

1. ActiveRecord’s query_attribute

Query methods are available for each of a record’s attributes, providing for a cleaner way to check for the presence of an attribute.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# == Schema Information
# Schema version: 17
#
# Table name: users
#
#  id                    :integer(11)     not null, primary key 
#  first_name            :string(255)     
#  last_name             :string(255) 

# Original
class User < ActiveRecord::Base
  def named?
    !first_name.blank? && !last_name.blank?
  end
end

# Refactored to use query_attribute
class User < ActiveRecord::Base
  def named?
     first_name? && last_name?
  end
end

2. Indifferent links with polymorphic paths.

Rails has polymorphic edit/new/formatted path routing available out of the box. Providing an array will namespace the path with those array parameters. Available Methods: (edit|new|formatted|)polymorphic_path(record_or_hash_or_array)

1
2
3
4
5
6
7
8
9
10

# Before:
<% if @record.is_a?(User) %>
<%= user_path(@record) %>
<% elsif @record.is_a?(Friend)
<%= friend_path(@record) %>
 ... etc.

# After:
<%= polymorphic_path(@record) %>
Quite a few options are supported, and other Rails methods take advantage of polymorphic routing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Paths can be namespaced:
#=> admin/users/5/edit
edit_polymorphic_path([:admin, @record])

# Polymorphic urls are also internally used by helpers:
# redirects to store_path(@store)
redirect_to @store
  
# builds a form with an action to 'new_admin_stores_path'
#=> <form action="admin/stores/new" ... />
form_for([:admin, Store.new])

# <a href="/stores/5">A store in Minneapolis, MN</a>
link_to @store.name, @store

3. debug

Especially useful when starting out a project, this is quick way to understand what objects are being used in the view.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


<%= debug @user %>

# Yields this in the view:
# - !ruby/object:User 
#  attributes: 
#    salt: 7be4287a1b27426fa6e5b6d733c707dd66425e82
#    updated_at: 2008-04-22 19:01:23
#    crypted_password: abb611def895dac923ba8ea59a78451f77473d5e
#    id: "1"
#    first_name: Eric
#    last_name: Chapweske
#    created_at: 2008-04-06 01:45:33
#  attributes_cache: {}

4. rake -T task

This is a handy Rake feature, and not limited to Rails. Can’t remember the exact syntax for a particular rake task? Trim the results generated with `rake -T` with an optional search parameter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

$rake -T

rake annotate_models                 # Add schema information (as comments)...
rake audit:purge                     # Removes Audit records older than 2 m...
rake db:abort_if_pending_migrations  # Raises an error if there are pending...
... etc.
rake tmp:sockets:clear               # Clears all files in tmp/sockets

// Searching by the task's name

$rake -T db:migrate:r

rake db:migrate:redo   # Rollbacks the database one migration and re migrat...
rake db:migrate:reset  # Resets your database using your migrations for the...

5. extract_options!

While not needed very often, Rails comes bundled with a method to extract the options from methods that utilize the splat operator. This method removes the last object from an array if it’s a Hash, otherwise an empty hash is returned.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


class Story < ActiveRecord::Base

  # Example: 
  # Story.published_and_tagged_with('deep', 'thoughts', :order => 'created_at desc') 
  # The generated options for this method look like this: 
  #=> { :include => :tags, :order => 'created_at desc' }
  def self.published_and_tagged_with(*tag_names)
    options = tag_names.extract_options!
    options[:include] ||= :tags
    
    ...
  end
end

References

I wasn’t able to find any write ups on the above methods, so reading the source code may be the best path if you’re curious about their exact implementations.

Good advertising

Posted by Luke
on Wednesday, April 23

While searching for Ezra Zygmuntowicz’s new book Deploying Rails Applications I got this as the first result. Oops.

Startup School: Paul Graham and David Heinemeier Hansson

Posted by Jon
on Monday, April 21

I attended Startup School at Stanford this weekend thought it was really well done. There were 11 (count ‘em) talks of about 20-30 minutes, which was a pretty good format: lots of information, and not much fluff.

Paul Graham’s Mid-Morning Keynote

Sure, it was 10:30am, but Paul Graham’s talk had the feel of a (short) keynote. He spelled out the YCombinator approach to startups: Make Something People Want, and don’t worry too much about making money early on. But this approach makes for a strange equation:

Make Something People Want + Don’t Worry About Making Money = Non-Profit

Of course, as an investor and libertarian, Paul Graham is all about making money. But if you really do make something that people want, you can often find a way to get their money. Think of Craigslist. It’s 99.9% free, and doesn’t seem especially concerned about money, but it is also extremely successful. They basically just made something that people wanted, and the rest fell into place.

So instead of nailing down a business model early on, Paul suggests that you work your way “upwind” of profit. If you’re fighting a sea battle in a frigate, your ultimate goal is to sink your opponent’s ship. But the way to do this is to work yourself into position where you can win, by being upwind of the enemy. In a sense, being in the right position is more important than firing your canons early on. (By the way, I’m a little inexperienced with naval warfare, so if you find yourself in a sea battle, I don’t recommend you rely on this advice.)

How, then, do you put yourself in position to make money? First, Make Something People Want. Second, consider benevolence. After all, if you build something people want, and treat them well, you’re well positioned to capture their money.

Beyond this, Paul gives three reasons why benevolence makes business sense.

  1. It improves morale: your employees will be happier, and people will be more interested in working for you.
  2. Being benevolent makes others want to help you.
  3. It also helps you be decisive. If you’re deciding on a course of action, and you choose whatever is best for your users, you’ve probably made a pretty good decision. Whereas if you’re out to screw people over, your life is a little more complicated. (Think of lying: if you lie a lot, you have to keep track of all the lies you’ve told; but if you tell the truth, you don’t need to worry about that.)

I’ve been thinking a lot about startups and ethics lately – not in the “business ethics” sense of “should I play dirty to win?”, but in the sense of “life isn’t really about making money.” This talk was an interesting call to build something worthwhile first, and to profit later.

Notice that this all depends on funding. If you have no funding or no day job, it probably isn’t a good idea to build something without worrying about the business model. But that’s YCombinator: YC provides the seed round, and often paves the way to Angel or VC money.

David Heinemeier Hansson provides a good counterpoint to this approach.

The secret to successful startups

David Heinemeier Hansson gave a great talk soon after Paul Graham, in which he proposed a different approach to successful startups. The secret, according to David, is the middle term in this common formula.

  1. Build a great application
  2. ???
  3. Profit!

Paul Graham suggests that you overlook #2 early on, and instead worry about #1. While David agrees that #1 is important (and is completely in line with the YCombinator “Make Something People Want” mantra), he suggests that #2 is actually pretty easy:

  1. Build a great application
  2. Price
  3. Profit!

In other words, if you want a successful startup, charge money! Don’t worry about VCs, complicated business models, or winning the $1.6B lottery. Instead, just build something people like and charge for it.

He goes into a little more detail, suggesting that you’re better off selling to businesses than to consumers. Consumers want things for free, but businesses are generally willing to pay for good services. He also provides some helpful math, like: $40/month * 2000 users = $1,000,000/year. In other words, you don’t need a ton of users in order to make good money.

There has been some discussion (blog post and news.yc thread), suggesting that it isn’t that simple. After all, 37signals is a PR machine, as much (or even more) than a software company. When they launched Basecamp, they already had a huge following, which gives them a huge advantage over the rest of us.

This is all true, and it’s true that David oversimplified things. But his point wasn’t that it’s easy to win – in fact, he suggested that you might only have a 1 in 10 chance of winning. His point was that you’re better off taking a 1 in 10 bet at a Basecamp-size success than a 1 in 10,000 success at a YouTube-size success. Even though the next YouTube may make 1,000 times the money of the next Basecamp, the marginal value of the first $1M is much higher than the last $1M. So if you only have one life to live, you’re probably better off aiming for a small success than a take-over-the-world success.

As a corollary – and I thought this was a great point – you’re better off enjoying yourself at a somewhat successful company than spending your life in meetings at a hugely successful company. Would you rather be a modest success and work 4 days a week or be a workaholic and hope that you win the M&A lottery?

Again, it’s not quite that simple. It is hard to build even a modestly successful company, and it doesn’t hurt to aim big. But in principle, I’m down with David. After your basic necessities are met, having more money doesn’t really make you happier. And I’d much rather build software 30 hours a week than sit in meetings 60 hours a week, even if the latter paid better. And though it isn’t easy to build a successful “lifestyle” business (which a terrible term, by the way) if you’re smart and apply yourself, you’ll probably figure it out eventually.

I’ll write about the other talks tomorrow. And if you didn’t attend, the videos are posted at Omnisio.

Six reasons to attend conferences (and one I'm attending)

Posted by Jon
on Thursday, April 17

Saturday is Startup School, a free one-day conference at Stanford put on by Paul Graham and YCombinator. I decided to apply this year and was accepted. Not that this is a real honor: my guess is that the criteria for being accepted are (1) applying before they’re full, and (2) being a software developer who is interested in startups. Apparently, I met both criteria.

So if you’re going to, let me know! Post a comment, email me, or say hi.

The problem: why pay to hear what you can read for free?

But why fly out to California just to hear a few people talk? Why pay a grand or two for a trip to OSCON, RubyFringe, etc.?

After all, the devil advocates, I could probably read a few books or a dozen blog posts and get access just about all of the information that will be communicated at these conferences. As a bonus, reading is faster than speaking, so I could probably see double the information in half the time. That would save me a lot of money and several days of my life.

Let’s take this to it’s extreme. I’ve seen Paul Graham speak once (at the first RailsConf). He basically wrote an essay for the conference, presented it, and then posted it to his blog. What a waste! I didn’t need to go to RailsConf just to hear something I could read on my own, right?

Six reasons that conferences are worthwhile

The thing is, learning doesn’t work that way. At least for me. I learn probably 10x-100x more when I sit down for a good talk than by reading the transcript. It has to be good, of course – a bad talk is no better than a bad transcript. But if the speaker and the information are worthwhile, hearing it in person that beats words on a page every time. I think there are several reasons for this.

First, being in a room with a speaker creates a stronger personal connection than just reading an article. The connection might still be weak; you might sit in the back of a room with a thousand other strangers, and the speaker might be mic’d and small. But even this weak connection allows for different, and stronger, relationship than you get from a blog post or a book.

Second, nonverbal communication is important, and is pretty hard to pick up from words on a page. In person, someone can communicate in at least four important ways: the words they speak; tone of voice and vocal emphases; physical gestures; and their overall manner and appearance. In writing, you just have words.

Third, in-person communication allows for a greater fidelity of communication. Dan has talked about a study of how audio quality impacts communication. Compare a PA system at a bus station to a CD, or a bad VOIP connection to an in-person conversation. Have you ever tried to have a conversation with a 1-second delay (think Apple video chat)? It is really tough. So the difference between reading someone’s words and hearing them speak is huge. (Bruno wrote a great article about email last year that describes this well.)

By the way, none of this is to say that there is anything wrong with books, blogs, and the written word. I love books, read blogs daily, and write emails every now and then. They have a place, and are better than oral communication for some things. They just don’t replace conferences. But I digress.

Fourth, when a speaker presents at a conference, they have a tighter feedback loop that offers them a little more control over their message. If they say something confusing or controversial, they can read the audience and slow down, clarify, or restate their point. Notice I say “a little” – I read enough Derrida in a former life to know that a speaker (or author) can’t control the hearer’s understanding of the words they say, and that writing and speech communicate in fundamentally the same way. But face-to-face (or face-to-audience) communication makes feedback and interaction a little easier.

Fifth, if I sit down to listen to someone, I’m making a larger commitment of time and attention. I may read 50 blog posts in one day, and devote a few minutes to each. You’re lucky if I spend more than 10 minutes reading your blog post (and your name is probably Steve Yegge). But if you have something to say, I’ll listen to you for an hour. And I probably won’t be listening to music or checking my email in the background while I do.

Sixth, conferences let you experience a talk with other people who are thinking about the same things. There is something about sitting next to people and seeing how they react. When do they laugh? When do they seem bored? When do they listen with rapt attention? Your learning is shaped by theirs, and you shape their experience too.

OK, so I probably still won’t drop $1,400 for Business of Software 2008. But it is tempting, and if my startup were profitable yet, I’d be there.

Command line history

Posted by Luke
on Wednesday, April 16

Here’s mine. Try it, it’s fun.


$ history 1000 | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head
222 hg
64 rake
40 cd
23 mate
17 ssh
14 script/server
11 cap
9 script/console
8 sudo
8 ack

(hg is Mercurial. ack is a grep replacement written in Perl)

Hiring: Ruby on Rails Dark Lord of the Sith

Posted by Jon
on Tuesday, April 01

Slantwise Design is hiring one Ruby on Rails Dark Lord of the Sith. Candidate will lead Rails projects in a fast-paced, show-no-mercy environment. Our ideal applicant will have 1-3 years of Rails experience, a strong programming background, and be open to the power of the dark side.

Desired skills:
  • Ruby on Rails
  • Ruby programming (non-Rails)
  • Web deployment experience (Linux/Unix, mongrel, etc.)
  • Java background a plus (and JRuby experience great), but not necessary
  • The force, esp. mind trick
  • Database knowledge (i.e. deeper than just ActiveRecord)

You will also be responsible for enforcing order within our projects. We practice rigorous waterfall project management, with heavy emphasis on meetings and documentation, so experience with the FAHS system (Fear -> Anger -> Hate -> Suffering) a plus.

We currently have two Rails Sith Lords on staff but are interested in bringing in some fresh talent. To apply, please send your resume to darklord@slantwisedesign.com and vanquish one of our current developers in single combat.

Edit: Happy April 1

Sadly, we aren’t actually hiring Rails developers at the moment, but special thanks to Darth Rubious, who put Eric in the hospital.

Configuring asset hosts for an app with subdomains

Posted by Luke
on Thursday, March 13

Tumblon allows users to create blogs with a custom subdomain like mysite.tumblon.com. Today, I was working on configuring asset hosts for Tumblon to improve download performance, and I ran into a snag.

We have a list of restricted subdomains which are not available for users to register, including the default Rails asset host names: assets0.*, assets1.*, assets2.* and assets4.*. I set up a new virtual host for the asset host with server aliases for the names (we have wildcard DNS to support the app’s subdomains).

This worked in the main application, but broke with the subdomains. All the subdomains started resolving to the asset virtual host (I think because it was first).

So I went back to the drawing board. I deleted the assets virtual host and came up with this re-write rule to fix my problem:


# Check for asset hosts
RewriteRule %{REMOTE_HOST} ^assets\d.* [L]

What this does is matches any request like that starts with assets and a digit and stops it from going to Rails, thus having Apache handle it. This is above the rewrite rule for the Mongrel Cluster proxy, so any other subdomains will go to Rails.

I put this out there in case it helps anyone else who has this problem.