Skip to content

Instantly share code, notes, and snippets.

@davidcelis
Created March 1, 2012 17:51
Show Gist options
  • Save davidcelis/1951662 to your computer and use it in GitHub Desktop.
Save davidcelis/1951662 to your computer and use it in GitHub Desktop.
Overview of talks given at Ruby on Ales

Ruby on Ales

Outgrowing the Cloud (Mike Moore)

  • Requests hitting the same load balancer can't handle HTTP and HTTPS at the same time because of SSL issues
  • If you are trying to access an outside resource behind a firewall, you have to tell them every time you get a new webserver so they can whitelist the new IP
  • If you know the IPs of your web servers and database servers, you can have requests hit these directly and bypass the load balancers.
  • Could buy your own data center, but then you have to buy a load balancing router. Those are fucking expensive (tens or hundreds of thousands of dollars)
  • Private network in the cloud vís a vís Amazon
    • A public subnet with an elastic load balancer, which hands requests off to private subnets for web servers and database servers
    • Servers on the subnets only have private IP addresses!
    • But what if you need to directly access web servers or database servers for maintenance? Have a bastion server you can SSH into and it will hand you off to the private subnets
    • Outbound connections can be routed through a single NAT server with one public IP so that whitelists only need that one IP

Start Your Engines! (Ryan Bigg)

  • Available since Rails 0.14.3 as a plugin for Rails
  • Rails 2.3 implements engines natively
  • Rails 3.1 greatly improves rails engines by supporting the asset pipeline and making it easy to copy migrations from the engine to the core app
  • Namespacing issue: if both the engine and the core app have a Product model, core app's Product model takes precedence and the engine will break
  • rails plugin new test-plugin --full --mountable
  • All plugins in Rails are gems by default
  • Add dependencies to the gemspec, NOT Gemfile
  • A Rails::Application actually inherits from Rails::Engine but is responsible for coordinating the boot process
  • Generating a model now places it in app/models/engine_name/model.rb so that it is namespaced to avoid collision. EngineName::Model

How Ruby Made Me a Better Objective-C Programmer (Michael Harper)

  • Commonisms
    • Modifying classes/methods at runtime (a la core_ext)
    • Sending a method to an object (separation of the method from the object)
    • Blocks
    • Good lord this talk was just mostly incomprehensible.
      • Relevant to my interests, but just incomprehensible

bundle install, Y U SO SLOW!? (Terence Lee & Andre Arko)

  • Ruby applications used to have no good way of defining gem dependencies. Often, devs would just list the gems in their README
  • .gems file: cat .gems and iterate through the list of gems, install them
  • Rails tried to solve this problem with the config.gem list in config/environment.rb
  • DHH submitted a patch to bundler 1.1 so you can do :git => "rails/rails"
  • bundle outdated: get a list of outdated gems without having to run bundle upgrade
  • Orphaned gem files
    • bundle clean
  • Self-loading bundles
    • bundle install --standalone
    • Creates a .bundle/bundler/setup.rb file that you can require; it sets up load paths for all the bundled gems
  • Bundler 1.1 improves speed of installing one gem (sinatra) from 18s to 3s
    • Uses API endpoints to fetch each gem's metadata instead of fetching the entire source index to quickly find each gem
    • Falls back to fetching the full source index if the RubyGems API endpoints are, for some reason, unavailable
  • Proposed features for bundler 1.2
    • Ruby version check
    • a :local option that falls back to :git. Takes a local path to a gem you are developing locally (local gems no longer get put in Gemfile.lock)
    • NO BUNDLE EXEC (checks that the gem is in your Gemfile and uses that bundled version. if it's not, use the gem install'd version)

Dreaming of Freshies (Timmy Crawford)

  • This talk was just fucking awesome.

Keynote (Yehuda Katz)

  • tower.js
    • Feature-by-feature clone of what most people associate with Rails, client-side with Node.js and CoffeeScript
    • DHH: "Flexibility is overrated, constraints are liberating"
  • Is Rails obsolete?
    • No: the core principles that make it Rails are still controversial
  • A simple web service in node.js
    • Journey: JSON-only HTTP request router
    • Cradle: CouchDB ORM
    • ...
  • Most people don't agree with everything in Rails, so Rails is always evolving
  • Javascript web frameworks claim "convention over configuration", but then say things like "you can do X instead of Y" right off the bat. Rails gives a default option for everything and the configuration is an afterthought, mostly given by community members
  • Points of failures in Rails
    • Every command you copy and paste out of a blog post for Rails has a "10% chance of failure"
    • Installation
$ sudo gem install rails
$ rails new app
$ cd app
$ rails server
  • Caveat: this doesn't work in Rails 3.2, which should be considered a huge bug. Why doesn't this work?
  • Default Gemfile now has gem 'json' which requires native C extensions to be built.
  • Another caveat: Rails 4 drops support for Ruby 1.8.7, which is still the default system Ruby for OSX.
  • How to fix this? Binary Ruby, Binary Gems. Treat OSX users like Windows users and ship compiled Rubies/Gems
  • Asset pipeline is too slow
  • Booting Rails is too slow
  • bundle exec should be run by default and just show a warning instead of rake dying
  • Traditional Rails
    • Model => Controller => `@post = Post.find(1) => Template
  • Rails with JS
    • Model => Controller => { 'post' => { ... } } => In-browser Template

How Groupon Uses Redis

  • keys is an O(n) operation that returns the number of keys. If you have a huge data set, this will probably time out. Resque uses this by default!?
class Post < ActiveRecord::Base
  def after_save
    Resque.enqueue(NotifyPeople, self.id)
  end
end
  • This causes a race condition because of transactions.
  • Resque/Redis might start processing the job before the transaction is over, so the worker may not see the updated record if it starts quickly enough.
  • Solution: Use after_commit instead.
  • What have they learned?
    • Start with expireat. Do we need this forever?
    • Start with slaveof. Keep a replica or two around.
    • Upgrade to 2.4.6 made hset/hgetall performant.
    • Resque can't be entirely trusted (see fork).
    • Redis Cluster is still a ways off, so PRESHARD.
    • Single-purpose instances over one multi-purpose.
    • resque-jobs-per-fork has a nasty bug (fixed).
    • Use fakeredis (work in progress) for testing

Frustration Driven Development (Evan Light)

  • Put your models' logic in modules, mixin just at the right time (User::Validations, etc.)?
  • Instead of monkey patching, extend the module and inject hooks/dependencies
  • Law of Demeter (don't tightly couple your code)
  • Don't write long, horizontal lines of code. Style your code.
  • Try to stick to REST. Let your controllers be boring and predictable (CRUD) and don't define random controller actions that force you to match a bunch of shit.
  • Give your join tables better names (TeamMembership instead of UserTeam)

Maintainable Rails - Future Proofing Your Software (Steven Baker)

  • Wrote a hockey trivia rails app as a kid, made new questions by copypasting old ones and changing the words
  • It should be easy and fast to add new features to an application. Your app shouldn't need to be born again.
  • Conventions over configuration means everyone is on the same page.
  • Which conventions?
    • Do I follow the Rails convention?
    • Do I follow the Ruby convention?
    • Do I follow the OO convention?
    • Do I follow the team's convention?
    • These can all conflict; you have to decide.
  • Avoid violating conventions; they're called best practices for a reason.
  • Don't generate code. When you generate code, you now have to pay for code you didn't write and may not understand.
  • Delete code. Every line of code has cost and you should straight up delete shit you don't use.
  • Technical debt: "I know I'm making a mistake here, and I'm making it deliberately to easily achieve a goal."
  • Boy Scout Rule: every module you check out, check it back in cleaner than you found it.
  • Listen to your tests
    • If your tests are slow, your software is slow.
    • If your tests fail randomly, your software fails randomly.
    • If your tests have timezone issues, your software has timezone issues.
    • Write good tests and listen to them.
  • Design patterns
    • Get everyone speaking the same language
    • If you follow design patterns where they're appropriate, you can explain the architectures of entire systems within minutes
    • "Hey, we use this pattern." Done.
  • Manage your dependencies
    • Tight coupling sucks with dependencies
    • Every time you type a constant, you've created a hard dependency
    • If you are typing any raw SQL, you're tightly coupled to a specifically structured database
  • Object-Oriented Design
    • Encourages less coupling
    • Gives you the vocabulary to talk about the ways your software can be improved
    • Commits/comments should give the WHY of what you did
    • SOLID principles
  • Don't stub third-party libraries. Write a proxy to the library and stub that to avoid tight coupling
  • If you're stubbing a class method (i.e. Post.stub(:find).and_return(@post)), you're clearly tightly coupled to ActiveRecord and you're probably Doing It Wrong™.

Client-Side Framework Shootout (Scott Burton)

  • MVC frameworks
  • Delegate the V to the client using Javascript MVC
  • Server-side views are expensive
  • There's a catch...
    • Frameworks are opinionated
    • Testing is hard
    • Code duplication (rewriting some server logic on the client)
    • Longer iterations
    • IE support is expensive
  • Unexpected upsides
    • You need an API anyway, so build it now
    • Wean yourself off of the monolith
    • Better subjectives (faster apparent loading, browser is native-ish)
  • Denormalize your data into one large response
  • Bootstrap common assets
    • Cacheable layout (depersonalize, asset package, app shell)
    • Common domain objects (US States, Categories)
    • Bootstrap your data? (check Backbone.js documentation)
  • Respond to every route with HTML

Backbone.js

  • Probably the most widely-used client-side framework right now
  • Very flexible
  • Lightweight
  • Few dependencies
  • Arbitrary collections
  • Rendering is up to you
  • Views: Rendering, event handling
  • Models: key-value stores, change management, persistent
  • Collections: Array proxies, enumerable via Underscore.js
  • Events: General-purpose abstraction, lightweight coupling across layers, Collections/Models/Properties/Custom

Spine.js

  • Inspired by Backbone.js
  • Sugar for common practices
  • Never wait for the server
  • Manage everything
  • Flexible rendering
  • Prototypical
  • Controllers: Rendering, event handling, application hierarchy, routing
  • Models: key-value stores, weak collection management, Active-Record Style, opinionated
  • Stacks: extends Controller, view state machine, manage visibility, hierarchy building block
  • Events: General-purpose abstraction, Lightweight coupling across layers, Models/Custom, Questionable Implementation

Ember.js

  • "Eliminate Boilerplate"
  • Highly opinionated
  • Don't manage the DOM yourself
  • Property Bindings: auto-sync data across layers, declarative
  • Computed Properties: Treat function() like property, can have dependent properties, composition across layers
  • Auto-updating views: views react to data changes, no calls to render(), per-property minimizes reflow, only Handlebars.js, DOM madness
  • Everything else: Object, View, ArrayController, Set, ...

Building Distributed Systems (ReinH)

  • Systems get exponentially more complex

  • Try not to screw it up

  • Level 0: Oblivious system

    • Systems go down, dunno why
  • Level 1: Informed system

    • Systems go down, we know about it (alerts)
  • Level 2: Defined system

    • Systems go down, we know about it, and how to fix it
    • Documentation for fixes
  • Level 3: Managed system

    • Systems go down, we know about it and why, and the system has a plan to recover itself
  • Level 4: Optimized system

    • Systems go down and magically come up
    • Don't try to fix it, replace the component that's broken with a new component that works
  • Alerts

    • Has to be actionable
    • "Boy Who Cried Wolf" (alerts that are trivial or are about things you have no control over)
    • No silent failures
    • Alert with context, including a chain of evidence (full stack trace)
    • Alert with recipe
  • Tolerance & Recovery

    • Expect failure and design systems with failures in mind to minimize impact
    • Isolate failures and degrade gracefully. Show a page with less functionality instead of no page at all
    • Recover quickly from failures
    • Health monitoring: sending a ping out to your severs every few seconds to see if they're responding
    • Roll back (checkpointing). If a deployment fails, you can roll back to the previous deployment
    • Roll forward for eventual compliance
    • When a system fails, nuke it and create a new one in its place
    • Look for opportunities for replication, sharding
  • CAP Theorem

    • "It is impossible for a distributed computer system to simultaneously provide all three of Consistency, Availability and Partition tolerance."
    • Partition tolerance isn't actually a choice
    • This leaves a choice between consistency and availability
  • Testing & Releasing

    • Use shipping systems (systems that are already in production somewhere)
    • Ship often
    • Deliver incrementally
    • Full-system development: make sure you're developing against a local version of the entire system
    • Hire a chaos monkey (have someone who wears a hat and is willing to go into your system to break it for fun)

Deconstructing the Framework (Gary Bernhardt)

Design in the Small

  • Don't design a Model to be coupled to an API
  • Create a Service that talks to both your Model and the API

Service Wrapper Record

  • You have services, stateless objects that talk to the application
  • You have records, objects that talk to the database
  • And you have Wrappers, a thin class for a narrow interface to an API
  • Services can also talk to other Services

Garlic Pressing Rule

  • SRP Rule: A class should have one, and only one, reason to change.
  • Controllers tend to authenticate, authorize, wrap HTTP, manipulate models, manipulate databases (reload), query the database, present models, contain view content, create response content, route, choose content type, contain model logic...
  • "If you have a big thing, and you put it into a press to squeeze it out into a lot of little things, you'll have a lot of great little things that are better than the big thing.
  • Split the controller into various singular responsibilities.

Sidekiq (Mike Perham Lightning Talk)

  • Threads are awesome
  • But they suck!
    • Hard to develop
    • Hard to test
  • Never, ever create a Thread in Ruby
  • "Don't communicate by sharing data, share data by communicating"
  • gem install celluloid
  • Sidekiq is a peer to resque and delayed_job
  • Uses redis for storage
  • Massively concurrent, using a default of 25 workers for process
  • Instead of 25 200MB processes, one 300MB process
  • Rails 3 native
  • Async extensions for AR and AM
  • Same metrics as resque, resque-web works!
  • Capistrano integration
  • Heroku
  • Airbrake/Exceptional
  • User-defined middleware
  • 160 resque dynos ==> 10 sidekiq dynos
  • $60k/yr savings
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment