Ruby For Startups

50 %
50 %
Information about Ruby For Startups
Technology

Published on August 28, 2009

Author: subelsky

Source: slideshare.net

Description

My experiences using Ruby and Rails to build OtherInbox, a startup software company.

Startup Ruby Separate things that change from things that stay the same Program to an interface, not an implementation Prefer composition over inheritance Delegate, delegate, delegate You Ain't Gonna Need It (YAGNI)

I’m Mike Subelsky @subelsky

I’m Mike Subelsky @subelsky This is what I have learned while building

What’s unique about startup programming? Facing unknown problems & unknown solutions With scarce time and resources

“Ferocious customer-centric rapid iteration” @ericries startuplessonslearned.com

What advice would I give myself to thrive in these conditions?

Design thoughtfully before implementing Don’t make these specific mistakes

Separate things that change from things that stay the same Program to interfaces, not implementations Prefer composition over inheritance Delegate, delegate, delegate You Ain't Gonna Need It (YAGNI)

Design for Change "Separate code for general functionality from code for specialized functionality" Isolate design decisions in their own modules

First Use of SQS SQS = RightAws::SqsGen2.new(access_key_i d, secret_access_key], { :multi_thread => true }) queue = SQS.queue("#{RAILS_ENV}_#{queue_name }")

First Use of SQS SQS = RightAws::SqsGen2.new(access_key_i d, secret_access_key], { :multi_thread => true }) queue = SQS.queue("#{RAILS_ENV}_#{queue_name }") Then both of these changed

Designed for Change queue = QueueFetcher.fetch(queue_name) queue.send_message({ :user_id => user_id }.to_yaml Isolates how we connect to the messaging system Isolates naming convention for the messaging system

class QueueFetcher def self.fetch(queue_name) SQS2.queue("#{queue_env}_#{queue_name}") end private def self.queue_env APP_CONFIG['queue_context'] end end

class QueueFetcher def self.fetch(queue_name) SQS2.queue("#{queue_env}_#{queue_name}") end private def self.queue_env APP_CONFIG['queue_context'] end end More isolation

I don’t like this class QueueFetcher def self.fetch(queue_name) SQS2.queue("#{queue_env}_#{queue_name}") end private def self.queue_env APP_CONFIG['queue_context'] end end More isolation

Business Logic class Envelope def deliver_first_message new_mailbox_name = Mailbox.new_mailbox_name(recipient) mailbox = Mailbox.create!(:user_id => user_id, :name => new_mailbox_name) prepare_delivery_for_spam prepare_delivery_for_forwarding(mailbox) self.first_message = true return deliver(mailbox) end

Program to interfaces, not implementations Program to general types "Don’t call it a car if you can get away with calling it a vehicle"

Program to interfaces, not implementations Easy for us to do with duck-typing

class Message < ActiveRecord::Base end class ArticleMessage < Message end class SmtpMessage < Message end class SentMessage < Message end

class Message < ActiveRecord::Base end ? class ArticleMessage < Message end class SmtpMessage < Message end class SentMessage < Message end

Prefer composition over inheritance Equip objects with references to other objects which implement common behavior

module S3MessageContent private def head_from_s3(filename) S3.head(APP_CONFIG['message_bucket_name'],filename) end end

class Attachment < ActiveRecord::Base include S3MessageContent belongs_to :message before_create :put_attachment_on_s3 before_destroy :remove_from_s3 end

Delegate, delegate, delegate Objects express certain outward behavior but actually delegate responsibility for that behavior to another object

Delegate, delegate, delegate Really good for ActiveRecord relationships

Delegate, delegate, delegate Really good for ActiveRecord relationships class ExternalEmailAccount < ActiveRecord::Base belongs_to :external_email_server delegate :server_info, :mail_server, :to => :external_email_server

Delegate, delegate, delegate Forwardable and Delegate modules also make this easy

YAGNI

YAGNI We love solving cool, new problems with cool, new toys

YAGNI We love solving cool, new problems with cool, new toys So sometimes we look into the future for opportunities

YAGNI This is a fatal instinct in startups

YAGNI I’ve built things to be super-scalable that turned out not to be core to the product

YAGNI I’ve built things to be super-scalable that turned out not to be core to the product

YAGNI In the early days, focus on learning not performance*

YAGNI In the early days, focus on learning not performance* Concentrate on 80% solutions

YAGNI In the early days, focus on learning not performance* Concentrate on 80% solutions *startuplessonslearned.com

YAGNI Be a duct tape programmer

YAGNI Be a duct tape programmer “...any kind of coding technique that’s even slightly complicated is going to doom your project.” http://www.joelonsoftware.com/items/ 2009/09/23.html

Don’t make these specific mistakes

Plan to move everything out of the web request

Plan to move everything out of the web request ar_mailer, delayed_job, EventMachine, SQS, beanstalkd, etc.

Plan to move everything out of the web request But remember YAGNI

Make careful use of concurrency

Make careful use of concurrency Prefer processes communicating via message bus (SQS, Starling, delayed_job, Rabbit MQ, etc.)

Make careful use of concurrency Check out Unicorn http://tomayko.com/writings/unicorn-is-unix

Make careful use of concurrency Threading: EventMachine is your friend

Make careful use of concurrency Threading: EventMachine is your friend EMH.safe_defer do begin UserMailer.deliver_verification_email(@user, @email) rescue StandardError logger.warn("Unable to deliver signup verification to #{@user.login} due to #{$!.message}") end end

Consider your RDBMS relationship

Consider your RDBMS relationship Avoid touching the DB when storing non-critical data

Consider your RDBMS relationship Avoid touching the DB when storing non-critical data Don’t use an RDBMS for things it’s not good at

Consider your RDBMS relationship Avoid touching the DB when storing non-critical data Don’t use an RDBMS for things it’s not good at We rely heavily on AWS

Consider your RDBMS relationship Storing large text blobs (S3) Messaging system (SQS) Logging events (SimpleDB) Caching dynamic text (S3)

Consider your RDBMS relationship We use data_fabric gem to make master-slave transparent

Consider your RDBMS relationship We also just used it to shard our DB

default: &default adapter: 'mysql' username: otherinbox_mysql database: otherinbox_production shard_0: &shard_0 password: --------- <<: *controller encoding: utf8 pool: 15 shard_0_slave: &shard_0_slave <<: *controller_slave controller: &controller <<: *default <% 1.upto(10) do |n| %> host: ##### <%= "shard_#{n}: &shard_#{n}" %> <%= " <<: *default" %> controller_slave: &controller_slave <%= " host: shard#{n}.####" %> <<: *default <%= %> username: otherinbox_ro <%= "shard_#{n}_slave: &shard_#{n}_slave" %> host: #### <%= " <<: *shard_#{n}" %> <% end %> # production! production: <<: *controller <% 0.upto(10) do |n| %> <%= "shard_#{n}_production:" %> <%= " <<: *shard_#{n}" %> <% end %>

Great DB Scaling Videos Scaling Your DB Part 1 and 2: http://railslab.newrelic.com

Reconsider Virtualization

DB indexes degrade over time Everyone blogs about EXPLAIN but what about ANALYZE and OPTIMIZE?

Know Your Query Planner One of our biggest speedups came from upgrading to the latest minor MySQL version

Organize your code nicely We have too much code in lib/*

Organize your code nicely A lot of this stuff is plumbing and could be extracted as plugins or gems

Organize your code nicely A lot of this stuff is plumbing and could be extracted as plugins or gems And released open source!

Organize your code nicely ActiveMerchant has a great layout

Organize your con g variables Dangerous / difficult to change Rarely changing Changeable at runtime

Dangerous / difficult to change INBOX_MESSAGE = 1 ARCHIVED_MESSAGE = 2 DELETED_MESSAGE = 3 SENT_MESSAGE = 4 REJECTED_MESSAGE = 5 Nearly immutable, identical in all situations

Rarely changing default: &default full_host_name: 'my.otherinbox.com' tech_support_address: 'support@otherinbox.com' max_subdomains_per_user: 2 max_alternate_domain_name_results: 10 domain_registration_api_timeout: 10 Dump into a YAML file

Rarely changing development: <<: *default full_host_name: 'oib.local' domain_registration_api_timeout: 1 You want it under version control

Changeable at Runtime >> Configuration.default_blocked_addresses => "admin,support,help,info,sales,jobs,webmaster" >> Configuration.default_blocked_addresses += ",oib" => "admin,support,help,info,sales,jobs,webmaster,oib"

Changeable at Runtime >> Configuration.default_blocked_addresses => "admin,support,help,info,sales,jobs,webmaster" >> Configuration.default_blocked_addresses += ",oib" => "admin,support,help,info,sales,jobs,webmaster,oib" http://beautifulpixel.com/svn/plugins/settings

Changeable at Runtime >> Configuration.default_blocked_addresses => "admin,support,help,info,sales,jobs,webmaster" >> Configuration.default_blocked_addresses += ",oib" => "admin,support,help,info,sales,jobs,webmaster,oib" http://beautifulpixel.com/svn/plugins/settings http://toolmantim.com/articles/ consolidating_your_apps_constants

Avoid Boolean Columns Often want to know what time something changed Or you later end up needing more than 2 states

Bundle complex view logic into Presenters

Bundle complex view logic into Presenters class RefreshController < ApplicationController before_filter :signin_required def index render :text => JSON.generate(AdvancedRefresher.new(params).to_hash) end end

Maybe don't test all the time, at the beginning?

Maybe don't test all the time, at the beginning?

Maybe don't test all the time, at the beginning? Can slow down exploratory programming

Maybe don't test all the time, at the beginning? You’ll probably throw away half the stuff you write at the beginning anyway

Maybe don't test all the time, at the beginning? You’ll definitely change the names of things!

Maybe don't test all the time, at the beginning? On the other hand, tests can be a design tool (as with BDD) I wrote our SMTP code this way

Maybe don't test all the time, at the beginning? Would be interesting to see how many Rails Rumble teams use tests

Afford regular access to designers

Questions? @subelsky mike@oib.com

Thank you! Slides posted at subelsky.com

Add a comment

Related presentations

Related pages

Why do so many startups use Ruby on Rails? - Quora

We have delivered many web projects for Startups in Ruby on Rails. From our experience, I believe these points below could answer the question why they ...
Read more

Ruby for Startups - Google+

Ruby for Startups - Ruby for Startups. ... Problem loading Google+. There was a problem loading the Google+ CSS. Please double check your network ...
Read more

Ruby for Startups - Austin on Rails 2009 by @Subelsky ...

How to Learn Rails and Change Your Life: Two Ruby on Rails Developers Share Their Secrets - Duration: 1:03:36. Skillcrush Team 56,336 views
Read more

Ruby on Rails for Startups - Idyllic Software

The blog highlights how Ruby on Rails can address the most concerns that startups have when launching their product.
Read more

Why are startups using Python/Ruby mostly? - Quora

Most of the startups are using python or ruby.Any specific reason behind their decision?
Read more

Ruby Startup Jobs

Finde die besten Startup Jobs in Deutschland Immer aktuell Immer die neuesten Startups
Read more

Ruby for Startups (2)Ruby on Rails | Microservices | UI/UX ...

Eric Ries defined Minimum Viable Product (MVP) as “The minimum viable product is that version of a new product which allows a team to collect the maximum ...
Read more

Startup Web Development Company - Ruby on Rails Startup

SumatoSoft team provides high-end web and mobile development services for startups at reasonable cost. Build your Ruby on Rails web startup with us!
Read more

For Start-Ups | Welcome to Ruby Software

We offer our expertise in three distinct areas. We have been helping start-ups as well as enterprises to bring out their ideas and dreams to the market.
Read more