SlideShare a Scribd company logo
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
Ad

More Related Content

What's hot (20)

The road to Ember 2.0
The road to Ember 2.0The road to Ember 2.0
The road to Ember 2.0
Filippo Zanella
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Ryan Weaver
 
Dan Webb Presentation
Dan Webb PresentationDan Webb Presentation
Dan Webb Presentation
RubyOnRails_dude
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
Ignacio Martín
 
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
Ryan Weaver
 
The Complementarity of React and Web Components
The Complementarity of React and Web ComponentsThe Complementarity of React and Web Components
The Complementarity of React and Web Components
Andrew Rota
 
Javascript REST with Jester
Javascript REST with JesterJavascript REST with Jester
Javascript REST with Jester
Mike Bailey
 
Introduction to Vue.js
Introduction to Vue.jsIntroduction to Vue.js
Introduction to Vue.js
Meir Rotstein
 
learning react
learning reactlearning react
learning react
Eueung Mulyana
 
Wicket 2010
Wicket 2010Wicket 2010
Wicket 2010
Martijn Dashorst
 
Html5 and beyond the next generation of mobile web applications - Touch Tou...
Html5 and beyond   the next generation of mobile web applications - Touch Tou...Html5 and beyond   the next generation of mobile web applications - Touch Tou...
Html5 and beyond the next generation of mobile web applications - Touch Tou...
RIA RUI Society
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
Ryan Weaver
 
WCLV13 JavaScript
WCLV13 JavaScriptWCLV13 JavaScript
WCLV13 JavaScript
Jeffrey Zinn
 
The Next Five Years of Rails
The Next Five Years of RailsThe Next Five Years of Rails
The Next Five Years of Rails
Alex Mercer
 
React && React Native workshop
React && React Native workshopReact && React Native workshop
React && React Native workshop
Stacy Goh
 
Rails 3.1 Asset Pipeline
Rails 3.1 Asset PipelineRails 3.1 Asset Pipeline
Rails 3.1 Asset Pipeline
eallam
 
Hooks WCSD12
Hooks WCSD12Hooks WCSD12
Hooks WCSD12
Jeffrey Zinn
 
How to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScriptHow to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScript
Katy Slemon
 
Apache Wicket Web Framework
Apache Wicket Web FrameworkApache Wicket Web Framework
Apache Wicket Web Framework
Luther Baker
 
Building Single Page Apps with React.JS
Building Single Page Apps with React.JSBuilding Single Page Apps with React.JS
Building Single Page Apps with React.JS
Vagmi Mudumbai
 
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and moreSymfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Symfony Guard Authentication: Fun with API Token, Social Login, JWT and more
Ryan Weaver
 
Symfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worldsSymfony & Javascript. Combining the best of two worlds
Symfony & Javascript. Combining the best of two worlds
Ignacio Martín
 
Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)Symfony: Your Next Microframework (SymfonyCon 2015)
Symfony: Your Next Microframework (SymfonyCon 2015)
Ryan Weaver
 
The Complementarity of React and Web Components
The Complementarity of React and Web ComponentsThe Complementarity of React and Web Components
The Complementarity of React and Web Components
Andrew Rota
 
Javascript REST with Jester
Javascript REST with JesterJavascript REST with Jester
Javascript REST with Jester
Mike Bailey
 
Introduction to Vue.js
Introduction to Vue.jsIntroduction to Vue.js
Introduction to Vue.js
Meir Rotstein
 
Html5 and beyond the next generation of mobile web applications - Touch Tou...
Html5 and beyond   the next generation of mobile web applications - Touch Tou...Html5 and beyond   the next generation of mobile web applications - Touch Tou...
Html5 and beyond the next generation of mobile web applications - Touch Tou...
RIA RUI Society
 
Guard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful SecurityGuard Authentication: Powerful, Beautiful Security
Guard Authentication: Powerful, Beautiful Security
Ryan Weaver
 
The Next Five Years of Rails
The Next Five Years of RailsThe Next Five Years of Rails
The Next Five Years of Rails
Alex Mercer
 
React && React Native workshop
React && React Native workshopReact && React Native workshop
React && React Native workshop
Stacy Goh
 
Rails 3.1 Asset Pipeline
Rails 3.1 Asset PipelineRails 3.1 Asset Pipeline
Rails 3.1 Asset Pipeline
eallam
 
How to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScriptHow to Build ToDo App with Vue 3 + TypeScript
How to Build ToDo App with Vue 3 + TypeScript
Katy Slemon
 
Apache Wicket Web Framework
Apache Wicket Web FrameworkApache Wicket Web Framework
Apache Wicket Web Framework
Luther Baker
 
Building Single Page Apps with React.JS
Building Single Page Apps with React.JSBuilding Single Page Apps with React.JS
Building Single Page Apps with React.JS
Vagmi Mudumbai
 

Similar to Ruby For Startups (20)

Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on Rails
Mark Menard
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
New Relic
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
3camp
 
Developing faster than ever (Liferay DEVCON 2017)
Developing faster than ever (Liferay DEVCON 2017)Developing faster than ever (Liferay DEVCON 2017)
Developing faster than ever (Liferay DEVCON 2017)
Sébastien Le Marchand
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop
Wolfram Arnold
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
Mike Subelsky
 
Lean Php Presentation
Lean Php PresentationLean Php Presentation
Lean Php Presentation
Alan Pinstein
 
Porting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability SystemsPorting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability Systems
Marcelo Pinheiro
 
TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...
TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...
TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...
tdc-globalcode
 
Harmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and PuppetHarmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and Puppet
Achieve Internet
 
The "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsThe "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/Ops
Erik Osterman
 
Multi-tenancy with Rails
Multi-tenancy with RailsMulti-tenancy with Rails
Multi-tenancy with Rails
Paul Gallagher
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
Daniel Spector
 
RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteRubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - Keynote
Dr Nic Williams
 
Rails antipattern-public
Rails antipattern-publicRails antipattern-public
Rails antipattern-public
Chul Ju Hong
 
Rails antipatterns
Rails antipatternsRails antipatterns
Rails antipatterns
Chul Ju Hong
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
singingfish
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great Justice
Domenic Denicola
 
Webpack
Webpack Webpack
Webpack
Sofian Hadiwijaya
 
Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!
mold
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on Rails
Mark Menard
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
New Relic
 
Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2 Osiąganie mądrej architektury z Symfony2
Osiąganie mądrej architektury z Symfony2
3camp
 
Developing faster than ever (Liferay DEVCON 2017)
Developing faster than ever (Liferay DEVCON 2017)Developing faster than ever (Liferay DEVCON 2017)
Developing faster than ever (Liferay DEVCON 2017)
Sébastien Le Marchand
 
2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop2011-02-03 LA RubyConf Rails3 TDD Workshop
2011-02-03 LA RubyConf Rails3 TDD Workshop
Wolfram Arnold
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
Mike Subelsky
 
Lean Php Presentation
Lean Php PresentationLean Php Presentation
Lean Php Presentation
Alan Pinstein
 
Porting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability SystemsPorting Rails Apps to High Availability Systems
Porting Rails Apps to High Availability Systems
Marcelo Pinheiro
 
TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...
TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...
TDC2017 | Florianopolis - Trilha DevOps How we figured out we had a SRE team ...
tdc-globalcode
 
Harmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and PuppetHarmonious Development: Via Vagrant and Puppet
Harmonious Development: Via Vagrant and Puppet
Achieve Internet
 
The "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsThe "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/Ops
Erik Osterman
 
Multi-tenancy with Rails
Multi-tenancy with RailsMulti-tenancy with Rails
Multi-tenancy with Rails
Paul Gallagher
 
Crossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end FrameworkCrossing the Bridge: Connecting Rails and your Front-end Framework
Crossing the Bridge: Connecting Rails and your Front-end Framework
Daniel Spector
 
RubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - KeynoteRubyEnRails2007 - Dr Nic Williams - Keynote
RubyEnRails2007 - Dr Nic Williams - Keynote
Dr Nic Williams
 
Rails antipattern-public
Rails antipattern-publicRails antipattern-public
Rails antipattern-public
Chul Ju Hong
 
Rails antipatterns
Rails antipatternsRails antipatterns
Rails antipatterns
Chul Ju Hong
 
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010
singingfish
 
Unit Testing for Great Justice
Unit Testing for Great JusticeUnit Testing for Great Justice
Unit Testing for Great Justice
Domenic Denicola
 
Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!Catalyst - refactor large apps with it and have fun!
Catalyst - refactor large apps with it and have fun!
mold
 
Ad

More from Mike Subelsky (11)

STAQ Development Manual (Redacted)
STAQ Development Manual (Redacted)STAQ Development Manual (Redacted)
STAQ Development Manual (Redacted)
Mike Subelsky
 
Coding for uncertainty
Coding for uncertaintyCoding for uncertainty
Coding for uncertainty
Mike Subelsky
 
Ruby Concurrency Realities
Ruby Concurrency RealitiesRuby Concurrency Realities
Ruby Concurrency Realities
Mike Subelsky
 
Generating Good Ideas
Generating Good IdeasGenerating Good Ideas
Generating Good Ideas
Mike Subelsky
 
Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)
Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)
Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)
Mike Subelsky
 
Let's Make Baltimore More Innovative (TEDxBaltimore)
Let's Make Baltimore More Innovative (TEDxBaltimore)Let's Make Baltimore More Innovative (TEDxBaltimore)
Let's Make Baltimore More Innovative (TEDxBaltimore)
Mike Subelsky
 
Social Media for Everybody
Social Media for EverybodySocial Media for Everybody
Social Media for Everybody
Mike Subelsky
 
It's Not Always Sunny in the Clouds
It's Not Always Sunny in the CloudsIt's Not Always Sunny in the Clouds
It's Not Always Sunny in the Clouds
Mike Subelsky
 
Introduction to SproutCore at JSConf
Introduction to SproutCore at JSConfIntroduction to SproutCore at JSConf
Introduction to SproutCore at JSConf
Mike Subelsky
 
Scaling Rails Applications In The Cloud
Scaling Rails Applications In The CloudScaling Rails Applications In The Cloud
Scaling Rails Applications In The Cloud
Mike Subelsky
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
Mike Subelsky
 
STAQ Development Manual (Redacted)
STAQ Development Manual (Redacted)STAQ Development Manual (Redacted)
STAQ Development Manual (Redacted)
Mike Subelsky
 
Coding for uncertainty
Coding for uncertaintyCoding for uncertainty
Coding for uncertainty
Mike Subelsky
 
Ruby Concurrency Realities
Ruby Concurrency RealitiesRuby Concurrency Realities
Ruby Concurrency Realities
Mike Subelsky
 
Generating Good Ideas
Generating Good IdeasGenerating Good Ideas
Generating Good Ideas
Mike Subelsky
 
Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)
Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)
Baltimore: A Great Place to Pick Up Ideas and Run WIth Them (Ignite)
Mike Subelsky
 
Let's Make Baltimore More Innovative (TEDxBaltimore)
Let's Make Baltimore More Innovative (TEDxBaltimore)Let's Make Baltimore More Innovative (TEDxBaltimore)
Let's Make Baltimore More Innovative (TEDxBaltimore)
Mike Subelsky
 
Social Media for Everybody
Social Media for EverybodySocial Media for Everybody
Social Media for Everybody
Mike Subelsky
 
It's Not Always Sunny in the Clouds
It's Not Always Sunny in the CloudsIt's Not Always Sunny in the Clouds
It's Not Always Sunny in the Clouds
Mike Subelsky
 
Introduction to SproutCore at JSConf
Introduction to SproutCore at JSConfIntroduction to SproutCore at JSConf
Introduction to SproutCore at JSConf
Mike Subelsky
 
Scaling Rails Applications In The Cloud
Scaling Rails Applications In The CloudScaling Rails Applications In The Cloud
Scaling Rails Applications In The Cloud
Mike Subelsky
 
SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
Mike Subelsky
 
Ad

Recently uploaded (20)

Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdfThe Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
Abi john
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
Semantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AISemantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AI
artmondano
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc
 
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdfSAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
Precisely
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven InsightsAndrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 
Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
 
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In FranceManifest Pre-Seed Update | A Humanoid OEM Deeptech In France
Manifest Pre-Seed Update | A Humanoid OEM Deeptech In France
chb3
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
AI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global TrendsAI and Data Privacy in 2025: Global Trends
AI and Data Privacy in 2025: Global Trends
InData Labs
 
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdfThe Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
The Evolution of Meme Coins A New Era for Digital Currency ppt.pdf
Abi john
 
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded DevelopersLinux Support for SMARC: How Toradex Empowers Embedded Developers
Linux Support for SMARC: How Toradex Empowers Embedded Developers
Toradex
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
Semantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AISemantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AI
artmondano
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
tecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdftecnologias de las primeras civilizaciones.pdf
tecnologias de las primeras civilizaciones.pdf
fjgm517
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc Webinar: Consumer Expectations vs Corporate Realities on Data Broker...
TrustArc
 
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdfSAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
Precisely
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptxIncreasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Increasing Retail Store Efficiency How can Planograms Save Time and Money.pptx
Anoop Ashok
 
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven InsightsAndrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell: Transforming Business Strategy Through Data-Driven Insights
Andrew Marnell
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
Generative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in BusinessGenerative Artificial Intelligence (GenAI) in Business
Generative Artificial Intelligence (GenAI) in Business
Dr. Tathagat Varma
 

Ruby For Startups

  • 1. 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)
  • 3. I’m Mike Subelsky @subelsky This is what I have learned while building
  • 4. What’s unique about startup programming? Facing unknown problems & unknown solutions With scarce time and resources
  • 5. “Ferocious customer-centric rapid iteration” @ericries startuplessonslearned.com
  • 6. What advice would I give myself to thrive in these conditions?
  • 7. Design thoughtfully before implementing Don’t make these specific mistakes
  • 8. 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)
  • 9. Design for Change "Separate code for general functionality from code for specialized functionality" Isolate design decisions in their own modules
  • 10. 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 }")
  • 11. 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
  • 12. 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
  • 13. 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
  • 14. 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
  • 15. 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
  • 16. 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
  • 17. 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"
  • 18. Program to interfaces, not implementations Easy for us to do with duck-typing
  • 19. class Message < ActiveRecord::Base end class ArticleMessage < Message end class SmtpMessage < Message end class SentMessage < Message end
  • 20. class Message < ActiveRecord::Base end ? class ArticleMessage < Message end class SmtpMessage < Message end class SentMessage < Message end
  • 21. Prefer composition over inheritance Equip objects with references to other objects which implement common behavior
  • 22. module S3MessageContent private def head_from_s3(filename) S3.head(APP_CONFIG['message_bucket_name'],filename) end end
  • 23. class Attachment < ActiveRecord::Base include S3MessageContent belongs_to :message before_create :put_attachment_on_s3 before_destroy :remove_from_s3 end
  • 24. Delegate, delegate, delegate Objects express certain outward behavior but actually delegate responsibility for that behavior to another object
  • 25. Delegate, delegate, delegate Really good for ActiveRecord relationships
  • 26. 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
  • 27. Delegate, delegate, delegate Forwardable and Delegate modules also make this easy
  • 28. YAGNI
  • 29. YAGNI We love solving cool, new problems with cool, new toys
  • 30. YAGNI We love solving cool, new problems with cool, new toys So sometimes we look into the future for opportunities
  • 31. YAGNI This is a fatal instinct in startups
  • 32. YAGNI I’ve built things to be super-scalable that turned out not to be core to the product
  • 33. YAGNI I’ve built things to be super-scalable that turned out not to be core to the product
  • 34. YAGNI In the early days, focus on learning not performance*
  • 35. YAGNI In the early days, focus on learning not performance* Concentrate on 80% solutions
  • 36. YAGNI In the early days, focus on learning not performance* Concentrate on 80% solutions *startuplessonslearned.com
  • 37. YAGNI Be a duct tape programmer
  • 38. 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
  • 39. Don’t make these specific mistakes
  • 40. Plan to move everything out of the web request
  • 41. Plan to move everything out of the web request ar_mailer, delayed_job, EventMachine, SQS, beanstalkd, etc.
  • 42. Plan to move everything out of the web request But remember YAGNI
  • 43. Make careful use of concurrency
  • 44. Make careful use of concurrency Prefer processes communicating via message bus (SQS, Starling, delayed_job, Rabbit MQ, etc.)
  • 45. Make careful use of concurrency Check out Unicorn http://tomayko.com/writings/unicorn-is-unix
  • 46. Make careful use of concurrency Threading: EventMachine is your friend
  • 47. 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
  • 48. Consider your RDBMS relationship
  • 49. Consider your RDBMS relationship Avoid touching the DB when storing non-critical data
  • 50. 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
  • 51. 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
  • 52. Consider your RDBMS relationship Storing large text blobs (S3) Messaging system (SQS) Logging events (SimpleDB) Caching dynamic text (S3)
  • 53. Consider your RDBMS relationship We use data_fabric gem to make master-slave transparent
  • 54. Consider your RDBMS relationship We also just used it to shard our DB
  • 55. 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 %>
  • 56. Great DB Scaling Videos Scaling Your DB Part 1 and 2: http://railslab.newrelic.com
  • 58. DB indexes degrade over time Everyone blogs about EXPLAIN but what about ANALYZE and OPTIMIZE?
  • 59. Know Your Query Planner One of our biggest speedups came from upgrading to the latest minor MySQL version
  • 60. Organize your code nicely We have too much code in lib/*
  • 61. Organize your code nicely A lot of this stuff is plumbing and could be extracted as plugins or gems
  • 62. Organize your code nicely A lot of this stuff is plumbing and could be extracted as plugins or gems And released open source!
  • 63. Organize your code nicely ActiveMerchant has a great layout
  • 64. Organize your con g variables Dangerous / difficult to change Rarely changing Changeable at runtime
  • 65. 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
  • 66. Rarely changing default: &default full_host_name: 'my.otherinbox.com' tech_support_address: '[email protected]' max_subdomains_per_user: 2 max_alternate_domain_name_results: 10 domain_registration_api_timeout: 10 Dump into a YAML file
  • 67. Rarely changing development: <<: *default full_host_name: 'oib.local' domain_registration_api_timeout: 1 You want it under version control
  • 68. 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"
  • 69. 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
  • 70. 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
  • 71. Avoid Boolean Columns Often want to know what time something changed Or you later end up needing more than 2 states
  • 72. Bundle complex view logic into Presenters
  • 73. 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
  • 74. Maybe don't test all the time, at the beginning?
  • 75. Maybe don't test all the time, at the beginning?
  • 76. Maybe don't test all the time, at the beginning? Can slow down exploratory programming
  • 77. Maybe don't test all the time, at the beginning? You’ll probably throw away half the stuff you write at the beginning anyway
  • 78. Maybe don't test all the time, at the beginning? You’ll definitely change the names of things!
  • 79. 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
  • 80. Maybe don't test all the time, at the beginning? Would be interesting to see how many Rails Rumble teams use tests
  • 83. Thank you! Slides posted at subelsky.com