Allan & Steve are the chubby founders of LessEverything. This is their blog, hear them rant, praise, give advice and talk about Just Stuff, Less Accounting, Lovd by Less, More Honey, Events, Less Memories, Code, Business, Design, Marketing

Help us speak at SXSW 2010

written by Allan Branch on August 18th, 2009

We need your votes to speak at SXSW

Steve and I are hoping to speak SouthbySouthwest (SXSW) 2010. If you haven't heard of this conference you've been living in a cave and let me welcome you to the world outside.

Steve's Talk Summary

How to choose what to say yes or no to. How to market. How to design. How to pick a team/partners. How to split the money. How/when to launch, what's the bare minimum needed to launch. What is "good enough." How to do customer service. What are good problems to have. How to plan for scaling. How to have good UI and how important is it. Lot's more.

Allan's Talk Summary

This talk will focus on how to create a user interface to make things easy for users. What are things you need to think about to design your application. How to make your users love your application. 1) How to create a user interface to make things easy for users. 2) What are things you need to think about to design your application. 3) How to make your users love your application.

If we're not speaking at SXSW I will blame you personally. :)

Build, Design, Launch an App in <40 Man Hours

written by Allan Branch on August 5th, 2009

Two weeks ago we launched LessCabinFever.com, start to finish it took less than 40 total man hours. In this blog post I'm going to tell you how we did it and why we consider this a successful product launch.

What is LessCabinFever?

LessCabinFever is a directory of laptop workers that are interested in exchanging homes for a short period of time. We call them work-vacations, a vacation from working in the same place. Basically, do you work from home? Would you like to work from another city for a week?

Why we did it.

We built this app for two reasons. (1) I want to work from somewhere else about four times a year. Some place nice, some place new. (2) It's so easy to write a blog about launching early and waiting on building that feature that seems so important. We wanted to practice what we preach.

Here's how we did it

Budgeted time, stuck to it.

We estimated 40 total man hours to launch this project. We knew it would be tight but we wanted to push the comfort zone of the constraint. We wanted something that could be built in a weekend.

Code Base

The code base is LovdbyLess.com. With some minor tweaks, adds and mods we were able to get the app to the current state in 27 hours. LovdbyLess gave us a lot of the core features we needed. Are there other features that could have been added? Yes. Would they have made the app something more to talk about? Probably not.

Design

I purchased the logo illustration from istockphoto.com for $10. The logo took 15 minutes to create. The overall app design took 12 hours total, including writing the markup for the app. I believe "design" is hard to bid for a consultancy, many clients want collaboration and collaboration costs money because it makes the process longer. Would it have been worth it for me to create the logo by hand, taking a few more hours? I don't believe so, this logo is good enough.

Overall

We spent another couple hours testing the app and talking about the next set of features. Overall we're pleased with the app. It's not perfect, it's not bug free, but we stuck to our budget and launched something. We're excited, so far has been well received, users are talking and people are tweeting about it.

Going Forward

The app isn't on the front page of digg and we're not worried about the whole world seeing this app. A few people per day are adding their homes and we're excited. Once a few hundred listings are in the app we'll spend some more time making the app better and easier to use.

Launch is the Starting Line

We always caution our clients that launching an app is the starting line, not the finish line. We know all too well that for this app to reach people and be useful it will take time, marketing, attention and love.

Consider this a success?

I call this a success for many reasons. Working on a project with a looming deadline and then launching it on schedule is exciting. Building an app and forcing yourself to make tough decisions is a great process. Going from paper to launch in an extremely fast time is a great way for a consultancy to flex their muscles.

Rails in the Enterprise

written by Steven Bristol on August 3rd, 2009

We have a client who, although I can’t say their name, is a billion dollar company with offices around the world. I was speaking to the head of application development last week and heard some very encouraging news about Rails in their enterprise: They have around 100 apps in production, all for internal use. Of these 16 are Rails apps and the rest are Java. They receive about 1800 application support calls each month. Of these an average of 6 are for the Rails applications, the rest are for the Java apps. They employ 40 support people who are dedicated to the Java applications and zero for the Rails applications. I was astounded. What’s your best Rails/Enterprise story or statistic?

#10 Rules for Bootstrapped Web App Startups

written by Allan Branch on July 7th, 2009


  • Build something people need and love. People will talk about it.
  • Release, release and release. Release it before you think it's ready, you're wrong, you don't need that feature.
  • Your app will probably fail, most of them do.
  • Be ballsy, don't follow the herd, make a courageous moves.
  • Build something you want to use. Continue to use it, feel the user's pain.
  • Google AdSense isn't a revenue model.
  • Find the cheapest, fastest way to 500 paid users. People will pay for your app, if it's good.
  • Design is an iterative process, not just development. And you won't get it right the first time, so don't sweat so much.
  • Don't scale until you actually need to. (The front page of Digg does not count as need.)
  • Don't spend any money.

RailsWayCon - Berlin Wrap UP

written by Steven Bristol on May 29th, 2009

WARNING: LONG BLOG POST AHEAD.

This is my last day in Berlin and I wanted to give an update on the conference and the trip.

RailsWayCon was awesome. It was the best conference I’ve attended since RubyConf 2007. Landing in Berlin on Saturday, I met up with Jonathan Weiss”:http://twitter.com/jwiess, Mathias Meyer and Alex Lang at Berlin’s premier cupcake cafe, Cupcake. Methias has a new baby girl, so he skipped out of dinner, really good Thai food. Jonathan took us to a few bars where we were joined by Lourens Naude, Pratik, Sven Fuchs, Clemens Kofler and Koz.

Sunday we met to work on our talks at Karvana. That night Yehuda arrived and we all got together for dinner and drinks. “Good times.” We ended up at an all you can eat sushi bar and spent most of the night drinking bad saki, eating too much fish and trying to distract Yehuda and Koz from the endless love fest. I was glad to see Pratik join in the distracting instead of the ongoing goingson about the what should or should not be in Rails. Highlight of the day was getting a tweenbot sent to me by Sven (photo1 photo2).

Monday we met at Alex and Thilo Utke’s) Upstream office to work on our talks. Jonathan and Mathias spent the day doing a seven hour workshop on deployment. These are two of the best ruby guys in Europe, and work at Jonathan’s company Peritor. Our work was very interrupted by the lover’s quarrels going on between Yehuda and Koz. They really do make a very lovely couple. That night was the speaker’s party where I found my old friends Michael Johann, Aditya Sanghi and conference organizer Sebastian Meyen. Pratik was hungry so we all left for Pizza. Good za and good friends.

The conference started on Tuesday with Mathias giving a really good talk on Async Processing in Ruby. Next up Lourens talked deeply about ruby performance in 1.8, 1.9 and JRuby, discussing fibers, context switching and async database access. I was next up with my tirade against Glassfish while praising JRuby. After lunch Ola Bini gave a great keynote about programing languages. I then listened to Koz’s talk about taking a good idea too far and I ended the day with my What Is Good UI talk. I did something new this time by taking git revisions of Less Time Spent and showing six different version of the UI as it’s progressed over the last year. It was interesting to see how we added UI elements, took them away and added some back during it’s life span. UI is a process, not a destination. The conference party was that night, but we only stayed for a short time preferring to go back to the hotel and play Werewolf and have a group therapy session for me. Stefan Tilkov arrived that morning to give his famous RESTful Rails talk. He turned out to be a most excellent werewolf.

Wednesday started with me arriving late (and tired) to Neal Ford’s talk about how to make Ruby feel more like Java by adding interfaces. Having arrived late I also left early because the room was too hot, so in all fairness, I might have missed the point of his talk. In lieu, Koz and I spent the hour talking about xero, Less Accounting and VAT. It was a great conversation for me as my understanding of VAT was a bit overly complicated. Look for VAT support in Less Accounting in the next week or two! :) Koz talked next about performance tuning Rails followed by Yehuda’s keynote about Rails 3 and the Ruby community. I was sitting between Mathias and Thilo in a very crowded room and not even Yehuda’s excellent talk could keep the sandman away as I fell asleep for about ten minutes at the end. Fortunately I’ve seen this talk before so I don’t think I missed too much. During the Q&A Yehuda confirmed that Rails 4 would be Sinatra, that Rails 3 should be done before this year’s Christmas present of the gamma release of 1.9 (he’s actually hoping for October) and when asked who his favorite core team member he shied away from revealing the love he shares with Koz and just said “I like everybody.” After lunch Lourens gave a great, but all to brief, discussion of Ruby internals. I was next talking about Advanced Javascript and Rails (it’s all about state) and we opted for a nap (in our separate rooms, not together) rather than hear about enterprise Rails. Jonathan and Mathias stayed for that talk and it turns out that enterprise Rails is really just about parsing XML. The nap was good. That night I went to dinner with Aditya and his wife, Vas, who happen to be in Berlin by coincidence. I spent some time with them in India and it was great to reconnect. A mellow evening followed when we met up with Yehuda, Lourens and Sven and discovered that Yehuda’s salary does not fall under the marketing budget at EY.

The quality of the content was surprisingly high. The rooms were small but filled, usually with people sitting on the floor, which at first seemed upsetting, but turned out to offer an intimacy that was quite unique and wonderful. The food was good and people were all first rate, very friendly and warm. I hope next year this becomes the big Rails conference in Europe. It was great.

Thursday Lourens and I spent the day working at the Upstream offices followed by a long night of partying with Sven. Three things to note: 1. I tried to go home at midnight, but Lourens was in rare form and was unusually talkative and open (which should not be missed if the opportunity presents itself), 2. There was headbutting and C. Sven can Dance!!

Today will be a half day of work for me followed by a tour of the palace at Postdam with Jonathan and Mathias. I leave Saturday morning and am looking forward to sleeping for 13 hours on the plane.

I had a great time in Berlin. I haven’t been here since ‘92 and it’s like a completely different city. Seeing old friends and making new ones is the best part of any conference for me, and this was no exception here. I enjoyed my visit so much that I’m thinking of moving here. Thanks to everyone who I got to see. I’m really looking forward to seeing you all again.

Fixjour is Awesome

written by Steven Bristol on February 18th, 2009

This was supposed to be a very technical post about the merits of Fixjour over other fixture replacement libraries. But I simply don’t have time so I will just say that I am really enjoying using Fixjour and recommend everyone check it out. You can find Fixjour on github. It is authored by the excellent and prolific Pat Nakajima.

The thing I really like about it is it’s simplicity. It does everything I need and nothing I don’t. Please see the readme file for an example of how to use it.

Using it you can get your daily fix! Ha, get it? “Fix” like fixture and “daily” like jour (jour is day in French). —That’s funny, right?

Path Variable Being "Unset"

written by Steven Bristol on January 16th, 2009

We had an interesting bug recently that affected the Less Accounting website. One of the functions in Less Accounting is the ability to send invoices and proposals. The system let’s you send them as an email or as a PDF file attached to an email, or you can download a PDF of the invoice. Recently we started seeing some problems with the PDF generator process. After a seemingly random period of time a mongrel would stop generating PDFs. Wait a little longer and another mongrel would fail until they were all failing. This also started happening more frequently; two weeks ago this was a rare occurrence, but a few days ago it would start failing almost immediately. Restarting the mongrels always fixed the problem, but obviously setting them to restart every five minutes was not acceptable.

Besides nil exceptions, the only other exception raised was a Broken Pipe Exception. Since no output was being generated by the PDF service for these failed PDFs I started adding all kinds of debug info. Due to the Broken Pipe Exception I started to suspect a problem with file descriptors. I even rewrote the generation code to use files as input and output instead of stdin and stdout. Once I had the raw input as files I could run the PDF generation manually which always worked. The oddest part was that this happened over time, the same input would succeed after a restart, but not a short time later.

Lourens Naudé took some time with me to help sort this out. We used strace on the mongrels and when that didn’t help I added strace to the PDF generator. What was odd was that strace didn’t log anything when there was a failure, just as the PDF generator didn’t log anything on failure. I decided to log the command that calls the PDF generator and discovered that the failures were caused by the PDF generator not being called at all.

The lib shelled out `which` to get the path to the generator and at some point `which` could no longer find the command. It acted as if the $PATH variable was being unset. The generator is in the same location in dev and production, so hard coding the path fixed the problem.

I’m not sure why the path variable would be unset and didn’t have time to investigate further. If you have any insights, please share them.

Wanna work for Less?

written by Steven Bristol on January 8th, 2009

Wanna work with Less Everything? We’re currently looking for one or two persons to join the team on a 40 hr/wk basis. If you’re interested send me an email (steve [at] lesseverything.com) with the following info:

  • What’s your hourly/weekly/annual rate? (we’re looking for someone not expensive)
  • How good is your code?
  • How many hours per week can you do (40 or more is good)?
  • What do you think of jQuery and jRails?
  • What testing framework do you use?
  • How do you feel about testing?
  • What do you think about the code quality in lovd by less?
  • Are you interested in being mentored?
  • Are you interested in mentoring?
  • 1 – 10 how polished do you consider your tasks when you say they are done?
  • When can you start?
  • Can you work independently?
  • Are you near Jacksonville, FL or Panama City, FL?
  • Do you have trouble with self motivation?
  • Would you be willing to do a small “audition application?”
  • Do you have links to sites you’ve done (please explain your involvement), or any open source code?

P.S. If you’ve worked with us in the past and want to do so again, please let me know. (You know who you are :)

Guarded Assignment in Ruby

written by Steven Bristol on December 16th, 2008

Most people familiar with Ruby are familiar with the Ruby operator ||=. What it does is assign the value of the right to the variable on the left if left is nil (or false). Here is an example:

Most people however are not familiar with the corollary operator &&=. What it does is assign the value of the right to the variable on the left if left is not nil (or false). Here is an example:

Here is an example of how one might use &&=. The idea is that you have an array of something and you only really care if they all completed or not. I used AR::Base.save to show a poor man’s transactions.

Includes and Conditions in Named Scope

written by Steven Bristol on November 10th, 2008

I was making a change to NewsMilk the other day where I needed to make sure that once a user sees a story, it is not shown to that user again. To do this I added a has many between stories and people, and I wanted to make a nice named scope to handle this. Currently the code that gets new stories looks something like this:

story = viewable.first

where viewable is a named scope that adds the proper conditions to the find. I wanted to make a little something something, like this:

story = viewable.not_viewed(person).first

where the person argument is the person that should not have seen this story before.

My first attempt at this was:

  
named_scope :not_viewed, lambda { |person|
    if person
      {:include=>:viewed_stories, :conditions=>{:person_id=>person.id}}
    else
      {}
    end
  }

Which outputs this sql:

SELECT * 
FROM `stories` 
WHERE (person_id != 1)
And this error:
ActiveRecord::StatementInvalid (Mysql::Error: Unknown column 'person_id' in 'where clause': ....

This doesn’t work because the rails eager loading optimization stuff takes the query and transforms it into two queries. The first query gets the stories and the second the viewed_stories. Since the person_id column does not exist in the stories table, the sql bombs. So I made one small change, I went back to old school conditions array and used the qualified column name for person_id:

named_scope :not_viewed, lambda { |person|
    if person
      {:include=>:viewed_stories, :conditions=>["viewed_stories.person_id != ?", person.id]}
    else
      {}
    end
  }

Which outputs this sql:

SELECT DISTINCT `stories`.id 
FROM `stories` 
  LEFT OUTER JOIN `viewed_stories` ON viewed_stories.stories_id = stories.id 
WHERE (viewed_stories.person_id != 1) 
ORDER BY published_at desc LIMIT 1

Notice how now Rails is only doing one query with a join instead of two. And for those of you wondering why I check the existence of person in the named scope, it’s just to avoid the join if it is not needed, because without a person there is nothing to where on.

Custom Parameters in ActiveResource#create

written by Steven Bristol on October 30th, 2008

I recently created a public API for Less Accounting. In addition to requiring the username a password for the user that is logging in, the API also requires a application specific api_key to be provided for each request. This allows me to track every api call and turn off malicious applications. This works great, every request adds the query string parameter “api_key” with the value of their key and Bob’s your uncle.

Except if you happen to be writing a rails app and want to create a model using ActiveResource. Then you’re screwed. This is because the create method in AR doesn’t allow you to pass in extra parameters. It takes a hash of attributes and then wraps the hash in a {:model=>attributes} and that is all. So if you add a parameter, like :api_key, then it will be delivered as model[api_key]=key in the params hash. Not nice. And it’s even worse because there has been a patch out there since 2007 which address this problem. (I just nudged the core team, so hopefully this patch will finally be applied).

But in the mean time I wrote a nice little hack:

class ActiveResource::Base

  def self.custom_method_collection_url(method_name, options = {})
    prefix_options, query_options = split_options(options)
    if method_name == :create
      "#{prefix(prefix_options)}#{collection_name}.#{format.extension}#{query_string(query_options)}" 
    else
      "#{prefix(prefix_options)}#{collection_name}/#{method_name}.#{format.extension}#{query_string(query_options)}" 
    end
  end
end

And then you can call create using the post method:

post(:create, {:expense=>{:title => expense.title,
        :notes => expense.note
        :amount => expense.amount
      }, :api_key=>'68e050b6-e879-4f78-adf3-d898387036fc'})

I admit it is not the cleanest solution, and you would have to do something similar for update, but at least it’s done.

Note: Lourens had an idea to concat the password with the api_key like this: ”#{password}|{#api_key}” and split it on the server. That is also a nice solution. So take your pick.

Less Reverse Captcha

written by Steven Bristol on October 8th, 2008

We just released a new open source plugin for rails called Less Reverse Captcha. This is another way of doing captchas. This reverse captcha plugin does not require the user to do anything. Instead it has a hidden form field that won’t be filled out by people (because it’s hidden) but will be filled out by bots. If the field has a value the model won’t validate. That’s it, easy peasy. This plugin is similar to Erik Peterson’s negative_captcha plugin. The big differences being that the Less plugin acts at the model layer, not the controller and so only needs two lines of code to make work, one for the helper method and one in the model. This plugin is already in use in Lovd By Less and now can be used in your app too!

The default error messages is configurable and obscure: “You can not create this because you are the sux.”

It’s easy to use:

new.html.erb

<= flash[:notice] %>
<%= error_messages_for :comment %>

<% form_for @comment do |form| %>

  <%= form.text_area :comment %>
  <%= less_reverse_captcha_field :comment %>

  <%= submit_tag %>
<% end %>

comments_controller.rb

def create
  @comment = Comment.create params[:comment]
  if @comment.new_record?
    render :action=>'index'
  else
    redirect_to comments_path
  end
end

comment.rb

class Comment < ActiveRecord::Base

  validates_less_reverse_captcha

That’s it!

Rails Links

written by Steven Bristol on September 18th, 2008

For my training class last week I put together some links that might be useful to people that are new to rails. I thought I would share these links here too.

Git tool: SVN tool: Rails google group: Rails google group for core: Documentation sites: Less Everything Products: Rails built in Java Script libraries: jQuery: IRC channels (on freenode):
  • #rails
  • #rails-contrib
  • #lovdbyless (where I can almost always be found)
Open Source rails apps: Firefox tools: Automatically sanitize: Misc:

Passionate Training

written by Steven Bristol on September 11th, 2008

I am currently in Los Angeles leading a week of Rails training. I was given a very cool compliment yesterday that I wanted to share. One of the leads at the company said he has never seen this team so passionate. This is during training!

EnvyCasts should be called AwesomeCasts

written by Steven Bristol on September 1st, 2008

Gregg and Jason, the guys from Rails Envy have just release their first instructional video. They’re calling the series EnvyCasts but the should be called AwesomeCasts.

This is not your usual screen cast where the whole thing is just the screen and a voice over. Envy Casts are lively, funny and informative. These guys are the most entertaining pair in the Rails community (except when Gregg and I were the most entertaining pair). And the EnvyCasts does not disappoint.

There is only one video so far which covers “Advanced Active Record” and features Dr. Pollack edumicating everyone. Very worth watching. Check it out!

Note: I understand that Gregg is working on a LOLKATZ type site called EnvyCats.