There are times when I’m glad I’m not a big wheel in the Ruby community. Saves me all sorts of angst, apparently. 960 Grid System - Another CSS scaffolding system. Nice looking home page, at the very least. The Art & Science of CSS - And speaking of CSS, here’s a free book download from SitePoint. I’ve [...]
There has been an astounding amount of invective and discussion over a recent addition to Rails. Briefly, if you have an array in Rails, you can now use ordinal numbers to get at the first ten members through aliases such as Array#second, Array#third, and so on. Some people are concerned about code bloat, some are [...]
Want to make sure your post-receive hook only gets called by GitHub? Post-receive URLs now support HTTP basic auth.
Some days I am amazed that any software at all ever works. Mike T’s SQLite Database Administrator Tool - The icon is butt-ugly, but the tool is reasonably functional. Ruby Isn’t Fun Anymore - Apparently some people are not feeling the upstart excitement. I’m not one of them. Gist Support for TextMate - Some people are clearly trying [...]
Those of you using Chris Wanstrath’s slick little try trick will now have access to that functionality in Rails with this ActiveSupport update.
Basically, try lets you attempt to invoke a method on an object without worrying about a NoMethodError being raised. If the method doesn’t exist, or if the target object nil, then nil will be returned without exceptions:
1 2 3 4 5 |
# No exceptions when receiver is nil nil.try(:destroy) #=> nil # Useful when chaining potential nil items User.admins.first.try(:address).try(:reset) |
Just a small little bit of syntactical candy pulled in from the community.
tags: ruby, rubyonrails
render is one of those oft-used view-helper methods that always seems to be a little cumbersome. The most common use is to render a partial within another view:
render :partial => 'articles/article', :locals => { :article => @article } |
But this is a lot of work for a simple operation, and now it becomes much simpler. Now the default is to assume that a partial is requested (in the past render a :file was the default) and that the final hash argument is the locals hash. Here is the above functionality using the new syntax:
1 2 3 4 5 6 7 8 9 |
# Render the 'article' partial with an article local variable render 'articles/article', :article => @article # Or even better (same as above) render @article # And for collections, same as: # render :partial => 'articles/article', :collection => @articles render @articles |
If you’ve got some old render calls hanging around that aren’t using partials you’ll have to specify the :file option now:
render :file => 'original' |
Hassle free partial rendering. Yay.
tags: ruby, rubyonrails
Most companies see competition as a threat. If someone’s products could substitute for mine, they’re a competitor; and if a potential customer chooses another product instead of mine, that’s a bad thing.
Lightweight startups take this even further. If you see a need, but another startup has already started addressing the need, then you came at it too late. You’re lightweight, and so your only real advantage is speed. But someone beat you to market. Makes sense, right?
Except it doesn’t work that way.
Going it alone
The typical, but wrong, paradigm goes like this:
- Competition is bad
- Competitors are enemies
- Fewer competitors are better than more competitors
- An opportunity addressed by a few people already is “taken”
- An opportunity with zero competitors looks attractive
There is some truth to these things. Growing in the web search market today is pretty difficult. So is the operating system industry. So are dozens of other industries, and in these spaces, competitors may be be enemies.
But these are mature, settled industries. If you want to create a new search engine, or a new operating system, more power to you – but Google and Microsoft ARE going to be threats. Of course, most startups don’t try to dislodge Microsoft. If you’re working in an emerging market, on a disruptive or innovative technology, you might want to consider a different approach to competition.
Running in packs
This alternative model was described by Andrew Van de Ven of the University of Minnesota in an article called Running in Packs Versus Going It Alone. Andrew and his team found that in emerging, information-based technologies, competition often does not occur between individual startups, but between groups of startups. So as an alternative to trying to go it alone, startups may be better off running in packs: coordinating their efforts by simultaneously cooperating and competing.
This means that when a disruptive technology appears on the scene, its success is dependent upon the whole field of companies working on the technology, not on a single company.
So startups who run in packs should seek the growth of the entire market, in addition to trying to grow their own market share. Better to have a good slice of a growing market, than total domination of a dead market.
Actors seek both to maximize their total surplus and their respective shares in the surplus. ... This draws actors together and drives them to cooperate because no one actor has sufficient resources, competence, or legitimacy to do it alone.
Running in packs works for at least two reasons. First, competitors may help speed adoption of the emerging technology. Second, strong competition may improve and sharpen the quality of the technology.
This also means that politics is important when running in packs, as startups both compete and coordinate.
Actors with political savvy – an ability to recognize the interests of key actors and enroll them to one’s viewpoint – will be more successful in effecting institutional change and realizing their goals than actors without political savvy.
Van de Ven also found that the (disputed) first-mover advantage only really materializes with technologies with strong IP protection, and which can’t easily be reverse engineered, imitated, or substituted. Most web startups these days fall squarely in the “easily imitated” category – including giants like Facebook, Digg, Flickr, and Twitter. And even with a head start and strong patents, first movers may be better off seeking a pack to run with rather than going alone.
Of course, the advantage of running in packs probably only works up to a point. Settled, mature, and (worse) shrinking industries are far more competitive than emerging industries. This means that they’ll have a harder time working together to grow the whole industry, that adoption is less of a problem, and that technological improvement is slower.
This perhaps is why population ecology studies have found that having more competitors in a new organizational niche increases the survival probability of its members until a threshold level is reached where resource scarcity limits the growth of all members of a population.
A retail example
For a low-tech example of running in packs, look at clothing retailers. If going it alone worked in the retail industry, stores wouldn’t pay huge sums for space at the Mall of America – they would avoid it like the plague. After all, clothing stores are highly competitive – one can be substituted for another quite easily, and innovation happens slowly, with the basics (pants, shirts, socks) having been around for quite some time. So you would think that these stores would want to destroy their nearby competitors and be the only place to buy clothes for miles.
But in reality, the opposite is true. Retailers like to locate near other retailers, because going it alone as a retailer apparently doesn’t work very well. When someone needs a new pair of pants, their first thought is to go to a place where lots of people are selling pants. A shopping mall acts as a center of gravity to pull in buyers, and a lone clothing store without competition gets forgotten. So the stores simultaneously coordinate (bringing in lots of buyers to a single area) and compete with each other (for individual buyers). And as a pack, they compete with other packs of stores.
Consulting and Rails
Running in packs works for some location-based businesses, and it often works in emerging industries (the internet, mobile devices, etc.). But it also works with non-commercial technologies, like programming languages.
I’m a co-founder of Slantwise Design, a Ruby on Rails consulting shop. We mostly build web applications for startups. And while there are lots of companies trying to build web applications for startups, a majority of the time, our clients didn’t solicit bids from other competing shops. And as far as I’m aware, after 30+ projects and twice as many proposals, we’ve only competed directly with other Ruby on Rails shops twice.
(There are a few reasons for this, and I won’t go into them in much detail. The most important one is that by the time we give a proposal to a client, they’ve already made up their minds. They don’t want to decide between 10 consulting firms; they’re trying to confirm that we’ll do a good job.)
Ruby on Rails is still a growing technology, and adoption is still increasing. If you want to provide Rails consulting services, there is far more room to grow by taking business from Java or PHP shops than by taking business from other Rails shops. And the technology is still improving, so the growth of the Rails industry is fueled by knowledge sharing between Rails shops. Hence, not only is competition rare between Rails shops, but competitors should be seen as friends, not enemies.
So running in packs works for both Rails consulting firms, and for the proliferation of the Ruby on Rails technology itself.
What about you?
Every startup is different. But a lot of us need to start running in packs. Which model is best for your startup: running in packs or going it alone?
| Run in packs | Go it alone | |
|---|---|---|
| Market size | Lots of growth potential | Level or shrinking |
| Degree of innovation | High – you spend time educating your customers | Low – everyone already understands |
| IP protection | Low – your startup could be imitated or substituted | High – given time and money, someone could do what you’re doing |
| Industry concentration | There is room for lots of companies to profit | The industry will only support 1-2 companies |
And of course, this leads into a second question: which sort of industry would you like to be a part of?
Further reading
This post is based on “Running in packs to develop knowledge-intensive technologies,” by Andrew Van de Ven. MIS Quarterly, June 1, 2005. You can buy this article at Amazon as a downloadable PDF for $3.95
For other thoughts on startups in emerging markets, check out Steve Blank’s Four Steps to the Epiphany.
Now don’t get me wrong, I’m not saying you guys are a pain in the ass. We love our users. Didn’t you get the box of chocolates we sent you? Blasted post office…
The pain has been how we’ve handled support. We’ve tried to give you many ways to get help, perhaps too many. None of them have been as easy to use as we would like. So today we’re going to set things right. Today we’re launching support.github.com, powered by entp’s new app, Tender
But, why?
Over the past weeks we’ve identified these major problems with support:
- Too many options – So you have an issue, where do you report it? The Google group? IRC? Lighthouse? Should you email support@github.com? What if it’s an account issue or a private repo? You don’t want that out in the open. Which place do you go for the fastest response?
- Too many steps – If you go to the group or Lighthouse, you have to make an account. To get to IRC you have to install a client, log in, and hunt down someone who is paying attention to the channel. For email you have to launch up your client and fire off a message. It shouldn’t take this much effort!
- Snowball effect in Lighthouse – Many users have submitted their ideas and issues to Lighthouse. We want to hear from you, but the massive number of tickets in Lighthouse has become unmanageable. The things we want to add and need to fix get lost in the flood of tickets. Most days we receive more new tickets than we close in a week! This is not good for us or for you.
The first step in making support better was taken about a week ago. We added a contact form, a fast, one-step means of contacting support. Support requests nearly doubled. Quick and simple access to help, just what we wanted.
However, there are tons of helpful people in the Google group and on IRC that can help too. This form doesn’t put you in contact with them. The solution to this comes from the wonderful people at entp, the same people that made Lighthouse. They saw the same issues we saw, and they created Tender as a solution. Tender disguises itself as a discussion forum, but it’s much more than that. Issues can be opened without logging in, they can be made private at any time (so only GitHub staff and the submitter can view them), and users can help each other out. On our side of things, we have fast access to all outstanding issues and we can link Tender reports to Lighthouse tickets. In short, it gives users a one-stop shop for all their support needs, and it frees Lighthouse up to do what it’s intended to do, track the things we need to get done.
The public Lighthouse tracker has been made read-only, we will be migrating tickets into the private tracker as we see fit. support@github.com will of course remain active, but will likely be forwarded into Tender sometime in the future. The Google group will remain open for general discussions, but we ask that support issues be directed to Tender instead.
I'm super busy with my duties as technical chair and M.C. for the conference and I'm not getting the opportunity to live-blog the Professional Ruby Conference the way I would like to. Luckily Nick Quaranto is doing a great job documenting the proceedings in details here: Professional Ruby Conference Notes
Liana (with baby in tow sometimes) is also doing a great job of documenting the highlights of the sessions.
So far it's been a really great experience. Along with friends and familiar faces, I'm also meeting amazing people from all sorts of backgrounds and it's doing wonders for my reputation (heh!)
The single track, 30-minute format is wonderful and we've gotten ample praise about it. Everyone in the audience gets the same content at the same time and has plenty of opportunities to meet informally and discuss what was presented. We have quite a mix of experience levels in the audience -- keeping the talks short and sweet ensures that no single group is bored for an extended period of time. We've covered the gamut of topical ranges, from pure case study "this is what we did" in the New York Times newsroom to Philippe's detailed explanation of DTrace.
Our Tuesday morning keynoter, Giles Bowkett, canceled at the last minute, so I had to scramble. After some undecidedness, I opted to try a concept that I witnessed last week at Conferencia Rails in Madrid. Sebastian Delmont and I brainstormed the content over single-malts in the hotel bar last night.
Photo credit: Sebastian Delmont
We distributed two pieces of colored paper to each person, which they used to vote on their preferred choice from the two displayed on the screen. After most of the votes, I asked for the audience to chip in with an explanation (and occasionally apology) for their choice.
Photo credit: Sebastian Delmont
I was asked to post the results, so here is my list of the smackdown lineup:
vim vs emacs: About half of the audience voted, skewed heavily to vim. I didn't want to start a "religious war" so I didn't ask for elaboration.
svn vs. git: Heavy voting, with fairly even split (perhaps slightly skewed to svn). Will from
jQuery vs. Prototype Apparently when I introduced this lineup I said "...still using Prototype" which I apologize for, since it was leading the audience and it got a laugh. I've been a fan of Prototype for a long time, but Hashrocket as a whole has switched over to jQuery in the last 6 months.
Chad Pytel told us that he's still using Prototype on existing projects because it doesn't make sense to switch over, essentially "if it's broke don't fix it".
Sinatra vs. Camping A few people in the back of the room voted for Sinatra. Matt Bauer told us that it's good for very small standalone web apps and yes, it's ready for production-use.
Blueprint vs. YUI About half the audience voted, skewed towards Blueprint. Someone pointed out that the 960 Grid System is cool, and then we spent at least 30 seconds trying to figure out the name and URL.
MySQL vs. Postgres Heavy vote for MySQL. Consensus appears to be that if you come from big enterprise databases then you're going to prefer Postgres. Also, Postgres is more standards-compliant and
blank? vs. empty? This one was a joke (pretty much) that Sebastian and I included in the smackdown to remind the audience to consider the semantic meaning of API methods. The correct vote would have been for both, since they are not used for the same purpose. The blank? method is for strings and returns true for strings consisting of purely space characters. The empty? method is primarily meant for arrays, but works on strings and returns false for strings consisting of purely space characters.
attachment_fu vs. paperclip Evenly split audience, but consensus was that Paperclip is better than attachment_fu in terms of features and flexibility and its implementation code is very clean and easy to figure out. Also, paperclip allows for attaching more than one file to a single model.
system gems vs. frozen gems Frozen gems won hands-down. Bryan Liles said that if anyone thinks system gems is the way to go then obviously they aren't doing production deployment. Sebastian chimed in that using system gems saves 10 seconds on his deploy time, which everyone took as a joke. Not sure if he meant it seriously. :)
Vlad vs. Capistrano A handful of people voted for Vlad, but otherwise the audience favored Capistrano heavily. I asked Matt Bauer to defend Vlad. He mentioned some reasons about its simplicity and how bad early versions of Capistrano were, but in the end he said it's not worth switching at this point because the pain-points of Capistrano have been resolved.
Mocha vs. Flexmock Mike Schwab was the only person who voted for Flexmock, but wasn't really able to defend the choice except to tell us that Chad Fowler and Marcel Molina suggested it once at a conference. (Comments welcome -- Is this reason still valid? Was it ever?)
FactoryGirl vs. ObjectDaddy Not too many people voted and those that did went for FactoryGirl. Earlier in the conference we heard from the testing panel that ObjectDaddy has way too much magic to be useful.
resource_controller vs. make_resourceful A couple of people voted for each. Got the impression that the audience was largely unfamiliar with these great plugins, so I asked Joe Fiorini to explain them. Bottom line, if you're writing your apps in a RESTful manner then you should check out and use one of these libraries because it'll spare you a bunch of boilerplate code.
HAML vs. ERB One of my favorite topics! The split was maybe 33% HAML with surprisingly heavy voting. The reasons for sticking with ERB? Mostly to keep designers happy or based on what I detect as a resistance to change. I gave my typical impassioned explanation of how HAML lessens the amount of mental mapping needed to effectively think of your views as semantic markup and match them to your CSS.
Bluecloth vs. Redcloth Meh...
RMagick vs. ImageScience Meh...
TinyMCE vs. FCKEditor Rich-text editor widgets in Javascript. They're not that different from each other and the audience was all like, "Meh.." :)
restful_authentication vs. clearance This one was funny. A handful of votes went up for Clearance, which disturbed its author, Chad Pytel. He stood up and told us not to use it since it's not ready. The offshoot of Github's popularity, is that once public projects go up, they start getting used -- whether they're ready or not. :)
Test::Unit vs. RSpec I was pretty much out of time at this point, so I skipped a bunch of slides to this matchup. Even distribution and some confusion about whether Shoulda belongs to TestUnit (yes) or RSpec. I think the consensus is that it doesn't matter as long as you're putting some effort into testing. I wondered to myself if the people that didn't vote weren't doing any testing. Things that make you go "hmm..."
If you're so inclined, take a moment to tell me your vote for the following smackdown matchups that I didn't have time to get to in the session...
Mongrel vs. Passenger
Sphinx vs. SOLR
ThinkingSphinx vs. UltraSphinx
exception_noti?er vs. hoptoad
Gruff vs. Google Charts
CouchDB vs. SimpleDB
Vim user? Emacs true believer? Don’t feel left out – we’ve got Gist support for you too!
Vim users can grab Gist.vim (GitHub repo) while Emacsers will enjoy gist.el (which I maintain).
In Vim: :Gist
In Emacs: M-x gist-buffer
They both support Gisting selected text, private Gists, and will tie your Gists to your GitHub account (assuming you followed the Global Git Config instructions on your account page).
It’s hard to work real effectively when your head is ready to explode. But self-employment doesn’t come with paid sick days. What’s New in Edge Rails: Default Scoping - Ryan Daigle covers some of the latest changes. SQL Injection Cheat Sheet - Read it as things to guard against rather than a cookbook, please. Shoulda for RSpec is [...]
gtcaz has begun improving the Gist support in drnic’s GitHub TextMate Bundle
The Gist support was originally written by mattmatt. It uses gist.rb and supports authentication out of the box – when you make a Gist, it’ll be tied to your GitHub account (assuming you followed the Global Git Config instructions on your account page). It also can detect and set the Gist’s language, based on your current TextMate.
Installation is simple:
cd ~/"Library/Application Support/TextMate/Bundles/" git clone git://github.com/gtcaz/github-tmbundle.git "GitHub.tmbundle" osascript -e 'tell app "TextMate" to reload bundles'
Update: Whoops, mattmatt wrote the Gist support. Updated post.
Ever wonder why your ArticlesController has to live in a file called articles_controller.rb but that special ApplicationController gets to hang out in application.rb? Well no more.. That snooty little controller will now live in application_controller.rb and abide by the same naming restrictions that the rest of us do.
As you can see by the comments, by the time this is in a stable Rails release there will be upgrade help. However, for those of you on Edge Rails, you’ll need to make this change yourself.
tags: ruby, rubyonrails
It’s pretty common to want SQL queries against a particular table to always be sorted the same way, and is one of the reasons why I added the ordered scope to the utility scopes gem. For instance, when dealing with collections of articles it is reasonable to expect that the default ordering be most recent first, i.e. created_at DESC. Well now you can specify default ordering, and other scopes, in edge rails directly in your ActiveRecord model.
Taking our Article example let’s specify the aforementioned default ordering:
1 2 3 |
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC' end |
Now, when any find method or named_scope is executed the default ordering comes along for the ride:
Article.find(:all) #=> "SELECT * FROM `articles` ORDER BY created_at DESC" |
The same holds true for any named scopes you might have:
1 2 3 4 5 6 |
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC' named_scope :published, :conditions => { :published => true } end Article.published #=> "SELECT * FROM `articles` WHERE published = true ORDER BY created_at DESC" |
There are some things to keep in mind, however. First is that scopes like :join, :offset, :limit and :order will get clobbered by the innermost rule. For example, here the default scope ordering loses out to the named_scope ordering.
1 2 3 4 5 6 7 8 9 |
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC' named_scope :published, :conditions => { :published => true }, :order => 'published_at DESC' end # published_at DESC clobbers default scope Article.published #=> "SELECT * FROM `articles` WHERE published = true ORDER BY published_at DESC" |
Also keep in mind that the default scoping is inherited, so child-classes of Article will have the same default scoping.
And for those occasions when you want to override or remove your default scope, just use with_exclusive_scope:
1 2 3 4 5 6 |
class Article < ActiveRecord::Base default_scope :order => 'created_at DESC' end # Ignore other scoping within this block Article.with_exclusive_scope { find(:all) } #=> "SELECT * FROM `articles` |
default_scope is a great way to specify reasonable query defaults and relieve yourself of having to create your own named_scopes for that purpose or specify such conditions at every invocation. Yes, I just said ‘relieve yourself’... giggity giggity
tags: ruby, rubyonrails