About a year and a half ago, Pivotal Labs started a new practice, focused on product-led startups. It's not the traditional VC/EIR model though. With Pivotal, our clients are the ones with the product vision. They're the entrepreneurs. We focus on bootstrapping development, and getting the engineering effort going. We're just here to make sure the technology works, and that engineering execution doesn't get in the way.
When we take on a project, we like to hit the ground running. We seed the project with an experienced team, ready to begin executing immediately on the client's product vision. As the vision grows and changes, our team adapts. Usually the client will start hiring their development team as development continues. Often, we'll help them recruit and interview. Then we'll weave their new folks into the team, teaching them the code base, and all our techniques as well. We want to make sure that when we're done with the project, their team can move into the next phase of development with confidence, and keep things running smoothly.
When our clients already have an established development team, we weave our developers in with theirs, and co-develop with them. If they're new to agile, we teach them agile practices by doing, as we write code with them. Rather than dropping in with a day-long lecture based on toy problems, and then vanishing into the sunset, we show them how agile works, in their own development environment. We fill in any gaps in their design, modeling and testing skills, and generally improve development practices as we go. Once they're self-sufficient, we weave our developers back out, and move on to the next engagement.
Build-Operate-Transfer
Rob Mee, our founder and CEO, likes to borrow a phrase from the civil engineering world to describe how we engage with start-ups: Build-Operate-Transfer. When an enterprise is first getting started, they typically don't have the engineering resources to get going quickly, and can lose months of lead-time trying to build a team. That's where we come in: Our job is to take our clients from a standing start to a fully functional product, something we can typically do in a few months. Once things are up and running, we're ready to turn over the reins, and let their team run things for themselves.
Flexibility
One thing that's special about us is that we can vary the team size on demand. During the early stages of development, start-ups will often have big fluctuations in workload. We can ramp the team size up or down, depending on development objectives and financing constraints. We can develop at full speed for a week, a month, or a year, then stop on a dime—and stop burning capital—and stop for as long as it takes for the client to close a funding round, or get some traction in the marketplace, or decide on the next round of features. Our clients are done with us when they decide they're done. Their business goals and product needs are always in the driver's seat.
We strive to be a strategic partner for our clients. We are not an outsourcing firm but instead work to get our clients self-sufficient. We believe our approach offers a unique balance between the short term need for execution and the long term need of sustainability.
Interesting Things
- Rspec vs. Rails' Test::Unit Gotcha: In a Controller test, Rspec provides access to that Controller's attributes with
assigns[:attr_name], or "array notation", but Test::Unit does not. Both supportassigns(:attr_name), or "method-call notation."
Ask for Help
- "How should we migrate/upgrade database when we add new versions of assets, such as photos?" The consensus is that, for now, we'll do it lazily: if an application (using our asset management plugin) needs a new version to be stored (perhaps we need a 'tiny' version...) when we will create them on-the-fly when requested rather than generate thousands of photos in one shot. If that has performance implications we'll revisit that decision.
- Anyone want to be RailsConf roomies? Our sizable RailsConf contingent is going to try to share hotel rooms and such.
- We're out of beer! A posse of those whom have been late to standup will make a run later today
Total Stand-up Meeting Time: 13:00 minutes
Interesting Things
- Rails Gotcha: If you name a Rails Migration class the same name as an ActiveRecord class, you will get a non-obvious "superclass mismatch" error.
- Javascript:
Date.now()is not supported by Internet Explorer! Firefox is fine. If you useDate.now(), the cryptic and maddening "Object does not support this property or method" will be your reward. Cross-browser solution:new Date().getTime(). - Brown Bag Lunch today: Rails performance testing.
Ask for Help
- "Any JQuery experts in the house?" Unfortunately not, since most of us have used the Rails-favored Prototype libraries.
- If anyone has unbiased hosting service recommendations we would love to hear them. We've used several companies with mixed results.
- Rspec: "Does Rspec support all of the various route testing helpers that Rails' Test::Unit extensions has?". We think the answer is "yes" because Rspec extends Test::Unit, but we'll have to research that one.
Total Stand-up Meeting Time: 15:00 minutes

Mark and I were just waxing poetic about how great it is to delete code, especially code you just wrote. We pity the attitude of people who think deleting code is somehow wrong -- they feel so guilty that they won't even delete it right off, they just comment it out, and then check it in... We came up with the following simile:
Writing code is circling your way around a solution, like a dog on the hunt. When you're done, the final solution is going to be a lot smaller than your original perimeter.
This reminds me (Alex) of my favorite quote about writing: "Murder your darlings," said by Sir Arthur Quiller-Couch... or was it..?
Interesting Things
- One pair had this reinforced: you should not generate random data in your test case to be the subject of your assertions. In their case they were generating random usernames to test an "allowed characters" filter, but their tests would intermittently succeed or fail because the test was not deterministic.
- "A
privatedeclaration in a Helper doesn't do jack crap!" Truer words were never spoken:privateandprotecteddeclarations are not enforced in Rails View Helpers due to how that code is injected into View instances. - A developer suggested that we attempt to do "RESTful CSS." An explanation and debate is due soon.
- We are officially changing Wiki technologies from Twiki to Trac.
- Rails Gotcha: You can use Named routes to generate a URL for a link with
my_named_route_url, but watch out: that URL is fully qualified! If you want a relative "URL", usemy_named_route_path. Example:
<code> # config/routes.rb login "/login", :controller => "user_management", :action => "login" </code>
And in a any RHTML template:
<code> login_url # generates http://example.com/login login_path # generates /login </code>
- People need to take more time to... blog! We have a laundry list of topics but no free time.
Total Stand-up Meeting Time: 17:00 minutes
Interesting Things
- Rails Observers: Observers need to be "primed" before they start working. Call
Observer.instancebefore you start testing your Observers. - Cookies in Rspec and Test::Unit: Cookie keys are not symbols, unlike many collection-like constructs in Rails; they are instead always Strings. Thus, use
"cookie_name"not:cookie_name - Rails reminder: ActiveRecord::create returns the stored object if successful, and the unsaved and invalid object in memory if the object could not be saved. If you want to know whether or not your save was successful, use ActiveRecord::save, which returns
truewhen successful andfalseotherwise. - And on a further note, a larger discussion should be had regarding when to use ActiveRecord::create, ActiveRecord::save, ActiveRecord::new, and ActiveRecord.dependent_object.build the latter of which is created when you have a
has_manyrelationship with anotherActiveRecord.
Total Stand-up Meeting Time: 20:00 minutes
Interesting Things
- Running initialization blocks per environment
- Set an array in
environment.rbto capture your procs that will do your post-initialization:POST_LOAD_BLOCKS = [] - Now, in your environment-specific initialization files, you can do stuff like:
- Then, back in
environment.rb, after your environment has been initialized, loop over your array:
- Set an array in
<code>
POST_LOAD_BLOCKS << Proc.new {
a.runFoo
b.runBar
}
</code>
Paydirt! These procs you're appending to the POST_LOAD_BLOCKS array will get executed after your environment is completely initialized.
- Use
silence_warningsto (you guessed it!) 'silence' warnings in Ruby - only pros should use it, and only when its clear exactly what you are doing!
Ask for Help
- None need today
Total Stand-up Meeting Time: ?
I was just sitting around my living room listening to NPR, and heard the following Car Talk puzzler:
I want you to get a pencil and write down the numbers, 1 - 9, inclusive, and leave enough space between them. At your disposal you have one plus sign and two minus signs. You can insert those plus and minus signs wherever you want, to make the total come out to 100.
Naturally, I thought, "Gee, that would be tedious to solve it by hand. But it would be fun to write a Ruby program to solve it!" 9 minutes later I was sending the result (and the source code) to Car Talk Plaza.
So here's your challenge: can you write a program to solve this puzzle? And can you beat my time?
My solution is below the fold... don't click "more" until you've taken a stab at it yourself.
