Enable Labs @mark_menard
A Tour of Wyriki
Mark Menard
Ruby Nation!
June 7, 2014
@mark_menard !
Enable Labs
Enable Labs @mark_menard
Jim Weirich
Enable Labs @mark_menardhttp://www.flickr.com/photos/langalex
Enable Labs @mark_menard
TDD
Enable Labs @mark_menard
Yea…
whatever…
Enable Labs @mark_menard
What is Wyriki?
Enable Labs @mark_menard
The Wyriki Domain
Page
Wiki
*
1
Create Wiki
Create Page
Update
Page
Create User
Loged
In User
Ano...
Enable Labs @mark_menard
Business Logic
ActiveRecord
ActionPack
Controllers
MySQL MongoDB PostgreSQL
Redis
Sidekiq
Resque
...
Enable Labs @mark_menard
Testing
Enable Labs @mark_menard
Why?!
!
When?
Enable Labs @mark_menard
Typical Rails
Enable Labs @mark_menard
Create Page
Loged
In User
Action
Controller ::
Base
ActiveRecord
:: Base
Pages
Controller
Applica...
Enable Labs @mark_menard
Create Page
Loged
In User
Action
Controller ::
Base
ActiveRecord
:: Base
Pages
Controller
Applica...
Enable Labs @mark_menard
Create Page
Loged
In User
Action
Controller ::
Base
ActiveRecord
:: Base
Pages
Controller
Applica...
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
@wiki = Wiki.find(params[:wiki_id])
@page = @wik...
Enable Labs @mark_menard
Wyriki Style
Enable Labs @mark_menard
Runners
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = NamedCallbacks.n...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
...
Enable Labs @mark_menard
Enable Labs @mark_menard
Runners
Enable Labs @mark_menard
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
This is the !
Domain
Enable Labs @mark_menard
This is the !
Domain
This is Rails
Enable Labs @mark_menard
This is our Context.
Enable Labs @mark_menard
# app/controllers/page_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on...
Enable Labs @mark_menard
# app/controllers/page_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on...
Enable Labs @mark_menard
# app/controllers/page_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |on...
Enable Labs @mark_menard
# app/runners/page_runners.rb
class Create < Runner
def run(wiki_id, page_params)
wiki = Wiki.fin...
Enable Labs @mark_menard
# app/runners/page_runners.rb
class Create < Runner
def run(wiki_id, page_params)
wiki = Wiki.fin...
Enable Labs @mark_menard
# app/runners/page_runners.rb
class Create < Runner
def run(wiki_id, page_params)
wiki = Wiki.fin...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
Enough Architecture! !
What about the Ruby!!
!
How did Jim actually !
do the callbacks and the
ru...
Enable Labs @mark_menard
Runner
Named
Callbacks
<<protocol>>
context
<<protocol>>
Repo
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |o...
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |o...
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |o...
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = ...
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = ...
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = ...
Enable Labs @mark_menard
# app/runners/runner.rb
class Runner
attr_reader :context
!
def initialize(context)
@callbacks = ...
Enable Labs @mark_menard
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def me...
Enable Labs @mark_menard
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def me...
Enable Labs @mark_menard
# app/runners/named_callbacks.rb
class NamedCallbacks
def initialize
@callbacks = {}
end
!
def me...
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |o...
Enable Labs @mark_menard
# app/controllers/pages_controller.rb
def create
run(Create, params[:wiki_id], page_params) do |o...
Enable Labs @mark_menard
Some Lessons
Enable Labs @mark_menard
Repositories
Enable Labs @mark_menard
Domain Rails
Enable Labs @mark_menard
Enable Labs @mark_menard
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
# app/services/wiki_repository.rb
class WikiRepository
include Repo::UserMethods
include Repo::Wi...
Enable Labs @mark_menard
# app/services/repo/page_methods.rb
module PageMethods
def find_wiki_page(wiki_id, page_id)
wiki ...
Enable Labs @mark_menard
Domain
Enable Labs @mark_menard
Biz Objects
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Page
Wiki
C...
Enable Labs @mark_menard
Biz Model
ActiveRecord
:: Base
Simple
Delegator
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
de...
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
de...
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
de...
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
de...
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
de...
Enable Labs @mark_menard
# app/models/biz/model.rb
module Biz
class Model < SimpleDelegator
include BlockActiveRecord
!
de...
Enable Labs @mark_menard
# app/services/repo/page_methods.rb
module PageMethods
def find_wiki_page(wiki_id, page_id)
wiki ...
Enable Labs @mark_menard
# app/services/repo/page_methods.rb
module PageMethods
def find_wiki_page(wiki_id, page_id)
wiki ...
Enable Labs @mark_menard
module Biz
class Page < Model
def wiki
Biz::Wiki.wrap(super)
end
!
def html_content(context)
Kram...
Enable Labs @mark_menard
module Biz
class Page < Model
def wiki
Biz::Wiki.wrap(super)
end
!
def html_content(context)
Kram...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
...
Enable Labs @mark_menard
Action
Controller ::
Base
ActiveRecord
:: Base
Page
Controller
Application
Controller
Some Model
...
Enable Labs @mark_menard
More Lessons
Enable Labs @mark_menard
Why?
Enable Labs @mark_menard
Isolated Business Logic
Enable Labs @mark_menard
Incremental Approach
Enable Labs @mark_menard
Fast Tests
Enable Labs @mark_menard
$ time rspec spec/runners spec/models/biz (git)-[master]
...........................................
Enable Labs @mark_menard
Should we decouple?
Enable Labs @mark_menard
http://www.flickr.com/photos/dwortlehock/
Thanks for Everything Jim!
Enable Labs @mark_menard
Start Today
http://www.enablelabs.com/
mark@enablelabs.com
866-895-8189
Enable Labs
@mark_menard
Upcoming SlideShare
Loading in...5
×

A Tour of Wyriki

300

Published on

Jim Weirich gave us many things. Among his last was Wyriki, a small Rails app described in his own words as an "Experimental Rails application to explore decoupling app logic from Rails." Many of us paid our final respects to Jim on his last commit to this project. Now it's time to learn from it.

In this talk we'll explore how Jim applied the principles of Object Oriented Design to achieve his goals of decoupling; look at how he used decoupling to speed up testing; how decoupling improved and simplified his tests; and look at his design style. Jim's legacy leaves a lot to learn from, let's do it.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
300
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
2
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

A Tour of Wyriki

  1. 1. Enable Labs @mark_menard A Tour of Wyriki Mark Menard Ruby Nation! June 7, 2014 @mark_menard ! Enable Labs
  2. 2. Enable Labs @mark_menard Jim Weirich
  3. 3. Enable Labs @mark_menardhttp://www.flickr.com/photos/langalex
  4. 4. Enable Labs @mark_menard TDD
  5. 5. Enable Labs @mark_menard Yea… whatever…
  6. 6. Enable Labs @mark_menard What is Wyriki?
  7. 7. Enable Labs @mark_menard The Wyriki Domain Page Wiki * 1 Create Wiki Create Page Update Page Create User Loged In User Anony mous User
  8. 8. Enable Labs @mark_menard Business Logic ActiveRecord ActionPack Controllers MySQL MongoDB PostgreSQL Redis Sidekiq Resque What was Jim trying to accomplish?
  9. 9. Enable Labs @mark_menard Testing
  10. 10. Enable Labs @mark_menard Why?! ! When?
  11. 11. Enable Labs @mark_menard Typical Rails
  12. 12. Enable Labs @mark_menard Create Page Loged In User Action Controller :: Base ActiveRecord :: Base Pages Controller Application Controller Page Wiki
  13. 13. Enable Labs @mark_menard Create Page Loged In User Action Controller :: Base ActiveRecord :: Base Pages Controller Application Controller Page Wiki
  14. 14. Enable Labs @mark_menard Create Page Loged In User Action Controller :: Base ActiveRecord :: Base Pages Controller Application Controller Page Wiki
  15. 15. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create @wiki = Wiki.find(params[:wiki_id]) @page = @wiki.pages.new(page_params) if @page.save redirect_to [@wiki, @page], notice: "#{@page.name} created" else render :new end end
  16. 16. Enable Labs @mark_menard Wyriki Style
  17. 17. Enable Labs @mark_menard Runners class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! def repo context.repo end ! def success(*args) callback(:success, *args) end ! def failure(*args) callback(:failure, *args) end ! def callback(name, *args) @callbacks.call(name, *args) args end end class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end ! def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end !end Business Models Repositories module UserMethods def all_users Biz::User.wraps(User.all_users) end ! def new_user(attrs={}) Biz::User.wrap(User.new(attrs)) end ! def find_user(user_id) Biz::User.wrap(User.find(user_id)) end ! def save_user(user) user.data.save end ! def update_user(user, attrs) user.data.update_attributes(attrs) end ! def destroy_user(user_id) User.destroy(user_id) end end
  18. 18. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context <<protocol>> Biz Page <<protocol>> Biz Wiki Biz::Wiki Biz::Page <<protocol>> Wiki Data <<protocol>> Page Data <<wraps>> <<wraps>>
  19. 19. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >> << gets and saves stuff >>
  20. 20. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >> << gets and saves stuff >>
  21. 21. Enable Labs @mark_menard
  22. 22. Enable Labs @mark_menard Runners
  23. 23. Enable Labs @mark_menard
  24. 24. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> context Rails Not Rails Create Page Loged In User
  25. 25. Enable Labs @mark_menard This is the ! Domain
  26. 26. Enable Labs @mark_menard This is the ! Domain This is Rails
  27. 27. Enable Labs @mark_menard This is our Context.
  28. 28. Enable Labs @mark_menard # app/controllers/page_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  29. 29. Enable Labs @mark_menard # app/controllers/page_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  30. 30. Enable Labs @mark_menard # app/controllers/page_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  31. 31. Enable Labs @mark_menard # app/runners/page_runners.rb class Create < Runner def run(wiki_id, page_params) wiki = Wiki.find(params[:wiki_id]) page = wiki.pages.new(page_params) if page.save success(page) else failure(wiki, page) end end end
  32. 32. Enable Labs @mark_menard # app/runners/page_runners.rb class Create < Runner def run(wiki_id, page_params) wiki = Wiki.find(params[:wiki_id]) page = wiki.pages.new(page_params) if page.save success(page) else failure(wiki, page) end end end # app/controllers/page_controller.rb def create Create.new(self, params[:wiki_id], page_params).run do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  33. 33. Enable Labs @mark_menard # app/runners/page_runners.rb class Create < Runner def run(wiki_id, page_params) wiki = Wiki.find(params[:wiki_id]) page = wiki.pages.new(page_params) if page.save success(page) else failure(wiki, page) end end end # app/controllers/page_controller.rb def create Create.new(self, params[:wiki_id], page_params).run do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  34. 34. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> context Rails Not Rails Create Page Loged In User
  35. 35. Enable Labs @mark_menard Enough Architecture! ! What about the Ruby!! ! How did Jim actually ! do the callbacks and the runners?
  36. 36. Enable Labs @mark_menard Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  37. 37. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  38. 38. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  39. 39. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  40. 40. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! def repo context.repo end ! def success(*args) callback(:success, *args) end ! def failure(*args) callback(:failure, *args) end ! def callback(name, *args) @callbacks.call(name, *args) args end end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  41. 41. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! def repo context.repo end ! def success(*args) callback(:success, *args) end ! def failure(*args) callback(:failure, *args) end ! def callback(name, *args) @callbacks.call(name, *args) args end end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Runner Named Callbacks <<protocol>> context <<protocol>> Repo
  42. 42. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! # … end # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  43. 43. Enable Labs @mark_menard # app/runners/runner.rb class Runner attr_reader :context ! def initialize(context) @callbacks = NamedCallbacks.new @context = context yield(@callbacks) if block_given? end ! # … end # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  44. 44. Enable Labs @mark_menard # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  45. 45. Enable Labs @mark_menard # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  46. 46. Enable Labs @mark_menard # app/runners/named_callbacks.rb class NamedCallbacks def initialize @callbacks = {} end ! def method_missing(sym, *args, &block) @callbacks[sym] = block end ! # … end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end
  47. 47. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Weirich Block Style
  48. 48. Enable Labs @mark_menard # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end # app/controllers/pages_controller.rb def create run(Create, params[:wiki_id], page_params) do |on| on.success { |page| redirect_to [page.wiki, page], notice: "#{page.name} created" } on.failure { |wiki, page| render :new } end end Weirich Block Style
  49. 49. Enable Labs @mark_menard Some Lessons
  50. 50. Enable Labs @mark_menard Repositories
  51. 51. Enable Labs @mark_menard Domain Rails
  52. 52. Enable Labs @mark_menard
  53. 53. Enable Labs @mark_menard
  54. 54. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context
  55. 55. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  56. 56. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  57. 57. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  58. 58. Enable Labs @mark_menard # app/services/wiki_repository.rb class WikiRepository include Repo::UserMethods include Repo::WikiMethods include Repo::PageMethods include Repo::PermissionMethods end
  59. 59. Enable Labs @mark_menard # app/services/repo/page_methods.rb module PageMethods def find_wiki_page(wiki_id, page_id) wiki = Wiki.find(wiki_id) page = wiki.pages.find(page_id) ! # … end ! # … ! def save_page(page) page.data.save end ! # … end
  60. 60. Enable Labs @mark_menard Domain
  61. 61. Enable Labs @mark_menard Biz Objects
  62. 62. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Page Wiki Create Page Runner <<protocol>> Repo Repo <<protocol>> context Domain
  63. 63. Enable Labs @mark_menard Biz Model ActiveRecord :: Base Simple Delegator
  64. 64. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  65. 65. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  66. 66. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  67. 67. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  68. 68. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  69. 69. Enable Labs @mark_menard # app/models/biz/model.rb module Biz class Model < SimpleDelegator include BlockActiveRecord ! def data datum = self while datum.biz? datum = datum.__getobj__ end datum end ! def ==(other) if other.respond_to?(:data) data == other.data else data == other end end def biz? true end ! def class data.class end ! def self.wrap(model) model ? new(model) : nil end ! def self.wraps(models) models.map { |model| wrap(model) } end ! end end
  70. 70. Enable Labs @mark_menard # app/services/repo/page_methods.rb module PageMethods def find_wiki_page(wiki_id, page_id) wiki = Wiki.find(wiki_id) page = wiki.pages.find(page_id) Biz::Page.wrap(page) end ! # … ! def save_page(page) page.data.save end ! # … end
  71. 71. Enable Labs @mark_menard # app/services/repo/page_methods.rb module PageMethods def find_wiki_page(wiki_id, page_id) wiki = Wiki.find(wiki_id) page = wiki.pages.find(page_id) Biz::Page.wrap(page) end ! # … ! def save_page(page) page.data.save end ! # … end
  72. 72. Enable Labs @mark_menard module Biz class Page < Model def wiki Biz::Wiki.wrap(super) end ! def html_content(context) Kramdown::Document.new(referenced_content(context)).to_html end ! def referenced_content(context) content.gsub(/(([A-Z][a-z0-9]+){2,})/) { |page_name| if wiki.page?(context.repo, page_name) "[#{page_name}](#{context.named_page_path(wiki.name,page_name)})" elsif context.current_user.can_write?(wiki) "#{page_name}[?](#{context.new_named_page_path(wiki.name, page_name)})" else page_name end } end end end
  73. 73. Enable Labs @mark_menard module Biz class Page < Model def wiki Biz::Wiki.wrap(super) end ! def html_content(context) Kramdown::Document.new(referenced_content(context)).to_html end ! def referenced_content(context) content.gsub(/(([A-Z][a-z0-9]+){2,})/) { |page_name| if wiki.page?(context.repo, page_name) "[#{page_name}](#{context.named_page_path(wiki.name,page_name)})" elsif context.current_user.can_write?(wiki) "#{page_name}[?](#{context.new_named_page_path(wiki.name, page_name)})" else page_name end } end end end
  74. 74. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >>
  75. 75. Enable Labs @mark_menard Action Controller :: Base ActiveRecord :: Base Page Controller Application Controller Some Model Runner Repo Biz Model << wraps >>
  76. 76. Enable Labs @mark_menard More Lessons
  77. 77. Enable Labs @mark_menard Why?
  78. 78. Enable Labs @mark_menard Isolated Business Logic
  79. 79. Enable Labs @mark_menard Incremental Approach
  80. 80. Enable Labs @mark_menard Fast Tests
  81. 81. Enable Labs @mark_menard $ time rspec spec/runners spec/models/biz (git)-[master] ...................................................................................................... ! Finished in 0.17573 seconds 102 examples, 0 failures rspec spec/runners spec/models/biz 0.61s user 0.07s system 99% cpu 0.683 total
  82. 82. Enable Labs @mark_menard Should we decouple?
  83. 83. Enable Labs @mark_menard http://www.flickr.com/photos/dwortlehock/ Thanks for Everything Jim!
  84. 84. Enable Labs @mark_menard Start Today http://www.enablelabs.com/ mark@enablelabs.com 866-895-8189 Enable Labs @mark_menard
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×