A rather sad Rails commit

For some reason, this commit makes me a bit sad:

deOMGifying Railties, Active Support, and ActionPack on Github

Removing humor from a codebase is a bug, not a patch.

February 01, 2010

Recruit virtual mentors

I don’t know most of my mentors. Instead, I digitally stalk them, read everything they say and watch all their interviews and talks.

This has been decisive for me in that learning from these people has proven to be incredibly fruitful in terms of my own company’s revenue.

To recruit a virtual mentor, first find someone whose success and ideas you respect. Second, find literally everything that they’ve written. Third, find everything in video that they’ve done. Finally, find all of their products or apps or books and get them too. Once you’ve consumed everything that they’ve produced, setup a google alert for them and read anything new as it comes out.

One of the best ways to grow is to take things that your mentor does and apply them to your own company.

As an example, here are mine over the last few years. As you can see, they change based on what I’m currently doing.

Current (Focused on page flow, ‘golden mechanics’, and business):

Pincus

Past (Focused on testing and clarity):

Marissa Mayer

Eric Ries (Before he switched to self-marketing-mode)

Andrew Chen

Ryan Singer + Jason

A year ago (Focused on programming):

DHH (See “A little less hokus pokus“)

Yehuda (See “Writing code that doesn’t suck”)

Ilya Grigorik (w/r/t doing interesting stuff w/ ruby)

Norvig

pg

Send me an e-mail at f.mischa@gmail.com if you know of anyone else you think I might be interested in!

February 01, 2010

Are you living in a cave?

Too many startup people act like they are sitting in a cave inventing something utterly new.

Changes are, they’re not.

I constantly find myself amazed when I recommend a blog post, or a tactic to someone and they are like “Oh, that’s just what I need! I never thought to search for that.” Even more amazing is when someone labors day and night trying to figure out how to make a successful app yet has never heard of something like a/b testing.

I feel like these people must be living in caves.

One of the fun parts of the University of Chicago was that we constantly had to do research. This, plus being a programmer, entirely convinced me of the following:

“Whatever I am doing, a lot of other people have probably also tried to do it. Some of them have probably been way more successful than I have been so far. Some of them have probably written books or blog posts about how they successfully did what I am doing now. I can find these books and blog posts on Google and then apply what they say.”

The four sentences above are somehow not common knowledge, in my experience. I have no idea why.

February 01, 2010

Rails Star Ratings Plugin Comparison

There are a kajillion Rails rating plugins.

Diversity is good, but choice is time-consuming. Here’s a quick rundown of the options.

This post reviews the existing options from the perspective of a rails developer who wants a star rating system that handles views and jquery ajax without costing very much time to setup. This means that if the README wasn’t clear, I often wrote off the plugin.

To review each plugin, I setup a rails app with a User model and a Frog model. Users can, of course, rate frogs. You can find the git repo here. The ones that I went through on trying are in branches.

Here are the plugins/gems that I tried:

Ajaxful rating

  • Github followers: 136
  • Actively being updated: Yes
  • README usefulness: high
  • Lines of code I had to add to rate frogs: 16
  • Deals with views for you: Yes
  • Gem: Yes
  • Javascript Library: Prototype
  • Obtrusiveness: High. It includes all the javascript inline.
  • Time investment to get working: a few minutes
  • Changing the stars: Just change a line in the stylesheet that it generates

acs_as_rateable

  • Github followers: 98
  • Actively being updated: Not since June 2008
  • README usefulness: Very low. The readme doesn’t even include what generator to run. You have to look in the code, which is fine but annoying.
  • Lines of code I had to add to rate frogs from the console: 1
  • Deals with views for you: No
  • Gem: plugin only
  • Javascript Library: Doesn’t handle views
  • Time investment to get working: a few minutes

is_rateable

  • Github followers: 51
  • Actively being updated: Not since June 2009
  • README usefulness: Low/fail. The readme says to run script/generate rateable—by_user, but this doesn’t actually work. I had to run the generator normally then edit the migration to make it work. Furthermore, the formatting is messed up on github, making it hard to copy/paste code from the browser. Of course, this is easy to work around.
  • Lines of code I had to add to kind of rate frogs: 28
  • Deals with views for you: Yes
  • Gem: plugin only
  • Javascript Library: Prototype??
  • Time investment to get working: a little while. The readme didn’t accurately describe how to get it working out of the box in the way that I wanted it to. I got bored after about 5 minutes and did not feel the need to press on to get this working.
  • Notes: this will only work if you have a User class, otherwise it goes by ip address. This means that if wouldn’t work for the case that I’m testing here since in my app it is a different class than User that will be doing the ratings

acts-as-rated

  • Github followers:34
  • Actively being updated: Not since January 2009
  • README usefulness: High
  • Lines of code I had to add to kind of rate frogs: 1
  • Deals with views for you: No.
  • Gem: plugin only. It says “coming soon” but that was about a year ago.
  • Javascript Library: None. Doesn’t deal with views.
  • Time investment to get working: low.

has_ratings

  • Github followers:14
  • Actively being updated: Not since June 2009
  • README usefulness: Low. The readme contains no installation instructions.
  • Lines of code I had to add to kind of rate frogs: 1
  • Deals with views for you: No.
  • Gem: Yes.
  • Javascript Library: None. Doesn’t deal with ajax.
  • Time investment to get working: low.
  • Notes: This appears to be written in the style of an engine. The description is that it “demonstrates a reference implemenattion for handling ratings.” so it’s unclear if this is actually meant to be used as a plugin or gem or what.

Conclusion

There isn’t really a good solution that does jquery ratings out of the box. If you’re looking for something that uses prototype, the ajaxful ratings plugin is great, in that you can have it working in minutes. On the other hand, it is relatively obtrusive and makes me feel like I’m in 2007 in terms of javascript cleanliness. However, it’s definitely a great option.

The other options either do not handle views or are non-trivial to setup.

January 31, 2010

Ideas vs Features

It’s frustrating when people confuse ideas with features. While it sounds like an obvious difference, it’s one of the larger sources of tension in product development.

Over the past year, I’ve seen cases where an idea had a 0% conversion rate with one implementation and a 5% paid conversion rate with another. Of course, the 5% wouldn’t have been possible without the idea. But a 0 vs 5% conversion rate can make or break a company. The implementation added 100% of the value.

The confusion begins when someone champions a idea masquerading as a feature. For example, say that we have a website that sells a system of raising a perfect dog. Your partner has an idea for a feature. He pitches it as a system of ranking puppy choices using a combination of color, hairiness, and bark pitch. He wants you to build it yesterday.

The problem is that currently this “feature” is literally 0% done. Without an implementation, code, a page flow, metrics and conversions, the feature is actually an idea.

What the person is really saying is “I want our product to include this idea and I want it to increase the rate at which people pay us.”

What’s an idea?

Ideas are very similar to goals. When I say “let’s make a feature to recommend dogs to people based on their interests,” what I’m really saying is “I think it would be valuable if we had a feature to recommend dogs that worked well and converted.”

The hard part is realizing that the actual feature is 0% done. Nothing is successful yet. All the work of making the feature a success hasn’t happened yet. Ideas are value-less without an actual feature-implementation.

What’s a feature?

Features can be thought of in terms of actual web pages. Features have to take into consideration everything that ideas don’t, like how to motivate customers to actually use the feature, how to make it clear what the feature is, how to integrate it in without changing the engagement/conversion metrics of existing features , how to improve it over time, how to measure whether it is a success, and how to get it released quickly.

For example, adding in a new feature could drop the conversion rate and usage of another feature, unless they are both re-implemented. Ideas don’t have to take this into account.

Deciding whether an idea is good or not has to take into account what kind of features it could be implemented as.

My experience with product development hammered this into me over and over again over the past year. Simply the placement of a link can make 5x differences in the usage of a feature. 5x is a make or break multiplier, in terms of whether a feature succeeds or not. The success or failure of the feature often has absolutely nothing to do with the original idea.

Avoiding idea overload

If you can accept that ideas are goals that are 0% complete and that implementation makes or breaks features, then the cost of ideas becomes apparent. For each idea that you take on as a goal, you have to commit to making it successful. This means accepting that everything that you have’t yet thought of will make the difference between whether the idea ends up being seen as good or bad 3 months later. Things like:

—email subjects

—text changes

—link placement

—button copy

—button placement

—page flow

—relationship to other features

all have the power to decide the fate of a feature. These things all take time to test and tweak. Furthermore, in order to learn what is actually going on, you’ll have to isolate these changes by user. Unless you have a user base the size of Zynga or Google, this means spending at least a week running just the initial test so that you can see what mechanics make the feature tick. All of this takes several weeks or months.

Choose a few ideas, then focus on implementation and be patient

An idea typically takes several months to turn a profit. Each idea, in order to be made successful, has to have large amounts of time devoted to deal with all of the human parts of how to release it and make it valuable for customers.

Ideas, then, are best thought of as goals, not features. Each goal takes time to turn a profit, and sucks up resources in the meantime.

An idea without a working page flow should always be considered 0% done. The less ideas you try to implement, the more chances you have to make each one successful.

January 29, 2010

Decisions, motivation, and commitment

Higher motivation and lower commitment lead to higher signup and conversion rates.

The decision to initially engage involves lowering commitment and increasing motivation (bokardo).

People who are not sufficiently motivated will exit immediately after being asked to pay. Premature limits both reduce motivation and immensely increase commitment at the same time. If commitment rises above motivation, you get an exit.

Extremely high perceived value, plus immediacy, plus high motivation, plus low commitment yields higher conversion rates.

How can we measure this? We could measure the level of impact a page has on the avg pageviews for those who see it. We can also identify pages where commitment is high, reduce the commitment, and measure the a/b outcome. Further, we can identify pages where motivation is possibly low, and do the same.

Tactics

Optimally, in the first five minutes and perhaps even beyond, users should be clicking every 1-7 seconds or so. Establishing a click rhythm decreases commitment. It’s also easy to change text from things like “Enter your personal information and signup” to the lower commitment “Try it”.

Buying decisions could be introduced by the machine at appropriate times, if users’ motivation could be measured. In the absence of this, it makes sense to introduce decisions in places where there is the most immediate, rather than long term, value. For example, it makes more sense to introduce a buying decision where the users life, ego, or status will be immediately improved.

Immediately prior to introducing the decision, it’s worthwhile to increase motivation as much as possible.

Subscriptions

For these reasons, I think that subscription based models will have a much harder time monetizing than micro-payment models. The commitment involved in signing up for a subscription is higher than that involved in buying something once.

For subscriptions, you are making a much more long-term value proposition, in that you are telling your customer that they will continue to want to use our app for quite a while. This massively increases commitment, and skews the incentives for the designer.

Since immediate benefits, high motivation, and low commitment work best, subscription-based companies are incentivized to craft buying decisions that offer immediate, aspirin/crayon value. Unfortunately, this means that the actual usefulness of the app will be easy to ignore, given that what’s driving customer buying decisions is the perception of immediate value points. People tend to not cancel subscriptions immediately, so one the customer is acquired, they’re all too easy to forget.

Micro payments

Micro payments are probably going to take over from subscriptions.

Imagine if there were 10 restaurants, and 9 of them each offered a plan where I could eat there twice a month for $20 / month, and 1 restaurant offered a meal at $10/meal. The subscription based restaurant has to not only convince customers that it has good food, but it has to convince them to commit to them for at least two nights of the month.

The $10/meal restaurant, on the other hand, offers the same price per meal, but no lock-in. They only have to convince customers that their food is good. The buying decision is more immediate, and there is less of a commitment.

This is obvious in the real world, but not on the internet for some reason. Subscriptions are now the least creative, and the least interesting way to monetize.

January 22, 2010

Revisiting the hidden cost of features

I constantly find myself reminded about the hidden costs of features.

37signals’ chapter on this is great, but it doesn’t apply to how I operate.

I’ve extracted the core idea here, as well as updated the list of things that new features involve for me.

1. Say no.
2. Have strong opinions. Whoever proposed the feature might be emotionally 
attached to it, so there are often arguments here.
3. Have meetings. Whoever proposed the feature will likely keep bringing it up.
4. If "no" again, end here. If "yes," continue...
5. Prioritize the feature
6. If it's a big feature, break it up into parts. Negotiate requirements.
7. Sketch the feature. At this point, the feature is appears almost done in the eyes of 
everyone except the development team.
8. Possibly disagree on the design.
9. As the feature gets more fleshed out, it often gets bigger after being prioritized.
10. Re-prioritize.
11. Contact the developer who is actually going to build it.
12. Make sure that the developer understands what's involved.
13. Be in contact with the developer to answer their questions. Update the requirements
as it becomes clear how the code is going.
14. When the developer is done, make sure that everything works.
15. Read over the code. Make sure it's tested and well written.
16. If it's not properly tested, send it back to the developer or write the tests yourself.
17. Make sure that the design will work for your customers.
18. Make sure that the design works in ie6.
19. Make sure that the design works in ie7.
20. Make sure that the new feature works with old data.
21. Setup whatever metrics the feature needs, like an a/b test.
21. Make sure the feature is secure.
23. Make sure that the metrics that were added don't break anything.
24. Merge the feature with the master branch, fix any conflicts.
25. Make sure that marketing copy / terms of service don't have to be changed.
26. Deploy the feature. Run migrations. If it's adding a column or index to a table
with millions of rows, make sure nothing crashes.
27. Make sure the feature actually works in production.
28. Run sql queries and check analytics to see how the feature is going.
29. Report on how the feature is going to your team.
30-32. Continue to checkup on the feature. Spend time running regressions or other analysis.
Have discussions with team about whether or not to keep the feature.
33. Make tweaks to the feature if it isn't succeeding.
34-40. Make more tweaks until it either clearly does or doesn't succeed with customers.
41. Consider how the feature will affect pricing.
42. Update pricing if necessary.
43. If the feature failed or succeeded notify the team.
44. If the feature failed and team members really don't want to get rid of the feature, 
keep it and maintain it. Otherwise, spend time getting rid of the code and making 
sure that everything still works. If it succeeded, spend time ending the a/b test and 
making sure everything still works and that customers have relatively seamless experiences.
45. Continually make sure that no other new features break this feature. 
Maintain the test suite so that this feature always works.
46.  Going forward, continue to make sure that this feature is successful in its metrics.
47. Update AARRR metrics to consider this feature.
48. Consider the impact on this feature of other new features, in terms of how customers engage.
49. Deal with longer-term bugs caused by the feature that weren't obvious initially.
50. Deal with customer support issues caused by a minority of people not liking the changes.
51. If the feature involves ongoing work, for example moderation in the case of a forum,
continually do this work.

Lots of hidden costs.

January 17, 2010

Avoid test specific code

Don’t write code that checks the environment. It’s a recipe for disaster.

For example:

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

def security
  return false if (Rails.env.test? || Rails.env.cucumber?)
  really_complicated_method
end

private

def really_complicated_method
  fail "Oops"
end

In the above example, you are screwed because your entire suite will pass. But then, once you cap deploy, everything will crash and burn.

Checking for the environment is a code smell.

In my experience, code like above causes bugs ranging from small but insidious to outright disasters.

Ways to ensure environment agnosticism

There are cases where being entirely environment-agnostic this doesn’t always make sense. I would argue that these cases should only be when you have to hit an external API that will either significantly slow down your test suite or otherwise be annoying, for example if it cost $2/request or something.

In these cases, I recommend mocking out the service in a class included in the environment file. You can then set the actual service to be a constant. This allows you to turn the mocking on and off.

You turn it off when you want to avoid hitting an API in your tests, and you turn it on when you want to make sure that everything works.

Mocking a payment gateway

Here’s an example of how you might do this for a subscription based site. Note that all you have to do to test the live API is comment out the mock, provided you’ve defined it elsewhere. This is a far better than having environment checks hidden everywhere in your code.

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


# config/environments/cucumber.rb

require 'spec/mocks'
@recurring = Spec::Mocks::Mock.new("Recurring Response",
                                  :params => {"subscription_id" => 12323231},
                                  :success? => true,
                                  :authorization => '232323',
                                  :message => 'message string'
                                  )
                                  
@purchase = Spec::Mocks::Mock.new("Immediate Response",
                                  :success? => true,
                                  :authorization => "12143242",
                                  :message => "message string", :params => {})

GATEWAY = Spec::Mocks::Mock.new("Gateway",
               :purchase => @purchase,
               :recurring => @recurring,
               :cancel_recurring => true)



At the same time, I really try to avoid doing things like this. I think that environment constants are also a code smell, since they often unnecessarily obfuscate what’s going on. In general, it’s best to just keep production, development, and test as closely aligned as possible to avoid issues that slip past tests.

January 17, 2010