Building Web Service Clients with ActiveModel
Upcoming SlideShare
Loading in...5
×
 

Building Web Service Clients with ActiveModel

on

  • 2,295 views

 

Statistics

Views

Total Views
2,295
Views on SlideShare
2,275
Embed Views
20

Actions

Likes
4
Downloads
16
Comments
0

1 Embed 20

http://www.slideshare.net 20

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Building Web Service Clients with ActiveModel Building Web Service Clients with ActiveModel Presentation Transcript

  • Building Web Service Clients with ActiveModel Paul Dix http://pauldix.net @pauldix
  • IM Paul Dix photo credit: Sebastian Delmont
  • I am a Ruby love machine!
  • Web Services, duh!
  • ActiveModel
  • Web Services Abstract Complexity
  • Scale
  • Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
  • Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
  • Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
  • Split into Logical Parts
  • How ActiveResource killed my best friend
  • Brian Hathcock (http://www.flickr.com/photos/22961976@N00/3040920714/)
  • Understandable Code
  • Client libraries goal: readable and maintainable code
  • Parallel Connections
  • Make Stubbing Easy for Development
  • define:”Web Services”
  • External Services
  • Internal Services
  • ActiveModel is for use with rails forms helpers and other things. Things that are only used inside user requests. Calls Inside User Requests
  • focus(:internal_services)
  • Abstracting Complexity
  • Work with large code base
  • Scale
  • Not Traffic
  • NoSQL is getting there
  • Code Complexity
  • Team Size
  • Examples
  • Processor
  • Operating System
  • MapReduce
  • Web Services?
  • Email Service
  • User Service
  • Haystack
  • Indexing
  • How to separate functionality
  • Partition on Iteration Speed
  • Partition on Logical Fucntion
  • Partition on Read/Write Frequencies
  • Partition on Join Frequency
  • Goals
  • Denormalize and Replicate
  • Separation of Concerns
  • Abstraction
  • ActiveResource and ActiveRecord killed these
  • Both make connections inside the model
  • class Collect < Base end class ShippingAddress < Base end class BillingAddress < Base end class LineItem < Base end class ShippingLine < Base end class NoteAttribute < Base end
  • lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
  • class Collect < Base end class ShippingAddress < Base end class BillingAddress < Base end class LineItem < Base end class ShippingLine < Base end class NoteAttribute < Base end
  • Makes requests serially
  • Requests in Parallel
  • ActiveModel
  • helpers for adding prefixes and suffixes to methods.... boring AttributeMethods
  • Callbacks
  • class User include ActiveModel::Callbacks before_create :do_stuff def create # ... end def do_stuff # ... end end
  • Dirty Tracking
  • class Person include ActiveModel::Dirty define_attribute_methods [:name] def name @name end def name=(val) name_will_change! @name = val end def save @previously_changed = changes end end
  • # A newly instantiated object is unchanged: person = Person.find_by_name('Uncle Bob') person.changed? # => false
  • # Change the name: person.name = 'Bob' person.changed? # => true person.name_changed? # => true person.name_was # => 'Uncle Bob' person.name_change # => ['Uncle Bob', 'Bob'] person.name = 'Bill' person.name_change # => ['Uncle Bob', 'Bill']
  • # Save the changes: person.save person.changed? # => false person.name_changed? # => false
  • # Assigning the same value leaves the # attribute unchanged: person.name = 'Bill' person.name_changed? # => false person.name_change # => nil
  • # Which attributes have changed? person.name = 'Bob' person.changed # => ['name'] person.changes # => {'name' => ['Bill', 'Bob']}
  • # Resetting an attribute returns it to # its original state: person.reset_name! # => 'Bill' person.changed? # => false person.name_changed? # => false person.name # => 'Bill'
  • Errors
  • class User def errors @errors ||= ActiveModel::Errors.new(self) end def validate! errors.add(:name, "can not be nil") end end user.errors[:name] #=> ["can not be nil"]
  • Serialization
  • class User include ActiveModel::Serialization def attributes { :id => @id, :name => @name, :email => @email } end end user.to_json(:only => [:id, :name]) user.to_xml(:except => [:email])
  • Validations
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_acceptance_of :terms_of_service end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_confirmation_of :password end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_presence_of :name end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_exclusion_of :name, :in => ["admin"] end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_inclusion_of :role, :in => ["user", "admin"] end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_format_of :email, :with => /A([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})Z/i end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_length_of :password, :minimum => 6 end user = User.new puts user.valid?
  • class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_numericality_of :age end user = User.new puts user.valid?
  • validates_uniqueness_of?
  • ehpien (http://www.flickr.com/photos/91499534@N00/343313257/)
  • Testing
  • require 'rubygems' require 'active_model' require 'test/unit' require 'user' class LintTest < ActiveModel::TestCase include ActiveModel::Lint::Tests def setup @model = User.new end end
  • class User include ActiveModel::Conversion extend ActiveModel::Naming def valid?() true end def errors @errors ||= ActiveModel::Errors.new(self) end def persisted? true end end
  • Parallel Connections
  • Asynchronous
  • EventMachine
  • Curb
  • Typhoeus Mushkush (http://www.flickr.com/photos/43002463@N00/2877016310/)
  • Quick Example
  • PauldixReadingList::ReadingList.for_user( "paul", :include => [:entry, :rating_total]) do |list| reading_list = list end HYDRA.run # now we can access the reading list reading_list.entries.each do |entry| puts entry.id puts entry.title puts entry.body puts "up: #{entry.rating_total.up_count} | down: #{entry.rating_total.down_count}nn" end
  • def self.for_user(user_id, options = {}, &block) includes = options[:include] || [] request = Typhoeus::Request.new(get_by_id_uri(user_id)) request.on_complete do |response| list = new(response.body, options) list.request_entries if includes.include?(:entry) list.request_rating_totals if includes.include?(:rating_total) block.call(list) end PauldixReadingList::Config.hydra.queue(request) end
  • def self.get_ids(ids, &block) request = Typhoeus::Request.new(get_ids_uri(ids)) request.on_complete do |response| json = Yajl::Parser.parse(response.body) entries = ids.map do |id| new(json[id].merge("id" => id)) end block.call(entries) end PauldixEntries::Config.hydra.queue(request) end
  • def self.get_ids(ids, &block) request = Typhoeus::Request.new(get_ids_uri(ids)) request.on_complete do |response| json = Yajl::Parser.parse(response.body) ratings = ids.map do |id| new(json[id]) end block.call(ratings) end PauldixRatings::Config.hydra.queue(request) end
  • Gunnsi (http://www.flickr.com/photos/38735097@N00/440198755/)
  • Threaded
  • require 'net/http' include Java import 'java.util.concurrent.Executors' class Request include java.util.concurrent.Callable def initialize(url) @url = url end def call Net::HTTP.get(URI.parse(@url)) end end
  • thread_pool = Executors.new_fixed_thread_pool(50) futures = [] 100.times do |i| request = Request.new("http://localhost:3000/entries/#{i}") futures << thread_pool.submit(request) end results = futures.map {|f| f.get} # do something with results thread_pool.shutdown
  • Keep Alive
  • Awesome art credit: Joe West
  • Stubbing
  • Review
  • Readable Client Code
  • lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
  • Models Build Requests
  • Parallel Connections
  • Validate Early
  • Easy Stubs
  • Abstract Complexity
  • Scale
  • Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
  • Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
  • Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
  • Thanks!
  • Questions?