Bootstrapping is the Rage

Web startups boot strapping themselves are all the rage.  Every few weeks someone approaches me with a new idea.  The implementation plans for the venture are almost always identical.

  • web application
  • open source framework, usually Ruby on Rails, sometimes PHP
  • free database, almost always MySQL
  • cloud hosting
  • small group of guys, typically people who have made money at a previous venture
  • no salaries, just equity

Inspirations for these companies are places such 37signals, Wufoo, Plentyoffish and World of Goo.

I enjoy hearing the ideas and almost joined one venture.  But in the end none have been compelling enough for me to risk 6 to 12 months of income.  Hopefully I’ll think of one on my own. 🙂

Specifying One-to-Many Relationship in ATG Repositories

Monta driving on Flickr
(Photo: Monta driving by Yogma)

Specifying one-to-many relationships is ridiculously easy in Ruby on Rails.  Unfortunately it’s not so straight-forward in ATG repositories.

First you specify the “belongs to” relationship.  In this example the player belongs to a team.

[xml]<item-descriptor name="player">
<table name="team_players" type="auxiliary" id-column-names="team_id" shared-table-sequence="1">
<property name="team" column-name="team_id" item-type="team" />
</table>
</item-descriptor>[/xml]

Then you specify the “has many” relationship.  In this example the team has many players.

[xml]<item-descriptor name="team">
<table name="team_players" type="multi" id-column-names="player_id" shared-table-sequence="2">
<property name="players" column-name="player_id" data-type="set" component-item-type="player" />
</table>
</item-descriptor>[/xml]

Note the trick is specifying the “shared-table-sequence.”

Here is the SQL for the table that specifies this relationship in our example.

[sql]CREATE TABLE team_players
(
team_id VARCHAR2(40) NOT NULL,
player_id VARCHAR2(40) NOT NULL,
CONSTRAINT team_players_pk PRIMARY KEY (team_id, player_id),
CONSTRAINT team_players_players_fk foreign key (player_id) references players (id),
CONSTRAINT team_players_team_fk foreign key (team_id) references teams (id)
);[/sql]

Questions to Consider When Starting an eCommerce Site

I have done many eCommerce projects and am looking forward to doing more.

The most interesting eCommerce projects are the ones that are starting from scratch.  I was fortunate to be a part of several such projects including NFLShop.com, CasualMale.com and OriginalPenguin.com.  Of these the OriginalPenguin.com project was by far the most interesting because I was simultaneously the director, lead engineer, and QA. 🙂

Whenever I start a project or am consulting for one I ask the following questions to help determine the scope and range of the project.

  1. What technology will be used?  J2EE?  ATG?  .Net?  PHP?  Ruby on Rails?
  2. What platform?  Windows?  Linux?  Solaris?  FreeBSD?
  3. How will it be hosted?  Locally?  Shared host?  Virtual host?  Exclusive host?
  4. What database do you use or plan to use?
  5. How many products, product categories and SKU’s do you have?
  6. How will catalog administration be done?  Should it be part of the web application?  Or will you use a separate third-party application?
  7. How will you manage price lists?
  8. How will you keep track of inventory?
  9. When an order is submitted, how will it be fulfilled?  Who does fulfillment?
  10. How will you handle payments?  Payflow Pro?  Cyber Cash?  CyberSource?  PayPal?
  11. How will you handle taxes?  TAXWARE?
  12. What kind of security do you want?  Will everything be handled securely via SSL?  Do you already have an SSL server certificate for the site?
  13. Will you require that to buy something you have to have an account?  If not will you want to still try to encourage buyers to get an account?  Will you be saving credit card numbers with the account?
  14. Can buyers track their order history, order status, etc.?
  15. What kind of emails do you want sent during the order/fulfillment process?
  16. Will you want to implement promotions and/or coupons?
  17. What kind of catalog navigation do you want?  Do you want a menu like navigation like Amazon.com?
  18. Do you want the buyer to be able to search for items?
  19. Do you want product comparison?

Formatting Text

For text fields one typically wants to allow some HTML tags, add support for link breaks and even auto link URL’s and emails.

This method which I got from this forum thread, Adding a line break … safely, does all of this and is a must add to my application_helper.rb.

def format_content(content)
  # allow only tags specified in tags options, likewise in attributes
  content = sanitize(content, :tags => %w(b strong i em img), :attributes => %w(src))

  # add support for line breaks
  content = simple_format(content)

  # auto link URL's and emails
  content = auto_link(content, :all, :target => '_blank')

  return content
end

rake db:migrate hangs

Recently I tried running my RoR applications on Oracle.

I noticed that when I ran rake db:migrate it would hang. Specifically it would hang during the schema dump phase.

E:\work\sandbox>rake db:migrate --trace -v
(in E:/work/sandbox)
** Invoke db:migrate (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:migrate
** Invoke db:schema:dump (first_time)
** Invoke environment
** Execute db:schema:dump

I realized later that this was because the schema dump phase is very slow and the database I was using had many other tables from other applications. When I left it running it finally completed after 10 minutes.

You can see the slow progress of the schema dump phase by tailing schema.rb in the db directory.

Ruby on Rails and Oracle

  1. Get the Ruby OCI8 driver.  Download the file that ends with “mswin32.rb” and install like this:
    E:\ruby>ruby ruby-oci8-1.0.3-mswin32.rb
    Copy OCI8.rb to e:/ruby/lib/ruby/site_ruby/1.8/DBD/OCI8
    Copy oci8.rb to e:/ruby/lib/ruby/site_ruby/1.8
    Copy oci8lib.so to e:/ruby/lib/ruby/site_ruby/1.8/i386-msvcrt
    OK?
    Enter Yes/No: Yes
    Copying OCI8.rb to e:/ruby/lib/ruby/site_ruby/1.8/DBD/OCI8 ... done
    Copying oci8.rb to e:/ruby/lib/ruby/site_ruby/1.8 ... done
    Copying oci8lib.so to e:/ruby/lib/ruby/site_ruby/1.8/i386-msvcrt ... done
    OK

    You can test the driver by running a query using Ruby.

    E:\>ruby -r oci8 -e "OCI8.new('foo','12345','sid').exec(
    'SELECT * from users') do |r| puts r.join(' | ') ; end"
  2. Install the ActiveRecord Oracle adapter.gem
    E:\ruby>install activerecord-oracle-adapter --source http://gems.rubyonrails.org
  3. Update config/database.yml to connect to Oracle
    development:
      adapter: oracle
      database: sid
      username: foo
      password: 12345
      timeout: 5000
  4. Test by doing a rake db:migrate.
  5. Test by running the Ruby on Rails server and making sure there are no errors upon startup.

This article is based on these articles.

Twitter and Rails

Twitter has become the poster child of why not to use Ruby on Rails.  Recently a friend of mine started a company and when I noticed he used PHP I asked why he didn’t use Rails.  He responded “Twitter uses Rails and they keep going down.  Facebook uses PHP.  We’ll use PHP.”

There is an interesting interview w/ Twitter developer Alex Payne about the issues Twitter has had with Ruby on Rails.

The common wisdom in the Rails community at this time is that scaling Rails is a matter of cost: just throw more CPUs at it. The problem is that more instances of Rails (running as part of a Mongrel cluster, in our case) means more requests to your database. At this point in time there’s no facility in Rails to talk to more than one database at a time. The solutions to this are caching the hell out of everything and setting up multiple read-only slave databases..

All the convenience methods and syntactical sugar that makes Rails such a pleasure for coders ends up being absolutely punishing, performance-wise. Once you hit a certain threshold of
traffic, either you need to strip out all the costly neat stuff that Rails does for you (RJS, ActiveRecord, ActiveSupport, etc.) or move the slow parts of your application out of Rails, or both.

It’s also worth mentioning that there shouldn’t be doubt in anybody’s mind at this point that Ruby itself is slow. It’s great that people are hard at work on faster implementations of the language, but right now, it’s tough. If you’re looking to deploy a big web application and you’re language-agnostic, realize that the same operation in Ruby will take less time in Python. All of us working on Twitter are big Ruby fans, but I think it’s worth being frank that this isn’t one of those relativistic language issues. Ruby is slow.

In April 2007, former Chief Architect Blaine Cook made a presentation called Scaling Twitter.  It’s a well done presentation, even if everything is black.

In May 2008 there were rumors that Twitter was abandoning Rails.  SitePoints believes it is not a framework issue but rather an architectural issue that is causing Twitter’s problems.

There are many large sites that run Rails well and many smaller ones that do not.  It seems like another case of the “leaky abstraction” where we have such a nice framework that we think we can abstract away issues like scaling but in the end when the site becomes big enough we have to look under the covers.

Ruby has been documented to have I/O issues and general performance issues.  Like PHP before it looks like Ruby needs to mature more and deal better with scaling and I/O issues.  I am confident though this will happen because of the tremendous momentum of Ruby on Rails.  However I am keeping on eye on Django, especially now that Google has thrown its large hat into Django’s ring.

Monit and Mongrel

This post about Monit and Mongrel is based on this fantastic post, Monit makes Mongrel play nice!

Install Monit from source:

$ wget http://www.tildeslash.com/monit/dist/monit-4.10.1.tar.gz
$ tar xvfz monit-4.10.1.tar.gz
$ cd monit-4.10.1
$ ./configure -prefix=/usr  (the default prefix is /usr/local)
$ make
$ make install

Configure Monit:

In the monit source you will find a sample monitrc which is completely commented out. You can then copy it to wherever you like and then edit it. Here is my monitrc.

# Start monit in the background (run as a daemon) and check services at
# 1-minute intervals.
set daemon  60

# Set logging.
set logfile /tmp/monit.log

# Set the list of mail servers for alert delivery.
set mailserver localhost

# Set alert recipients.
set alert foo@example.com                # receive all alerts

# Start Monit's embedded web server.
set httpd port 2812 and
     allow admin:monit      # require user 'admin' with password 'monit'

# Mongrel - Development
# Check that Mongrel is running and that it responds to HTTP
# requests. Check its resource usage such as cpu and memory. If the
# process is not running, monit will restart it by default. In case
# the service was restarted very often and the problem remains, it is
# possible to disable monitoring using the TIMEOUT statement.
check process mongrel-dev with pidfile /rails/log/mongrel.pid
    start program = "/usr/bin/mongrel_rails start -d  -c /rails
                          -p 3000 -P /rails/log/mongrel.pid"
    stop program  = "/usr/bin/mongrel_rails stop
                           -P /rails/log/mongrel.pid"
    if cpu > 50% for 2 cycles then alert
    if cpu > 80% for 5 cycles then restart
    if totalmem > 60.0 MB for 5 cycles then restart
    if loadavg(5min) greater than 10 for 8 cycles then restart
    if failed port 3000 protocol http
       with timeout 15 seconds
       for 2 cycles
       then restart
    if 3 restarts within 5 cycles then timeout
    group mongrel-dev

After you are done configuring monitrc copy it to /etc.

$ sudo cp monitrc /etc

To test the configuration:

$ sudo monit -t

Run Monit:

To start monit:

$ sudo monit

To restart monit:

$ sudo monit reload

To stop monit:

$ sudo monit quit

To see monit’s log (assuming you are using my configuration):

$ tail -f /tmp/monit.log

Learn More:

Monit Getting Started
Monit Manual

My First Rails 2.0 Application w/ Restful Authentication

Today I took the plunge and installed Rails 2.0.2. Notes on the Rails 2.0 release can be found here.

Here are the steps I took.

  1. Upgrade Ruby Gems to the latest version (in this case 1.0.1).
    gem update --system
  2. Install Ruby on Rails 2.0.2.
    gem install rails -v 2.0.2
  3. Install MySQL gem (as of March 5, 2008, it is version 2.7.3) and add MySQL executable to path.
    gem install mysql
  4. Create prayer application.
    rails prayer -d mysql
  5. Install Restful Authentication plugin.
    cd prayer
    ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/
  6. Create scaffold for prayer model.
    ruby script/generate scaffold Prayer title:string body:text

    The first thing I noticed different about Rails 2.0 is that the scaffold now also generates the model and data migration file with title and body as columns in the prayer table. Also the format of the data migration file is slightly more compact.
  7. Create user model with authentication. The --include-activation flag is to create the mailers for activation and signup notification.
    ruby script/generate authenticated user sessions --include-activation
  8. Configure config/database.yml and then create prayer and user tables in DB.
    rake db:migrate
  9. Configure SMTP settings.
  10. Modify app/models/user_mailer.rb, replacing the place holders with constants which you can configure with different values for different environments using config/environments/development.rb, config/environments/production.rb.
  11. Modify user_observer.rb to incorporate the reset and forgotten password features.
  12. Create scaffold for role model. Add an admin user.
    ruby script/generate scaffold Role rolename:string
  13. Create permission model. Modify role and permission models to know about each other.
    ruby script/generate model Permission
  14. Modify user model to use permissions.

Much of this post is based on this excellent post, Restful Authentication with all the bells and whistles.  At this point I did not continue with much of the tutorial, especially with parts like password forgotten, separate account controller, etc.