Your SlideShare is downloading. ×
0
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Ruby For Startups
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Ruby For Startups

3,983

Published on

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

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

Published in: Technology, Education
0 Comments
12 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,983
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
70
Comments
0
Likes
12
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Transcript

    • 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)
    • 2. I’m Mike Subelsky @subelsky
    • 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
    • 57. Reconsider Virtualization
    • 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: 'support@otherinbox.com' 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
    • 81. Afford regular access to designers
    • 82. Questions? @subelsky mike@oib.com
    • 83. Thank you! Slides posted at subelsky.com

    ×