Building Web Service Clients with ActiveModel

2,243 views
2,113 views

Published on

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,243
On SlideShare
0
From Embeds
0
Number of Embeds
22
Actions
Shares
0
Downloads
19
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide





















































































































  • Building Web Service Clients with ActiveModel

    1. 1. Building Web Service Clients with ActiveModel Paul Dix http://pauldix.net @pauldix
    2. 2. IM Paul Dix photo credit: Sebastian Delmont
    3. 3. I am a Ruby love machine!
    4. 4. Web Services, duh!
    5. 5. ActiveModel
    6. 6. Web Services Abstract Complexity
    7. 7. Scale
    8. 8. Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
    9. 9. Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
    10. 10. Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
    11. 11. Split into Logical Parts
    12. 12. How ActiveResource killed my best friend
    13. 13. Brian Hathcock (http://www.flickr.com/photos/22961976@N00/3040920714/)
    14. 14. Understandable Code
    15. 15. Client libraries goal: readable and maintainable code
    16. 16. Parallel Connections
    17. 17. Make Stubbing Easy for Development
    18. 18. define:”Web Services”
    19. 19. External Services
    20. 20. Internal Services
    21. 21. ActiveModel is for use with rails forms helpers and other things. Things that are only used inside user requests. Calls Inside User Requests
    22. 22. focus(:internal_services)
    23. 23. Abstracting Complexity
    24. 24. Work with large code base
    25. 25. Scale
    26. 26. Not Traffic
    27. 27. NoSQL is getting there
    28. 28. Code Complexity
    29. 29. Team Size
    30. 30. Examples
    31. 31. Processor
    32. 32. Operating System
    33. 33. MapReduce
    34. 34. Web Services?
    35. 35. Email Service
    36. 36. User Service
    37. 37. Haystack
    38. 38. Indexing
    39. 39. How to separate functionality
    40. 40. Partition on Iteration Speed
    41. 41. Partition on Logical Fucntion
    42. 42. Partition on Read/Write Frequencies
    43. 43. Partition on Join Frequency
    44. 44. Goals
    45. 45. Denormalize and Replicate
    46. 46. Separation of Concerns
    47. 47. Abstraction
    48. 48. ActiveResource and ActiveRecord killed these
    49. 49. Both make connections inside the model
    50. 50. class Collect < Base end class ShippingAddress < Base end class BillingAddress < Base end class LineItem < Base end class ShippingLine < Base end class NoteAttribute < Base end
    51. 51. lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
    52. 52. class Collect < Base end class ShippingAddress < Base end class BillingAddress < Base end class LineItem < Base end class ShippingLine < Base end class NoteAttribute < Base end
    53. 53. Makes requests serially
    54. 54. Requests in Parallel
    55. 55. ActiveModel
    56. 56. helpers for adding prefixes and suffixes to methods.... boring AttributeMethods
    57. 57. Callbacks
    58. 58. class User include ActiveModel::Callbacks before_create :do_stuff def create # ... end def do_stuff # ... end end
    59. 59. Dirty Tracking
    60. 60. 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
    61. 61. # A newly instantiated object is unchanged: person = Person.find_by_name('Uncle Bob') person.changed? # => false
    62. 62. # 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']
    63. 63. # Save the changes: person.save person.changed? # => false person.name_changed? # => false
    64. 64. # Assigning the same value leaves the # attribute unchanged: person.name = 'Bill' person.name_changed? # => false person.name_change # => nil
    65. 65. # Which attributes have changed? person.name = 'Bob' person.changed # => ['name'] person.changes # => {'name' => ['Bill', 'Bob']}
    66. 66. # Resetting an attribute returns it to # its original state: person.reset_name! # => 'Bill' person.changed? # => false person.name_changed? # => false person.name # => 'Bill'
    67. 67. Errors
    68. 68. 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"]
    69. 69. Serialization
    70. 70. 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])
    71. 71. Validations
    72. 72. 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?
    73. 73. 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?
    74. 74. 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?
    75. 75. 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?
    76. 76. 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?
    77. 77. 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?
    78. 78. 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?
    79. 79. 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?
    80. 80. validates_uniqueness_of?
    81. 81. ehpien (http://www.flickr.com/photos/91499534@N00/343313257/)
    82. 82. Testing
    83. 83. 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
    84. 84. 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
    85. 85. Parallel Connections
    86. 86. Asynchronous
    87. 87. EventMachine
    88. 88. Curb
    89. 89. Typhoeus Mushkush (http://www.flickr.com/photos/43002463@N00/2877016310/)
    90. 90. Quick Example
    91. 91. 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
    92. 92. 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
    93. 93. 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
    94. 94. 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
    95. 95. Gunnsi (http://www.flickr.com/photos/38735097@N00/440198755/)
    96. 96. Threaded
    97. 97. 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
    98. 98. 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
    99. 99. Keep Alive
    100. 100. Awesome art credit: Joe West
    101. 101. Stubbing
    102. 102. Review
    103. 103. Readable Client Code
    104. 104. lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
    105. 105. Models Build Requests
    106. 106. Parallel Connections
    107. 107. Validate Early
    108. 108. Easy Stubs
    109. 109. Abstract Complexity
    110. 110. Scale
    111. 111. Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
    112. 112. Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
    113. 113. Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
    114. 114. Thanks!
    115. 115. Questions?

    ×