• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Rotterdam.rb   Domain Driven Design
 

Rotterdam.rb Domain Driven Design

on

  • 2,996 views

A presentation about Domain Driven Design with examples in Ruby. Inspired by the talk by Pat Maddox on RailsConf 2010.

A presentation about Domain Driven Design with examples in Ruby. Inspired by the talk by Pat Maddox on RailsConf 2010.

Statistics

Views

Total Views
2,996
Views on SlideShare
2,817
Embed Views
179

Actions

Likes
8
Downloads
21
Comments
0

4 Embeds 179

http://rotterdam-rb.org 174
http://www.linkedin.com 3
http://feeds.feedburner.com 1
https://www.linkedin.com 1

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 />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Rotterdam.rb   Domain Driven Design Rotterdam.rb Domain Driven Design Presentation Transcript

  • Domain Driven Design
  • Iain Hecker • Ruby developer at Finalist IT Group • 4 years of Ruby experience • Contributed to Rails core / i18n • 9 gems released • http://iain.nl • http://github.com/iain • @iain_nl
  • the problem
  • symptoms • maintaining code is annoying • adding features is a pain • development speed is low • system is unstable, but you don't exactly know why • inconsistency and side effects fuck everything up • fear of upgrading • "I'm not touching that code!"
  • complexity
  • two categories of complexity
  • accidental complexity vs. essential complexity
  • "I need to do ..... because the code needs ....." vs. "I need to do ..... because the business needs ....."
  • lower accidental complexity • use great frameworks (like Rails) • test all the fucking time • refactor all the fucking time • use programming patterns (like MVC) • pair-programming
  • domain-driven design
  • it's a book!
  • "Tackling Complexity in the Heart of Software"
  • organizing essential complexity
  • actions to organize complexity • use the right language • finding the core domain • set the proper boundaries • find the right models
  • the right language
  • ubiquitous language technical terms domain model terms business terms
  • refactor when you got the name wrong
  • organizing complexity
  • example: local government
  • AgreementReference AgreementSubscription AgreementType Agreement
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType User Agreement
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search Party Department Person Group Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Group Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • high complexity
  • no clear structure
  • risk of side effects
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • bounded contexts • boundaries lower complexity • different contexts can interfere • leaking between boundaries is called coupling • side effects are bound to one context
  • prioritize your design
  • domain types • core domains • support domains • generic support domains
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • As an council member (gemeenteraadslid) I can see which agreements have been made So I can supervise the execution of my policy
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • As a civil servant (ambtenaar) I can see which agreements have been made So I know what to work on
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • adding real value • find what is important for your users • invest time and effort in designing those core domains • slack your efforts in support domains • use existing products for generic support domains (like authentication)
  • models
  • models • describe a version of reality to solve a certain problem • do not represent technical terms like 'database tables' • have a meaning in the business domain
  • AgreementReference RecentView UserSession AgreementSubscription AgreementType SearchSubscription User Agreement Search ProgressNote Party Department Mutation Person Meeting Group Notification Member
  • AgreementReference AgreementType AgreementSubscription User Agreement Search Mutation Party Meeting
  • Reference User Subscription Type Search Agreement Involvement Responsible Charger Charged Party Mutation Meeting
  • guarding your boundaries
  • Mexico - United States barrier
  • modular design
  • modular design != mixins
  • namespacing
  • not just about name clashing
  • organizing complexity
  • but what about overlap?
  • Reference user Subscription Type search Agreement Involvement Responsible Charger Charged party mutation meeting
  • Reference user Subscription Type search Agreement Involvement Responsible Charger Charged one normalized table party mutation meeting
  • how not to do it
  • module Agreement   class Involvement     has_one :charged,     :class_name => "Party::Group"     has_one :charger,     :class_name => "Party::Group"     has_one :responsible, :class_name => "Party::Group"   end end module Party   class Group < ActiveRecord::Base   end end
  • Reference user Subscription Type search Agreement Involvement Responsible Charger Charged party mutation meeting
  • not just 3 boundary violations
  • methods are shared too
  • module Agreement   class Involvement     def charger_busy?       charger.tasks.count > 4     end     def charged_busy?       charger.tasks.count > 0     end   end end
  • module Party   class Group < ActiveRecord::Base     def busy_charger?       tasks.count > 4     end     def busy_charged?       tasks.count > 0     end   end end
  • module Party   class Group < ActiveRecord::Base     def busy?(charger = true)       tasks.count > (charger ? 4 : 0)     end   end end
  • one simple breach of the boundary can cause a lot of pain
  • a better way
  • class Group < ActiveRecord::Base end module Agreement   class Involvement     has_one :charged     has_one :charger     has_one :responsible   end   class Charged < Group   end   class Charger < Group   end   class Responsible < Group   end end
  • } class Group < ActiveRecord::Base end module Agreement   class Involvement     has_one :charged     has_one :charger domain logic     has_one :responsible   end   class Charged < Group   end   class Charger < Group   end   class Responsible < Group   end end
  • } implementation detail } class Group < ActiveRecord::Base end module Agreement   class Involvement     has_one :charged     has_one :charger domain logic     has_one :responsible   end   class Charged < Group   end   class Charger < Group   end   class Responsible < Group   end end
  • class Group < ActiveRecord::Base   delegate :count, :to => :tasks, :prefix => true end module Agreement   class Charged < Group     def busy?       tasks_count > 0     end   end   class Charger < Group     def busy?       tasks_count > 4     end   end end
  • there are other benefits too!
  • some (unrelated) problems of bleeding boundaries
  • class Post < ActiveRecord::Base   scope :published, where(:published => true) end class PostsController < ApplicationController   respond_to :html   def index     respond_with(@posts = Post.published)   end   def show     respond_with(@post = Post.published.find(params[:id]))   end end
  • class Post < ActiveRecord::Base   scope :published, where(:published => true)   scope :visible, where(:visible => true) end class PostsController < ApplicationController   respond_to :html   def index     respond_with(@posts = Post.published.visible.all)   end   def show     respond_with(@post = Post.published.visible.find(params[:id])   end end
  • class Post < ActiveRecord::Base   scope :published, where(:published => true)   scope :visible, where(:visible => true)   scope :for_frontend, published.visible end class PostsController < ApplicationController   respond_to :html   def index     respond_with(@posts = Post.for_frontend.all)   end   def show     respond_with(@post = Post.for_frontend.find(params[:id])   end end
  • default scope would be nice
  • but that introduces a lot of complexity for admins
  • "the local representative pattern" term coined right now by me
  • # app/models/frontend/post.rb module Frontend   class Post < ::Post     default_scope published.visible   end end # app/controllers/frontend/posts_controller.rb module Frontend   class PostsController     respond_to :html     def index       respond_with(@posts = Post.all)     end     def show       respond_with(@post = Post.find(params[:id]))     end   end end
  • module PersonalModel   extend ActiveSupport::Concern   included do     attr_accessor  :current_user module Public     before_update :check_current_user   class Comment < ::Comment     before_destroy :check_current_user     include PersonalModel   end     attr_accessible :body   end   def owned_record? end     current_user == user   end   def check_current_user     raise UnauthorizedUserError.new(self) unless owned_record?   end end
  • works great for • (default) scopes • validations • attr_protected / attr_accessible • associations • any other piece of code
  • problems • introduces problems with identity • getting the right objects • Rails conventions
  • class Comment < ActiveRecord::Base end module Frontend   class Comment < ::Comment   end end Comment.first != Frontend::Comment.first
  • class Public::CommentsController < ApplicationController   respond_to :html   def new     respond_with(@comment = Comment.new)   end end
  • class Public::CommentsController < ApplicationController   respond_to :html   def new     respond_with(@comment = Comment.new)   end end module Public   class CommentsController < ApplicationController     respond_to :html     def new       respond_with(@comment = Comment.new)     end   end end
  • = form_for Comment.new do |f|   = f.text_field :body <form action="/comments" method="post">   <input type="text" name="comment[body]" id="comment_body" /> </form>
  • = form_for Comment.new do |f|   = f.text_field :body <form action="/comments" method="post">   <input type="text" name="comment[body]" id="comment_body" /> </form> = form_for @comment do |f|   = f.text_field :body <form action="/public/comments" method="post">   <input type="text" name="public_comment[body]" id="public_comment_body" /> </form>
  • conclusion
  • divide and conquer
  • keep accidental complexity to a minimum
  • essential complexity needs to be clear and organized
  • fix leaking contexts
  • prioritize on what you design perfectly
  • don't lose sight of reality
  • !ink ab"t it!