Ruby sittin' on the Couch

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    7 Favorites

    Ruby sittin' on the Couch - Presentation Transcript

    1. * #sor09
    2. Ruby sittin’ on the Couch
    3. About me • Alexander Lang • Upstream Agile GmbH, Berlin programmer, owner • http://upstream-berlin.com
    4. 11/52
    5. Web development w/ Ruby
    6. BDD
    7. Buzzword Driven Development
    8. TDD BDD “agile” Pair Programming * all the f****** time
    9. About me • playing with CouchDB since 09/2008 • helped hack the CouchDB statistics module (with @janl) • wrote Couch Potato • working on smaller production apps
    10. Who are you?
    11. Who is in this room? • Chris Anderson • George Palmer • Paul Carey • Johan Sørensen • Cheah Chu Yeow/Carlos Villela
    12. Who is in this room? • Chris Anderson (couchrest + couchapp) • George Palmer (couch_foo) • Paul Carey (relaxdb) • Johan Sørensen (couchbject) • Cheah Chu Yeow/Carlos Villela (activecouch)
    13. Forget it!
    14. Agenda • CouchDB introduction • The CouchDB example wiki • The frameworks • Conclusion: where to go from here? • Q &A
    15. CouchDB introduction
    16. What is CouchDB?
    17. Apache Project so it has to be good
    18. Document oriented Database
    19. Store/read any JSON document
    20. Powerful map/reduce views for querying* * we’ll see what that is
    21. Why CouchDB?
    22. Buzzword compliant
    23. JavaScript
    24. REST HTTP interface
    25. JSON
    26. Map/Reduce the thing that made Google rich
    27. Fun !
    28. No more SQL/Schema/ Migrations
    29. JavaScript views instead
    30. Simple!
    31. HTTP interface
    32. can use existing clients, libraries
    33. It scales
    34. just like Ruby :)
    35. No locks, instead MVCC
    36. integrated replication (yes, multi master)
    37. use existing load balancer, proxies etc. HTTP ftw
    38. and so on...
    39. So how does Couch work?
    40. JSON { _id: “some UUID”, _rev: “MVCC key”, title: “page one” body: “this is page one.”, tags: [“ruby”, “couchdb”, “sor09”] metadata: {created_at: “2009/03/28 06:34:00”, author: “alex”} }
    41. HTTP API • POST ‘/my_db’, {my_json} • GET ‘/my_db/my_document_id’ • PUT ‘/my_db/my_document_id’, {new_json} • DELETE ‘/my_db/my_document_id’
    42. Map/Reduce views • views are documens • provide a map (and optional reduce function) written in JavaScript • this creates an index over all documents • query that index via GET
    43. Map/Reduce views { title: “page one”, tags: [“first”, important”] } { title: “page 2”, tags: [“funny”] }
    44. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } { title: “page 2”, tags: [“funny”] }
    45. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } key value { “page one” 2 title: “page 2”, tags: [“funny”] “page 2” 1 }
    46. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } key value { “page one” 2 title: “page 2”, tags: [“funny”] “page 2” 1 } function(keys, values) { return sum(values); }
    47. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } key value { “page one” 2 title: “page 2”, tags: [“funny”] “page 2” 1 } function(keys, values) { return sum(values); 3 }
    48. Query a View
    49. Query a View /my_db/_design/wiki/_view/tags_count
    50. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false
    51. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false /my_db/_design/wiki/_view/tags_count?limit=1
    52. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false /my_db/_design/wiki/_view/tags_count?limit=1 /my_db/_design/wiki/_view/tags_count?key=page one
    53. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false /my_db/_design/wiki/_view/tags_count?limit=1 /my_db/_design/wiki/_view/tags_count?key=page one
    54. Query a View
    55. Query a View ?key=‘page one’
    56. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’
    57. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’ ?key=[‘composite’, ‘key’]
    58. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’ ?key=[‘composite’, ‘key’] ?keys=[‘set’, ‘of’, ‘keys’]
    59. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’ ?key=[‘composite’, ‘key’] ?keys=[‘set’, ‘of’, ‘keys’]
    60. That is CouchDB (the basics) • upload documents via POST/PUT • read documents via GET • create indexes by providing map/reduce functions • query views via GET, pass keys + other options
    61. The CouchDB example wiki
    62. Example Wiki • ActiveRecord • RelaxDB • CouchRest • Couch Potato • ActiveCouch • CouchOject • CouchFoo • CouchApp
    63. • a wiki example app implemented in all frameworks I could find • + in ActiveRecord for comparison DISCLAIMER: implementations are insecure, have bugs and aren’t meant for production at all
    64. http://github.com/langalex/couchdb_example_wiki
    65. Example Wiki • a few simple features • create a page • add new pages by clicking on a CamelCase link • list of pages
    66. Example Wiki • and a few special cases • keep history of each page, browse old versions • statistics: count occurrences of all words in all pages
    67. Example Wiki • creating pages is easy • versioning, statistics harder • views are the source of CouchDB’s power
    68. let me show you how it works Example Wiki
    69. ActiveRecord Wiki
    70. routes.rb map.resources :pages do |pages| pages.resources :versions end map.resources :statistics map.root :controller => \"pages\", :action => 'show'
    71. page.rb class Page < ActiveRecord::Base acts_as_versioned def to_param title end end
    72. pages/show.html.erb <%= <%= simple_format linkify(@page.body) %> simple_format linkify(@page.body) %> def linkify(text) text.gsub(/([A-Z][a-z]+([A-Z][a-z]+)+)/) do link_to($1, page_path($1)) end end replace CamelCase words with links to #show
    73. pages_controller.rb def show @page = Page.first unless params[:id] @page ||= Page.find_by_title params[:id] redirect_to new_page_path(:title => params[:id]) unless @page end redirect to #new if no page found
    74. statistics def self.word_counts Page.all.map(&:body).join(\" \").split(/\\s +/).grep(/\\w+/i).inject(Hash.new(0)) do |res, word| res[word] += 1 res end end
    75. schema.rb create_table \"page_versions\", :force => true do |t| t.integer \"page_id\" t.integer \"version\" t.text \"body\" t.datetime \"created_at\" t.datetime \"updated_at\" end create_table \"pages\", :force => true do |t| t.string \"title\" t.text \"body\" t.datetime \"created_at\" t.datetime \"updated_at\" t.integer \"version\", :default => 1 end
    76. AR Summary • Page has_many PageVersions • ugly schema with duplicated table • acts_as_versioned does the magic for us • statistics - ?!?
    77. CouchDB Wiki How does it work?
    78. The Page { _id: “89765”, _rev: “lb7tlb”, type: “Page”, title: “page one”, body: “this is page one” }
    79. Page Versions { _id: “765”, _rev: “lhjb97” type: “PageVersion”, title: “page one”, body: “this is page one”, version: 23, page_id: “89765” }
    80. All in one namespace { { _id: “ 89765”, { _id: “ 9753”, _id: “97865”, _rev: “lb7tlb”, _rev: “lb7tlb”, _rev: “lhjb97” type: “Page”, type: “PageVersion”, type: “Page”, title: “page one”, title: “page one”, title: “page one”, body: “this is page one”, body: “this is page one” version: 23, body: “this is page one” page_id: “89765” } { } } _id: “6437”, _rev: “lhjb97” { type: “PageVersion”, _id: “6367”, title: “page one”, { { _rev: “lhjb97” body: “this is page one”, type: “PageVersion”, _id: “ 76538”, _id: “ 8975763”, version: 23, title: “page one”, page_id: “89765” _rev: “lb7tlb”, } _rev: “lb7tlb”, body: “this is page one”, version: 23, type: “Page”, type: “Page”, page_id: “89765” title: “page one”, title: “page one”, } body: “this is page one” body: “this is page one” } }
    81. Finding pages function(doc) { key value if(doc.type == “Page”) { emit(doc.title, doc); “page 2” {...} } } “page one” {...}
    82. Finding Page Versions function(doc) { if(doc.type == “PageVersion”) { emit([doc.page_id, doc.version], doc); } } key value [“ladsb7gi”, 1] {...} [“ladsb7gi”, 2] {...} [“nloh79d”, 1] {...}
    83. Finding Page Versions key value [“ladsb7gi”, 1] {...} [“ladsb7gi”, 2] {...} [“nloh79d”, 1] {...} GET /mydb/_design/page_versions/_view/by_page? \\ startkey=[“ladsb7gi”, 1]&endkey=[“ ladsb7gi”,{}]
    84. Counting Words - Map
    85. Counting Words - Map {body: “page one”} {body: “page 2”}
    86. Counting Words - Map function(doc) { if(doc.type == 'Page') { var words = doc.body.split(/\\\\W/); words.forEach(function(word) { if (word.length > 0) emit(word, 1); });}} {body: “page one”} {body: “page 2”}
    87. Counting Words - Map function(doc) { if(doc.type == 'Page') { var words = doc.body.split(/\\\\W/); words.forEach(function(word) { if (word.length > 0) emit(word, 1); });}} key value “page” 1 {body: “page one”} “page” 1 {body: “page 2”} “one” 1 “2” 1
    88. Counting Words - reduce
    89. Counting Words - reduce key value “page” 1 “page” 1 “one” 1 “2” 1
    90. Counting Words - reduce key value “page” 1 “page” 1 “one” 1 “2” 1 function(keys, values) { return sum(values); }
    91. Counting Words - reduce key value “page” 1 “page” 1 “one” 1 “2” 1 key value “page” 2 function(keys, values) { return sum(values); “one” 1 } “2” 1
    92. CouchDB summary • no schema, arbitrary documents in one namespace • still use foreign keys to implement associations • create views instead of join tables • views! views! views!
    93. Show us the frameworks already
    94. What’s the framework’s job?
    95. What’s the framework’s job? ActiveRecord
    96. What’s the framework’s job? ActiveRecord • map objects to relations and back • do the whole SQL thing
    97. What’s the framework’s job? ActiveRecord schema attribute auto tracking detection serialized attributes pagination groups JOINS unique lazy loading caching • map objects to relations and back count • do the whole SQL thing HABTM create or update? has_many :through conditions eager association loading connection DDL :dependent => :destroy
    98. What’s the framework’s job? ActiveRecord Page.all :include => :tags SELECT pages.id ... JOIN tags ON ... WHERE ... ... [10 more lines] ...
    99. What’s the framework’s job? ActiveRecord big fat abstraction SQL
    100. What’s the framework’s job? ActiveCouchRelaxFooDBObject
    101. What’s the framework’s job? ActiveCouchRelaxFooDBObject <#134 Page title=”page one”> {type: “Page”, title: “page one”}
    102. What’s the framework’s job? ActiveCouchRelaxFooDBObject POST /mydb/, {title: “page one”, type: “Page”} GET /mydb/page-one
    103. What’s the framework’s job? ActiveCouchRelaxFooDBObject skinny CouchDB abstraction
    104. ActiveCouchRelaxFooDBObject ... are not *that* important
    105. The frameworks CouchPoato RelaxDB CouchObject ActiveCouch CouchRest CouchFoo
    106. CouchRest • 2 in 1 • foundation for most other frameworks
    107. Low level part • relatively thin layer on top of RestClient • store and retrieve JSON structures • query views the Couch way
    108. Class mapping part • map Ruby classes to JSON documents • CRUD • declarative views with CouchDB semantics
    109. RelaxDB • CRUD + very basic associations • automatic view generation via view_by • a bit of support for custom views via RelaxDB::View • CouchDB like view API
    110. Couch Object • last updated in 2007 • pretty low level - okay for learning the details of Couch the DIY way • no update, no properties, no automatic view creation
    111. Couch Potato • CRUD, associations + JSON mapping • built-in acts_as_versioned - 60 LOC but doing it by hand only requires 7 • ViewQuery class for creating/querying custom views • AR like finders
    112. CouchFoo • takes ActiveRecord and makes it work with CouchDB • if you (have) to migrate an AR app... • doesn’t give you the power of CouchDB
    113. ActiveCouch • “Object Relational Mapper for [..] CouchDB” • “Since, the Rubyists here at Wego are already very familiar with ActiveRecord semantics, care has been taken to ensure that ActiveCouch resembled it in many ways.”
    114. ActiveCouch • one database per model • View class to upload #@!? views via Rake task • no support for custom views
    115. Use the source
    116. CouchRest Wiki
    117. Page CRUD class Page < CouchRest::ExtendedDocument update_callback :after, :create_version property :title can’t infer attributes from table property :body view_by :title auto-generate simple views def create_version PageVersion.new(:page_id => id, :body => @body_was, :version => versions_count + 1).save! end create version on update end
    118. PageVersion class PageVersion < CouchRest::ExtendedDocument property :body property :version property :page_id view_by [:page_id, :version] end
    119. Word Count class WordCount < CouchRest::ExtendedDocument view_by :all, :map => \"function(doc) { if(doc['couchrest-type'] == 'Page') { var words = doc.body.split(/\\\\W/); words.forEach(function(word) { if (word.length > 0) emit(word, 1); }); } }\", :reduce => \"function(keys, values) { return sum(values); }\" end
    120. Querying Views Page.by_title Page.by_created_at(:limit => 1) PageVersion.get params[:id] Page.by_title(:key => title, :limit => 1).first WordCount.all
    121. One more thing
    122. CouchApp • serve entire apps directly from CouchDB • just JSON, HTML & JavaScript
    123. What is CouchApp • bunch of Ruby Python scripts to help with development/deployment • data, CouchDB views, validations, shows, lists and assets in one database
    124. AJAX apps • serve HTML, CSS as assets • do all the work in JavaScript • in the browser: GET from couch and append HTML, POST form data to CouchDB to update documents • in CouchDB: views to retrieve, compute data, validations
    125. “real” apps • lists • shows • server HTML, XML etc. from CouchDB
    126. Conclusion
    127. DON’T use ActiveCouch unless you understand why it is the way it is or Couch Potato I’ll break all of its bones and APIS
    128. DON’T or CouchFoo unless you want more power than AR can give you
    129. Conclusion forgetting about the ActiveRecord way is more important than what framework
    130. Conclusion think in documents & views, not in records and associations
    131. Conclusion CouchDB is not about finding your records, it’s about clever map/reduce to get exactly what you want
    132. What you want is a thin abstraction CouchDB semantics, not ActiveRecord start simple with CouchREST or RelaxDB
    133. and relax... time to relax
    134. Resources • The CouchDB book http://books.couchdb.org/relax/ • jchris CouchApp talk http://jchrisa.net/drl/CouchDB%20Talk%20at%20Vidoop/ VidoopCouchTalk.pdf • janl CouchDB talk http://www.slideshare.net/bbcwebdev/introduction-into-couchdb- jan-lehnardt-presentation • The example wiki http://github.com/langalex/couchdb_example_wiki/ • http://couch.io support, training, hosting, development
    135. Questions? • Email: alex@upstream-berlin.com • Twitter: @langalex time to relax

    + langalexlangalex, 8 months ago

    custom

    2629 views, 7 favs, 0 embeds more stats

    The talk gives an introduction to CouchDB by showin more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 2629
      • 2629 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 7
    • Downloads 53
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories